1 #include <signal.h>
2 #include <errno.h>
3 #include <setjmp.h>
4 #include <stdlib.h>
5 #include <stdarg.h>
6 #include <sys/ioctl.h>
7 #if HAVE_UNISTD_H
8 # include <unistd.h>
9 #endif
10 #if HAVE_SYS_WAIT_H
11 # include <sys/wait.h>
12 #endif
13 #include "deco.h"
14 #include "env.h"
15
16 #define QUANT 16
17
18 typedef (*funcptr) ();
19
20 static char **arg;
21 static arglen, argp;
22
23 static run ();
24
runset(char * dest)25 void runset (char *dest)
26 {
27 arg = (char**) malloc (QUANT * sizeof (char *));
28 arglen = QUANT;
29 arg [0] = dest;
30 argp = 1;
31 }
32
runarg(char * name)33 void runarg (char *name)
34 {
35 mcheck (arg, char **, arglen, QUANT, argp);
36 arg [argp++] = name;
37 }
38
rundone(char * name,char * a0,char * a1,char * a2)39 int rundone (char *name, char *a0, char *a1, char *a2)
40 {
41 register char **p, **q, *a;
42 int ret;
43
44 if (a2)
45 runarg (a2);
46 if (a1)
47 runarg (a1);
48 runarg (a0);
49 for (p=arg, q=arg+argp-1; p<q; ++p, --q) {
50 a = *p;
51 *p = *q;
52 *q = a;
53 }
54 runarg (0);
55 ret = runv (1, name, arg) == 0;
56 free (arg);
57 return (ret);
58 }
59
runcancel()60 void runcancel ()
61 {
62 free (arg);
63 }
64
execat(char * s1,char * s2,char * si)65 static char *execat (char *s1, char *s2, char *si)
66 {
67 register char *s;
68
69 s = si;
70 while (*s1 && *s1!=':')
71 *s++ = *s1++;
72 if (si != s)
73 *s++ = '/';
74 while (*s2)
75 *s++ = *s2++;
76 *s = 0;
77 return (*s1 ? ++s1 : 0);
78 }
79
80 #if !HAVE_EXECVPE
execvpe(char * name,char ** argv,char ** envstr)81 static int execvpe (char *name, char **argv, char **envstr)
82 {
83 static char *pathstr;
84 char fname [128];
85 char *newargs [256];
86 int i;
87 register char *cp;
88 register unsigned etxtbsy = 1;
89 register eacces = 0;
90
91 if (! pathstr && ! (pathstr = EnvGet ("PATH")))
92 pathstr = ":/bin:/usr/bin";
93 for (cp=name; ; ++cp) { /* check if name contains '/' */
94 if (! *cp) {
95 cp = pathstr; /* if no, set cp to pathstr */
96 break;
97 }
98 if (*cp == '/') {
99 cp = ""; /* else path is empty */
100 break;
101 }
102 }
103 do {
104 cp = execat (cp, name, fname);
105 retry: (void) execve (fname, argv, envstr);
106 switch (errno) {
107 case ENOEXEC:
108 newargs [0] = "sh";
109 newargs [1] = fname;
110 for (i=1; (newargs [i+1] = argv [i]); ++i) {
111 if (i >= 254) {
112 errno = E2BIG;
113 return (-1);
114 }
115 }
116 (void) execve ("/bin/sh", newargs, envstr);
117 return (-1);
118 case ETXTBSY:
119 if (++etxtbsy > 5)
120 return (-1);
121 (void) sleep (etxtbsy);
122 goto retry;
123 case EACCES:
124 ++eacces;
125 break;
126 case ENOMEM:
127 case E2BIG:
128 return (-1);
129 }
130 } while (cp);
131 if (eacces)
132 errno = EACCES;
133 return (-1);
134 }
135 #endif
136
runl(int silent,char * name,...)137 int runl (int silent, char *name, ...)
138 {
139 va_list ap;
140 int err;
141 char **argv, **argp;
142 int argc;
143
144 argc = 1;
145 va_start (ap, name);
146 while (va_arg (ap, char *) != NULL)
147 argc++;
148 va_end (ap);
149 argv = (char **) malloc (argc * sizeof (char *));
150 argp = argv;
151 va_start (ap, name);
152 while ((*argp++ = va_arg (ap, char *)) != NULL);
153 *argp = NULL;
154 va_end (ap);
155 err = run (name, argv, execve, silent);
156 free (argv);
157 return err;
158 }
159
runv(int silent,char * name,char ** a0)160 int runv (int silent, char *name, char **a0)
161 {
162 return (run (name, a0, execvpe, silent));
163 }
164
sigchild(int sig)165 RETSIGTYPE sigchild (int sig)
166 {
167 int status = 0;
168
169 signal (SIGCHLD, sigchild);
170 waitpid (-1, &status, WNOHANG | WUNTRACED);
171 }
172
sigign()173 void sigign ()
174 {
175 signal (SIGTERM, SIG_IGN);
176 signal (SIGQUIT, SIG_IGN);
177 signal (SIGINT, SIG_IGN);
178 signal (SIGCHLD, sigchild);
179 signal (SIGTTOU, SIG_IGN);
180 #ifdef SIGTSTP
181 signal (SIGTSTP, SIG_IGN);
182 #endif
183 }
184
sigdfl()185 void sigdfl ()
186 {
187 signal (SIGTERM, SIG_DFL);
188 signal (SIGQUIT, SIG_DFL);
189 signal (SIGINT, SIG_DFL);
190 signal (SIGCHLD, SIG_DFL);
191 #ifdef SIGTSTP
192 signal (SIGTSTP, SIG_DFL);
193 #endif
194 }
195
run(char * name,char ** a0,int (* exe)(),int silent)196 static int run (char *name, char **a0, int (*exe)(), int silent)
197 {
198 register t;
199 int status = 0;
200 static char **arg;
201
202 arg = a0;
203 signal (SIGCHLD, SIG_IGN);
204 if ((t = vfork ()) == -1)
205 /* cannot fork */
206 return (0x7e00);
207 if (t == 0) {
208 /* Child. */
209 sigdfl ();
210 if (silent) {
211 close (0);
212 close (1);
213 close (2);
214 open ("/dev/null", 0);
215 open ("/dev/null", 1);
216 dup (1);
217 } else {
218 /* Set for child the separate process group.
219 * Give the terminal to the child. */
220 int child_pid = getpid ();
221 setpgid (child_pid, child_pid);
222 tcsetpgrp (2, child_pid);
223 }
224 signal (SIGTTOU, SIG_DFL);
225 (*exe) (name, arg, EnvVector);
226 if (! silent)
227 outerr ("%s: Command not found.\n", name);
228 _exit (0x7f); /* file not found */
229 }
230
231 /* Parent. */
232 waitpid (t, &status, WUNTRACED);
233
234 /* Get back the terminal. */
235 if (! silent) {
236 tcsetpgrp (2, main_pid);
237 killpg (t, SIGCONT);
238 }
239 signal (SIGCHLD, sigchild);
240
241 if (WIFSTOPPED (status))
242 return -t;
243 return (status);
244 }
245