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 return -1; 169 } 170 171 static int 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 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 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