aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@users.noreply.github.com>2025-06-23 10:03:07 -0400
committerGitHub <noreply@github.com>2025-06-23 10:03:07 -0400
commitcc9f67b49f6e4d3eecdbee5f8c83733f6925540d (patch)
treeefa3a1ad9534583c7598594e6d0e2ee3e6dd91de
parent151b32e7715b8f96739b7732df58b622c6ee52ae (diff)
parentd9d34004fa98b214bedcdd867272fd8e03d4d4eb (diff)
downloadstasis-cc9f67b49f6e4d3eecdbee5f8c83733f6925540d.tar.gz
Merge pull request #110 from jhunkeler/dynamic-commands
Dynamic commands & fixups
-rw-r--r--src/lib/core/conda.c99
-rw-r--r--src/lib/core/include/conda.h2
-rw-r--r--src/lib/core/include/utils.h37
-rw-r--r--src/lib/core/template.c17
-rw-r--r--src/lib/core/utils.c31
-rw-r--r--src/lib/delivery/delivery_install.c54
6 files changed, 168 insertions, 72 deletions
diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c
index 44af34d..268b433 100644
--- a/src/lib/core/conda.c
+++ b/src/lib/core/conda.c
@@ -4,7 +4,7 @@
#include "conda.h"
-int micromamba(struct MicromambaInfo *info, char *command, ...) {
+int micromamba(const struct MicromambaInfo *info, char *command, ...) {
struct utsname sys;
uname(&sys);
@@ -24,7 +24,12 @@ int micromamba(struct MicromambaInfo *info, char *command, ...) {
sprintf(installer_path, "%s/latest", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
if (access(installer_path, F_OK)) {
- download(url, installer_path, NULL);
+ char *errmsg = NULL;
+ const long http_code = download(url, installer_path, &errmsg);
+ if (HTTP_ERROR(http_code)) {
+ fprintf(stderr, "download failed: %ld: %s\n", http_code, errmsg);
+ return -1;
+ }
}
char mmbin[PATH_MAX];
@@ -62,37 +67,38 @@ int micromamba(struct MicromambaInfo *info, char *command, ...) {
}
int python_exec(const char *args) {
- int result = -1;
const char *command_base = "python ";
- const size_t required_len = strlen(command_base) + strlen(args) + 1;
+ const char *command_fmt = "%s%s";
- char *command = calloc(required_len, sizeof(*command));
+ const int len = snprintf(NULL, 0, command_fmt, command_base, args);
+ char *command = calloc(len + 1, sizeof(*command));
if (!command) {
- SYSERROR("Unable to allocate %zu bytes for command string", required_len);
- return result;
+ SYSERROR("Unable to allocate %d bytes for command string", len);
+ return -1;
}
- snprintf(command, required_len, "%s%s", command_base, args);
+
+ snprintf(command, len + 1, command_fmt, command_base, args);
msg(STASIS_MSG_L3, "Executing: %s\n", command);
- result = system(command);
+ const int result = system(command);
guard_free(command);
return result;
}
int pip_exec(const char *args) {
- int result = -1;
const char *command_base = "python -m pip ";
- const size_t required_len = strlen(command_base) + strlen(args) + 1;
+ const char *command_fmt = "%s%s";
- char *command = calloc(required_len, sizeof(*command));
+ const int len = snprintf(NULL, 0, command_fmt, command_base, args);
+ char *command = calloc(len + 1, sizeof(*command));
if (!command) {
- SYSERROR("Unable to allocate %zu bytes for command string", required_len);
- return result;
+ SYSERROR("Unable to allocate %d bytes for command string", len);
+ return -1;
}
- snprintf(command, required_len, "%s%s", command_base, args);
+ snprintf(command, len + 1, command_fmt, command_base, args);
msg(STASIS_MSG_L3, "Executing: %s\n", command);
- result = system(command);
+ const int result = system(command);
guard_free(command);
return result;
}
@@ -199,7 +205,6 @@ int pkg_index_provides(int mode, const char *index, const char *spec) {
}
int conda_exec(const char *args) {
- char command[PATH_MAX];
const char *mamba_commands[] = {
"build",
"install",
@@ -224,15 +229,24 @@ int conda_exec(const char *args) {
}
}
- snprintf(command, sizeof(command) - 1, "%s %s", conda_as, args);
+ const char *command_fmt = "%s %s";
+ const int len = snprintf(NULL, 0, command_fmt, conda_as, args);
+ char *command = calloc(len + 1, sizeof(*command));
+ if (!command) {
+ return -1;
+ }
+
+ snprintf(command, len + 1, command_fmt, conda_as, args);
msg(STASIS_MSG_L3, "Executing: %s\n", command);
- return system(command);
+ const int result = system(command);
+ guard_free(command);
+ return result;
}
static int conda_prepend_bin(const char *root) {
char conda_bin[PATH_MAX] = {0};
- snprintf(conda_bin, sizeof(conda_bin) - 1, "%s/bin", root);
+ snprintf(conda_bin, sizeof(conda_bin), "%s/bin", root);
if (env_manipulate_pathstr("PATH", conda_bin, PM_PREPEND | PM_ONCE)) {
return -1;
}
@@ -242,7 +256,7 @@ static int conda_prepend_bin(const char *root) {
static int conda_prepend_condabin(const char *root) {
char conda_condabin[PATH_MAX] = {0};
- snprintf(conda_condabin, sizeof(conda_condabin) - 1, "%s/condabin", root);
+ snprintf(conda_condabin, sizeof(conda_condabin), "%s/condabin", root);
if (env_manipulate_pathstr("PATH", conda_condabin, PM_PREPEND | PM_ONCE)) {
return -1;
}
@@ -351,7 +365,7 @@ int conda_activate(const char *root, const char *env_name) {
return -1;
}
- snprintf(command, sizeof(command) - 1,
+ snprintf(command, sizeof(command),
"set -a\n"
"source %s\n"
"__conda_exe() (\n"
@@ -521,10 +535,8 @@ int conda_setup_headless() {
}
int conda_env_create_from_uri(char *name, char *uri, char *python_version) {
- char env_command[PATH_MAX];
char *uri_fs = NULL;
-
// Convert a bare system path to a file:// path
if (!strstr(uri, "://")) {
uri_fs = calloc(strlen(uri) + strlen("file://") + 1, sizeof(*uri_fs));
@@ -545,25 +557,50 @@ int conda_env_create_from_uri(char *name, char *uri, char *python_version) {
// We'll create a new file with the same random bits, ending with .yml
strcat(tempfile, ".yml");
char *errmsg = NULL;
- download(uri_fs ? uri_fs : uri, tempfile, &errmsg);
+ const long http_code = download(uri_fs ? uri_fs : uri, tempfile, &errmsg);
+ if (HTTP_ERROR(http_code)) {
+ if (errmsg) {
+ fprintf(stderr, "download failed: %ld: %s\n", http_code, errmsg);
+ guard_free(errmsg);
+ }
+ guard_free(uri_fs);
+ return -1;
+ }
guard_free(uri_fs);
// Rewrite python version
char spec[255] = {0};
- snprintf(spec, sizeof(spec) - 1, "- python=%s\n", python_version);
+ snprintf(spec, sizeof(spec), "- python=%s\n", python_version);
file_replace_text(tempfile, "- python\n", spec, 0);
- sprintf(env_command, "env create -n '%s' --file='%s'", name, tempfile);
- int status = conda_exec(env_command);
+ const char *fmt = "env create -n '%s' --file='%s'";
+ int len = snprintf(NULL, 0, fmt, name, tempfile);
+ char *env_command = calloc(len + 1, sizeof(*env_command));
+ if (!env_command) {
+ return -1;
+ }
+
+ snprintf(env_command, len + 1, fmt, name, tempfile);
+ const int status = conda_exec(env_command);
unlink(tempfile);
+ guard_free(env_command);
return status;
}
int conda_env_create(char *name, char *python_version, char *packages) {
- char env_command[PATH_MAX];
- sprintf(env_command, "create -n %s python=%s %s", name, python_version, packages ? packages : "");
- return conda_exec(env_command);
+ const char *fmt = "create -n %s python=%s %s";
+ const int len = snprintf(NULL, 0, fmt, name, python_version, packages ? packages : "");
+ char *env_command = calloc(len + 1, sizeof(*env_command));
+ if (!env_command) {
+ return -1;
+ }
+
+ snprintf(env_command, len + 1, fmt, name, python_version, packages ? packages : "");
+ const int result = conda_exec(env_command);
+ guard_free(env_command);
+
+ return result;
}
int conda_env_remove(char *name) {
diff --git a/src/lib/core/include/conda.h b/src/lib/core/include/conda.h
index ea8613f..f3d481c 100644
--- a/src/lib/core/include/conda.h
+++ b/src/lib/core/include/conda.h
@@ -38,7 +38,7 @@ struct MicromambaInfo {
* @param ... variadic arguments
* @return exit code
*/
-int micromamba(struct MicromambaInfo *info, char *command, ...);
+int micromamba(const struct MicromambaInfo *info, char *command, ...);
/**
* Execute Python
diff --git a/src/lib/core/include/utils.h b/src/lib/core/include/utils.h
index b405b2a..583a8b8 100644
--- a/src/lib/core/include/utils.h
+++ b/src/lib/core/include/utils.h
@@ -419,4 +419,41 @@ int gen_file_extension_str(char *filename, const char *extension);
char *remove_extras(char *s);
void debug_hexdump(char *data, int len);
+
+/**
+ * Realloc helper
+ *
+ * @code{.c}
+ * #include <stdio.h>
+ * #include <stdlib.h>
+ * #include <string.h>
+ * #include "utils.h"
+ *
+ * int main(int argc, char *argv[]) {
+ * size_t sz = 10;
+ * char *data = calloc(sz, sizeof(*data));
+ *
+ * // populate data
+ * strncat(data, "/path/to/", sz - 1);
+ *
+ * // Double the allocation size for data
+ * if (grow(sz * 2, &sz, &data)) {
+ * // memory error
+ * }
+ *
+ * // sz is now 20
+ * strncat(data, "filename", sz - 1 - strlen(data));
+ *
+ * puts(data);
+ * // output: "/path/to/filename"
+ * }
+ * @endcode
+ *
+ * @param size_new increase by `size_new` bytes
+ * @param size_orig address of variable containing the original allocation size (modified)
+ * @param data address to write data
+ * @return 0 on success
+ * @return -1 on error
+ */
+int grow(size_t size_new, size_t *size_orig, char **data);
#endif //STASIS_UTILS_H
diff --git a/src/lib/core/template.c b/src/lib/core/template.c
index ba45a5a..68d20c9 100644
--- a/src/lib/core/template.c
+++ b/src/lib/core/template.c
@@ -137,23 +137,6 @@ struct tplfunc_frame *tpl_getfunc(char *key) {
return result;
}
-static int grow(size_t z, size_t *output_bytes, char **output) {
- if (z >= *output_bytes) {
- size_t new_size = *output_bytes + z + 1;
- SYSDEBUG("template output buffer new size: %zu\n", new_size);
-
- char *tmp = realloc(*output, new_size);
- if (!tmp) {
- perror("realloc failed");
- return -1;
- } else if (tmp != *output) {
- *output = tmp;
- }
- *output_bytes = new_size;
- }
- return 0;
-}
-
char *tpl_render(char *str) {
if (!str) {
return NULL;
diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c
index a9c9ea5..f02a7ea 100644
--- a/src/lib/core/utils.c
+++ b/src/lib/core/utils.c
@@ -892,10 +892,11 @@ int gen_file_extension_str(char *filename, const char *extension) {
return replace_text(ext_orig, ext_orig, extension, 0);
}
+#define DEBUG_HEXDUMP_FMT_BYTES 6
#define DEBUG_HEXDUMP_ADDR_MAXLEN 20
#define DEBUG_HEXDUMP_BYTES_MAXLEN (16 * 3 + 2)
#define DEBUG_HEXDUMP_ASCII_MAXLEN (16 + 1)
-#define DEBUG_HEXDUMP_OUTPUT_MAXLEN (DEBUG_HEXDUMP_ADDR_MAXLEN + DEBUG_HEXDUMP_BYTES_MAXLEN + DEBUG_HEXDUMP_ASCII_MAXLEN + 1)
+#define DEBUG_HEXDUMP_OUTPUT_MAXLEN (DEBUG_HEXDUMP_FMT_BYTES + DEBUG_HEXDUMP_ADDR_MAXLEN + DEBUG_HEXDUMP_BYTES_MAXLEN + DEBUG_HEXDUMP_ASCII_MAXLEN + 1)
void debug_hexdump(char *data, int len) {
int count = 0;
@@ -936,10 +937,32 @@ void debug_hexdump(char *data, int len) {
// Add group padding
strcat(bytes, " ");
}
- int padding = 16 - count;
+ const int padding = 16 - count;
for (int i = 0; i < padding; i++) {
strcat(bytes, " ");
}
- sprintf(output, "%s | %s | %s", addr, bytes, ascii);
+ snprintf(output, DEBUG_HEXDUMP_FMT_BYTES + sizeof(addr) + sizeof(bytes) + sizeof(ascii), "%s | %s | %s", addr, bytes, ascii);
puts(output);
-} \ No newline at end of file
+}
+
+int grow(const size_t size_new, size_t *size_orig, char **data) {
+ if (!*data) {
+ return 0;
+ }
+ if (size_new >= *size_orig) {
+ const size_t new_size = *size_orig + size_new + 1;
+ SYSDEBUG("template data buffer new size: %zu\n", new_size);
+
+ char *tmp = realloc(*data, new_size);
+ if (!tmp) {
+ perror("realloc failed");
+ return -1;
+ }
+ if (tmp != *data) {
+ *data = tmp;
+ }
+ *size_orig = new_size;
+ }
+ return 0;
+}
+
diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c
index 7c900cb..b1de992 100644
--- a/src/lib/delivery/delivery_install.c
+++ b/src/lib/delivery/delivery_install.c
@@ -190,7 +190,6 @@ int delivery_purge_packages(struct Delivery *ctx, const char *env_name, int use_
int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, char *env_name, int type, struct StrList **manifest) {
char command_base[PATH_MAX];
- char pkgs[STASIS_BUFSIZ];
const char *env_current = getenv("CONDA_DEFAULT_ENV");
if (env_current) {
@@ -204,7 +203,6 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
}
memset(command_base, 0, sizeof(command_base));
- memset(pkgs, 0, sizeof(pkgs));
strcat(command_base, "install");
typedef int (*Runner)(const char *);
@@ -227,8 +225,8 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
}
sprintf(command_base + strlen(command_base), " --extra-index-url 'file://%s'", ctx->storage.wheel_artifact_dir);
- size_t args_alloc_len = STASIS_BUFSIZ + 1;
- char *args = calloc(args_alloc_len, sizeof(*args));
+ size_t args_alloc_len = STASIS_BUFSIZ;
+ char *args = calloc(args_alloc_len + 1, sizeof(*args));
if (!args) {
SYSERROR("%s", "Unable to allocate bytes for command arguments");
return -1;
@@ -280,9 +278,9 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
fprintf(stderr, "No wheel packages found that match the description of '%s'", info->name);
} else {
// found
- guard_strlist_free(&tag_data);
info->version = strdup(whl->version);
}
+ guard_strlist_free(&tag_data);
wheel_free(&whl);
}
@@ -297,20 +295,17 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
}
}
- const size_t required_len = strlen(args) - strlen(info->name) - strlen(info->version) + 5 + 1;
- if (required_len + args_alloc_len > args_alloc_len) {
- args_alloc_len += required_len;
- char *tmp = realloc(args, args_alloc_len * sizeof(*args));
- if (!tmp) {
+ const char *fmt_append = "%s '%s==%s'";
+ const char *fmt = " '%s==%s'";
+ const int required_len = snprintf(NULL, 0, fmt_append, args, req, info->version);
+ if (required_len > (int) args_alloc_len) {
+ if (grow(required_len, &args_alloc_len, &args)) {
+ SYSERROR("Unable to allocate %d bytes for command arguments", required_len);
guard_free(args);
- SYSERROR("%s", "Unable to reallocate memory for args");
return -1;
}
- args = tmp;
}
- snprintf(args + strlen(args),
- required_len,
- " '%s==%s'", req, info->version);
+ snprintf(args + strlen(args), required_len, fmt, req, info->version);
} else {
fprintf(stderr, "Deferred package '%s' is not present in the tested package list!\n", name);
guard_free(args);
@@ -318,9 +313,29 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
}
} else {
if (startswith(name, "--") || startswith(name, "-")) {
- sprintf(args + strlen(args), " %s", name);
+ const char *fmt_append = "%s %s";
+ const char *fmt = " %s";
+ const int required_len = snprintf(NULL, 0, fmt_append, args, name);
+ if (required_len > (int) args_alloc_len) {
+ if (grow(required_len, &args_alloc_len, &args)) {
+ SYSERROR("Unable to allocate %d bytes for command arguments", required_len);
+ guard_free(args);
+ return -1;
+ }
+ }
+ sprintf(args + strlen(args), fmt, name);
} else {
- sprintf(args + strlen(args), " '%s'", name);
+ const char *fmt_append = "%s '%s'";
+ const char *fmt = " '%s'";
+ const int required_len = snprintf(NULL, 0, fmt_append, args, name);
+ if (required_len > (int) args_alloc_len) {
+ if (grow(required_len, &args_alloc_len, &args)) {
+ SYSERROR("Unable to allocate %d bytes for command arguments", required_len);
+ guard_free(args);
+ return -1;
+ }
+ }
+ sprintf(args + strlen(args), fmt, name);
}
}
}
@@ -332,9 +347,10 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
}
int status = runner(command);
+ guard_free(args);
+ guard_free(command);
if (status) {
- guard_free(args);
- guard_free(command);
+ // fail quickly
return status;
}
}