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