📄 jobs.c
字号:
/*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)jobs.c 5.1 (Berkeley) 3/7/91";#endif /* not lint */#include "shell.h"#if JOBS#include "sgtty.h"#undef CEOF /* syntax.h redefines this */#endif#include "main.h"#include "parser.h"#include "nodes.h"#include "jobs.h"#include "options.h"#include "trap.h"#include "signames.h"#include "syntax.h"#include "input.h"#include "output.h"#include "memalloc.h"#include "error.h"#include "mystring.h"#include "redir.h"#include <sys/types.h>#include <fcntl.h>#include <signal.h>#include <errno.h>#ifdef BSD#include <sys/types.h>#include <sys/wait.h>#include <sys/time.h>#include <sys/resource.h>#endif#if POSIX#include <sys/wait.h>#endifstruct job *jobtab; /* array of jobs */int njobs; /* size of array */MKINIT short backgndpid = -1; /* pid of last background process */#if JOBSint initialpgrp; /* pgrp of shell on invocation */short curjob; /* current job */#endif#ifdef __STDC__STATIC void restartjob(struct job *);STATIC struct job *getjob(char *);STATIC void freejob(struct job *);STATIC int procrunning(int);STATIC int dowait(int, struct job *);STATIC int waitproc(int, int *);STATIC char *commandtext(union node *);#elseSTATIC void restartjob();STATIC struct job *getjob();STATIC void freejob();STATIC int procrunning();STATIC int dowait();STATIC int waitproc();STATIC char *commandtext();#endif #if JOBS/* * Turn job control on and off. * * Note: This code assumes that the third arg to ioctl is a character * pointer, which is true on Berkeley systems but not System V. Since * System V doesn't have job control yet, this isn't a problem now. */MKINIT int jobctl;voidsetjobctl(on) { int ldisc; if (on == jobctl || rootshell == 0) return; if (on) { do { /* while we are in the background */ if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { out2str("ash: can't access tty; job control turned off\n"); jflag = 0; return; } if (initialpgrp == -1) initialpgrp = getpgrp(0); else if (initialpgrp != getpgrp(0)) { killpg(initialpgrp, SIGTTIN); continue; } } while (0); if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { out2str("ash: need new tty driver to run job control; job control turned off\n"); jflag = 0; return; } setsignal(SIGTSTP); setsignal(SIGTTOU); setpgrp(0, rootpid); ioctl(2, TIOCSPGRP, (char *)&rootpid); } else { /* turning job control off */ setpgrp(0, initialpgrp); ioctl(2, TIOCSPGRP, (char *)&initialpgrp); setsignal(SIGTSTP); setsignal(SIGTTOU); } jobctl = on;}#endif#ifdef mkinitSHELLPROC { backgndpid = -1;#if JOBS jobctl = 0;#endif}#endif#if JOBSfgcmd(argc, argv) char **argv; { struct job *jp; int pgrp; int status; jp = getjob(argv[1]); if (jp->jobctl == 0) error("job not created under job control"); pgrp = jp->ps[0].pid; ioctl(2, TIOCSPGRP, (char *)&pgrp); restartjob(jp); INTOFF; status = waitforjob(jp); INTON; return status;}bgcmd(argc, argv) char **argv; { struct job *jp; do { jp = getjob(*++argv); if (jp->jobctl == 0) error("job not created under job control"); restartjob(jp); } while (--argc > 1); return 0;}STATIC voidrestartjob(jp) struct job *jp; { struct procstat *ps; int i; if (jp->state == JOBDONE) return; INTOFF; killpg(jp->ps[0].pid, SIGCONT); for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { if ((ps->status & 0377) == 0177) { ps->status = -1; jp->state = 0; } } INTON;}#endifintjobscmd(argc, argv) char **argv; { showjobs(0); return 0;}/* * Print a list of jobs. If "change" is nonzero, only print jobs whose * statuses have changed since the last call to showjobs. * * If the shell is interrupted in the process of creating a job, the * result may be a job structure containing zero processes. Such structures * will be freed here. */voidshowjobs(change) { int jobno; int procno; int i; struct job *jp; struct procstat *ps; int col; char s[64]; TRACE(("showjobs(%d) called\n", change)); while (dowait(0, (struct job *)NULL) > 0); for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { if (! jp->used) continue; if (jp->nprocs == 0) { freejob(jp); continue; } if (change && ! jp->changed) continue; procno = jp->nprocs; for (ps = jp->ps ; ; ps++) { /* for each process */ if (ps == jp->ps) fmtstr(s, 64, "[%d] %d ", jobno, ps->pid); else fmtstr(s, 64, " %d ", ps->pid); out1str(s); col = strlen(s); s[0] = '\0'; if (ps->status == -1) { /* don't print anything */ } else if ((ps->status & 0xFF) == 0) { fmtstr(s, 64, "Exit %d", ps->status >> 8); } else { i = ps->status;#if JOBS if ((i & 0xFF) == 0177) i >>= 8;#endif if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F]) scopy(sigmesg[i & 0x7F], s); else fmtstr(s, 64, "Signal %d", i & 0x7F); if (i & 0x80) strcat(s, " (core dumped)"); } out1str(s); col += strlen(s); do { out1c(' '); col++; } while (col < 30); out1str(ps->cmd); out1c('\n'); if (--procno <= 0) break; } jp->changed = 0; if (jp->state == JOBDONE) { freejob(jp); } }}/* * Mark a job structure as unused. */STATIC voidfreejob(jp) struct job *jp; { struct procstat *ps; int i; INTOFF; for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { if (ps->cmd != nullstr) ckfree(ps->cmd); } if (jp->ps != &jp->ps0) ckfree(jp->ps); jp->used = 0;#if JOBS if (curjob == jp - jobtab + 1) curjob = 0;#endif INTON;}intwaitcmd(argc, argv) char **argv; { struct job *job; int status; struct job *jp; if (argc > 1) { job = getjob(argv[1]); } else { job = NULL; } for (;;) { /* loop until process terminated or stopped */ if (job != NULL) { if (job->state) { status = job->ps[job->nprocs - 1].status; if ((status & 0xFF) == 0) status = status >> 8 & 0xFF;#if JOBS else if ((status & 0xFF) == 0177) status = (status >> 8 & 0x7F) + 128;#endif else status = (status & 0x7F) + 128; if (! iflag) freejob(job); return status; } } else { for (jp = jobtab ; ; jp++) { if (jp >= jobtab + njobs) { /* no running procs */ return 0; } if (jp->used && jp->state == 0) break; } } dowait(1, (struct job *)NULL); }}jobidcmd(argc, argv) char **argv; { struct job *jp; int i; jp = getjob(argv[1]); for (i = 0 ; i < jp->nprocs ; ) { out1fmt("%d", jp->ps[i].pid); out1c(++i < jp->nprocs? ' ' : '\n'); } return 0;}/* * Convert a job name to a job structure. */STATIC struct job *getjob(name) char *name; { int jobno; register struct job *jp; int pid; int i; if (name == NULL) {#if JOBScurrentjob: if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) error("No current job"); return &jobtab[jobno - 1];#else error("No current job");#endif } else if (name[0] == '%') { if (is_digit(name[1])) { jobno = number(name + 1); if (jobno > 0 && jobno <= njobs && jobtab[jobno - 1].used != 0) return &jobtab[jobno - 1];#if JOBS } else if (name[1] == '%' && name[2] == '\0') { goto currentjob;#endif } else { register struct job *found = NULL; for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { if (jp->used && jp->nprocs > 0 && prefix(name + 1, jp->ps[0].cmd)) { if (found) error("%s: ambiguous", name); found = jp; } } if (found) return found; } } else if (is_number(name)) { pid = number(name); for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { if (jp->used && jp->nprocs > 0 && jp->ps[jp->nprocs - 1].pid == pid) return jp; } } error("No such job: %s", name);}/* * Return a new job structure, */struct job *makejob(node, nprocs) union node *node; { int i; struct job *jp; for (i = njobs, jp = jobtab ; ; jp++) { if (--i < 0) { INTOFF; if (njobs == 0) { jobtab = ckmalloc(4 * sizeof jobtab[0]); } else { jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); bcopy(jobtab, jp, njobs * sizeof jp[0]); for (i= 0; i<njobs; i++) { if (jobtab[i].ps == &jobtab[i].ps0) jp[i].ps= &jp[i].ps0; } ckfree(jobtab); jobtab = jp; } jp = jobtab + njobs; for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); INTON; break; } if (jp->used == 0) break; } INTOFF; jp->state = 0; jp->used = 1; jp->changed = 0; jp->nprocs = 0;#if JOBS jp->jobctl = jobctl;#endif if (nprocs > 1) { jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); } else { jp->ps = &jp->ps0; } INTON; TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1)); return jp;} /* * Fork of a subshell. If we are doing job control, give the subshell its * own process group. Jp is a job structure that the job is to be added to. * N is the command that will be evaluated by the child. Both jp and n may * be NULL. The mode parameter can be one of the following: * FORK_FG - Fork off a foreground process. * FORK_BG - Fork off a background process. * FORK_NOJOB - Like FORK_FG, but don't give the process its own * process group even if job control is on. * * When job control is turned off, background processes have their standard * input redirected to /dev/null (except for the second and later processes * in a pipeline). */intforkshell(jp, n, mode) union node *n; struct job *jp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -