summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Camera <skonfig@dtnr.ch>2022-08-19 23:48:48 +0200
committerDennis Camera <skonfig@dtnr.ch>2022-08-19 23:48:48 +0200
commitccb0ff5437495985b585439be935ec0e956cf68d (patch)
treef5a5758b8328a92d5177096daf42fcd3c894e782
parent862ced7ee59ace6fb68ff7ec48e41ac3eb69c3bc (diff)
downloadskonfig-c-ccb0ff5437495985b585439be935ec0e956cf68d.tar.gz
skonfig-c-ccb0ff5437495985b585439be935ec0e956cf68d.zip
Implement creation of local temporary workdir
-rw-r--r--configure.ac8
-rw-r--r--src/run.c159
-rw-r--r--src/run.h2
3 files changed, 159 insertions, 10 deletions
diff --git a/configure.ac b/configure.ac
index d87a1ac..a0457ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,7 +88,13 @@ AC_TYPE_SIZE_T
AC_TYPE_UINT8_T
# Checks for library functions.
-AC_CHECK_FUNCS_ONCE([getenv getpwuid stat strncpy strncat])
+
+AC_CHECK_FUNCS_ONCE([getenv getpwuid stat])
+AC_CHECK_FUNCS_ONCE([strdup strncpy strncat])
+
+AC_CHECK_FUNCS_ONCE([mktemp mkdtemp tempnam])
+AC_CHECK_DECLS([mkdtemp, mktemp], [], [], [[#include <stdlib.h>]])
+AC_CHECK_DECLS([tempnam], [], [], [[#include <stdio.h>]])
# Add debug support
AC_ARG_ENABLE(
diff --git a/src/run.c b/src/run.c
index 1dcf609..875f6cc 100644
--- a/src/run.c
+++ b/src/run.c
@@ -2,10 +2,140 @@
#include "log.h"
+#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#include <sys/stat.h>
+#include <limits.h>
+#ifndef P_tmpdir
+#define P_tmpdir "/tmp"
+#endif
+
+#if HAVE_MKDTEMP && !HAVE_DECL_MKDTEMP
+extern char *mkdtemp(char *);
+#endif
+#if HAVE_MKTEMP && !HAVE_DECLMKTEMP
+extern char *mktemp(char *);
+#endif
+#if HAVE_TEMPNAM && !HAVE_DECL_TEMPNAM
+extern char *tempnam(const char *, const char *);
+#endif
+
+#ifndef P_tmpdir
+/* fallback */
+#define P_tmpdir "/tmp"
+#endif
+
+/**
+ * mktempdir:
+ * creates a temporary directory in a suitable location.
+ *
+ * @param dest: must be a pointer to a buffer of a least PATH_MAX+1 length.
+ * @return dest if a directory was created successfully, NULL otherwise.
+ */
+char *mktempdir(char *dest) {
+ static const char *pfx = "tmp";
+
+ for (size_t try = 1; try < TMP_MAX; ++try) {
+#if HAVE_MKDTEMP || HAVE_MKTEMP
+ if (PATH_MAX < snprintf(
+ dest, PATH_MAX+1, "%s/%sXXXXXX",
+ (getenv("TMPDIR") ? getenv("TMPDIR") : P_tmpdir),
+ pfx)) {
+ goto fail;
+ }
+
+#if HAVE_MKDTEMP
+ if (NULL != mkdtemp(dest)) {
+ return dest;
+ }
+#elif HAVE_MKTEMP
+ if (0 < strlen(mktemp(dest))) {
+ if (0 > mkdir(dest, S_IRWXU)) {
+ continue;
+ }
+ return dest;
+ } else if (errno = EINVAL) {
+ goto fail;
+ }
+#endif /* HAVE_MKTEMP */
+
+#elif HAVE_TEMPNAM
+ char *name = tempnam(NULL, pfx);
+ if (NULL == name) {
+ continue;
+ }
+
+ dest[PATH_MAX] = '\0';
+ (void)strncpy(dest, name, PATH_MAX);
+ free(name);
+
+ if (dest[PATH_MAX]) {
+ continue;
+ }
+
+ if (0 == mkdir(dest, S_IRWXU)) {
+ return dest;
+ }
+#else
+#error no implementation to create temporary directories
+#endif
+ }
+
+ goto fail; /* hack around error: label defined but not used */
+ fail:
+ sk_error("mktempdir failed: %s", dest);
+ return NULL;
+}
+
+/**
+ * sk_run_gen_workdir_path:
+ * determine the path to use for the local workdir and create it if necessary.
+ *
+ * @param config: config struct
+ * @param dest: pointer to a buffer of at least PATH_MAX+1 length.
+ * @return pointer to dest, on error: NULL
+ */
+char *sk_run_gen_workdir_path(struct sk_config *config, char *dest) {
+ dest[PATH_MAX] = '\0';
+
+ if (NULL != config->global.out_path) {
+ (void)strncpy(dest, config->global.out_path, PATH_MAX);
+ } else {
+ /* generate a random directory */
+ if (NULL == mktempdir(dest)) {
+ sk_error("local_workdir creation failed (%s): %s",
+ dest, "retries exhausted");
+ return NULL;
+ }
+ }
+
+ if (dest[PATH_MAX]) {
+ goto too_long;
+ }
+
+ return dest;
+
+ too_long:
+ sk_error("local_workdir too long: %s", dest);
+ return NULL;
+}
+
+sk_run_error sk_run_prepare_local_workdir(const char *target_host, const char *workdir) {
+ char *host_dir = pathjoin(workdir, target_host);
+
+ if (mkdir(host_dir, 0700)) {
+ sk_error("failed to create host directory (%s): %s",
+ host_dir, strerror(errno));
+ free(host_dir);
+ return SK_RUN_GENERIC_ERROR;
+ };
+
+ return SK_RUN_OK;
+}
sk_run_error sk_run_init_manifest(
const char *target_host, bool dry_run, struct sk_config *config) {
@@ -15,30 +145,43 @@ sk_run_error sk_run_init_manifest(
if (access(init_manifest, F_OK)) {
sk_error("cannot find initial manifest (%s): %s",
init_manifest, strerror(errno));
- return SK_RUN_ERROR_GENERIC;
+ return SK_RUN_GENERIC_ERROR;
}
sk_error("%s: running manifest not yet implemented.", target_host);
- return SK_RUN_ERROR_GENERIC;
+ return SK_RUN_GENERIC_ERROR;
+}
+
+sk_run_error sk_run_host(
+ const char *target_host, bool dry_run, struct sk_config *config) {
+ return SK_RUN_OK;
}
sk_run_error sk_run_start(
const char *target_host, bool dry_run, struct sk_config *config) {
sk_run_error rv = SK_RUN_OK;
+ if (1 < config->global.jobs) {
+ sk_warn("using multiple jobs is currently not implemented.");
+ }
+
if (NULL == target_host) {
- sk_error("Target host missing");
- return (rv = SK_RUN_ERROR_GENERIC);
+ sk_error("target host missing");
+ return (rv = SK_RUN_GENERIC_ERROR);
}
sk_info("%s: Starting configuration run", target_host);
- /* TODO: set up local cache paths */
-
- rv = sk_run_init_manifest(target_host, dry_run, config);
+ /* set up local cache paths */
+ char local_workdir[PATH_MAX+1];
+ if ((NULL == sk_run_gen_workdir_path(config, local_workdir))) {
+ return SK_RUN_GENERIC_ERROR;
+ }
+ sk_debug("%s: local work directory: %s", target_host, local_workdir);
+ sk_run_prepare_local_workdir(target_host, local_workdir);
- /* TODO: cleanup */
+ rv = sk_run_host(target_host, dry_run, config);
if (SK_RUN_OK != rv) {
sk_error("failed to configure the following host: %s", target_host);
diff --git a/src/run.h b/src/run.h
index 2dded89..d553b97 100644
--- a/src/run.h
+++ b/src/run.h
@@ -9,7 +9,7 @@
enum sk_run_error {
SK_RUN_OK = 0,
- SK_RUN_ERROR_GENERIC = 1,
+ SK_RUN_GENERIC_ERROR = 1,
SK_RUN_CONNECTION_ERROR = 2
};
typedef enum sk_run_error sk_run_error;