| /* 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; |
| } |