void proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, int argc, char **argv, enum privsep_procid proc_id) { struct privsep_proc *p = NULL; unsigned int proc; unsigned int src, dst; if (proc_id == PROC_PARENT) { privsep_process = PROC_PARENT; proc_setup(ps, procs, nproc); /* Open socketpair()s for everyone. */ for (src = 0; src < PROC_MAX; src++) for (dst = 0; dst < PROC_MAX; dst++) proc_open(ps, src, dst); /* Engage! */ proc_exec(ps, procs, nproc, argc, argv); return; } /* Initialize a child */ for (proc = 0; proc < nproc; proc++) { if (procs[proc].p_id != proc_id) continue; p = &procs[proc]; break; } if (p == NULL || p->p_init == NULL) fatalx("%s: process %d missing process initialization", __func__, proc_id); p->p_init(ps, p); fatalx("failed to initiate child process"); }
void proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, int argc, char **argv, enum privsep_procid proc_id) { struct privsep_proc *p = NULL; struct privsep_pipes *pa, *pb; unsigned int proc; unsigned int dst; int fds[2]; /* Don't initiate anything if we are not really going to run. */ if (ps->ps_noaction) return; if (proc_id == PROC_PARENT) { privsep_process = PROC_PARENT; proc_setup(ps, procs, nproc); /* * Create the children sockets so we can use them * to distribute the rest of the socketpair()s using * proc_connect() later. */ for (dst = 0; dst < PROC_MAX; dst++) { /* Don't create socket for ourselves. */ if (dst == PROC_PARENT) continue; for (proc = 0; proc < ps->ps_instances[dst]; proc++) { pa = &ps->ps_pipes[PROC_PARENT][0]; pb = &ps->ps_pipes[dst][proc]; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, PF_UNSPEC, fds) == -1) fatal("%s: socketpair", __func__); pa->pp_pipes[dst][proc] = fds[0]; pb->pp_pipes[PROC_PARENT][0] = fds[1]; } } /* Engage! */ proc_exec(ps, procs, nproc, argc, argv); return; } /* Initialize a child */ for (proc = 0; proc < nproc; proc++) { if (procs[proc].p_id != proc_id) continue; p = &procs[proc]; break; } if (p == NULL || p->p_init == NULL) fatalx("%s: process %d missing process initialization", __func__, proc_id); p->p_init(ps, p); fatalx("failed to initiate child process"); }
/* everything is based on this exec, we have an extra flag (_EXEC_EXECONLY) to differentiate between the exec and fork_exec families. the difference is that the latter forks and then execs the process thereby returning in the parent */ static int fork_execve0(const char *path, char *const argv[], char * const envptr[], int fd, u_int flags) { u_int k = 0; int target_cpu = 0; struct Uenv cu; int NewPid = 0; int envid = 0; /* XXX -- init to supress warning */ char **old_argv = (char **)argv; int r, exec_format; struct Env e; OSCALLENTER(OSCALL_execve); /* verify executable permission */ if (!(flags & _EXEC_USE_FD) && access(path, X_OK) == -1) { /* access will set errno */ r = -errno; goto err; } if (!(envid = sys_env_alloc (0, &r))) { fprintf(stderr,"could not sys_env_alloc\n"); r = -ENOEXEC; goto err; } e = __envs[envidx(envid)]; if ((exec_format = fork_execve0_part2(path, argv, envptr, &e, fd, flags)) < 0) goto err_env_free; /* write environment */ if ((r = sys_wrenv (k, envid, &e)) < 0) { kprintf ("sys_wrenv failed\n"); r = -ENOEXEC; goto err; } if (ExecuteOnExecHandlers(k, envid, flags & _EXEC_EXECONLY) == -1) { fprintf(stderr,"cleanup code not done yet\n"); assert(-1); } #ifdef PROCESS_TABLE if (flags & _EXEC_EXECONLY) { /* because true exec */ NewPid = getpid(); dlockputs(__PROCD_LD,"fork_execve0 get lock "); EXOS_LOCK(PROCINFO_LOCK); dlockputs(__PROCD_LD,"... got lock\n"); EnterCritical (); ProcChangeEnv(NewPid,envid); EXOS_UNLOCK(PROCINFO_LOCK); dlockputs(__PROCD_LD,"fork_execve0 release lock\n"); ExitCritical (); } else { /* because we are forking */ NewPid = AllocateFreePid (envid); } cu = UAREA; if (!execonly) { AddProcEntry (&cu, (char *)path, (char **)argv, NewPid, UAREA.pid); if ((cu.parent_slot = GetChildSlot (NewPid)) < 0) { r = -ENOEXEC; goto err_env_free; } } else { /* TO TOM: what do we do this for? strncpy (UAREA.name, (char*)(((u_int)argv[0]) + ARGV_START_LOCAL - ARGV_START), U_NAMEMAX-1); UAREA.name[U_NAMEMAX-1] = '\0'; */ } /* XXX -- on an exec we'll forget to unref our children's pids */ /* TO TOM: shouldnt this clearchildinfo be at the top */ ClearChildInfo (&cu); #else #ifdef PROCD if (flags & _EXEC_EXECONLY) { NewPid = getpid(); /* only register us if we are of the right format */ if (exec_format == EXEC_EXOS_AOUT) proc_exec(envid); } else { NewPid = proc_fork(envid); } cu = UAREA; //kprintf("NewPid %d envid: %d %s proc_%s: (%d) -> %d\n", //NewPid,__envid,execonly ? "exec" : "fork",path,envid,NewPid); #else NewPid = envid; #endif /* PROCD */ #endif /* PROCESS_TABLE */ strncpy (cu.name, path, U_NAMEMAX-1); cu.name[U_NAMEMAX-1] = '\0'; cu.u_fpu = 0; cu.u_in_critical = 0; cu.u_status = U_RUN; cu.u_entprologue = e.env_tf.tf_eip; cu.u_entepilogue = e.env_tf.tf_eip; cu.u_entfault = 0; cu.u_entipc1 = 0; cu.u_entipc2 = 0; cu.u_ppc = 0; #ifdef PROCESS_TABLE cu.u_chld_state_chng = 0; #endif /* PROCESS_TABLE */ cu.u_next_timeout = 0; cu.u_in_pfault = 0; cu.u_donate = -1; cu.u_yield_count = 0; cu.u_epilogue_count = 0; cu.u_epilogue_abort_count = 0; STOPP(misc,step7); ISTART(misc,step8); cu.u_start_kern_call_counting = 0; if ((r = sys_wru (0, envid, &cu)) < 0) { fprintf (stderr,"sys_wru failed\n"); r = -ENOEXEC; goto err_env_free; } target_cpu = 0; #ifdef __SMP__ if (strncmp(path,"_cpu",4)==0 && strlen(path)>4) { target_cpu = path[4]-'0'; if (target_cpu<0 || target_cpu>sys_get_num_cpus()-1) target_cpu = 0; } #endif /* we can't do this until all the child state is setup */ if ((r = sys_quantum_alloc (k, -1, target_cpu, envid)) < 0) { fprintf (stderr,"could not alloc quantum\n"); r = -ENOEXEC; goto err_env_free; } /* if we're doing a true unix exec and not a combined fork/spawn we need to destroy ourselves since our child should have replaced us. */ if (flags & _EXEC_EXECONLY) { /* if not an exos format, should not expect normal child behaviors, so we * just quit from procd to avoid any hanging... */ if (exec_format == EXEC_SIMPLE) proc_exit(0); /* we die anyways, so free quantum and env */ ProcessFreeQuanta(__envid); sys_env_free (0, __envid); } if (old_argv != argv) __free((char**)argv); OSCALLEXIT(OSCALL_execve); return (NewPid); err_env_free: ProcessFreeQuanta(__envid); sys_env_free (k, envid); err: if (old_argv != argv) __free((char**)argv); errno = -r; OSCALLEXIT(OSCALL_execve); return -1; }
int job_start(struct job *j) { struct proc *p; struct redir *redir_iter; int pipey[2] = { -1, -1 }; #define REDIR(a, b) \ do{ \ if(a != b){ \ /* close b and copy a into b */ \ if(dup2(a, b) == -1) \ perror("dup2()"); \ if(close(a) == -1) \ perror("close()"); \ } \ }while(0) for(redir_iter = j->redir; redir_iter; redir_iter = redir_iter->next){ int fd; if(redir_iter->fname){ fd = open(redir_iter->fname, O_WRONLY | O_CREAT | O_TRUNC); /* FIXME: only out for now - need "<" and ">>" */ if(fd == -1){ fprintf(stderr, "ush: open %s: %s\n", redir_iter->fname, strerror(errno)); /* FIXME: close all other fds */ return 1; } }else{ fd = redir_iter->fd_out; } fprintf(stderr, "job_start(): REDIR(%d [%s], %d)\n", fd, redir_iter->fname, redir_iter->fd_in); REDIR(fd, redir_iter->fd_in); } j->proc->in = STDIN_FILENO; for(p = j->proc; p; p = p->next){ p->err = STDERR_FILENO; if(p->next){ if(pipe(pipey) < 0){ perror("pipe()"); goto bail; } p->out = pipey[1]; p->next->in = pipey[0]; }else{ p->out = STDOUT_FILENO; } /* TODO: cd, fg, rehash */ switch(p->pid = fork()){ case 0: p->pid = getpid(); REDIR(p->in, STDIN_FILENO); REDIR(p->out, STDOUT_FILENO); REDIR(p->err, STDERR_FILENO); #undef REDIR job_close_fds(j, p->next); proc_exec(p, j->gid); break; /* unreachable */ case -1: perror("fork()"); goto bail; default: if(interactive){ if(!j->gid) j->gid = p->pid; setpgid(p->pid, j->gid); } p->state = PROC_RUN; } } /* close our access to all these pipes */ job_close_fds(j, NULL); j->state = JOB_RUNNING; return 0; bail: fprintf(stderr, "warning: error starting job: %s\n", strerror(errno)); for(; p; p = p->next) p->state = PROC_FIN; job_close_fds(j, NULL); job_sig(j, SIGCONT); return 1; }