brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 7739b52 Raw
219 lines · c
1// SPDX-License-Identifier: GPL-2.02#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	3215#define PATH_MAX	409616 17static const char *argv_exec_path;18static const char *argv0_path;19 20void 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 34static int is_absolute_path(const char *path)35{36	return path[0] == '/';37}38 39static 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 57static 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 77char *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 89const 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 108void 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. */119char *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 133static 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 148void 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	else161		astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin");162 163	setenv("PATH", new_path, 1);164 165	free(new_path);166}167 168static 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 184int 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 195int 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