^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "subcmd-util.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "exec-cmd.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "subcmd-config.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define MAX_ARGS 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define PATH_MAX 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) static const char *argv_exec_path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static const char *argv0_path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) void exec_cmd_init(const char *exec_name, const char *prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) const char *exec_path, const char *exec_path_env)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) subcmd_config.exec_name = exec_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) subcmd_config.prefix = prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) subcmd_config.exec_path = exec_path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) subcmd_config.exec_path_env = exec_path_env;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define is_dir_sep(c) ((c) == '/')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int is_absolute_path(const char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return path[0] == '/';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static const char *get_pwd_cwd(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static char cwd[PATH_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) char *pwd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct stat cwd_stat, pwd_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (getcwd(cwd, PATH_MAX) == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) pwd = getenv("PWD");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (pwd && strcmp(pwd, cwd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) stat(cwd, &cwd_stat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (!stat(pwd, &pwd_stat) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) pwd_stat.st_dev == cwd_stat.st_dev &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) pwd_stat.st_ino == cwd_stat.st_ino) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) strlcpy(cwd, pwd, PATH_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return cwd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static const char *make_nonrelative_path(const char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static char buf[PATH_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (is_absolute_path(path)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) die("Too long path: %.*s", 60, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) const char *cwd = get_pwd_cwd();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (!cwd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) die("Cannot determine the current working directory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) die("Too long path: %.*s", 60, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) char *system_path(const char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) char *buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (is_absolute_path(path))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return strdup(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) astrcatf(&buf, "%s/%s", subcmd_config.prefix, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) const char *extract_argv0_path(const char *argv0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) const char *slash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!argv0 || !*argv0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) slash = argv0 + strlen(argv0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) while (argv0 <= slash && !is_dir_sep(*slash))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) slash--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (slash >= argv0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) argv0_path = strndup(argv0, slash - argv0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return argv0_path ? slash + 1 : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return argv0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) void set_argv_exec_path(const char *exec_path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) argv_exec_path = exec_path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * Propagate this setting to external programs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) setenv(subcmd_config.exec_path_env, exec_path, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* Returns the highest-priority location to look for subprograms. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) char *get_argv_exec_path(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) char *env;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (argv_exec_path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return strdup(argv_exec_path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) env = getenv(subcmd_config.exec_path_env);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (env && *env)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return strdup(env);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return system_path(subcmd_config.exec_path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static void add_path(char **out, const char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (path && *path) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (is_absolute_path(path))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) astrcat(out, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) astrcat(out, make_nonrelative_path(path));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) astrcat(out, ":");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) void setup_path(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) const char *old_path = getenv("PATH");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) char *new_path = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) char *tmp = get_argv_exec_path();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) add_path(&new_path, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) add_path(&new_path, argv0_path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) free(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (old_path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) astrcat(&new_path, old_path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) setenv("PATH", new_path, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) free(new_path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static const char **prepare_exec_cmd(const char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int argc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) const char **nargv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) for (argc = 0; argv[argc]; argc++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) ; /* just counting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) nargv = malloc(sizeof(*nargv) * (argc + 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) nargv[0] = subcmd_config.exec_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) for (argc = 0; argv[argc]; argc++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) nargv[argc + 1] = argv[argc];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) nargv[argc + 1] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return nargv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) int execv_cmd(const char **argv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) const char **nargv = prepare_exec_cmd(argv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* execvp() can only ever return if it fails */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) execvp(subcmd_config.exec_name, (char **)nargv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) free(nargv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) int execl_cmd(const char *cmd,...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) int argc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) const char *argv[MAX_ARGS + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) const char *arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) va_list param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) va_start(param, cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) argv[0] = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) argc = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) while (argc < MAX_ARGS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) arg = argv[argc++] = va_arg(param, char *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (!arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) va_end(param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (MAX_ARGS <= argc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) fprintf(stderr, " Error: too many args to run %s\n", cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) argv[argc] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return execv_cmd(argv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }