xref: /plan9/sys/src/ape/cmd/make/dosys.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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
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
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
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
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
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 }
169 
170 static int
171 doshell(char *comstring, int nohalt)
172 {
173 pid_t pid;
174 
175 if((pid = fork()) == 0)
176 	{
177 	enbint(SIG_DFL);
178 	doclose();
179 
180 	execl(SHELLCOM, "sh", (nohalt ? "-c" : "-ce"), comstring, 0);
181 	fatal("Couldn't load Shell");
182 	}
183 
184 return pid;
185 }
186 
187 static int
188 doexec(char *str)
189 {
190 char *t, *tend;
191 char **argv;
192 char **p;
193 int nargs;
194 pid_t pid;
195 
196 while( *str==' ' || *str=='\t' )
197 	++str;
198 if( *str == '\0' )
199 	return(-1);	/* no command */
200 
201 nargs = 1;
202 for(t = str ; *t ; )
203 	{
204 	++nargs;
205 	while(*t!=' ' && *t!='\t' && *t!='\0')
206 		++t;
207 	if(*t)	/* replace first white space with \0, skip rest */
208 		for( *t++ = '\0' ; *t==' ' || *t=='\t'  ; ++t)
209 			;
210 	}
211 
212 /* now allocate args array, copy pointer to start of each string,
213    then terminate array with a null
214 */
215 p = argv = (char **) ckalloc(nargs*sizeof(char *));
216 tend = t;
217 for(t = str ; t<tend ; )
218 	{
219 	*p++ = t;
220 	while( *t )
221 		++t;
222 	do	{
223 		++t;
224 		} while(t<tend && (*t==' ' || *t=='\t') );
225 	}
226 *p = NULL;
227 /*TEMP  for(p=argv; *p; ++p)printf("arg=%s\n", *p);*/
228 
229 if((pid = fork()) == 0)
230 	{
231 	enbint(SIG_DFL);
232 	doclose();
233 	enbint(intrupt);
234 	execvp(str, argv);
235 	printf("\n");
236 	fatal1("Cannot load %s",str);
237 	}
238 
239 free( (char *) argv);
240 return pid;
241 }
242 
243 void
244 touch(int force, char *name)
245 {
246 struct stat stbuff;
247 char junk[1];
248 int fd;
249 
250 if( stat(name,&stbuff) < 0)
251 	if(force)
252 		goto create;
253 	else
254 		{
255 		fprintf(stderr, "touch: file %s does not exist.\n", name);
256 		return;
257 		}
258 
259 if(stbuff.st_size == 0)
260 	goto create;
261 
262 if( (fd = open(name, O_RDWR)) < 0)
263 	goto bad;
264 
265 if( read(fd, junk, 1) < 1)
266 	{
267 	close(fd);
268 	goto bad;
269 	}
270 lseek(fd, 0L, SEEK_SET);
271 if( write(fd, junk, 1) < 1 )
272 	{
273 	close(fd);
274 	goto bad;
275 	}
276 close(fd);
277 return;
278 
279 bad:
280 	fprintf(stderr, "Cannot touch %s\n", name);
281 	return;
282 
283 create:
284 	if( (fd = creat(name, 0666)) < 0)
285 		goto bad;
286 	close(fd);
287 }
288