⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jobs.c

📁 Android 一些工具
💻 C
📖 第 1 页 / 共 3 页
字号:
	}#if JOBS	if (jp->jobctl) {		if (tcsetpgrp(ttyfd, mypgrp) == -1)			error("Cannot set tty process group (%s) at %d",			    strerror(errno), __LINE__);	}	if (jp->state == JOBSTOPPED && curjob != jp - jobtab)		set_curjob(jp, 2);#endif	status = jp->ps[jp->nprocs - 1].status;	/* convert to 8 bits */	if (WIFEXITED(status))		st = WEXITSTATUS(status);#if JOBS	else if (WIFSTOPPED(status))		st = WSTOPSIG(status) + 128;#endif	else		st = WTERMSIG(status) + 128;	TRACE(("waitforjob: job %d, nproc %d, status %x, st %x\n",		jp - jobtab + 1, jp->nprocs, status, st ));#if JOBS	if (jp->jobctl) {		/*		 * This is truly gross.		 * If we're doing job control, then we did a TIOCSPGRP which		 * caused us (the shell) to no longer be in the controlling		 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we		 * intuit from the subprocess exit status whether a SIGINT		 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft		 */		if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)			raise(SIGINT);	}#endif	if (! JOBS || jp->state == JOBDONE)		freejob(jp);	INTON;	return st;}/* * Wait for a process to terminate. */STATIC intdowait(int block, struct job *job){	int pid;	int status;	struct procstat *sp;	struct job *jp;	struct job *thisjob;	int done;	int stopped;	extern volatile char gotsig[];	TRACE(("dowait(%d) called\n", block));	do {		pid = waitproc(block, job, &status);		TRACE(("wait returns pid %d, status %d\n", pid, status));	} while (pid == -1 && errno == EINTR && gotsig[SIGINT - 1] == 0);	if (pid <= 0)		return pid;	INTOFF;	thisjob = NULL;	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {		if (jp->used) {			done = 1;			stopped = 1;			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {				if (sp->pid == -1)					continue;				if (sp->pid == pid) {					TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp - jobtab + 1, pid, sp->status, status));					sp->status = status;					thisjob = jp;				}				if (sp->status == -1)					stopped = 0;				else if (WIFSTOPPED(sp->status))					done = 0;			}			if (stopped) {		/* stopped or done */				int state = done ? JOBDONE : JOBSTOPPED;				if (jp->state != state) {					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));					jp->state = state;#if JOBS					if (done)						set_curjob(jp, 0);#endif				}			}		}	}	if (thisjob && thisjob->state != JOBRUNNING) {		int mode = 0;		if (!rootshell || !iflag)			mode = SHOW_SIGNALLED;		if (job == thisjob)			mode = SHOW_SIGNALLED | SHOW_NO_FREE;		if (mode)			showjob(out2, thisjob, mode);		else {			TRACE(("Not printing status, rootshell=%d, job=%p\n",				rootshell, job));			thisjob->changed = 1;		}	}	INTON;	return pid;}/* * Do a wait system call.  If job control is compiled in, we accept * stopped processes.  If block is zero, we return a value of zero * rather than blocking. * * System V doesn't have a non-blocking wait system call.  It does * have a SIGCLD signal that is sent to a process when one of it's * children dies.  The obvious way to use SIGCLD would be to install * a handler for SIGCLD which simply bumped a counter when a SIGCLD * was received, and have waitproc bump another counter when it got * the status of a process.  Waitproc would then know that a wait * system call would not block if the two counters were different. * This approach doesn't work because if a process has children that * have not been waited for, System V will send it a SIGCLD when it * installs a signal handler for SIGCLD.  What this means is that when * a child exits, the shell will be sent SIGCLD signals continuously * until is runs out of stack space, unless it does a wait call before * restoring the signal handler.  The code below takes advantage of * this (mis)feature by installing a signal handler for SIGCLD and * then checking to see whether it was called.  If there are any * children to be waited for, it will be. * * If neither SYSV nor BSD is defined, we don't implement nonblocking * waits at all.  In this case, the user will not be informed when * a background process until the next time she runs a real program * (as opposed to running a builtin command or just typing return), * and the jobs command may give out of date information. */#ifdef SYSVSTATIC int gotsigchild;STATIC int onsigchild() {	gotsigchild = 1;}#endifSTATIC intwaitproc(int block, struct job *jp, int *status){#ifdef BSD	int flags = 0;#if JOBS	if (jp != NULL && jp->jobctl)		flags |= WUNTRACED;#endif	if (block == 0)		flags |= WNOHANG;	return wait3(status, flags, (struct rusage *)NULL);#else#ifdef SYSV	int (*save)();	if (block == 0) {		gotsigchild = 0;		save = signal(SIGCLD, onsigchild);		signal(SIGCLD, save);		if (gotsigchild == 0)			return 0;	}	return wait(status);#else	if (block == 0)		return 0;	return wait(status);#endif#endif}/* * return 1 if there are stopped jobs, otherwise 0 */int job_warning = 0;intstoppedjobs(void){	int jobno;	struct job *jp;	if (job_warning || jobs_invalid)		return (0);	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {		if (jp->used == 0)			continue;		if (jp->state == JOBSTOPPED) {			out2str("You have stopped jobs.\n");			job_warning = 2;			return (1);		}	}	return (0);}/* * Return a string identifying a command (to be printed by the * jobs command). */STATIC char *cmdnextc;STATIC int cmdnleft;voidcommandtext(struct procstat *ps, union node *n){	int len;	cmdnextc = ps->cmd;	if (iflag || mflag || sizeof ps->cmd < 100)		len = sizeof(ps->cmd);	else		len = sizeof(ps->cmd) / 10;	cmdnleft = len;	cmdtxt(n);	if (cmdnleft <= 0) {		char *p = ps->cmd + len - 4;		p[0] = '.';		p[1] = '.';		p[2] = '.';		p[3] = 0;	} else		*cmdnextc = '\0';	TRACE(("commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n",		ps->cmd, cmdnextc, cmdnleft, ps->cmd));}STATIC voidcmdtxt(union node *n){	union node *np;	struct nodelist *lp;	const char *p;	int i;	char s[2];	if (n == NULL || cmdnleft <= 0)		return;	switch (n->type) {	case NSEMI:		cmdtxt(n->nbinary.ch1);		cmdputs("; ");		cmdtxt(n->nbinary.ch2);		break;	case NAND:		cmdtxt(n->nbinary.ch1);		cmdputs(" && ");		cmdtxt(n->nbinary.ch2);		break;	case NOR:		cmdtxt(n->nbinary.ch1);		cmdputs(" || ");		cmdtxt(n->nbinary.ch2);		break;	case NPIPE:		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {			cmdtxt(lp->n);			if (lp->next)				cmdputs(" | ");		}		break;	case NSUBSHELL:		cmdputs("(");		cmdtxt(n->nredir.n);		cmdputs(")");		break;	case NREDIR:	case NBACKGND:		cmdtxt(n->nredir.n);		break;	case NIF:		cmdputs("if ");		cmdtxt(n->nif.test);		cmdputs("; then ");		cmdtxt(n->nif.ifpart);		if (n->nif.elsepart) {			cmdputs("; else ");			cmdtxt(n->nif.elsepart);		}		cmdputs("; fi");		break;	case NWHILE:		cmdputs("while ");		goto until;	case NUNTIL:		cmdputs("until ");until:		cmdtxt(n->nbinary.ch1);		cmdputs("; do ");		cmdtxt(n->nbinary.ch2);		cmdputs("; done");		break;	case NFOR:		cmdputs("for ");		cmdputs(n->nfor.var);		cmdputs(" in ");		cmdlist(n->nfor.args, 1);		cmdputs("; do ");		cmdtxt(n->nfor.body);		cmdputs("; done");		break;	case NCASE:		cmdputs("case ");		cmdputs(n->ncase.expr->narg.text);		cmdputs(" in ");		for (np = n->ncase.cases; np; np = np->nclist.next) {			cmdtxt(np->nclist.pattern);			cmdputs(") ");			cmdtxt(np->nclist.body);			cmdputs(";; ");		}		cmdputs("esac");		break;	case NDEFUN:		cmdputs(n->narg.text);		cmdputs("() { ... }");		break;	case NCMD:		cmdlist(n->ncmd.args, 1);		cmdlist(n->ncmd.redirect, 0);		break;	case NARG:		cmdputs(n->narg.text);		break;	case NTO:		p = ">";  i = 1;  goto redir;	case NCLOBBER:		p = ">|";  i = 1;  goto redir;	case NAPPEND:		p = ">>";  i = 1;  goto redir;	case NTOFD:		p = ">&";  i = 1;  goto redir;	case NFROM:		p = "<";  i = 0;  goto redir;	case NFROMFD:		p = "<&";  i = 0;  goto redir;	case NFROMTO:		p = "<>";  i = 0;  goto redir;redir:		if (n->nfile.fd != i) {			s[0] = n->nfile.fd + '0';			s[1] = '\0';			cmdputs(s);		}		cmdputs(p);		if (n->type == NTOFD || n->type == NFROMFD) {			s[0] = n->ndup.dupfd + '0';			s[1] = '\0';			cmdputs(s);		} else {			cmdtxt(n->nfile.fname);		}		break;	case NHERE:	case NXHERE:		cmdputs("<<...");		break;	default:		cmdputs("???");		break;	}}STATIC voidcmdlist(union node *np, int sep){	for (; np; np = np->narg.next) {		if (!sep)			cmdputs(" ");		cmdtxt(np);		if (sep && np->narg.next)			cmdputs(" ");	}}STATIC voidcmdputs(const char *s){	const char *p, *str = 0;	char c, cc[2] = " ";	char *nextc;	int nleft;	int subtype = 0;	int quoted = 0;	static char vstype[16][4] = { "", "}", "-", "+", "?", "=",					"#", "##", "%", "%%" };	p = s;	nextc = cmdnextc;	nleft = cmdnleft;	while (nleft > 0 && (c = *p++) != 0) {		switch (c) {		case CTLESC:			c = *p++;			break;		case CTLVAR:			subtype = *p++;			if ((subtype & VSTYPE) == VSLENGTH)				str = "${#";			else				str = "${";			if (!(subtype & VSQUOTE) != !(quoted & 1)) {				quoted ^= 1;				c = '"';			} else				c = *str++;			break;		case CTLENDVAR:			if (quoted & 1) {				c = '"';				str = "}";			} else				c = '}';			quoted >>= 1;			subtype = 0;			break;		case CTLBACKQ:			c = '$';			str = "(...)";			break;		case CTLBACKQ+CTLQUOTE:			c = '"';			str = "$(...)\"";			break;		case CTLARI:			c = '$';			str = "((";			break;		case CTLENDARI:			c = ')';			str = ")";			break;		case CTLQUOTEMARK:			quoted ^= 1;			c = '"';			break;		case '=':			if (subtype == 0)				break;			str = vstype[subtype & VSTYPE];			if (subtype & VSNUL)				c = ':';			else				c = *str++;			if (c != '}')				quoted <<= 1;			break;		case '\'':		case '\\':		case '"':		case '$':			/* These can only happen inside quotes */			cc[0] = c;			str = cc;			c = '\\';			break;		default:			break;		}		do {			*nextc++ = c;		} while (--nleft > 0 && str && (c = *str++));		str = 0;	}	if ((quoted & 1) && nleft) {		*nextc++ = '"';		nleft--;	}	cmdnleft = nleft;	cmdnextc = nextc;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -