diff options
Diffstat (limited to 'src/utils.c')
-rw-r--r-- | src/utils.c | 819 |
1 files changed, 0 insertions, 819 deletions
diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index 6381cea..0000000 --- a/src/utils.c +++ /dev/null @@ -1,819 +0,0 @@ -#include <stdarg.h> -#include "core.h" - -char *dirstack[STASIS_DIRSTACK_MAX]; -const ssize_t dirstack_max = sizeof(dirstack) / sizeof(dirstack[0]); -ssize_t dirstack_len = 0; - -int pushd(const char *path) { - if (access(path, F_OK)) { - // the requested path doesn't exist. - return -1; - } - if (dirstack_len + 1 > dirstack_max) { - // the stack is full - return -1; - } - - dirstack[dirstack_len] = realpath(".", NULL); - dirstack_len++; - return chdir(path); -} - -int popd() { - int result = -1; - if (dirstack_len - 1 < 0) { - return result; - } - dirstack_len--; - result = chdir(dirstack[dirstack_len]); - guard_free(dirstack[dirstack_len]); - return result; -} - -int rmtree(char *_path) { - int status = 0; - char path[PATH_MAX] = {0}; - strncpy(path, _path, sizeof(path) - 1); - DIR *dir; - struct dirent *d_entity; - - dir = opendir(path); - if (!dir) { - return 1; - } - - while ((d_entity = readdir(dir)) != NULL) { - char abspath[PATH_MAX] = {0}; - strcat(abspath, path); - strcat(abspath, DIR_SEP); - strcat(abspath, d_entity->d_name); - - if (!strcmp(d_entity->d_name, ".") || !strcmp(d_entity->d_name, "..") || !strcmp(abspath, path)) { - continue; - } - - // Test for sufficient privilege - if (access(abspath, F_OK) < 0 && errno == EACCES) { - continue; - } - - // Push directories on to the stack first - if (d_entity->d_type == DT_DIR) { - rmtree(abspath); - } else { - remove(abspath); - } - } - closedir(dir); - - if (access(path, F_OK) == 0) { - remove(path); - } - return status; -} - -char *expandpath(const char *_path) { - if (_path == NULL) { - return NULL; - } - const char *homes[] = { - "HOME", - "USERPROFILE", - }; - char home[PATH_MAX]; - char tmp[PATH_MAX]; - char *ptmp = tmp; - char result[PATH_MAX]; - char *sep = NULL; - - memset(home, '\0', sizeof(home)); - memset(ptmp, '\0', sizeof(tmp)); - memset(result, '\0', sizeof(result)); - - strncpy(ptmp, _path, PATH_MAX - 1); - - // Check whether there's a reason to continue processing the string - if (*ptmp != '~') { - return strdup(ptmp); - } - - // Remove tilde from the string and shift its contents to the left - strchrdel(ptmp, "~"); - - // Figure out where the user's home directory resides - for (size_t i = 0; i < sizeof(homes) / sizeof(*homes); i++) { - char *tmphome; - if ((tmphome = getenv(homes[i])) != NULL) { - strncpy(home, tmphome, PATH_MAX - 1); - break; - } - } - - // A broken runtime environment means we can't do anything else here - if (isempty(home)) { - return NULL; - } - - // Scan the path for a directory separator - if ((sep = strpbrk(ptmp, "/\\")) != NULL) { - // Jump past it - ptmp = sep + 1; - } - - // Construct the new path - strncat(result, home, sizeof(result) - strlen(home) + 1); - if (sep) { - strncat(result, DIR_SEP, sizeof(result) - strlen(home) + 1); - strncat(result, ptmp, sizeof(result) - strlen(home) + 1); - } - - return strdup(result); -} - -char *path_basename(char *path) { - char *result = NULL; - char *last = NULL; - - if ((last = strrchr(path, '/')) == NULL) { - return path; - } - // Perform a lookahead ensuring the string is valid beyond the last separator - if (last++ != NULL) { - result = last; - } - - return result; -} - -char *path_dirname(char *path) { - if (!path) { - return ""; - } - if (strlen(path) == 1 && *path == '/') { - return "/"; - } - char *pos = strrchr(path, '/'); - if (!pos) { - return "."; - } - *pos = '\0'; - - return path; -} - -char **file_readlines(const char *filename, size_t start, size_t limit, ReaderFn *readerFn) { - FILE *fp = NULL; - char **result = NULL; - char *buffer = NULL; - size_t lines = 0; - int use_stdin = 0; - - if (strcmp(filename, "-") == 0) { - use_stdin = 1; - } - - if (use_stdin) { - fp = stdin; - } else { - fp = fopen(filename, "r"); - } - - if (fp == NULL) { - perror(filename); - SYSERROR("failed to open %s for reading", filename); - return NULL; - } - - // Allocate buffer - if ((buffer = calloc(STASIS_BUFSIZ, sizeof(char))) == NULL) { - SYSERROR("unable to allocate %d bytes for buffer", STASIS_BUFSIZ); - if (!use_stdin) { - fclose(fp); - } - return NULL; - } - - // count number the of lines in the file - while ((fgets(buffer, STASIS_BUFSIZ - 1, fp)) != NULL) { - lines++; - } - - if (!lines) { - guard_free(buffer); - if (!use_stdin) { - fclose(fp); - } - return NULL; - } - - rewind(fp); - - // Handle invalid start offset - if (start > lines) { - start = 0; - } - - // Adjust line count when start offset is non-zero - if (start != 0 && start < lines) { - lines -= start; - } - - - // Handle minimum and maximum limits - if (limit == 0 || limit > lines) { - limit = lines; - } - - // Populate results array - result = calloc(limit + 1, sizeof(char *)); - for (size_t i = start; i < limit; i++) { - if (i < start) { - continue; - } - - if (fgets(buffer, STASIS_BUFSIZ - 1, fp) == NULL) { - break; - } - - if (readerFn != NULL) { - int status = readerFn(i - start, &buffer); - // A status greater than zero indicates we should ignore this line entirely and "continue" - // A status less than zero indicates we should "break" - // A zero status proceeds normally - if (status > 0) { - i--; - continue; - } else if (status < 0) { - break; - } - } - result[i] = strdup(buffer); - memset(buffer, '\0', STASIS_BUFSIZ); - } - - guard_free(buffer); - if (!use_stdin) { - fclose(fp); - } - return result; -} - -char *find_program(const char *name) { - static char result[PATH_MAX] = {0}; - char *_env_path = getenv(PATH_ENV_VAR); - if (!_env_path) { - errno = EINVAL; - return NULL; - } - char *path = strdup(_env_path); - char *path_orig = path; - char *path_elem = NULL; - - if (!path) { - errno = ENOMEM; - return NULL; - } - - result[0] = '\0'; - while ((path_elem = strsep(&path, PATH_SEP))) { - char abspath[PATH_MAX] = {0}; - strcat(abspath, path_elem); - strcat(abspath, DIR_SEP); - strcat(abspath, name); - if (access(abspath, F_OK) < 0) { - continue; - } - strncpy(result, abspath, sizeof(result)); - break; - } - path = path_orig; - guard_free(path); - return strlen(result) ? result : NULL; -} - -int touch(const char *filename) { - if (access(filename, F_OK) == 0) { - return 0; - } - - FILE *fp = fopen(filename, "w"); - if (!fp) { - perror(filename); - return 1; - } - fclose(fp); - return 0; -} - -int git_clone(struct Process *proc, char *url, char *destdir, char *gitref) { - int result = -1; - char *chdir_to = NULL; - char *program = find_program("git"); - if (!program) { - return result; - } - - static char command[PATH_MAX]; - sprintf(command, "%s clone -c advice.detachedHead=false --recursive %s", program, url); - if (destdir && access(destdir, F_OK) < 0) { - sprintf(command + strlen(command), " %s", destdir); - result = shell(proc, command); - } - - if (destdir) { - chdir_to = destdir; - } else { - chdir_to = path_basename(url); - } - - pushd(chdir_to); - { - memset(command, 0, sizeof(command)); - sprintf(command, "%s fetch --all", program); - result += shell(proc, command); - - if (gitref != NULL) { - memset(command, 0, sizeof(command)); - sprintf(command, "%s checkout %s", program, gitref); - result += shell(proc, command); - } - popd(); - } - return result; -} - - -char *git_describe(const char *path) { - static char version[NAME_MAX]; - FILE *pp; - - memset(version, 0, sizeof(version)); - if (pushd(path)) { - return NULL; - } - - pp = popen("git describe --first-parent --always --tags", "r"); - if (!pp) { - return NULL; - } - fgets(version, sizeof(version) - 1, pp); - strip(version); - pclose(pp); - popd(); - return version; -} - -char *git_rev_parse(const char *path, char *args) { - static char version[NAME_MAX]; - char cmd[PATH_MAX]; - FILE *pp; - - memset(version, 0, sizeof(version)); - if (isempty(args)) { - fprintf(stderr, "git_rev_parse args cannot be empty\n"); - return NULL; - } - - if (pushd(path)) { - return NULL; - } - - sprintf(cmd, "git rev-parse %s", args); - pp = popen(cmd, "r"); - if (!pp) { - return NULL; - } - fgets(version, sizeof(version) - 1, pp); - strip(version); - pclose(pp); - popd(); - return version; -} - -void msg(unsigned type, char *fmt, ...) { - FILE *stream = NULL; - char header[255]; - char status[20]; - - if (type & STASIS_MSG_NOP) { - // quiet mode - return; - } - - if (!globals.verbose && type & STASIS_MSG_RESTRICT) { - // Verbose mode is not active - return; - } - - memset(header, 0, sizeof(header)); - memset(status, 0, sizeof(status)); - - va_list args; - va_start(args, fmt); - - stream = stdout; - fprintf(stream, "%s", STASIS_COLOR_RESET); - if (type & STASIS_MSG_ERROR) { - // for error output - stream = stderr; - fprintf(stream, "%s", STASIS_COLOR_RED); - strcpy(status, " ERROR: "); - } else if (type & STASIS_MSG_WARN) { - stream = stderr; - fprintf(stream, "%s", STASIS_COLOR_YELLOW); - strcpy(status, " WARNING: "); - } else { - fprintf(stream, "%s", STASIS_COLOR_GREEN); - strcpy(status, " "); - } - - if (type & STASIS_MSG_L1) { - sprintf(header, "==>%s" STASIS_COLOR_RESET STASIS_COLOR_WHITE, status); - } else if (type & STASIS_MSG_L2) { - sprintf(header, " ->%s" STASIS_COLOR_RESET, status); - } else if (type & STASIS_MSG_L3) { - sprintf(header, STASIS_COLOR_BLUE " ->%s" STASIS_COLOR_RESET, status); - } - - fprintf(stream, "%s", header); - vfprintf(stream, fmt, args); - fprintf(stream, "%s", STASIS_COLOR_RESET); - va_end(args); -} - -void debug_shell() { - msg(STASIS_MSG_L1 | STASIS_MSG_WARN, "ENTERING STASIS DEBUG SHELL\n" STASIS_COLOR_RESET); - if (system("/bin/bash -c 'PS1=\"(STASIS DEBUG) \\W $ \" bash --norc --noprofile'") < 0) { - SYSERROR("unable to spawn debug shell: %s", strerror(errno)); - exit(errno); - } - msg(STASIS_MSG_L1 | STASIS_MSG_WARN, "EXITING STASIS DEBUG SHELL\n" STASIS_COLOR_RESET); - exit(255); -} - -char *xmkstemp(FILE **fp, const char *mode) { - int fd = -1; - char tmpdir[PATH_MAX]; - char t_name[PATH_MAX * 2]; - - if (globals.tmpdir) { - strcpy(tmpdir, globals.tmpdir); - } else { - strcpy(tmpdir, "/tmp"); - } - memset(t_name, 0, sizeof(t_name)); - sprintf(t_name, "%s/%s", tmpdir, "STASIS.XXXXXX"); - - fd = mkstemp(t_name); - *fp = fdopen(fd, mode); - if (!*fp) { - // unable to open, die - if (fd > 0) - close(fd); - *fp = NULL; - return NULL; - } - - char *path = strdup(t_name); - if (!path) { - // strdup failed, die - if (*fp) { - // close the file handle - fclose(*fp); - *fp = NULL; - } - // fall through. path is NULL. - } - return path; -} - -int isempty_dir(const char *path) { - DIR *dp; - struct dirent *rec; - size_t count = 0; - - dp = opendir(path); - if (!dp) { - return -1; - } - while ((rec = readdir(dp)) != NULL) { - if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) { - continue; - } - count++; - } - closedir(dp); - return count == 0; -} - -int path_store(char **destptr, size_t maxlen, const char *base, const char *path) { - char *path_tmp; - size_t base_len = 0; - size_t path_len = 0; - - // Both path elements need to be defined to continue - if (!base || !path) { - return -1; - } - - // Initialize destination pointer to length of maxlen - path_tmp = calloc(maxlen, sizeof(*path_tmp)); - if (!path_tmp) { - return -1; - } - - // Ensure generated path will fit in destination - base_len = strlen(base); - path_len = strlen(path); - // 2 = directory separator and NUL terminator - if (2 + (base_len + path_len) > maxlen) { - goto l_path_setup_error; - } - - snprintf(path_tmp, maxlen - 1, "%s/%s", base, path); - if (mkdirs(path_tmp, 0755)) { - goto l_path_setup_error; - } - - if (*destptr) { - guard_free(*destptr); - } - - if (!(*destptr = realpath(path_tmp, NULL))) { - goto l_path_setup_error; - } - - guard_free(path_tmp); - return 0; - - l_path_setup_error: - guard_free(path_tmp); - return -1; -} - -int xml_pretty_print_in_place(const char *filename, const char *pretty_print_prog, const char *pretty_print_args) { - int status = 0; - char *tempfile = NULL; - char *result = NULL; - FILE *fp = NULL; - FILE *tmpfp = NULL; - char cmd[PATH_MAX]; - if (!find_program(pretty_print_prog)) { - // Pretty printing is optional. 99% chance the XML data will - // be passed to a report generator; not inspected by a human. - return 0; - } - memset(cmd, 0, sizeof(cmd)); - snprintf(cmd, sizeof(cmd) - 1, "%s %s %s", pretty_print_prog, pretty_print_args, filename); - result = shell_output(cmd, &status); - if (status || !result) { - goto pretty_print_failed; - } - - tempfile = xmkstemp(&tmpfp, "w+"); - if (!tmpfp || !tempfile) { - goto pretty_print_failed; - } - - fprintf(tmpfp, "%s", result); - fflush(tmpfp); - fclose(tmpfp); - - fp = fopen(filename, "w+"); - if (!fp) { - goto pretty_print_failed; - } - - if (copy2(tempfile, filename, CT_PERM)) { - goto pretty_print_failed; - } - - if (remove(tempfile)) { - goto pretty_print_failed; - } - - fclose(fp); - guard_free(tempfile); - guard_free(result); - return 0; - - pretty_print_failed: - if (fp) { - fclose(fp); - } - if (tmpfp) { - fclose(tmpfp); - } - guard_free(tempfile); - guard_free(result); - return -1; -} - -/** - * - * @param filename /path/to/tox.ini - * @param result path of replacement tox.ini configuration - * @return 0 on success, -1 on error - */ -int fix_tox_conf(const char *filename, char **result) { - struct INIFILE *toxini; - FILE *fptemp; - char *tempfile; - const char *with_posargs = " \\\n {posargs}\n"; - - // Create new temporary tox configuration file - tempfile = xmkstemp(&fptemp, "w+"); - if (!tempfile) { - return -1; - } - - // If the result pointer is NULL, allocate enough to store a filesystem path - if (!*result) { - *result = calloc(PATH_MAX, sizeof(**result)); - if (!*result) { - guard_free(tempfile); - return -1; - } - } - - // Consume the original tox.ini configuration - toxini = ini_open(filename); - if (!toxini) { - if (fptemp) { - guard_free(result); - guard_free(tempfile); - fclose(fptemp); - } - return -1; - } - - // Modify tox configuration - // - Allow passing positional arguments pytest - for (size_t i = 0; i < toxini->section_count; i++) { - struct INISection *section = toxini->section[i]; - if (section) { - char *section_name = section->key; - for (size_t k = 0; k < section->data_count; k++) { - struct INIData *data = section->data[k]; - if (data) { - int err = 0; - char *key = data->key; - char *value = ini_getval_str(toxini, section->key, data->key, INI_READ_RENDER, &err); - if (key && value) { - if (startswith(value, "pytest") && !strstr(value, "{posargs}")) { - strip(value); - char *tmp; - tmp = realloc(value, strlen(value) + strlen(with_posargs) + 1); - if (!tmp) { - SYSERROR("failed to increase size to +%zu bytes", - strlen(value) + strlen(with_posargs) + 1); - guard_free(*result); - return -1; - } else if (tmp != value) { - value = tmp; - } - strcat(value, with_posargs); - ini_setval(&toxini, INI_SETVAL_REPLACE, section_name, key, value); - } - } - guard_free(value); - } - } - } - } - - // Save modified configuration - ini_write(toxini, &fptemp, INI_WRITE_RAW); - fclose(fptemp); - - // Store path to modified config - strcpy(*result, tempfile); - guard_free(tempfile); - - ini_free(&toxini); - return 0; -} - -static size_t count_blanks(char *s) { - // return the number of leading blanks (tab/space) in a string - size_t blank = 0; - for (size_t i = 0; i < strlen(s); i++) { - if (isblank(s[i])) { - blank++; - } else { - break; - } - } - return blank; -} - -char *collapse_whitespace(char **s) { - char *x = (*s); - size_t len = strlen(x); - for (size_t i = 0; i < len; i++) { - size_t blank = count_blanks(&x[i]); - if (blank > 1) { - memmove(&x[i], &x[i] + blank, strlen(&x[i])); - } - } - - return *s; -} - -/** - * Replace sensitive text in strings with ***REDACTED*** - * @param to_redact a list of tokens to redact - * @param src to read - * @param dest to write modified string - * @param maxlen maximum length of dest string - * @return 0 on success, -1 on error - */ -int redact_sensitive(const char **to_redact, size_t to_redact_size, char *src, char *dest, size_t maxlen) { - const char *redacted = "***REDACTED***"; - - char *tmp = calloc(strlen(redacted) + strlen(src) + 1, sizeof(*tmp)); - if (!tmp) { - return -1; - } - strcpy(tmp, src); - - for (size_t i = 0; i < to_redact_size; i++) { - if (to_redact[i] && strstr(tmp, to_redact[i])) { - replace_text(tmp, to_redact[i], redacted, 0); - break; - } - } - - memset(dest, 0, maxlen); - strncpy(dest, tmp, maxlen - 1); - guard_free(tmp); - - return 0; -} - -/** - * Retrieve file names in a directory - * (no metadata, non-recursive) - * - * @param path directory path - * @return StrList structure - */ -struct StrList *listdir(const char *path) { - struct StrList *node; - DIR *dp; - struct dirent *rec; - - dp = opendir(path); - if (!dp) { - return NULL; - } - node = strlist_init(); - - while ((rec = readdir(dp)) != NULL) { - if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) { - continue; - } - strlist_append(&node, rec->d_name); - } - closedir(dp); - return node; -} - -long get_cpu_count() { -#if defined(STASIS_OS_LINUX) || defined(STASIS_OS_DARWIN) - return sysconf(_SC_NPROCESSORS_ONLN); -#else - return 0; -#endif -} - -int mkdirs(const char *_path, mode_t mode) { - int status; - char *token; - char pathbuf[PATH_MAX] = {0}; - char *path; - path = pathbuf; - strcpy(path, _path); - errno = 0; - - char result[PATH_MAX] = {0}; - status = 0; - while ((token = strsep(&path, "/")) != NULL && !status) { - if (token[0] == '.') - continue; - strcat(result, token); - strcat(result, "/"); - status = mkdir(result, mode); - if (status && errno == EEXIST) { - status = 0; - errno = 0; - continue; - } - } - return status; -} - -char *find_version_spec(char *str) { - return strpbrk(str, "@~=<>!"); -} |