| #define NOPLAN9DEFINES |
| #include "mk.h" |
| #include <sys/wait.h> |
| #include <signal.h> |
| #include <sys/stat.h> |
| #include <sys/time.h> |
| |
| char *shell = "/bin/sh"; |
| char *shellname = "sh"; |
| |
| extern char **environ; |
| |
| static void |
| mkperror(char *s) |
| { |
| fprint(2, "%s: %r\n", s); |
| } |
| |
| void |
| readenv(void) |
| { |
| char **p, *s; |
| Word *w; |
| |
| for(p = environ; *p; p++){ |
| /* rsc 5/5/2004 -- This misparses fn#cd={whatever} |
| s = shname(*p); |
| if(*s == '=') { |
| *s = 0; |
| w = newword(s+1); |
| } else |
| w = newword(""); |
| */ |
| s = strchr(*p, '='); |
| if(s){ |
| *s = 0; |
| w = newword(s+1); |
| } else |
| w = newword(""); |
| if (symlook(*p, S_INTERNAL, 0)) |
| continue; |
| s = strdup(*p); |
| setvar(s, (void *)w); |
| symlook(s, S_EXPORTED, (void*)"")->u.ptr = ""; |
| } |
| } |
| |
| /* |
| * done on child side of fork, so parent's env is not affected |
| * and we don't care about freeing memory because we're going |
| * to exec immediately after this. |
| */ |
| void |
| exportenv(Envy *e, Shell *sh) |
| { |
| int i; |
| char **p; |
| static char buf[16384]; |
| |
| p = 0; |
| for(i = 0; e->name; e++, i++) { |
| p = (char**) Realloc(p, (i+2)*sizeof(char*)); |
| if(e->values) |
| snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->values, sh->iws)); |
| else |
| snprint(buf, sizeof buf, "%s=", e->name); |
| p[i] = strdup(buf); |
| } |
| p[i] = 0; |
| environ = p; |
| } |
| |
| int |
| waitfor(char *msg) |
| { |
| int status; |
| int pid; |
| |
| *msg = 0; |
| pid = wait(&status); |
| if(pid > 0) { |
| if(status&0x7f) { |
| if(status&0x80) |
| snprint(msg, ERRMAX, "signal %d, core dumped", status&0x7f); |
| else |
| snprint(msg, ERRMAX, "signal %d", status&0x7f); |
| } else if(status&0xff00) |
| snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff); |
| } |
| return pid; |
| } |
| |
| void |
| expunge(int pid, char *msg) |
| { |
| if(strcmp(msg, "interrupt")) |
| kill(pid, SIGINT); |
| else |
| kill(pid, SIGHUP); |
| } |
| |
| int mypid; |
| |
| int |
| shargv(Word *cmd, int extra, char ***pargv) |
| { |
| char **argv; |
| int i, n; |
| Word *w; |
| |
| n = 0; |
| for(w=cmd; w; w=w->next) |
| n++; |
| |
| argv = Malloc((n+extra+1)*sizeof(argv[0])); |
| i = 0; |
| for(w=cmd; w; w=w->next) |
| argv[i++] = w->s; |
| argv[n] = 0; |
| *pargv = argv; |
| return n; |
| } |
| |
| int |
| execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcmd) |
| { |
| char *p, **argv; |
| int tot, n, pid, in[2], out[2]; |
| |
| if(buf && pipe(out) < 0){ |
| mkperror("pipe"); |
| Exit(); |
| } |
| pid = fork(); |
| mypid = getpid(); |
| if(pid < 0){ |
| mkperror("mk fork"); |
| Exit(); |
| } |
| if(pid == 0){ |
| if(buf) |
| close(out[0]); |
| if(pipe(in) < 0){ |
| mkperror("pipe"); |
| Exit(); |
| } |
| pid = fork(); |
| if(pid < 0){ |
| mkperror("mk fork"); |
| Exit(); |
| } |
| if(pid != 0){ |
| dup2(in[0], 0); |
| if(buf){ |
| dup2(out[1], 1); |
| close(out[1]); |
| } |
| close(in[0]); |
| close(in[1]); |
| if (e) |
| exportenv(e, sh); |
| n = shargv(shellcmd, 1, &argv); |
| argv[n++] = args; |
| argv[n] = 0; |
| execvp(argv[0], argv); |
| mkperror(shell); |
| _exit(1); |
| } |
| close(out[1]); |
| close(in[0]); |
| if(DEBUG(D_EXEC)) |
| fprint(1, "starting: %s\n", cmd); |
| p = cmd+strlen(cmd); |
| while(cmd < p){ |
| n = write(in[1], cmd, p-cmd); |
| if(n < 0) |
| break; |
| cmd += n; |
| } |
| close(in[1]); |
| _exit(0); |
| } |
| if(buf){ |
| close(out[1]); |
| tot = 0; |
| for(;;){ |
| if (buf->current >= buf->end) |
| growbuf(buf); |
| n = read(out[0], buf->current, buf->end-buf->current); |
| if(n <= 0) |
| break; |
| buf->current += n; |
| tot += n; |
| } |
| if (tot && buf->current[-1] == '\n') |
| buf->current--; |
| close(out[0]); |
| } |
| return pid; |
| } |
| |
| int |
| pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd) |
| { |
| int pid, pfd[2]; |
| int n; |
| char **argv; |
| |
| if(DEBUG(D_EXEC)) |
| fprint(1, "pipecmd='%s'\n", cmd);/**/ |
| |
| if(fd && pipe(pfd) < 0){ |
| mkperror("pipe"); |
| Exit(); |
| } |
| pid = fork(); |
| if(pid < 0){ |
| mkperror("mk fork"); |
| Exit(); |
| } |
| if(pid == 0){ |
| if(fd){ |
| close(pfd[0]); |
| dup2(pfd[1], 1); |
| close(pfd[1]); |
| } |
| if(e) |
| exportenv(e, sh); |
| n = shargv(shellcmd, 2, &argv); |
| argv[n++] = "-c"; |
| argv[n++] = cmd; |
| argv[n] = 0; |
| execvp(argv[0], argv); |
| mkperror(shell); |
| _exit(1); |
| } |
| if(fd){ |
| close(pfd[1]); |
| *fd = pfd[0]; |
| } |
| return pid; |
| } |
| |
| void |
| Exit(void) |
| { |
| while(wait(0) >= 0) |
| ; |
| exits("error"); |
| } |
| |
| static struct |
| { |
| int sig; |
| char *msg; |
| } sigmsgs[] = |
| { |
| SIGALRM, "alarm", |
| SIGFPE, "sys: fp: fptrap", |
| SIGPIPE, "sys: write on closed pipe", |
| SIGILL, "sys: trap: illegal instruction", |
| /* SIGSEGV, "sys: segmentation violation", */ |
| 0, 0 |
| }; |
| |
| static void |
| notifyf(int sig) |
| { |
| int i; |
| |
| for(i = 0; sigmsgs[i].msg; i++) |
| if(sigmsgs[i].sig == sig) |
| killchildren(sigmsgs[i].msg); |
| |
| /* should never happen */ |
| signal(sig, SIG_DFL); |
| kill(getpid(), sig); |
| } |
| |
| void |
| catchnotes(void) |
| { |
| int i; |
| |
| for(i = 0; sigmsgs[i].msg; i++) |
| signal(sigmsgs[i].sig, notifyf); |
| } |
| |
| char* |
| maketmp(int *pfd) |
| { |
| static char temp[] = "/tmp/mkargXXXXXX"; |
| static char buf[100]; |
| int fd; |
| |
| strcpy(buf, temp); |
| fd = mkstemp(buf); |
| if(fd < 0) |
| return 0; |
| *pfd = fd; |
| return buf; |
| } |
| |
| int |
| chgtime(char *name) |
| { |
| if(access(name, 0) >= 0) |
| return utimes(name, 0); |
| return close(creat(name, 0666)); |
| } |
| |
| void |
| rcopy(char **to, Resub *match, int n) |
| { |
| int c; |
| char *p; |
| |
| *to = match->s.sp; /* stem0 matches complete target */ |
| for(to++, match++; --n > 0; to++, match++){ |
| if(match->s.sp && match->e.ep){ |
| p = match->e.ep; |
| c = *p; |
| *p = 0; |
| *to = strdup(match->s.sp); |
| *p = c; |
| } |
| else |
| *to = 0; |
| } |
| } |
| |
| unsigned long |
| mkmtime(char *name) |
| { |
| struct stat st; |
| |
| if(stat(name, &st) < 0) |
| return 0; |
| |
| return st.st_mtime; |
| } |