parlib: Add __uth_sync_swap and __uth_sync_is_empty
[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/ros_debug.h>
7 #include <stdlib.h>
8
9 /* Control variables */
10 bool parlib_wants_to_be_mcp = TRUE;
11 bool parlib_never_yield = FALSE;
12 bool parlib_never_vc_request = FALSE;
13
14 /* Creates a child process for program @exe, with args and envs.  Will attempt
15  * to look in /bin/ if the initial lookup fails, and will invoke sh to handle
16  * non-elfs.  Returns the child's PID on success, -1 o/w. */
17 pid_t create_child(const char *exe, int argc, char *const argv[],
18                    char *const envp[])
19 {
20         pid_t kid;
21         char *path_exe;
22         char **sh_argv;
23         const char *sh_path = "/bin/sh";
24
25         kid = sys_proc_create(exe, strlen(exe), argv, envp, 0);
26         if (kid > 0)
27                 return kid;
28
29         /* Here's how we avoid infinite recursion.  We can only have ENOENT the
30          * first time through without bailing out, since all errno paths set exe to
31          * begin with '/'.  That includes calls from ENOEXEC, since sh_path begins
32          * with /.  To avoid repeated calls to ENOEXEC, we just look for sh_path as
33          * the exe, so if we have consecutive ENOEXECs, we'll bail out. */
34         switch (errno) {
35         case ENOENT:
36                 if (exe[0] == '/')
37                         return -1;
38                 path_exe = malloc(MAX_PATH_LEN);
39                 if (!path_exe)
40                         return -1;
41                 /* Our 'PATH' is only /bin. */
42                 snprintf(path_exe, MAX_PATH_LEN, "/bin/%s", exe);
43                 path_exe[MAX_PATH_LEN - 1] = 0;
44                 kid = create_child(path_exe, argc, argv, envp);
45                 free(path_exe);
46                 break;
47         case ENOEXEC:
48                 /* In case someone replaces /bin/sh with a non-elf. */
49                 if (!strcmp(sh_path, exe))
50                         return -1;
51                 /* We want enough space for the original argv, plus one entry at the
52                  * front for sh_path.  When we grab the original argv, we also need the
53                  * trailing NULL, which is at argv[argc].  That means we really want
54                  * argc + 1 entries from argv. */
55                 sh_argv = malloc(sizeof(char *) * (argc + 2));
56                 if (!sh_argv)
57                         return -1;
58                 memcpy(&sh_argv[1], argv, sizeof(char *) * (argc + 1));
59                 sh_argv[0] = (char*)sh_path;
60                 /* Replace the original argv[0] with the path to exe, which might have
61                  * been edited to include /bin/ */
62                 sh_argv[1] = (char*)exe;
63                 kid = create_child(sh_path, argc + 1, sh_argv, envp);
64                 free(sh_argv);
65                 break;
66         default:
67                 return -1;
68         }
69         return kid;
70 }
71
72 /* Creates a child process for exe, and shares the parent's standard FDs (stdin,
73  * stdout, stderr) with the child.  Returns the child's PID on success, -1 o/w.
74  */
75 pid_t create_child_with_stdfds(const char *exe, int argc, char *const argv[],
76                                char *const envp[])
77 {
78         struct childfdmap fd_dups[3] = { {0, 0}, {1, 1}, {2, 2} };
79         pid_t kid;
80         int ret;
81
82         kid = create_child(exe, argc, argv, envp);
83         if (kid < 0)
84                 return -1;
85         ret = syscall(SYS_dup_fds_to, kid, fd_dups, COUNT_OF(fd_dups));
86         if (ret != COUNT_OF(fd_dups)) {
87                 sys_proc_destroy(kid, -1);
88                 return -1;
89         }
90         return kid;
91 }