1 #include "defs.h"
2 #include <sys/wait.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <errno.h>
6
7 static int metas(char *);
8 static int waitproc(int *);
9 static int doshell(char *, int);
10 static int doexec(char *);
11
12 int
dosys(char * comstring,int nohalt,int nowait,char * prefix)13 dosys(char *comstring, int nohalt, int nowait, char *prefix)
14 {
15 int status;
16 struct process *procp;
17
18 /* make sure there is room in the process stack */
19 if(nproc >= MAXPROC)
20 waitstack(MAXPROC-1);
21
22 /* make sure fewer than proclimit processes are running */
23 while(proclive >= proclimit)
24 {
25 enbint(SIG_IGN);
26 waitproc(&status);
27 enbint(intrupt);
28 }
29
30 if(prefix)
31 {
32 fputs(prefix, stdout);
33 fputs(comstring, stdout);
34 }
35
36 procp = procstack + nproc;
37 procp->pid = (forceshell || metas(comstring) ) ?
38 doshell(comstring,nohalt) : doexec(comstring);
39 if(procp->pid == -1)
40 fatal("fork failed");
41 procstack[nproc].nohalt = nohalt;
42 procstack[nproc].nowait = nowait;
43 procstack[nproc].done = NO;
44 ++proclive;
45 ++nproc;
46
47 if(nowait)
48 {
49 printf(" &%d\n", procp->pid);
50 fflush(stdout);
51 return 0;
52 }
53 if(prefix)
54 {
55 putchar('\n');
56 fflush(stdout);
57 }
58 return waitstack(nproc-1);
59 }
60
61 static int
metas(char * s)62 metas(char *s) /* Are there are any Shell meta-characters? */
63 {
64 char c;
65
66 while( (funny[c = *s++] & META) == 0 )
67 ;
68 return( c );
69 }
70
71 static void
doclose(void)72 doclose(void) /* Close open directory files before exec'ing */
73 {
74 struct dirhd *od;
75
76 for (od = firstod; od; od = od->nxtdirhd)
77 if(od->dirfc)
78 closedir(od->dirfc);
79 }
80
81 /* wait till none of the processes in the stack starting at k is live */
82 int
waitstack(int k)83 waitstack(int k)
84 {
85 int npending, status, totstatus;
86 int i;
87
88 totstatus = 0;
89 npending = 0;
90 for(i=k ; i<nproc; ++i)
91 if(! procstack[i].done)
92 ++npending;
93 enbint(SIG_IGN);
94 if(dbgflag > 1)
95 printf("waitstack(%d)\n", k);
96
97 while(npending>0 && proclive>0)
98 {
99 if(waitproc(&status) >= k)
100 --npending;
101 totstatus |= status;
102 }
103
104 if(nproc > k)
105 nproc = k;
106 enbint(intrupt);
107 return totstatus;
108 }
109
110 static int
waitproc(int * statp)111 waitproc(int *statp)
112 {
113 pid_t pid;
114 int status;
115 int i;
116 struct process *procp;
117 char junk[50];
118 static int inwait = NO;
119
120 if(inwait) /* avoid infinite recursions on errors */
121 return MAXPROC;
122 inwait = YES;
123
124 pid = wait(&status);
125 if(dbgflag > 1)
126 fprintf(stderr, "process %d done, status = %d\n", pid, status);
127 if(pid == -1)
128 {
129 if(errno == ECHILD) /* multiple deaths, no problem */
130 {
131 if(proclive)
132 {
133 for(i=0, procp=procstack; i<nproc; ++i, ++procp)
134 procp->done = YES;
135 proclive = nproc = 0;
136 }
137 return MAXPROC;
138 }
139 fatal("bad wait code");
140 }
141 for(i=0, procp=procstack; i<nproc; ++i, ++procp)
142 if(procp->pid == pid)
143 {
144 --proclive;
145 procp->done = YES;
146
147 if(status)
148 {
149 if(procp->nowait)
150 printf("%d: ", pid);
151 if( WEXITSTATUS(status) )
152 printf("*** Error code %d", WEXITSTATUS(status) );
153 else printf("*** Termination code %d", WTERMSIG(status));
154
155 printf(procp->nohalt ? "(ignored)\n" : "\n");
156 fflush(stdout);
157 if(!keepgoing && !procp->nohalt)
158 fatal(CHNULL);
159 }
160 *statp = status;
161 inwait = NO;
162 return i;
163 }
164
165 sprintf(junk, "spurious return from process %d", pid);
166 fatal(junk);
167 /*NOTREACHED*/
168 return -1;
169 }
170
171 static int
doshell(char * comstring,int nohalt)172 doshell(char *comstring, int nohalt)
173 {
174 pid_t pid;
175
176 if((pid = fork()) == 0)
177 {
178 enbint(SIG_DFL);
179 doclose();
180
181 execl(SHELLCOM, "sh", (nohalt ? "-c" : "-ce"), comstring, NULL);
182 fatal("Couldn't load Shell");
183 }
184
185 return pid;
186 }
187
188 static int
doexec(char * str)189 doexec(char *str)
190 {
191 char *t, *tend;
192 char **argv;
193 char **p;
194 int nargs;
195 pid_t pid;
196
197 while( *str==' ' || *str=='\t' )
198 ++str;
199 if( *str == '\0' )
200 return(-1); /* no command */
201
202 nargs = 1;
203 for(t = str ; *t ; )
204 {
205 ++nargs;
206 while(*t!=' ' && *t!='\t' && *t!='\0')
207 ++t;
208 if(*t) /* replace first white space with \0, skip rest */
209 for( *t++ = '\0' ; *t==' ' || *t=='\t' ; ++t)
210 ;
211 }
212
213 /* now allocate args array, copy pointer to start of each string,
214 then terminate array with a null
215 */
216 p = argv = (char **) ckalloc(nargs*sizeof(char *));
217 tend = t;
218 for(t = str ; t<tend ; )
219 {
220 *p++ = t;
221 while( *t )
222 ++t;
223 do {
224 ++t;
225 } while(t<tend && (*t==' ' || *t=='\t') );
226 }
227 *p = NULL;
228 /*TEMP for(p=argv; *p; ++p)printf("arg=%s\n", *p);*/
229
230 if((pid = fork()) == 0)
231 {
232 enbint(SIG_DFL);
233 doclose();
234 enbint(intrupt);
235 execvp(str, argv);
236 printf("\n");
237 fatal1("Cannot load %s",str);
238 }
239
240 free( (char *) argv);
241 return pid;
242 }
243
244 void
touch(int force,char * name)245 touch(int force, char *name)
246 {
247 struct stat stbuff;
248 char junk[1];
249 int fd;
250
251 if( stat(name,&stbuff) < 0)
252 if(force)
253 goto create;
254 else
255 {
256 fprintf(stderr, "touch: file %s does not exist.\n", name);
257 return;
258 }
259
260 if(stbuff.st_size == 0)
261 goto create;
262
263 if( (fd = open(name, O_RDWR)) < 0)
264 goto bad;
265
266 if( read(fd, junk, 1) < 1)
267 {
268 close(fd);
269 goto bad;
270 }
271 lseek(fd, 0L, SEEK_SET);
272 if( write(fd, junk, 1) < 1 )
273 {
274 close(fd);
275 goto bad;
276 }
277 close(fd);
278 return;
279
280 bad:
281 fprintf(stderr, "Cannot touch %s\n", name);
282 return;
283
284 create:
285 if( (fd = creat(name, 0666)) < 0)
286 goto bad;
287 close(fd);
288 }
289