int main(int argc, char *argv[], char *envp[]) { char buff[BUFSIZ]; int rc; signal(SIGTTOU, SIG_IGN); signal(SIGINT, sigint_handler); rc = setpgid(0, 0); assert(rc != -1); builtin_init(); history_init(); job_init(); print_prompt(); while (fgets(buff, BUFSIZ, stdin)) { job_run_command(buff, envp); job_wait(); print_prompt(); } job_finalize(); history_finalize(); builtin_finalize(); return 0; }
// // Builtin `jobs`. // int b_jobs(int n, char *argv[], Shbltin_t *context) { int flag = 0; Shell_t *shp = context->shp; while ((n = optget(argv, sh_optjobs))) { switch (n) { case 'l': { flag = JOB_LFLAG; break; } case 'n': { flag = JOB_NFLAG; break; } case 'p': { flag = JOB_PFLAG; break; } case ':': { errormsg(SH_DICT, 2, "%s", opt_info.arg); break; } case '?': { errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); __builtin_unreachable(); } default: { break; } } } argv += opt_info.index; if (error_info.errors) { errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL)); __builtin_unreachable(); } if (*argv == 0) argv = NULL; if (job_walk(shp, sfstdout, job_list, flag, argv)) { errormsg(SH_DICT, ERROR_exit(1), e_no_job); __builtin_unreachable(); } job_wait((pid_t)0); return shp->exitval; }
int task_wait(struct task **tasks, struct task *t, int async) { struct proc *p; struct job *j; for(j = t->jobs; j; j = j->next) while(!job_complete(j)){ /* TODO: term_give_to() */ job_wait(j, async); if(async && j->state == JOB_RUNNING) /* no change */ return 0; else if(j->state == JOB_COMPLETE){ /* changed to complete, next job in the list */ if(j->next){ job_start(j->next); if(async) return 0; continue; }else{ task_rm(tasks, t); return 1; } } /* * check for a stopped proc * if we find one, it's * been ^Z'd, stop other procs and return */ for(p = j->proc; p; p = p->next) if(p->state == PROC_STOP){ job_sig(j, SIGSTOP); return 0; /* don't attempt to move onto any other jobs */ } } return 0; }
/* * used with command -x to run the command in multiple passes * spawn is non-zero when invoked via spawn * the exitval is set to the maximum for each execution */ static pid_t path_xargs(Shell_t *shp,const char *path, char *argv[],char *const envp[], int spawn) { register char *cp, **av, **xv; char **avlast= &argv[shp->xargmax], **saveargs=0; char *const *ev; long size, left; int nlast=1,n,exitval=0; pid_t pid; if(shp->xargmin < 0) return((pid_t)-1); size = shp->gd->lim.arg_max-1024; for(ev=envp; cp= *ev; ev++) size -= strlen(cp)-1; for(av=argv; (cp= *av) && av< &argv[shp->xargmin]; av++) size -= strlen(cp)-1; for(av=avlast; cp= *av; av++,nlast++) size -= strlen(cp)-1; av = &argv[shp->xargmin]; if(!spawn) job_clear(); shp->exitval = 0; while(av<avlast) { for(xv=av,left=size; left>0 && av<avlast;) left -= strlen(*av++)+1; /* leave at least two for last */ if(left<0 && (avlast-av)<2) av--; if(xv==&argv[shp->xargmin]) { n = nlast*sizeof(char*); saveargs = (char**)malloc(n); memcpy((void*)saveargs, (void*)av, n); memcpy((void*)av,(void*)avlast,n); } else { for(n=shp->xargmin; xv < av; xv++) argv[n++] = *xv; for(xv=avlast; cp= *xv; xv++) argv[n++] = cp; argv[n] = 0; } if(saveargs || av<avlast || (exitval && !spawn)) { if((pid=_spawnveg(shp,path,argv,envp,0)) < 0) return(-1); job_post(shp,pid,0); job_wait(pid); if(shp->exitval>exitval) exitval = shp->exitval; if(saveargs) { memcpy((void*)av,saveargs,n); free((void*)saveargs); saveargs = 0; } } else if(spawn && !sh_isoption(SH_PFSH)) { shp->xargexit = exitval; if(saveargs) free((void*)saveargs); return(_spawnveg(shp,path,argv,envp,spawn>>1)); } else { if(saveargs)
void bq_thr_t::impl_t::fini() { poke(); job_wait(thread); thread = 0; }
/* execute another program, possibly searching for it first * * if the 'exec' argument is set it will never return * ----------------------------------------------------------------------- */ int exec_program(char *path, char **argv, int exec, union node *redir) { int ret = 0; sigset_t nset, oset; /* if we're gonna execve() a program and 'exec' isn't set or we aren't in the root shell environment we have to fork() so we can return */ if(!exec || sh->parent) { pid_t pid; struct fdstack io; unsigned int n; fdstack_push(&io); /* buffered fds which have not a real effective file descriptor, like here-docs which are read from strallocs and command expansions, which write to strallocs can't be shared across different process spaces, so we have to establish pipes */ if((n = fdstack_npipes(FD_HERE|FD_SUBST))) fdstack_pipe(n, fdstack_alloc(n)); /* block child and interrupt signal, so we won't terminate ourselves when the child does */ /* sigemptyset(&nset); sigaddset(&nset, SIGINT); #ifdef SIGCHLD sigaddset(&nset, SIGCHLD); #endif sigemptyset(&oset); sigprocmask(SIG_BLOCK, &nset, &oset); */ sig_block(); /* in the parent wait for the child to finish and then return or exit, according to the 'exec' argument */ if((pid = fork())) { int status = 1; /* this will close child ends of the pipes and read data from the parent end :) */ fdstack_pop(&io); fdstack_data(); job_wait(NULL, pid, &status, 0); job_status(pid, status); ret = WEXITSTATUS(status); #ifndef __MINGW32__ sigprocmask(SIG_SETMASK, &oset, NULL); #endif /* exit if 'exec' is set, otherwise return */ if(exec) sh_exit(ret); return ret; } /* ...in the child we always exit */ sh_forked(); } fdtable_exec(); fdstack_flatten(); /* when there is a path then we gotta execute a command, otherwise we exit/return immediately */ if(path) { /* export environment */ char **envp; unsigned long envn = var_count(V_EXPORT) + 1; envp = var_export(alloca(envn * sizeof(char *))); /* try to execute the program */ execve(path, argv, envp); /* execve() returned so it failed, we're gonna map the error code to the appropriate POSIX errors */ ret = exec_error(); /* yield an error message */ sh_error(path); } /* we never return at this point! */ exit(ret); }
/* evaluate a pipeline (3.9.2) * ----------------------------------------------------------------------- */ int eval_pipeline(struct eval *e, struct npipe *npipe) { struct job *job; union node *node; struct fdstack st; unsigned int n; int pid = 0; int prevfd = -1; int status = -1; /* job = (e->flags & E_JCTL) ? job_new(npipe->ncmd) : NULL;*/ job = job_new(npipe->ncmd); if(job == NULL) { buffer_puts(fd_err->w, "no job control"); buffer_putnlflush(fd_err->w); } for(node = npipe->cmds; node; node = node->list.next) { fdstack_push(&st); /* if there was a previous command we read input from pipe */ if(prevfd >= 0) { struct fd *in; fd_alloca(in); fd_push(in, STDIN_FILENO, FD_READ|FD_PIPE); fd_setfd(in, prevfd); } /* if it isn't the last command we have to create a pipe to pass output to the next command */ if(node->list.next) { struct fd *out; fd_alloca(out); fd_push(out, STDOUT_FILENO, FD_WRITE|FD_PIPE); prevfd = fd_pipe(out); if(prevfd == -1) { close(prevfd); sh_error("pipe creation failed"); } } if((n = fdstack_npipes(FD_HERE|FD_SUBST))) fdstack_pipe(n, fdstack_alloc(n)); pid = job_fork(job, node, npipe->bgnd); if(!pid) { /* no job control for commands inside pipe */ /* e->mode &= E_JCTL;*/ /* exit after evaluating this subtree */ exit(eval_tree(e, node, E_EXIT)); } fdstack_pop(&st); fdstack_data(); } if(!npipe->bgnd) { job_wait(job, 0, &status, 0); } /* if(job) shell_free(job);*/ return WEXITSTATUS(status); }