URI:
       thavefork.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       thavefork.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 }