1 #include "dat.h" 2 #include "fns.h" 3 #include "error.h" 4 5 extern void vstack(void*); 6 7 /* 8 * all this is for the benefit of devcmd. 9 * i hope it's grateful. 10 */ 11 12 typedef struct Targ Targ; 13 struct Targ 14 { 15 int fd[3]; /* standard input, output and error */ 16 int wfd; 17 int* spin; 18 char** args; 19 char* dir; 20 int pid; 21 int nice; 22 }; 23 24 /* 25 * called by vstack once it has moved to 26 * the unshared stack in the new process. 27 */ 28 void 29 exectramp(Targ *t) 30 { 31 int *fd, i, nfd; 32 char filename[128], err[ERRMAX], status[2*ERRMAX]; 33 34 t->pid = getpid(); 35 *t->spin = 0; /* allow parent to proceed: can't just rendezvous: see below */ 36 fd = t->fd; 37 38 snprint(filename, sizeof(filename), "#d/%d", t->wfd); 39 t->wfd = open(filename, OWRITE|OCEXEC); 40 /* if it failed, we'll manage */ 41 42 nfd = MAXNFD; /* TO DO: should read from /fd */ 43 for(i = 0; i < nfd; i++) 44 if(i != fd[0] && i != fd[1] && i != fd[2] && i != t->wfd) 45 close(i); 46 47 if(fd[0] != 0){ 48 dup(fd[0], 0); 49 close(fd[0]); 50 } 51 if(fd[1] != 1){ 52 dup(fd[1], 1); 53 close(fd[1]); 54 } 55 if(fd[2] != 2){ 56 dup(fd[2], 2); 57 close(fd[2]); 58 } 59 60 if(t->dir != nil && chdir(t->dir) < 0){ 61 if(t->wfd > 0) 62 fprint(t->wfd, "chdir: %s: %r", t->dir); 63 _exits("bad dir"); 64 } 65 if(t->nice) 66 oslopri(); 67 68 exec(t->args[0], t->args); 69 err[0] = 0; 70 errstr(err, sizeof(err)); 71 if(t->args[0][0] != '/' && t->args[0][0] != '#' && 72 strncmp(t->args[0], "../", 3) != 0 && strncmp(t->args[0], "./", 2) != 0 && 73 strlen(t->args[0])+5 < sizeof(filename)){ 74 snprint(filename, sizeof(filename), "/bin/%s", t->args[0]); 75 exec(filename, t->args); 76 errstr(err, sizeof(err)); 77 } 78 snprint(status, sizeof(status), "%s: can't exec: %s", t->args[0], err); 79 if(t->wfd > 0) 80 write(t->wfd, status, strlen(status)); 81 _exits(status); 82 } 83 84 void* 85 oscmd(char **args, int nice, char *dir, int *fd) 86 { 87 Targ *t; 88 int spin, *spinptr, fd0[2], fd1[2], fd2[2], wfd[2], n; 89 Dir *d; 90 91 up->genbuf[0] = 0; 92 t = mallocz(sizeof(*t), 1); 93 if(t == nil) 94 return nil; 95 t->args = args; 96 t->dir = dir; 97 t->nice = nice; 98 fd0[0] = fd0[1] = -1; 99 fd1[0] = fd1[1] = -1; 100 fd2[0] = fd2[1] = -1; 101 wfd[0] = wfd[1] = -1; 102 if(dir != nil){ 103 d = dirstat(dir); 104 if(d == nil) 105 goto Error; 106 free(d); 107 } 108 if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0) 109 goto Error; 110 111 spinptr = &spin; 112 spin = 1; 113 114 t->fd[0] = fd0[0]; 115 t->fd[1] = fd1[1]; 116 t->fd[2] = fd2[1]; 117 t->wfd = wfd[1]; 118 t->spin = spinptr; 119 switch(rfork(RFPROC|RFMEM|RFREND|RFNOTEG|RFFDG|RFNAMEG|RFENVG)) { 120 case -1: 121 goto Error; 122 case 0: 123 /* if child returns first from rfork, its call to vstack replaces ... */ 124 vstack(t); 125 /* ... parent's return address from rfork and parent returns here */ 126 default: 127 /* if parent returns first from rfork, it comes here */ 128 /* can't call anything: on shared stack until child releases spin in exectramp */ 129 while(*spinptr) 130 ; 131 break; 132 } 133 134 close(fd0[0]); 135 close(fd1[1]); 136 close(fd2[1]); 137 close(wfd[1]); 138 139 n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1); 140 close(wfd[0]); 141 if(n > 0){ 142 close(fd0[1]); 143 close(fd1[0]); 144 close(fd2[0]); 145 up->genbuf[n] = 0; 146 errstr(up->genbuf, sizeof(up->genbuf)); 147 free(t); 148 return nil; 149 } 150 151 fd[0] = fd0[1]; 152 fd[1] = fd1[0]; 153 fd[2] = fd2[0]; 154 return t; 155 156 Error: 157 errstr(up->genbuf, sizeof(up->genbuf)); /* save the message before close */ 158 close(fd0[0]); 159 close(fd0[1]); 160 close(fd1[0]); 161 close(fd1[1]); 162 close(fd2[0]); 163 close(fd2[1]); 164 close(wfd[0]); 165 close(wfd[1]); 166 free(t); 167 errstr(up->genbuf, sizeof(up->genbuf)); 168 return nil; 169 } 170 171 int 172 oscmdkill(void *a) 173 { 174 Targ *t = a; 175 176 return postnote(PNGROUP, t->pid, "kill"); 177 } 178 179 int 180 oscmdwait(void*, char *buf, int n) 181 { 182 return await(buf, n); 183 } 184 185 void 186 oscmdfree(void *a) 187 { 188 free(a); 189 } 190