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
;
28 /* Setup environment variable for invoked shell script. */
29 setenv("PREFIX", prefix
, 1);
32 #define is_dir_sep(c) ((c) == '/')
34 static int is_absolute_path(const char *path
)
36 return path
[0] == '/';
39 static const char *get_pwd_cwd(char *buf
, size_t sz
)
42 struct stat cwd_stat
, pwd_stat
;
43 if (getcwd(buf
, sz
) == NULL
)
46 if (pwd
&& strcmp(pwd
, buf
)) {
48 if (!stat(pwd
, &pwd_stat
) &&
49 pwd_stat
.st_dev
== cwd_stat
.st_dev
&&
50 pwd_stat
.st_ino
== cwd_stat
.st_ino
) {
51 strlcpy(buf
, pwd
, sz
);
57 static const char *make_nonrelative_path(char *buf
, size_t sz
, const char *path
)
59 if (is_absolute_path(path
)) {
60 if (strlcpy(buf
, path
, sz
) >= sz
)
61 die("Too long path: %.*s", 60, path
);
63 const char *cwd
= get_pwd_cwd(buf
, sz
);
66 die("Cannot determine the current working directory");
68 if (strlen(cwd
) + strlen(path
) + 2 >= sz
)
69 die("Too long path: %.*s", 60, path
);
77 char *system_path(const char *path
)
81 if (is_absolute_path(path
))
84 astrcatf(&buf
, "%s/%s", subcmd_config
.prefix
, path
);
89 const char *extract_argv0_path(const char *argv0
)
93 if (!argv0
|| !*argv0
)
95 slash
= argv0
+ strlen(argv0
);
97 while (argv0
<= slash
&& !is_dir_sep(*slash
))
100 if (slash
>= argv0
) {
101 argv0_path
= strndup(argv0
, slash
- argv0
);
102 return argv0_path
? slash
+ 1 : NULL
;
108 void set_argv_exec_path(const char *exec_path
)
110 argv_exec_path
= exec_path
;
112 * Propagate this setting to external programs.
114 setenv(subcmd_config
.exec_path_env
, exec_path
, 1);
118 /* Returns the highest-priority location to look for subprograms. */
119 char *get_argv_exec_path(void)
124 return strdup(argv_exec_path
);
126 env
= getenv(subcmd_config
.exec_path_env
);
130 return system_path(subcmd_config
.exec_path
);
133 static void add_path(char **out
, const char *path
)
136 if (is_absolute_path(path
))
141 astrcat(out
, make_nonrelative_path(buf
, sizeof(buf
), path
));
148 void setup_path(void)
150 const char *old_path
= getenv("PATH");
151 char *new_path
= NULL
;
152 char *tmp
= get_argv_exec_path();
154 add_path(&new_path
, tmp
);
155 add_path(&new_path
, argv0_path
);
159 astrcat(&new_path
, old_path
);
161 astrcat(&new_path
, "/usr/local/bin:/usr/bin:/bin");
163 setenv("PATH", new_path
, 1);
168 static const char **prepare_exec_cmd(const char **argv
)
173 for (argc
= 0; argv
[argc
]; argc
++)
174 ; /* just counting */
175 nargv
= malloc(sizeof(*nargv
) * (argc
+ 2));
177 nargv
[0] = subcmd_config
.exec_name
;
178 for (argc
= 0; argv
[argc
]; argc
++)
179 nargv
[argc
+ 1] = argv
[argc
];
180 nargv
[argc
+ 1] = NULL
;
184 int execv_cmd(const char **argv
) {
185 const char **nargv
= prepare_exec_cmd(argv
);
187 /* execvp() can only ever return if it fails */
188 execvp(subcmd_config
.exec_name
, (char **)nargv
);
195 int execl_cmd(const char *cmd
,...)
198 const char *argv
[MAX_ARGS
+ 1];
202 va_start(param
, cmd
);
205 while (argc
< MAX_ARGS
) {
206 arg
= argv
[argc
++] = va_arg(param
, char *);
211 if (MAX_ARGS
<= argc
) {
212 fprintf(stderr
, " Error: too many args to run %s\n", cmd
);
217 return execv_cmd(argv
);