blob: 4f06efe8001d954fbd78c124c0b921ce29b913c7 [file] [log] [blame]
/* Copyright (c) 2015 Google, Inc.
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details. */
#include <parlib/parlib.h>
#include <parlib/core_set.h>
#include <parlib/ros_debug.h>
#include <stdlib.h>
/* Control variables */
bool parlib_wants_to_be_mcp = TRUE;
bool parlib_never_yield = FALSE;
bool parlib_never_vc_request = FALSE;
/* Creates a child process for program @exe, with args and envs. Will attempt
* to look in /bin/ if the initial lookup fails, and will invoke sh to handle
* non-elfs. Returns the child's PID on success, -1 o/w. */
pid_t create_child(const char *exe, int argc, char *const argv[],
char *const envp[])
{
pid_t kid;
char *path_exe;
char **sh_argv;
const char *sh_path = "/bin/sh";
kid = sys_proc_create(exe, strlen(exe), argv, envp, 0);
if (kid > 0)
return kid;
/* Here's how we avoid infinite recursion. We can only have ENOENT the
* first time through without bailing out, since all errno paths set exe
* to begin with '/'. That includes calls from ENOEXEC, since sh_path
* begins with /. To avoid repeated calls to ENOEXEC, we just look for
* sh_path as the exe, so if we have consecutive ENOEXECs, we'll bail
* out. */
switch (errno) {
case ENOENT:
if (exe[0] == '/')
return -1;
path_exe = malloc(MAX_PATH_LEN);
if (!path_exe)
return -1;
/* Our 'PATH' is only /bin. */
snprintf(path_exe, MAX_PATH_LEN, "/bin/%s", exe);
path_exe[MAX_PATH_LEN - 1] = 0;
kid = create_child(path_exe, argc, argv, envp);
free(path_exe);
break;
case ENOEXEC:
/* In case someone replaces /bin/sh with a non-elf. */
if (!strcmp(sh_path, exe))
return -1;
/* We want enough space for the original argv, plus one entry at
* the front for sh_path. When we grab the original argv, we
* also need the trailing NULL, which is at argv[argc]. That
* means we really want argc + 1 entries from argv. */
sh_argv = malloc(sizeof(char *) * (argc + 2));
if (!sh_argv)
return -1;
memcpy(&sh_argv[1], argv, sizeof(char *) * (argc + 1));
sh_argv[0] = (char*)sh_path;
/* Replace the original argv[0] with the path to exe, which
* might have been edited to include /bin/ */
sh_argv[1] = (char*)exe;
kid = create_child(sh_path, argc + 1, sh_argv, envp);
free(sh_argv);
break;
default:
return -1;
}
return kid;
}
/* Creates a child process for exe, and shares the parent's standard FDs (stdin,
* stdout, stderr) with the child. Returns the child's PID on success, -1 o/w.
*/
pid_t create_child_with_stdfds(const char *exe, int argc, char *const argv[],
char *const envp[])
{
struct childfdmap fd_dups[3] = { {0, 0}, {1, 1}, {2, 2} };
pid_t kid;
int ret;
kid = create_child(exe, argc, argv, envp);
if (kid < 0)
return -1;
ret = syscall(SYS_dup_fds_to, kid, fd_dups, COUNT_OF(fd_dups));
if (ret != COUNT_OF(fd_dups)) {
sys_proc_destroy(kid, -1);
return -1;
}
return kid;
}
/* Provisions the CG cores to PID. Returns -1 if any of them fail. */
int provision_core_set(pid_t pid, const struct core_set *cores)
{
struct core_set pvcores;
size_t max_cores = parlib_nr_total_cores();
parlib_get_ll_core_set(&pvcores);
parlib_not_core_set(&pvcores);
parlib_and_core_sets(&pvcores, cores);
for (size_t i = 0; i < max_cores; i++) {
if (parlib_get_core(&pvcores, i)) {
if (sys_provision(pid, RES_CORES, i))
return -1;
}
}
return 0;
}