1 /* -*- mode: C; mode: fold; -*- */
2 /*
3 Copyright (C) 2009-2017,2018 John E. Davis
4
5 This file is part of the S-Lang Library.
6
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA.
21 */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <errno.h>
27 #ifdef HAVE_SYS_TYPES_H
28 # include <sys/types.h>
29 #endif
30 #ifdef HAVE_SYS_WAIT_H
31 # include <sys/wait.h>
32 #endif
33 #include <unistd.h>
34
35 #include <string.h>
36 #include <slang.h>
37
38 /* WCONTINUED is not defined on Hurd, in waitflags.h. */
39 #ifndef WCONTINUED
40 # define WCONTINUED 0 /* Debian patch used 8, but 0 is safer */
41 #endif
42 SLANG_MODULE(fork);
43
fork_intrinsic(void)44 static int fork_intrinsic (void)
45 {
46 int ret = fork ();
47 if (ret == -1)
48 (void) SLerrno_set_errno (errno);
49 return ret;
50 }
51
52 typedef struct
53 {
54 int pid;
55 int exited;
56 int exit_status;
57 int signal;
58 int coredump;
59 int stopped;
60 int continued;
61 }
62 Waitpid_Type;
63
64 static SLang_CStruct_Field_Type Waitpid_Struct [] =
65 {
66 MAKE_CSTRUCT_FIELD(Waitpid_Type, pid, "pid", SLANG_INT_TYPE, 0),
67 MAKE_CSTRUCT_FIELD(Waitpid_Type, exited, "exited", SLANG_INT_TYPE, 0),
68 MAKE_CSTRUCT_FIELD(Waitpid_Type, exit_status, "exit_status", SLANG_INT_TYPE, 0),
69 MAKE_CSTRUCT_FIELD(Waitpid_Type, signal, "signal", SLANG_INT_TYPE, 0),
70 MAKE_CSTRUCT_FIELD(Waitpid_Type, coredump, "coredump", SLANG_INT_TYPE, 0),
71 MAKE_CSTRUCT_FIELD(Waitpid_Type, stopped, "stopped", SLANG_INT_TYPE, 0),
72 MAKE_CSTRUCT_FIELD(Waitpid_Type, continued, "continued", SLANG_INT_TYPE, 0),
73 SLANG_END_CSTRUCT_TABLE
74 };
75
waitpid_intrinsic(int * pid,int * options)76 static void waitpid_intrinsic (int *pid, int *options)
77 {
78 int status, ret;
79 Waitpid_Type s;
80
81 while (-1 == (ret = waitpid ((pid_t)*pid, &status, *options)))
82 {
83 if (errno == EINTR)
84 {
85 if (-1 != SLang_handle_interrupt ())
86 continue;
87 }
88 (void) SLerrno_set_errno (errno);
89 (void) SLang_push_null ();
90 return;
91 }
92
93 memset ((char *)&s, 0, sizeof(Waitpid_Type));
94 if (WIFEXITED(status))
95 {
96 s.exited = 1;
97 s.exit_status = WEXITSTATUS(status);
98 }
99 if (WIFSIGNALED(status))
100 {
101 s.signal = WTERMSIG(status);
102 #ifdef WCOREDUMP
103 s.coredump = WCOREDUMP(status) != 0;
104 #endif
105 }
106 if (WIFSTOPPED(status))
107 s.stopped = WSTOPSIG(status);
108 #ifdef WIFCONTINUED
109 s.continued = WIFCONTINUED(status);
110 #endif
111 s.pid = ret;
112 (void) SLang_push_cstruct ((VOID_STAR)&s, Waitpid_Struct);
113 }
114
pop_argv(SLang_Array_Type ** atp)115 static char **pop_argv (SLang_Array_Type **atp)
116 {
117 SLang_Array_Type *at;
118 char **argv;
119 SLuindex_Type i, num, argc;
120 char **strp;
121
122 *atp = NULL;
123
124 if (-1 == SLang_pop_array_of_type (&at, SLANG_STRING_TYPE))
125 return NULL;
126
127 num = at->num_elements;
128 if (NULL == (argv = (char **)SLmalloc ((num+1)*sizeof(char *))))
129 {
130 SLang_free_array (at);
131 return NULL;
132 }
133
134 strp = (char **)at->data;
135 argc = 0;
136 for (i = 0; i < num; i++)
137 {
138 if (strp[i] != NULL)
139 argv[argc++] = strp[i];
140 }
141 argv[argc] = NULL;
142 *atp = at;
143 return argv;
144 }
145
146 #define CALL_EXECV 1
147 #define CALL_EXECVP 2
148 #define CALL_EXECVE 3
149
call_what(int what,char * path,char ** argv,char ** envp)150 static int call_what (int what, char *path, char **argv, char **envp)
151 {
152 while (1)
153 {
154 int ret;
155
156 switch (what)
157 {
158 case CALL_EXECV:
159 ret = execv (path, argv);
160 break;
161
162 case CALL_EXECVP:
163 ret = execvp (path, argv);
164 break;
165
166 case CALL_EXECVE:
167 ret = execve (path, argv, envp);
168 break;
169 }
170
171 if (ret == 0)
172 return 0; /* should never happen */
173
174 SLerrno_set_errno (errno);
175 if (errno == EINTR)
176 {
177 if (-1 != SLang_handle_interrupt ())
178 continue;
179 }
180 break;
181 }
182 return -1;
183 }
184
exec_what(int what,int has_envp)185 static int exec_what (int what, int has_envp)
186 {
187 SLang_Array_Type *at_argv = NULL;
188 SLang_Array_Type *at_envp = NULL;
189 char **argv = NULL, **envp = NULL;
190 char *path = NULL;
191 int status = -1;
192
193 if (has_envp)
194 {
195 if (NULL == (envp = pop_argv (&at_envp)))
196 goto free_and_return;
197 }
198
199 if (NULL == (argv = pop_argv (&at_argv)))
200 goto free_and_return;
201
202 if (-1 == SLang_pop_slstring (&path))
203 goto free_and_return;
204
205 status = call_what (what, path, argv, envp);
206
207 free_and_return:
208
209 if (path != NULL) SLang_free_slstring (path);
210 if (argv != NULL) SLfree ((char *)argv);
211 if (at_argv != NULL) SLang_free_array (at_argv);
212 if (envp != NULL) SLfree ((char *)envp);
213 if (at_envp != NULL) SLang_free_array (at_envp);
214 return status;
215 }
216
execv_intrin(void)217 static int execv_intrin (void)
218 {
219 if (SLang_Num_Function_Args != 2)
220 SLang_verror (SL_Usage_Error, "Usage: ret = execv(path, argv[]);");
221
222 return exec_what (CALL_EXECV, 0);
223 }
224
execvp_intrin(void)225 static int execvp_intrin (void)
226 {
227 if (SLang_Num_Function_Args != 2)
228 SLang_verror (SL_Usage_Error, "Usage: ret = execvp(path, argv[]);");
229
230 return exec_what (CALL_EXECVP, 0);
231 }
232
execve_intrin(void)233 static int execve_intrin (void)
234 {
235 if (SLang_Num_Function_Args != 3)
236 SLang_verror (SL_Usage_Error, "Usage: ret = execve(path, argv[], env[]);");
237
238 return exec_what (CALL_EXECVE, 1);
239 }
240
_exit_intrin(int * s)241 static void _exit_intrin (int *s)
242 {
243 (void) fflush (stdout);
244 (void) fflush (stderr);
245 _exit (*s);
246 }
247
pipe_intrin(void)248 static void pipe_intrin (void)
249 {
250 int fds[2];
251 SLFile_FD_Type *f0;
252 SLFile_FD_Type *f1;
253
254 while (-1 == pipe (fds))
255 {
256 if (errno == EINTR)
257 {
258 if (-1 != SLang_handle_interrupt ())
259 continue;
260 }
261 SLerrno_set_errno (errno);
262 SLang_verror (SL_OS_Error, "pipe failed: %s", SLerrno_strerror(errno));
263 return;
264 }
265
266 f0 = SLfile_create_fd ("*pipe*", fds[0]);
267 f1 = SLfile_create_fd ("*pipe*", fds[1]);
268 if ((NULL != f0) && (NULL != f1))
269 {
270 /* Ignore errors and allow the free_fd routines to clean up */
271 (void) SLfile_push_fd (f0);
272 (void) SLfile_push_fd (f1);
273 }
274 SLfile_free_fd (f1);
275 SLfile_free_fd (f0);
276 }
277
278 static SLang_IConstant_Type Module_IConstants [] =
279 {
280 MAKE_ICONSTANT("WNOHANG", WNOHANG),
281 MAKE_ICONSTANT("WUNTRACED", WUNTRACED),
282 MAKE_ICONSTANT("WCONTINUED", WCONTINUED),
283 SLANG_END_ICONST_TABLE
284 };
285
286 static SLang_Intrin_Fun_Type Module_Intrinsics [] =
287 {
288 MAKE_INTRINSIC_0("fork", fork_intrinsic, SLANG_INT_TYPE),
289 MAKE_INTRINSIC_2("waitpid", waitpid_intrinsic, SLANG_VOID_TYPE, SLANG_INT_TYPE, SLANG_INT_TYPE),
290 MAKE_INTRINSIC_0("execv", execv_intrin, SLANG_INT_TYPE),
291 MAKE_INTRINSIC_0("execvp", execvp_intrin, SLANG_INT_TYPE),
292 MAKE_INTRINSIC_0("execve", execve_intrin, SLANG_INT_TYPE),
293 MAKE_INTRINSIC_0("pipe", pipe_intrin, SLANG_VOID_TYPE),
294 MAKE_INTRINSIC_1("_exit", _exit_intrin, SLANG_VOID_TYPE, SLANG_INT_TYPE),
295 SLANG_END_INTRIN_FUN_TABLE
296 };
297
init_fork_module_ns(char * ns_name)298 int init_fork_module_ns (char *ns_name)
299 {
300 SLang_NameSpace_Type *ns = SLns_create_namespace (ns_name);
301 if (ns == NULL)
302 return -1;
303
304 if ((-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL))
305 || (-1 == SLns_add_iconstant_table (ns, Module_IConstants, NULL)))
306 return -1;
307
308 return 0;
309 }
310
311 /* This function is optional */
deinit_fork_module(void)312 void deinit_fork_module (void)
313 {
314 }
315