havefork.c (5464B)
1 #include <u.h> 2 #include <signal.h> 3 #if defined(PLAN9PORT) && defined(__sun__) 4 # define BSD_COMP /* sigh. for TIOCNOTTY */ 5 #endif 6 #include <sys/ioctl.h> 7 #include "rc.h" 8 #include "getflags.h" 9 #include "exec.h" 10 #include "io.h" 11 #include "fns.h" 12 13 int havefork = 1; 14 15 void 16 Xasync(void) 17 { 18 int null = open("/dev/null", 0); 19 int tty; 20 int pid; 21 char npid[10]; 22 if(null<0){ 23 Xerror("Can't open /dev/null\n"); 24 return; 25 } 26 switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){ 27 case -1: 28 close(null); 29 Xerror("try again"); 30 break; 31 case 0: 32 clearwaitpids(); 33 /* 34 * I don't know what the right thing to do here is, 35 * so this is all experimentally determined. 36 * If we just dup /dev/null onto 0, then running 37 * ssh foo & will reopen /dev/tty, try to read a password, 38 * get a signal, and repeat, in a tight loop, forever. 39 * Arguably this is a bug in ssh (it behaves the same 40 * way under bash as under rc) but I'm fixing it here 41 * anyway. If we dissociate the process from the tty, 42 * then it won't be able to open /dev/tty ever again. 43 * The SIG_IGN on SIGTTOU makes writing the tty 44 * (via fd 1 or 2, for example) succeed even though 45 * our pgrp is not the terminal's controlling pgrp. 46 */ 47 if((tty = open("/dev/tty", OREAD)) >= 0){ 48 /* 49 * Should make reads of tty fail, writes succeed. 50 */ 51 signal(SIGTTIN, SIG_IGN); 52 signal(SIGTTOU, SIG_IGN); 53 ioctl(tty, TIOCNOTTY); 54 close(tty); 55 } 56 if(isatty(0)) 57 pushredir(ROPEN, null, 0); 58 else 59 close(null); 60 start(runq->code, runq->pc+1, runq->local); 61 runq->ret = 0; 62 break; 63 default: 64 addwaitpid(pid); 65 close(null); 66 runq->pc = runq->code[runq->pc].i; 67 inttoascii(npid, pid); 68 setvar("apid", newword(npid, (word *)0)); 69 break; 70 } 71 } 72 73 void 74 Xpipe(void) 75 { 76 struct thread *p = runq; 77 int pc = p->pc, forkid; 78 int lfd = p->code[pc++].i; 79 int rfd = p->code[pc++].i; 80 int pfd[2]; 81 if(pipe(pfd)<0){ 82 Xerror("can't get pipe"); 83 return; 84 } 85 switch(forkid = fork()){ 86 case -1: 87 Xerror("try again"); 88 break; 89 case 0: 90 clearwaitpids(); 91 start(p->code, pc+2, runq->local); 92 runq->ret = 0; 93 close(pfd[PRD]); 94 pushredir(ROPEN, pfd[PWR], lfd); 95 break; 96 default: 97 addwaitpid(forkid); 98 start(p->code, p->code[pc].i, runq->local); 99 close(pfd[PWR]); 100 pushredir(ROPEN, pfd[PRD], rfd); 101 p->pc = p->code[pc+1].i; 102 p->pid = forkid; 103 break; 104 } 105 } 106 107 /* 108 * Who should wait for the exit from the fork? 109 */ 110 void 111 Xbackq(void) 112 { 113 struct thread *p = runq; 114 char wd[8193]; 115 int c, n; 116 char *s, *ewd=&wd[8192], *stop, *q; 117 struct io *f; 118 var *ifs = vlook("ifs"); 119 word *v, *nextv; 120 int pfd[2]; 121 int pid; 122 Rune r; 123 stop = ifs->val?ifs->val->word:""; 124 if(pipe(pfd)<0){ 125 Xerror("can't make pipe"); 126 return; 127 } 128 switch(pid = fork()){ 129 case -1: 130 Xerror("try again"); 131 close(pfd[PRD]); 132 close(pfd[PWR]); 133 return; 134 case 0: 135 clearwaitpids(); 136 close(pfd[PRD]); 137 start(runq->code, runq->pc+1, runq->local); 138 pushredir(ROPEN, pfd[PWR], 1); 139 return; 140 default: 141 addwaitpid(pid); 142 close(pfd[PWR]); 143 f = openfd(pfd[PRD]); 144 s = wd; 145 v = 0; 146 while((c = rchr(f))!=EOF){ 147 if(s != ewd) { 148 *s++ = c; 149 for(q=stop; *q; q+=n) { 150 n = chartorune(&r, q); 151 if(s-wd >= n && memcmp(s-n, q, n) == 0) { 152 s -= n; 153 goto stop; 154 } 155 } 156 continue; 157 } 158 stop: 159 if(s != wd) { 160 *s = '\0'; 161 v = newword(wd, v); 162 } 163 s = wd; 164 } 165 if(s!=wd){ 166 *s='\0'; 167 v = newword(wd, v); 168 } 169 closeio(f); 170 Waitfor(pid, 0); 171 /* v points to reversed arglist -- reverse it onto argv */ 172 while(v){ 173 nextv = v->next; 174 v->next = runq->argv->words; 175 runq->argv->words = v; 176 v = nextv; 177 } 178 p->pc = p->code[p->pc].i; 179 return; 180 } 181 } 182 183 void 184 Xpipefd(void) 185 { 186 struct thread *p = runq; 187 int pc = p->pc, pid; 188 char name[40]; 189 int pfd[2]; 190 struct { int sidefd, mainfd; } fd[2], *r, *w; 191 192 r = &fd[0]; 193 w = &fd[1]; 194 switch(p->code[pc].i){ 195 case READ: 196 w = nil; 197 break; 198 case WRITE: 199 r = nil; 200 } 201 202 if(r){ 203 if(pipe(pfd)<0){ 204 Xerror("can't get pipe"); 205 return; 206 } 207 r->sidefd = pfd[PWR]; 208 r->mainfd = pfd[PRD]; 209 } 210 if(w){ 211 if(pipe(pfd)<0){ 212 Xerror("can't get pipe"); 213 return; 214 } 215 w->sidefd = pfd[PRD]; 216 w->mainfd = pfd[PWR]; 217 } 218 switch(pid = fork()){ 219 case -1: 220 Xerror("try again"); 221 break; 222 case 0: 223 clearwaitpids(); 224 start(p->code, pc+2, runq->local); 225 if(r){ 226 close(r->mainfd); 227 pushredir(ROPEN, r->sidefd, 1); 228 } 229 if(w){ 230 close(w->mainfd); 231 pushredir(ROPEN, w->sidefd, 0); 232 } 233 runq->ret = 0; 234 break; 235 default: 236 addwaitpid(pid); 237 if(w){ 238 close(w->sidefd); 239 pushredir(ROPEN, w->mainfd, w->mainfd); /* so that Xpopredir can close it later */ 240 strcpy(name, Fdprefix); 241 inttoascii(name+strlen(name), w->mainfd); 242 pushword(name); 243 } 244 if(r){ 245 close(r->sidefd); 246 pushredir(ROPEN, r->mainfd, r->mainfd); 247 strcpy(name, Fdprefix); 248 inttoascii(name+strlen(name), r->mainfd); 249 pushword(name); 250 } 251 p->pc = p->code[pc+1].i; 252 break; 253 } 254 } 255 256 void 257 Xsubshell(void) 258 { 259 int pid; 260 switch(pid = fork()){ 261 case -1: 262 Xerror("try again"); 263 break; 264 case 0: 265 clearwaitpids(); 266 start(runq->code, runq->pc+1, runq->local); 267 runq->ret = 0; 268 break; 269 default: 270 addwaitpid(pid); 271 Waitfor(pid, 1); 272 runq->pc = runq->code[runq->pc].i; 273 break; 274 } 275 } 276 277 int 278 execforkexec(void) 279 { 280 int pid; 281 int n; 282 char buf[ERRMAX]; 283 284 switch(pid = fork()){ 285 case -1: 286 return -1; 287 case 0: 288 clearwaitpids(); 289 pushword("exec"); 290 execexec(); 291 strcpy(buf, "can't exec: "); 292 n = strlen(buf); 293 errstr(buf+n, ERRMAX-n); 294 Exit(buf); 295 } 296 addwaitpid(pid); 297 return pid; 298 }