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