#include #include #include #include "exec.h" #include "fd.h" int exec_init(Exec **exec) { Exec *e; assert(exec); *exec = nil; e = mallocz(sizeof(Exec), 1); if(e == nil) return -1; e->stdin_fd = e->stdout_fd = e->stderr_fd = fd_null(); e->sync = chancreate(sizeof(ulong), 0); if(e->sync == nil){ free(e); return -1; } e->error = chancreate(sizeof(char*), 0); if(e->error == nil){ chanfree(e->sync); free(e); return -1; } *exec = e; return 0; } void exec_done(Exec *e) { int i; assert(e); free(e->path); if(e->argv != nil){ for(i = 0; e->argv[i] != nil; i++){ free(e->argv[i]); } free(e->argv); } if(e->environment != nil){ for(i = 0; e->environment[i] != nil; i++){ free(e->environment[i]); } free(e->environment); } chanclose(e->sync); chanfree(e->sync); chanclose(e->error); chanfree(e->error); free(e); } int exec_args_va(Exec *exec, char *fmt, va_list a) { int i; char *args; char **argv; char *tok[64]; int ntok; assert(exec); assert(fmt); argv = nil; args = vsmprint(fmt, a); if(args == nil) return -1; ntok = tokenize(args, tok, nelem(tok)); assert(ntok <= nelem(tok)); exec->path = strdup(tok[0]); if(exec->path == nil) goto fail; argv = mallocz(sizeof(char*) * (ntok+1), 1); if(argv == nil) goto fail; for(i = 0; i < ntok; i++){ argv[i] = strdup(tok[i]); if(argv[i] == nil) goto fail; } free(args); argv[ntok] = nil; exec->argv = argv; return 0; fail: if(argv != nil){ for(i = 0; i < ntok; i++){ free(argv[i]); } free(argv); } free(args); return -1; } int exec_args(Exec *exec, char *fmt, ...) { int r; va_list a; assert(exec); assert(fmt); va_start(a, fmt); r = exec_args_va(exec, fmt, a); va_end(a); return r; } static void spawner(void *v) { char err[ERRMAX], *errp; Exec *e; threadsetname("spawner"); e = v; rfork(RFFDG); if(e->stdin_fd >= 0){ dup(e->stdin_fd, 0); close(e->stdin_fd); } if(e->stdout_fd >= 0){ dup(e->stdout_fd, 1); close(e->stdout_fd); } if(e->stderr_fd >= 0){ dup(e->stderr_fd, 2); close(e->stderr_fd); } procexec(e->sync, e->path, e->argv); /* * exec failed, recover error * can't do much if anything fails. */ rerrstr(err, sizeof(err)); errp = strdup(err); assert(errp); assert(sendp(e->error, errp) == 1); threadexits("can't exec"); } int exec_spawn(Exec *exec) { ulong pid; char *err; proccreate(spawner, exec, 8192); pid = recvul(exec->sync); if(pid == ~0){ err = recvp(exec->error); assert(err); werrstr("%s", err); free(err); return -1; } return (int)pid; } int spawn_exec(Exec *exec) { USED(exec); return -1; } int spawn(char *fmt, ...) { int r; va_list a; Exec *e; r = exec_init(&e); if(r < 0) return -1; va_start(a, fmt); r = exec_args_va(e, fmt, a); va_end(a); if(r < 0) return -1; /* temp hack */ e->stdin_fd = dup(0, -1); e->stdout_fd = dup(1, -1); e->stderr_fd = dup(2, -1); r = exec_spawn(e); if(r < 0) return -1; exec_done(e); /* r is pid */ return r; }