xref: /plan9/sys/src/ape/cmd/make/dosys.c (revision 027288c8a8763d34db13dc89d8bcd6514dbc2163)
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