kconfig: use pkg-config for ncurses detection
[akaros.git] / user / parlib / parlib.c
1 /* Copyright (c) 2015 Google, Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details. */
4
5 #include <parlib/parlib.h>
6 #include <parlib/core_set.h>
7 #include <parlib/ros_debug.h>
8 #include <stdlib.h>
9
10 /* Control variables */
11 bool parlib_wants_to_be_mcp = TRUE;
12 bool parlib_never_yield = FALSE;
13 bool parlib_never_vc_request = FALSE;
14
15 /* Creates a child process for program @exe, with args and envs.  Will attempt
16  * to look in /bin/ if the initial lookup fails, and will invoke sh to handle
17  * non-elfs.  Returns the child's PID on success, -1 o/w. */
18 pid_t create_child(const char *exe, int argc, char *const argv[],
19                    char *const envp[])
20 {
21         pid_t kid;
22         char *path_exe;
23         char **sh_argv;
24         const char *sh_path = "/bin/sh";
25
26         kid = sys_proc_create(exe, strlen(exe), argv, envp, 0);
27         if (kid > 0)
28                 return kid;
29
30         /* Here's how we avoid infinite recursion.  We can only have ENOENT the
31          * first time through without bailing out, since all errno paths set exe
32          * to begin with '/'.  That includes calls from ENOEXEC, since sh_path
33          * begins with /.  To avoid repeated calls to ENOEXEC, we just look for
34          * sh_path as the exe, so if we have consecutive ENOEXECs, we'll bail
35          * out. */
36         switch (errno) {
37         case ENOENT:
38                 if (exe[0] == '/')
39                         return -1;
40                 path_exe = malloc(MAX_PATH_LEN);
41                 if (!path_exe)
42                         return -1;
43                 /* Our 'PATH' is only /bin. */
44                 snprintf(path_exe, MAX_PATH_LEN, "/bin/%s", exe);
45                 path_exe[MAX_PATH_LEN - 1] = 0;
46                 kid = create_child(path_exe, argc, argv, envp);
47                 free(path_exe);
48                 break;
49         case ENOEXEC:
50                 /* In case someone replaces /bin/sh with a non-elf. */
51                 if (!strcmp(sh_path, exe))
52                         return -1;
53                 /* We want enough space for the original argv, plus one entry at
54                  * the front for sh_path.  When we grab the original argv, we
55                  * also need the trailing NULL, which is at argv[argc].  That
56                  * means we really want argc + 1 entries from argv. */
57                 sh_argv = malloc(sizeof(char *) * (argc + 2));
58                 if (!sh_argv)
59                         return -1;
60                 memcpy(&sh_argv[1], argv, sizeof(char *) * (argc + 1));
61                 sh_argv[0] = (char*)sh_path;
62                 /* Replace the original argv[0] with the path to exe, which
63                  * might have been edited to include /bin/ */
64                 sh_argv[1] = (char*)exe;
65                 kid = create_child(sh_path, argc + 1, sh_argv, envp);
66                 free(sh_argv);
67                 break;
68         default:
69                 return -1;
70         }
71         return kid;
72 }
73
74 /* Creates a child process for exe, and shares the parent's standard FDs (stdin,
75  * stdout, stderr) with the child.  Returns the child's PID on success, -1 o/w.
76  */
77 pid_t create_child_with_stdfds(const char *exe, int argc, char *const argv[],
78                                char *const envp[])
79 {
80         struct childfdmap fd_dups[3] = { {0, 0}, {1, 1}, {2, 2} };
81         pid_t kid;
82         int ret;
83
84         kid = create_child(exe, argc, argv, envp);
85         if (kid < 0)
86                 return -1;
87         ret = syscall(SYS_dup_fds_to, kid, fd_dups, COUNT_OF(fd_dups));
88         if (ret != COUNT_OF(fd_dups)) {
89                 sys_proc_destroy(kid, -1);
90                 return -1;
91         }
92         return kid;
93 }
94
95 /* Provisions the CG cores to PID.  Returns -1 if any of them fail. */
96 int provision_core_set(pid_t pid, const struct core_set *cores)
97 {
98         struct core_set pvcores;
99         size_t max_cores = parlib_nr_total_cores();
100
101         parlib_get_ll_core_set(&pvcores);
102         parlib_not_core_set(&pvcores);
103         parlib_and_core_sets(&pvcores, cores);
104         for (size_t i = 0; i < max_cores; i++) {
105                 if (parlib_get_core(&pvcores, i)) {
106                         if (sys_provision(pid, RES_CORES, i))
107                                 return -1;
108                 }
109         }
110         return 0;
111 }