plan9port

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

exec.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 }