cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

exec-cmd.c (4227B)


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