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