plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }