1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/compiler.h>
3 #include <linux/string.h>
10 #include "subcmd-util.h"
12 #include "subcmd-config.h"
17 static const char *argv_exec_path
;
18 static const char *argv0_path
;
20 void exec_cmd_init(const char *exec_name
, const char *prefix
,
21 const char *exec_path
, const char *exec_path_env
)
23 subcmd_config
.exec_name
= exec_name
;
24 subcmd_config
.prefix
= prefix
;
25 subcmd_config
.exec_path
= exec_path
;
26 subcmd_config
.exec_path_env
= exec_path_env
;
29 #define is_dir_sep(c) ((c) == '/')
31 static int is_absolute_path(const char *path
)
33 return path
[0] == '/';
36 static const char *get_pwd_cwd(void)
38 static char cwd
[PATH_MAX
+ 1];
40 struct stat cwd_stat
, pwd_stat
;
41 if (getcwd(cwd
, PATH_MAX
) == NULL
)
44 if (pwd
&& strcmp(pwd
, cwd
)) {
46 if (!stat(pwd
, &pwd_stat
) &&
47 pwd_stat
.st_dev
== cwd_stat
.st_dev
&&
48 pwd_stat
.st_ino
== cwd_stat
.st_ino
) {
49 strlcpy(cwd
, pwd
, PATH_MAX
);
55 static const char *make_nonrelative_path(const char *path
)
57 static char buf
[PATH_MAX
+ 1];
59 if (is_absolute_path(path
)) {
60 if (strlcpy(buf
, path
, PATH_MAX
) >= PATH_MAX
)
61 die("Too long path: %.*s", 60, path
);
63 const char *cwd
= get_pwd_cwd();
65 die("Cannot determine the current working directory");
66 if (snprintf(buf
, PATH_MAX
, "%s/%s", cwd
, path
) >= PATH_MAX
)
67 die("Too long path: %.*s", 60, path
);
72 char *system_path(const char *path
)
76 if (is_absolute_path(path
))
79 astrcatf(&buf
, "%s/%s", subcmd_config
.prefix
, path
);
84 const char *extract_argv0_path(const char *argv0
)
88 if (!argv0
|| !*argv0
)
90 slash
= argv0
+ strlen(argv0
);
92 while (argv0
<= slash
&& !is_dir_sep(*slash
))
96 argv0_path
= strndup(argv0
, slash
- argv0
);
97 return argv0_path
? slash
+ 1 : NULL
;
103 void set_argv_exec_path(const char *exec_path
)
105 argv_exec_path
= exec_path
;
107 * Propagate this setting to external programs.
109 setenv(subcmd_config
.exec_path_env
, exec_path
, 1);
113 /* Returns the highest-priority location to look for subprograms. */
114 char *get_argv_exec_path(void)
119 return strdup(argv_exec_path
);
121 env
= getenv(subcmd_config
.exec_path_env
);
125 return system_path(subcmd_config
.exec_path
);
128 static void add_path(char **out
, const char *path
)
131 if (is_absolute_path(path
))
134 astrcat(out
, make_nonrelative_path(path
));
140 void setup_path(void)
142 const char *old_path
= getenv("PATH");
143 char *new_path
= NULL
;
144 char *tmp
= get_argv_exec_path();
146 add_path(&new_path
, tmp
);
147 add_path(&new_path
, argv0_path
);
151 astrcat(&new_path
, old_path
);
153 astrcat(&new_path
, "/usr/local/bin:/usr/bin:/bin");
155 setenv("PATH", new_path
, 1);
160 static const char **prepare_exec_cmd(const char **argv
)
165 for (argc
= 0; argv
[argc
]; argc
++)
166 ; /* just counting */
167 nargv
= malloc(sizeof(*nargv
) * (argc
+ 2));
169 nargv
[0] = subcmd_config
.exec_name
;
170 for (argc
= 0; argv
[argc
]; argc
++)
171 nargv
[argc
+ 1] = argv
[argc
];
172 nargv
[argc
+ 1] = NULL
;
176 int execv_cmd(const char **argv
) {
177 const char **nargv
= prepare_exec_cmd(argv
);
179 /* execvp() can only ever return if it fails */
180 execvp(subcmd_config
.exec_name
, (char **)nargv
);
187 int execl_cmd(const char *cmd
,...)
190 const char *argv
[MAX_ARGS
+ 1];
194 va_start(param
, cmd
);
197 while (argc
< MAX_ARGS
) {
198 arg
= argv
[argc
++] = va_arg(param
, char *);
203 if (MAX_ARGS
<= argc
) {
204 fprintf(stderr
, " Error: too many args to run %s\n", cmd
);
209 return execv_cmd(argv
);