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