URI:
       texec.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
       ---
       texec.c (3487B)
       ---
            1 #include "threadimpl.h"
            2 
            3 static Lock thewaitlock;
            4 static Channel *thewaitchan;
            5 
            6 static void
            7 execproc(void *v)
            8 {
            9         int pid;
           10         Channel *c;
           11         Execjob *e;
           12         Waitmsg *w;
           13 
           14         e = v;
           15         pid = _threadspawn(e->fd, e->cmd, e->argv, e->dir);
           16         sendul(e->c, pid);
           17         if(pid > 0){
           18                 w = waitfor(pid);
           19                 if((c = thewaitchan) != nil)
           20                         sendp(c, w);
           21                 else
           22                         free(w);
           23         }
           24         threadexits(nil);
           25 }
           26 
           27 int
           28 _runthreadspawn(int *fd, char *cmd, char **argv, char *dir)
           29 {
           30         int pid;
           31         Execjob e;
           32 
           33         e.fd = fd;
           34         e.cmd = cmd;
           35         e.argv = argv;
           36         e.dir = dir;
           37         e.c = chancreate(sizeof(void*), 0);
           38         proccreate(execproc, &e, 65536);
           39         pid = recvul(e.c);
           40         chanfree(e.c);
           41         return pid;
           42 }
           43 
           44 Channel*
           45 threadwaitchan(void)
           46 {
           47         if(thewaitchan)
           48                 return thewaitchan;
           49         lock(&thewaitlock);
           50         if(thewaitchan){
           51                 unlock(&thewaitlock);
           52                 return thewaitchan;
           53         }
           54         thewaitchan = chancreate(sizeof(Waitmsg*), 4);
           55         chansetname(thewaitchan, "threadwaitchan");
           56         unlock(&thewaitlock);
           57         return thewaitchan;
           58 }
           59 
           60 int
           61 _threadspawn(int fd[3], char *cmd, char *argv[], char *dir)
           62 {
           63         int i, n, p[2], pid;
           64         char exitstr[100];
           65 
           66         notifyoff("sys: child");        /* do not let child note kill us */
           67         if(pipe(p) < 0)
           68                 return -1;
           69         if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){
           70                 close(p[0]);
           71                 close(p[1]);
           72                 return -1;
           73         }
           74         switch(pid = fork()){
           75         case -1:
           76                 close(p[0]);
           77                 close(p[1]);
           78                 return -1;
           79         case 0:
           80                 /* can't RFNOTEG - will lose tty */
           81                 if(dir != nil )
           82                         chdir(dir); /* best effort */
           83                 dup2(fd[0], 0);
           84                 dup2(fd[1], 1);
           85                 dup2(fd[2], 2);
           86                 if(!isatty(0) && !isatty(1) && !isatty(2))
           87                         rfork(RFNOTEG);
           88                 for(i=3; i<100; i++)
           89                         if(i != p[1])
           90                                 close(i);
           91                 execvp(cmd, argv);
           92                 fprint(p[1], "%d", errno);
           93                 close(p[1]);
           94                 _exit(0);
           95         }
           96 
           97         close(p[1]);
           98         n = read(p[0], exitstr, sizeof exitstr-1);
           99         close(p[0]);
          100         if(n > 0){        /* exec failed */
          101                 free(waitfor(pid));
          102                 exitstr[n] = 0;
          103                 errno = atoi(exitstr);
          104                 return -1;
          105         }
          106 
          107         close(fd[0]);
          108         if(fd[1] != fd[0])
          109                 close(fd[1]);
          110         if(fd[2] != fd[1] && fd[2] != fd[0])
          111                 close(fd[2]);
          112         return pid;
          113 }
          114 
          115 int
          116 threadspawn(int fd[3], char *cmd, char *argv[])
          117 {
          118         return _runthreadspawn(fd, cmd, argv, nil);
          119 }
          120 
          121 int
          122 threadspawnd(int fd[3], char *cmd, char *argv[], char *dir)
          123 {
          124         return _runthreadspawn(fd, cmd, argv, dir);
          125 }
          126 
          127 int
          128 threadspawnl(int fd[3], char *cmd, ...)
          129 {
          130         char **argv, *s;
          131         int n, pid;
          132         va_list arg;
          133 
          134         va_start(arg, cmd);
          135         for(n=0; va_arg(arg, char*) != nil; n++)
          136                 ;
          137         n++;
          138         va_end(arg);
          139 
          140         argv = malloc(n*sizeof(argv[0]));
          141         if(argv == nil)
          142                 return -1;
          143 
          144         va_start(arg, cmd);
          145         for(n=0; (s=va_arg(arg, char*)) != nil; n++)
          146                 argv[n] = s;
          147         argv[n] = 0;
          148         va_end(arg);
          149 
          150         pid = threadspawn(fd, cmd, argv);
          151         free(argv);
          152         return pid;
          153 }
          154 
          155 int
          156 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
          157 {
          158         int pid;
          159 
          160         pid = threadspawn(fd, cmd, argv);
          161         if(cpid){
          162                 if(pid < 0)
          163                         chansendul(cpid, ~0);
          164                 else
          165                         chansendul(cpid, pid);
          166         }
          167         return pid;
          168 }
          169 
          170 void
          171 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
          172 {
          173         if(_threadexec(cpid, fd, cmd, argv) >= 0)
          174                 threadexits("threadexec");
          175 }
          176 
          177 void
          178 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
          179 {
          180         char **argv, *s;
          181         int n, pid;
          182         va_list arg;
          183 
          184         va_start(arg, cmd);
          185         for(n=0; va_arg(arg, char*) != nil; n++)
          186                 ;
          187         n++;
          188         va_end(arg);
          189 
          190         argv = malloc(n*sizeof(argv[0]));
          191         if(argv == nil){
          192                 if(cpid)
          193                         chansendul(cpid, ~0);
          194                 return;
          195         }
          196 
          197         va_start(arg, cmd);
          198         for(n=0; (s=va_arg(arg, char*)) != nil; n++)
          199                 argv[n] = s;
          200         argv[n] = 0;
          201         va_end(arg);
          202 
          203         pid = _threadexec(cpid, fd, cmd, argv);
          204         free(argv);
          205 
          206         if(pid >= 0)
          207                 threadexits("threadexecl");
          208 }