Rune - Implement hard-locking model feature
[rune.git] / libruntime / sys_proc.c
1 /*
2  * SYS_PROC.C
3  *
4  * Process-related system support
5  */
6
7 #include "defs.h"
8 #include <sys/wait.h>
9
10 typedef struct ProcStor {
11         runepid_t       pid;
12         int32_t         xcode;
13         int32_t         error;
14 #if LONG_BITS == 64
15         int             pad01;
16 #endif
17 } ProcStor;
18
19 /*
20  * Count includes NULL terminator.  Returns allocated array.
21  */
22 static
23 char **
24 argvcheck(PointerStor *psp, size_t *countp)
25 {
26         PointerStor *ps;
27         size_t count;
28         char **av;
29
30         if (psp->s_Addr == NULL)
31                 return NULL;
32
33         BOUNDSCHECK(psp, sizeof(PointerStor));
34         count = 0;
35         for (ps = (void *)psp->s_Addr; (void *)ps < (void *)psp->s_End; ++ps) {
36                 ++count;
37                 if (ps->s_Addr == NULL)
38                         break;
39         }
40         if ((void *)ps == (void *)psp->s_End)
41                 dpanic("char **array not NULL terminated");
42         *countp = count;
43
44         av = zalloc(sizeof(char **) * count);
45         count = 0;
46         for (ps = (void *)psp->s_Addr; (void *)ps < (void *)psp->s_End; ++ps) {
47                 if (ps->s_Addr == NULL)
48                         break;
49                 STRBOUNDSCHECK(ps, 0x3FFFFFFF);
50                 av[count] = strdup(ps->s_Addr);
51                 ++count;
52         }
53         av[count] = NULL;
54
55         return av;
56 }
57
58 static
59 void
60 argvfree(char **av)
61 {
62         size_t count;
63
64         if (av) {
65                 for (count = 0; av[count]; ++count)
66                         free(av[count]);
67                 ++count;
68                 zfree(av, sizeof(char **) * count);
69         }
70 }
71
72
73 struct fexec_args {
74         LValueStor      lvs;
75         PointerStor     path;
76         PointerStor     argv;
77         PointerStor     envp;
78         int             fd0;
79         int             fd1;
80         int             fd2;
81 #if LONG_BITS == 64
82         int             pad01;
83 #endif
84 };
85
86 extern char **environ;
87
88 void
89 RuneSysCall_fexec(struct fexec_args *args, int *rval)
90 {
91         ProcStor *proc = args->lvs.s_Addr;
92         size_t asize;
93         size_t esize;
94         char **av;
95         char **envp;
96         pid_t pid;
97
98         STRBOUNDSCHECK(&args->path, 0x3FFFFFFF);
99         av = argvcheck(&args->argv, &asize);
100         envp = argvcheck(&args->envp, &esize);
101         if ((pid = vfork()) == 0) {
102                 if (args->fd0 != 0)
103                         dup2(args->fd0, 0);
104                 if (args->fd1 != 1)
105                         dup2(args->fd1, 1);
106                 if (args->fd2 != 2)
107                         dup2(args->fd2, 2);
108                 fcntl(0, F_SETFD, 0);
109                 fcntl(1, F_SETFD, 0);
110                 fcntl(2, F_SETFD, 0);
111                 if (envp == NULL)
112                         envp = environ;
113
114                 execve(args->path.s_Addr, av, envp);
115                 _exit(99);
116         }
117         argvfree(av);
118         argvfree(envp);
119         if (sizeof(pid) < sizeof(runepid_t))
120                 proc->pid = (runepid_t)(int)pid;
121         else
122                 proc->pid = pid;
123         if (pid < 0)
124                 *rval = -1;
125         else
126                 *rval = 0;
127 }
128
129 struct fwait_args {
130         LValueStor      lvs;
131 #if 0
132         int             ms;
133 #if LONG_BITS == 64
134         int             pad01;
135 #endif
136 #endif
137 };
138
139 void
140 RuneSysCall_fwait(struct fwait_args *args, int *rval)
141 {
142         ProcStor *proc = args->lvs.s_Addr;
143         pid_t pid;
144
145         for (;;) {
146                 int status;
147
148                 pid = wait4(proc->pid, &status, WNOHANG, NULL);
149                 if (pid < 0) {
150                         if (errno == EINTR)
151                                 continue;
152                         if (errno != EAGAIN) {
153                                 proc->error = errno;
154                                 *rval = -1;
155                                 break;
156                         }
157                         pid = 0;
158                 }
159                 if (pid == 0) {
160                         threadWaitEvent(proc->pid, THWAIT_PROC);
161                         continue;
162                 }
163                 proc->pid = pid;
164                 proc->error = 0;
165                 proc->xcode = WEXITSTATUS(status);
166                 *rval = 0;
167                 break;
168         }
169 }
170
171 struct fwaitn_args {
172         LValueStor      lvs;
173 };
174
175 void
176 RuneSysCall_fwaitn(struct fwaitn_args *args, int *rval)
177 {
178         ProcStor *proc = args->lvs.s_Addr;
179         pid_t pid;
180
181         for (;;) {
182                 int status;
183                 pid = wait4(proc->pid, &status, WNOHANG, NULL);
184                 if (pid < 0) {
185                         if (errno == EINTR)
186                                 continue;
187                         proc->error = errno;
188                         *rval = -1;
189                         break;
190                 }
191                 if (pid == 0) {
192                         proc->error = EAGAIN;
193                         *rval = -1;
194                         break;
195                 }
196                 proc->pid = pid;
197                 proc->error = 0;
198                 proc->xcode = WEXITSTATUS(status);
199                 *rval = 0;
200                 break;
201         }
202 }
203