0001
0002 #include <linux/compiler.h>
0003 #include <linux/string.h>
0004 #include <sys/types.h>
0005 #include <sys/stat.h>
0006 #include <unistd.h>
0007 #include <string.h>
0008 #include <stdlib.h>
0009 #include <stdio.h>
0010 #include "subcmd-util.h"
0011 #include "exec-cmd.h"
0012 #include "subcmd-config.h"
0013
0014 #define MAX_ARGS 32
0015 #define PATH_MAX 4096
0016
0017 static const char *argv_exec_path;
0018 static const char *argv0_path;
0019
0020 void exec_cmd_init(const char *exec_name, const char *prefix,
0021 const char *exec_path, const char *exec_path_env)
0022 {
0023 subcmd_config.exec_name = exec_name;
0024 subcmd_config.prefix = prefix;
0025 subcmd_config.exec_path = exec_path;
0026 subcmd_config.exec_path_env = exec_path_env;
0027 }
0028
0029 #define is_dir_sep(c) ((c) == '/')
0030
0031 static int is_absolute_path(const char *path)
0032 {
0033 return path[0] == '/';
0034 }
0035
0036 static const char *get_pwd_cwd(void)
0037 {
0038 static char cwd[PATH_MAX + 1];
0039 char *pwd;
0040 struct stat cwd_stat, pwd_stat;
0041 if (getcwd(cwd, PATH_MAX) == NULL)
0042 return NULL;
0043 pwd = getenv("PWD");
0044 if (pwd && strcmp(pwd, cwd)) {
0045 stat(cwd, &cwd_stat);
0046 if (!stat(pwd, &pwd_stat) &&
0047 pwd_stat.st_dev == cwd_stat.st_dev &&
0048 pwd_stat.st_ino == cwd_stat.st_ino) {
0049 strlcpy(cwd, pwd, PATH_MAX);
0050 }
0051 }
0052 return cwd;
0053 }
0054
0055 static const char *make_nonrelative_path(const char *path)
0056 {
0057 static char buf[PATH_MAX + 1];
0058
0059 if (is_absolute_path(path)) {
0060 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
0061 die("Too long path: %.*s", 60, path);
0062 } else {
0063 const char *cwd = get_pwd_cwd();
0064 if (!cwd)
0065 die("Cannot determine the current working directory");
0066 if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
0067 die("Too long path: %.*s", 60, path);
0068 }
0069 return buf;
0070 }
0071
0072 char *system_path(const char *path)
0073 {
0074 char *buf = NULL;
0075
0076 if (is_absolute_path(path))
0077 return strdup(path);
0078
0079 astrcatf(&buf, "%s/%s", subcmd_config.prefix, path);
0080
0081 return buf;
0082 }
0083
0084 const char *extract_argv0_path(const char *argv0)
0085 {
0086 const char *slash;
0087
0088 if (!argv0 || !*argv0)
0089 return NULL;
0090 slash = argv0 + strlen(argv0);
0091
0092 while (argv0 <= slash && !is_dir_sep(*slash))
0093 slash--;
0094
0095 if (slash >= argv0) {
0096 argv0_path = strndup(argv0, slash - argv0);
0097 return argv0_path ? slash + 1 : NULL;
0098 }
0099
0100 return argv0;
0101 }
0102
0103 void set_argv_exec_path(const char *exec_path)
0104 {
0105 argv_exec_path = exec_path;
0106
0107
0108
0109 setenv(subcmd_config.exec_path_env, exec_path, 1);
0110 }
0111
0112
0113
0114 char *get_argv_exec_path(void)
0115 {
0116 char *env;
0117
0118 if (argv_exec_path)
0119 return strdup(argv_exec_path);
0120
0121 env = getenv(subcmd_config.exec_path_env);
0122 if (env && *env)
0123 return strdup(env);
0124
0125 return system_path(subcmd_config.exec_path);
0126 }
0127
0128 static void add_path(char **out, const char *path)
0129 {
0130 if (path && *path) {
0131 if (is_absolute_path(path))
0132 astrcat(out, path);
0133 else
0134 astrcat(out, make_nonrelative_path(path));
0135
0136 astrcat(out, ":");
0137 }
0138 }
0139
0140 void setup_path(void)
0141 {
0142 const char *old_path = getenv("PATH");
0143 char *new_path = NULL;
0144 char *tmp = get_argv_exec_path();
0145
0146 add_path(&new_path, tmp);
0147 add_path(&new_path, argv0_path);
0148 free(tmp);
0149
0150 if (old_path)
0151 astrcat(&new_path, old_path);
0152 else
0153 astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin");
0154
0155 setenv("PATH", new_path, 1);
0156
0157 free(new_path);
0158 }
0159
0160 static const char **prepare_exec_cmd(const char **argv)
0161 {
0162 int argc;
0163 const char **nargv;
0164
0165 for (argc = 0; argv[argc]; argc++)
0166 ;
0167 nargv = malloc(sizeof(*nargv) * (argc + 2));
0168
0169 nargv[0] = subcmd_config.exec_name;
0170 for (argc = 0; argv[argc]; argc++)
0171 nargv[argc + 1] = argv[argc];
0172 nargv[argc + 1] = NULL;
0173 return nargv;
0174 }
0175
0176 int execv_cmd(const char **argv) {
0177 const char **nargv = prepare_exec_cmd(argv);
0178
0179
0180 execvp(subcmd_config.exec_name, (char **)nargv);
0181
0182 free(nargv);
0183 return -1;
0184 }
0185
0186
0187 int execl_cmd(const char *cmd,...)
0188 {
0189 int argc;
0190 const char *argv[MAX_ARGS + 1];
0191 const char *arg;
0192 va_list param;
0193
0194 va_start(param, cmd);
0195 argv[0] = cmd;
0196 argc = 1;
0197 while (argc < MAX_ARGS) {
0198 arg = argv[argc++] = va_arg(param, char *);
0199 if (!arg)
0200 break;
0201 }
0202 va_end(param);
0203 if (MAX_ARGS <= argc) {
0204 fprintf(stderr, " Error: too many args to run %s\n", cmd);
0205 return -1;
0206 }
0207
0208 argv[argc] = NULL;
0209 return execv_cmd(argv);
0210 }