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

📄 jobs.c

📁 一个开放源代码的 AT&T 的 Korn Shell 的复制品, 支持大多数 ksh89 的特性。
💻 C
📖 第 1 页 / 共 3 页
字号:
				    (j->state == PEXITED) ? 0 : TF_MIPSKLUDGE);				/* Don't use tty mode if job is stopped and				 * later restarted and exits.  Consider				 * the sequence:				 *	vi foo (stopped)				 *	...				 *	stty something				 *	...				 *	fg (vi; ZZ)				 * mode should be that of the stty, not what				 * was before the vi started.				 */				if (j->state == PSTOPPED)					j->flags &= ~JF_USETTYMODE;			}		}#ifdef JOBS		/* If it looks like user hit ^C to kill a job, pretend we got		 * one too to break out of for loops, etc.  (at&t ksh does this		 * even when not monitoring, but this doesn't make sense since		 * a tty generated ^C goes to the whole process group)		 */		status = j->last_proc->status;		if (Flag(FMONITOR) && j->state == PSIGNALLED		    && WIFSIGNALED(status)		    && (sigtraps[WTERMSIG(status)].flags & TF_TTY_INTR))			trapsig(WTERMSIG(status));#endif /* JOBS */	}	j_usrtime = j->usrtime;	j_systime = j->systime;	rv = j->status;	if (!(flags & JW_ASYNCNOTIFY) 	    && (!Flag(FMONITOR) || j->state != PSTOPPED))	{		j_print(j, JP_SHORT, shl_out);		shf_flush(shl_out);	}	if (j->state != PSTOPPED	    && (!Flag(FMONITOR) || !(flags & JW_ASYNCNOTIFY)))		remove_job(j, where);	return rv;}/* SIGCHLD handler to reap children and update job states * * If jobs are compiled in then this routine expects sigchld to be blocked. */static RETSIGTYPEj_sigchld(sig)	int	sig;{	int		errno_ = errno;	Job		*j;	Proc		UNINITIALIZED(*p);	int		pid;	WAIT_T		status;	struct tms	t0, t1;#ifdef JOB_SIGS	/* Don't wait for any processes if a job is partially started.	 * This is so we don't do away with the process group leader	 * before all the processes in a pipe line are started (so the	 * setpgid() won't fail)	 */	for (j = job_list; j; j = j->next)		if (j->ppid == procpid && !(j->flags & JF_STARTED)) {			held_sigchld = 1;			return RETSIGVAL;		}#endif /* JOB_SIGS */	ksh_times(&t0);	do {#ifdef JOB_SIGS		pid = ksh_waitpid(-1, &status, (WNOHANG|WUNTRACED));#else /* JOB_SIGS */		pid = wait(&status);#endif /* JOB_SIGS */		if (pid <= 0)	/* return if would block (0) ... */			break;	/* ... or no children or interrupted (-1) */		ksh_times(&t1);		/* find job and process structures for this pid */		for (j = job_list; j != (Job *) 0; j = j->next)			for (p = j->proc_list; p != (Proc *) 0; p = p->next)				if (p->pid == pid)					goto found;found:		if (j == (Job *) 0) {			/* Can occur if process has kids, then execs shell			warningf(TRUE, "bad process waited for (pid = %d)",				pid);			 */			t0 = t1;			continue;		}		j->usrtime += t1.tms_cutime - t0.tms_cutime;		j->systime += t1.tms_cstime - t0.tms_cstime;		t0 = t1;		p->status = status;#ifdef JOBS		if (WIFSTOPPED(status))			p->state = PSTOPPED;		else#endif /* JOBS */		if (WIFSIGNALED(status))			p->state = PSIGNALLED;		else			p->state = PEXITED;		check_job(j);	/* check to see if entire job is done */	}#ifdef JOB_SIGS	while (1);#else /* JOB_SIGS */	while (0);#endif /* JOB_SIGS */	errno = errno_;	return RETSIGVAL;}/* * Called only when a process in j has exited/stopped (ie, called only * from j_sigchld()).  If no processes are running, the job status * and state are updated, asynchronous job notification is done and, * if unneeded, the job is removed. * * If jobs are compiled in then this routine expects sigchld to be blocked. */static voidcheck_job(j)	Job	*j;{	int	jstate;	Proc	*p;	/* XXX debugging (nasty - interrupt routine using shl_out) */	if (!(j->flags & JF_STARTED)) {		internal_errorf(0, "check_job: job started (flags 0x%x)",			j->flags);		return;	}	jstate = PRUNNING;	for (p=j->proc_list; p != (Proc *) 0; p = p->next) {		if (p->state == PRUNNING)			return;	/* some processes still running */		if (p->state > jstate)			jstate = p->state;	}	j->state = jstate;	switch (j->last_proc->state) {	case PEXITED:		j->status = WEXITSTATUS(j->last_proc->status);		break;	case PSIGNALLED:		j->status = 128 + WTERMSIG(j->last_proc->status);		break;	default:		j->status = 0;		break;	}#ifdef KSH	/* Note when co-process dies: can't be done in j_wait() nor	 * remove_job() since neither may be called for non-interactive 	 * shells.	 */	if (j->state == PEXITED || j->state == PSIGNALLED) {		/* No need to keep co-process input any more		 * (at leasst, this is what ksh93d thinks)		 */		if (coproc.job == j) {			coproc.job = (void *) 0;			/* XXX would be nice to get the closes out of here			 * so they aren't done in the signal handler.			 * Would mean a check in coproc_getfd() to			 * do "if job == 0 && write >= 0, close write".			 */			coproc_write_close(coproc.write);		}		/* Do we need to keep the output? */		if (j->coproc_id && j->coproc_id == coproc.id		    && --coproc.njobs == 0)			coproc_readw_close(coproc.read);	}#endif /* KSH */	j->flags |= JF_CHANGED;#ifdef JOBS	if (Flag(FMONITOR) && !(j->flags & JF_XXCOM)) {		/* Only put stopped jobs at the front to avoid confusing		 * the user (don't want finished jobs effecting %+ or %-)		 */		if (j->state == PSTOPPED)			put_job(j, PJ_ON_FRONT);		if (Flag(FNOTIFY)		    && (j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY)) != JF_WAITING)		{			/* Look for the real file descriptor 2 */			{				struct env *ep;				int fd = 2;				for (ep = e; ep; ep = ep->oenv)					if (ep->savefd && ep->savefd[2])						fd = ep->savefd[2];				shf_reopen(fd, SHF_WR, shl_j);			}			/* Can't call j_notify() as it removes jobs.  The job			 * must stay in the job list as j_waitj() may be			 * running with this job.			 */			j_print(j, JP_MEDIUM, shl_j);			shf_flush(shl_j);			if (!(j->flags & JF_WAITING) && j->state != PSTOPPED)				remove_job(j, "notify");		}	}#endif /* JOBS */	if (!Flag(FMONITOR) && !(j->flags & (JF_WAITING|JF_FG))	    && j->state != PSTOPPED)	{		if (j == async_job || (j->flags & JF_KNOWN)) {			j->flags |= JF_ZOMBIE;			j->job = -1;			nzombie++;		} else			remove_job(j, "checkjob");	}}/* * Print job status in either short, medium or long format. * * If jobs are compiled in then this routine expects sigchld to be blocked. */static voidj_print(j, how, shf)	Job		*j;	int		how;	struct shf	*shf;{	Proc	*p;	int	state;	WAIT_T	status;	int	coredumped;	char	jobchar = ' ';	char	buf[64];	const char *filler;	int	output = 0;	if (how == JP_PGRP) {		/* POSIX doesn't say what to do it there is no process		 * group leader (ie, !FMONITOR).  We arbitrarily return		 * last pid (which is what $! returns).		 */		shf_fprintf(shf, "%d\n", j->pgrp ? j->pgrp				: (j->last_proc ? j->last_proc->pid : 0));		return;	}	j->flags &= ~JF_CHANGED;	filler = j->job > 10 ?  "\n       " : "\n      ";	if (j == job_list)		jobchar = '+';	else if (j == job_list->next)		jobchar = '-';	for (p = j->proc_list; p != (Proc *) 0;) {		coredumped = 0;		switch (p->state) {		case PRUNNING:			strcpy(buf, "Running");			break;		case PSTOPPED:			strcpy(buf, sigtraps[WSTOPSIG(p->status)].mess);			break;		case PEXITED:			if (how == JP_SHORT)				buf[0] = '\0';			else if (WEXITSTATUS(p->status) == 0)				strcpy(buf, "Done");			else				shf_snprintf(buf, sizeof(buf), "Done (%d)",					WEXITSTATUS(p->status));			break;		case PSIGNALLED:			if (WIFCORED(p->status))				coredumped = 1;			/* kludge for not reporting `normal termination signals'			 * (ie, SIGINT, SIGPIPE)			 */			if (how == JP_SHORT && !coredumped			    && (WTERMSIG(p->status) == SIGINT				|| WTERMSIG(p->status) == SIGPIPE)) {				buf[0] = '\0';			} else				strcpy(buf, sigtraps[WTERMSIG(p->status)].mess);			break;		}		if (how != JP_SHORT)			if (p == j->proc_list)				shf_fprintf(shf, "[%d] %c ", j->job, jobchar);			else				shf_fprintf(shf, "%s", filler);		if (how == JP_LONG)			shf_fprintf(shf, "%5d ", p->pid);		if (how == JP_SHORT) {			if (buf[0]) {				output = 1;				shf_fprintf(shf, "%s%s ",					buf, coredumped ? " (core dumped)" : null);			}		} else {			output = 1;			shf_fprintf(shf, "%-20s %s%s%s", buf, p->command,				p->next ? "|" : null,				coredumped ? " (core dumped)" : null);		}		state = p->state;		status = p->status;		p = p->next;		while (p && p->state == state		       && WSTATUS(p->status) == WSTATUS(status))		{			if (how == JP_LONG)				shf_fprintf(shf, "%s%5d %-20s %s%s", filler, p->pid,					space, p->command, p->next ? "|" : null);			else if (how == JP_MEDIUM)				shf_fprintf(shf, " %s%s", p->command,					p->next ? "|" : null);			p = p->next;		}	}	if (output)		shf_fprintf(shf, newline);}/* Convert % sequence to job * * If jobs are compiled in then this routine expects sigchld to be blocked. */static Job *j_lookup(cp, ecodep)	const char *cp;	int	*ecodep;{	Job		*j, *last_match;	Proc		*p;	int		len, job = 0;	if (digit(*cp)) {		job = atoi(cp);		/* Look for last_proc->pid (what $! returns) first... */		for (j = job_list; j != (Job *) 0; j = j->next)			if (j->last_proc && j->last_proc->pid == job)				return j;		/* ...then look for process group (this is non-POSIX),		 * but should not break anything (so FPOSIX isn't used).		 */		for (j = job_list; j != (Job *) 0; j = j->next)			if (j->pgrp && j->pgrp == job)				return j;		if (ecodep)			*ecodep = JL_NOSUCH;		return (Job *) 0;	}	if (*cp != '%') {		if (ecodep)			*ecodep = JL_INVALID;		return (Job *) 0;	}	switch (*++cp) {	  case '\0': /* non-standard */	  case '+':	  case '%':		if (job_list != (Job *) 0)			return job_list;		break;	  case '-':		if (job_list != (Job *) 0 && job_list->next)			return job_list->next;		break;	  case '0': case '1': case '2': case '3': case '4':	  case '5': case '6': case '7': case '8': case '9':		job = atoi(cp);		for (j = job_list; j != (Job *) 0; j = j->next)			if (j->job == job)				return j;		break;	  case '?':		/* %?string */		last_match = (Job *) 0;		for (j = job_list; j != (Job *) 0; j = j->next)			for (p = j->proc_list; p != (Proc *) 0; p = p->next)				if (strstr(p->command, cp+1) != (char *) 0) {					if (last_match) {						if (ecodep)							*ecodep = JL_AMBIG;						return (Job *) 0;					}					last_match = j;				}		if (last_match)			return last_match;		break;	  default:		/* %string */		len = strlen(cp);		last_match = (Job *) 0;		for (j = job_list; j != (Job *) 0; j = j->next)			if (strncmp(cp, j->proc_list->command, len) == 0) {				if (last_match) {					if (ecodep)						*ecodep = JL_AMBIG;					return (Job *) 0;				}				last_match = j;			}		if (last_match)			return last_match;		break;	}	if (ecodep)		*ecodep = JL_NOSUCH;	return (Job *) 0;}static Job	*free_jobs;static Proc	*free_procs;/* allocate a new job and fill in the job number. * * If jobs are compiled in then this routine expects sigchld to be blocked. */static Job *new_job(){	int	i;	Job	*newj, *j;	if (free_jobs != (Job *) 0) {		newj = free_jobs;		free_jobs = free_jobs->next;	} else		newj = (Job *) alloc(sizeof(Job), APERM);	/* brute force method */	for (i = 1; ; i++) {		for (j = job_list; j && j->job != i; j = j->next)			;		if (j == (Job *) 0)			break;	}	newj->job = i;	return newj;}/* Allocate new process strut * * If jobs are compiled in then this routine expects sigchld to be blocked. */static Proc *new_proc(){	Proc	*p;	if (free_procs != (Proc *) 0) {		p = free_procs;		free_procs = free_procs->next;	} else		p = (Proc *) alloc(sizeof(Proc), APERM);	return p;}/* Take job out of job_list and put old structures into free list. * Keeps nzombies, last_job and async_job up to date. * * If jobs are compiled in then this routine expects sigchld to be blocked. */static voidremove_job(j, where)	Job	*j;	const char *where;{	Proc	*p, *tmp;	Job	**prev, *curr;	prev = &job_list;	curr = *prev;	for (; curr != (Job *) 0 && curr != j; prev = &curr->next, curr = *prev)		;	if (curr != j) {		internal_errorf(0, "remove_job: job not found (%s)", where);		return;	}	*prev = curr->next;	/* free up proc structures */	for (p = j->proc_list; p != (Proc *) 0; ) {		tmp = p;		p = p->next;		tmp->next = free_procs;		free_procs = tmp;	}	if ((j->flags & JF_ZOMBIE) && j->ppid == procpid)		--nzombie;	j->next = free_jobs;	free_jobs = j;	if (j == last_job)		last_job = (Job *) 0;	if (j == async_job)		async_job = (Job *) 0;}/* put j in a particular location (taking it out job_list if it is there * already) * * If jobs are compiled in then this routine expects sigchld to be blocked. */static voidput_job(j, where)	Job	*j;	int	where;{	Job	**prev, *curr;	/* Remove job from list (if there) */	prev = &job_list;	curr = job_list;	for (; curr && curr != j; prev = &curr->next, curr = *prev)		;	if (curr == j)		*prev = curr->next;	switch (where) {	case PJ_ON_FRONT:		j->next = job_list;		job_list = j;		break;	case PJ_PAST_STOPPED:		prev = &job_list;		curr = job_list;		for (; curr && curr->state == PSTOPPED; prev = &curr->next,							curr = *prev)			;		j->next = curr;		*prev = j;		break;	}}/* nuke a job (called when unable to start full job). * * If jobs are compiled in then this routine expects sigchld to be blocked. */static voidkill_job(j)	Job	*j;{	Proc	*p;	for (p = j->proc_list; p != (Proc *) 0; p = p->next)		if (p->pid != 0)			(void) kill(p->pid, SIGKILL);}/* put a more useful name on a process than snptreef does (in certain cases) */static voidfill_command(c, len, t)	char		*c;	int		len;	struct op	*t;{	int		alen;	char		**ap;	if (t->type == TEXEC || t->type == TCOM) {		/* Causes problems when set -u is in effect, can also		   cause problems when array indices evaluated (may have		   side effects, eg, assignment, incr, etc.)		if (t->type == TCOM)			ap = eval(t->args, DOBLANK|DONTRUNCOMMAND);		else		*/		ap = t->args;		--len; /* save room for the null */		while (len > 0 && *ap != (char *) 0) {			alen = strlen(*ap);			if (alen > len)				alen = len;			memcpy(c, *ap, alen);			c += alen;			len -= alen;			if (len > 0) {				*c++ = ' '; len--;			}			ap++;		}		*c = '\0';	} else		snptreef(c, len, "%T", t);}

⌨️ 快捷键说明

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