Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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      * Propagate this setting to external programs.
0108      */
0109     setenv(subcmd_config.exec_path_env, exec_path, 1);
0110 }
0111 
0112 
0113 /* Returns the highest-priority location to look for subprograms. */
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         ; /* just counting */
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     /* execvp() can only ever return if it fails */
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 }