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