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