diff options
| author | Dennis Camera <skonfig@dtnr.ch> | 2022-08-19 23:48:48 +0200 |
|---|---|---|
| committer | Dennis Camera <skonfig@dtnr.ch> | 2022-08-19 23:48:48 +0200 |
| commit | ccb0ff5437495985b585439be935ec0e956cf68d (patch) | |
| tree | f5a5758b8328a92d5177096daf42fcd3c894e782 | |
| parent | 862ced7ee59ace6fb68ff7ec48e41ac3eb69c3bc (diff) | |
| download | skonfig-c-ccb0ff5437495985b585439be935ec0e956cf68d.tar.gz skonfig-c-ccb0ff5437495985b585439be935ec0e956cf68d.zip | |
Implement creation of local temporary workdir
| -rw-r--r-- | configure.ac | 8 | ||||
| -rw-r--r-- | src/run.c | 159 | ||||
| -rw-r--r-- | src/run.h | 2 |
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( @@ -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); @@ -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; |
