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

📄 jobs.c

📁 一个开放源代码的 AT&T 的 Korn Shell 的复制品, 支持大多数 ksh89 的特性。
💻 C
📖 第 1 页 / 共 3 页
字号:
			}		}		remove_job(j, "child");	/* in case of `jobs` command */		nzombie = 0;#ifdef JOBS		ttypgrp_ok = 0;		Flag(FMONITOR) = 0;#endif /* JOBS */		Flag(FTALKING) = 0;#ifdef OS2		if (tty_fd >= 0)			flags |= XINTACT;#endif /* OS2 */		tty_close();		cleartraps();		execute(t, (flags & XERROK) | XEXEC); /* no return */		internal_errorf(0, "exchild: execute() returned");		unwind(LLEAVE);		/* NOTREACHED */	}	/* shell (parent) stuff */	/* Ensure next child gets a (slightly) different $RANDOM sequence */	change_random();	if (!(flags & XPIPEO)) {	/* last process in a job */#ifdef TTY_PGRP		/* YYY: Is this needed? (see also YYY above)		   if (Flag(FMONITOR) && !(flags&(XXCOM|XBGND)))			tcsetpgrp(tty_fd, j->pgrp);		*/#endif /* TTY_PGRP */		j_startjob(j);#ifdef KSH		if (flags & XCOPROC) {			j->coproc_id = coproc.id;			coproc.njobs++; /* n jobs using co-process output */			coproc.job = (void *) j; /* j using co-process input */		}#endif /* KSH */		if (flags & XBGND) {			j_set_async(j);			if (Flag(FTALKING)) {				shf_fprintf(shl_out, "[%d]", j->job);				for (p = j->proc_list; p; p = p->next)					shf_fprintf(shl_out, " %d", p->pid);				shf_putchar('\n', shl_out);				shf_flush(shl_out);			}		} else			rv = j_waitj(j, JW_NONE, "jw:last proc");	}#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */	return rv;}/* start the last job: only used for `command` jobs */voidstartlast(){#ifdef JOB_SIGS	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);#endif /* JOB_SIGS */	if (last_job) { /* no need to report error - waitlast() will do it */		/* ensure it isn't removed by check_job() */		last_job->flags |= JF_WAITING;		j_startjob(last_job);	}#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */}/* wait for last job: only used for `command` jobs */intwaitlast(){	int	rv;	Job	*j;#ifdef JOB_SIGS	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);#endif /* JOB_SIGS */	j = last_job;	if (!j || !(j->flags & JF_STARTED)) {		if (!j)			warningf(TRUE, "waitlast: no last job");		else			internal_errorf(0, "waitlast: not started");#ifdef JOB_SIGS		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */		return 125; /* not so arbitrary, non-zero value */	}	rv = j_waitj(j, JW_NONE, "jw:waitlast");#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */	return rv;}/* wait for child, interruptable. */intwaitfor(cp, sigp)	const char *cp;	int	*sigp;{	int	rv;	Job	*j;	int	ecode;	int	flags = JW_INTERRUPT|JW_ASYNCNOTIFY;#ifdef JOB_SIGS	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);#endif /* JOB_SIGS */	*sigp = 0;	if (cp == (char *) 0) {		/* wait for an unspecified job - always returns 0, so		 * don't have to worry about exited/signaled jobs		 */		for (j = job_list; j; j = j->next)			/* at&t ksh will wait for stopped jobs - we don't */			if (j->ppid == procpid && j->state == PRUNNING)				break;		if (!j) {#ifdef JOB_SIGS			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */			return -1;		}	} else if ((j = j_lookup(cp, &ecode))) {		/* don't report normal job completion */		flags &= ~JW_ASYNCNOTIFY;		if (j->ppid != procpid) {#ifdef JOB_SIGS			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */			return -1;		}	} else {#ifdef JOB_SIGS		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */		if (ecode != JL_NOSUCH)			bi_errorf("%s: %s", cp, lookup_msgs[ecode]);		return -1;	}	/* at&t ksh will wait for stopped jobs - we don't */	rv = j_waitj(j, flags, "jw:waitfor");#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */	if (rv < 0) /* we were interrupted */		*sigp = 128 + -rv;	return rv;}/* kill (built-in) a job */intj_kill(cp, sig)	const char *cp;	int	sig;{	Job	*j;	Proc	*p;	int	rv = 0;	int	ecode;#ifdef JOB_SIGS	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);#endif /* JOB_SIGS */	if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {#ifdef JOB_SIGS		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */		bi_errorf("%s: %s", cp, lookup_msgs[ecode]);		return 1;	}	if (j->pgrp == 0) {	/* started when !Flag(FMONITOR) */		for (p=j->proc_list; p != (Proc *) 0; p = p->next)			if (kill(p->pid, sig) < 0) {				bi_errorf("%s: %s", cp, strerror(errno));				rv = 1;			}	} else {#ifdef JOBS		if (j->state == PSTOPPED && (sig == SIGTERM || sig == SIGHUP))			(void) killpg(j->pgrp, SIGCONT);#endif /* JOBS */		if (killpg(j->pgrp, sig) < 0) {			bi_errorf("%s: %s", cp, strerror(errno));			rv = 1;		}	}#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */	return rv;}#ifdef JOBS/* fg and bg built-ins: called only if Flag(FMONITOR) set */intj_resume(cp, bg)	const char *cp;	int	bg;{	Job	*j;	Proc	*p;	int	ecode;	int	running;	int	rv = 0;	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);	if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);		bi_errorf("%s: %s", cp, lookup_msgs[ecode]);		return 1;	}	if (j->pgrp == 0) {		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);		bi_errorf("job not job-controlled");		return 1;	}	if (bg)		shprintf("[%d] ", j->job);	running = 0;	for (p = j->proc_list; p != (Proc *) 0; p = p->next) {		if (p->state == PSTOPPED) {			p->state = PRUNNING;			WSTATUS(p->status) = 0;			running = 1;		}		shprintf("%s%s", p->command, p->next ? "| " : null);	}	shprintf(newline);	shf_flush(shl_stdout);	if (running)		j->state = PRUNNING;	put_job(j, PJ_PAST_STOPPED);	if (bg)		j_set_async(j);	else {# ifdef TTY_PGRP		/* attach tty to job */		if (j->state == PRUNNING) {			if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) {				set_tty(tty_fd, &j->ttystate, TF_NONE);			}			/* See comment in j_waitj regarding saved_ttypgrp. */			if (ttypgrp_ok && tcsetpgrp(tty_fd, (j->flags & JF_SAVEDTTYPGRP) ? j->saved_ttypgrp : j->pgrp) < 0) {				if (j->flags & JF_SAVEDTTY) {					set_tty(tty_fd, &tty_state, TF_NONE);				}				sigprocmask(SIG_SETMASK, &omask,					(sigset_t *) 0);				bi_errorf("1st tcsetpgrp(%d, %d) failed: %s",					tty_fd, (int) ((j->flags & JF_SAVEDTTYPGRP) ? j->saved_ttypgrp : j->pgrp), strerror(errno));				return 1;			}		}# endif /* TTY_PGRP */		j->flags |= JF_FG;		j->flags &= ~JF_KNOWN;		if (j == async_job)			async_job = (Job *) 0;	}	if (j->state == PRUNNING && killpg(j->pgrp, SIGCONT) < 0) {		int	err = errno;		if (!bg) {			j->flags &= ~JF_FG;# ifdef TTY_PGRP			if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) {				set_tty(tty_fd, &tty_state, TF_NONE);			}			if (ttypgrp_ok && tcsetpgrp(tty_fd, our_pgrp) < 0) {				warningf(TRUE,				"fg: 2nd tcsetpgrp(%d, %d) failed: %s",					tty_fd, (int) our_pgrp,					strerror(errno));			}# endif /* TTY_PGRP */		}		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);		bi_errorf("cannot continue job %s: %s",			cp, strerror(err));		return 1;	}	if (!bg) {# ifdef TTY_PGRP		if (ttypgrp_ok) {			j->flags &= ~(JF_SAVEDTTY | JF_SAVEDTTYPGRP);		}# endif /* TTY_PGRP */		rv = j_waitj(j, JW_NONE, "jw:resume");	}	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);	return rv;}#endif /* JOBS *//* are there any running or stopped jobs ? */intj_stopped_running(){	Job	*j;	int	which = 0;	for (j = job_list; j != (Job *) 0; j = j->next) {#ifdef JOBS		if (j->ppid == procpid && j->state == PSTOPPED)			which |= 1;#endif /* JOBS */		if (Flag(FLOGIN) && !Flag(FNOHUP) && procpid == kshpid		    && j->ppid == procpid && j->state == PRUNNING)			which |= 2;	}	if (which) {		shellf("You have %s%s%s jobs\n",			which & 1 ? "stopped" : "",			which == 3 ? " and " : "",			which & 2 ? "running" : "");		return 1;	}	return 0;}/* list jobs for jobs built-in */intj_jobs(cp, slp, nflag)	const char *cp;	int	slp;		/* 0: short, 1: long, 2: pgrp */	int	nflag;{	Job	*j, *tmp;	int	how;	int	zflag = 0;#ifdef JOB_SIGS	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);#endif /* JOB_SIGS */	if (nflag < 0) { /* kludge: print zombies */		nflag = 0;		zflag = 1;	}	if (cp) {		int	ecode;		if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {#ifdef JOB_SIGS			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */			bi_errorf("%s: %s", cp, lookup_msgs[ecode]);			return 1;		}	} else		j = job_list;	how = slp == 0 ? JP_MEDIUM : (slp == 1 ? JP_LONG : JP_PGRP);	for (; j; j = j->next) {		if ((!(j->flags & JF_ZOMBIE) || zflag)		    && (!nflag || (j->flags & JF_CHANGED)))		{			j_print(j, how, shl_stdout);			if (j->state == PEXITED || j->state == PSIGNALLED)				j->flags |= JF_REMOVE;		}		if (cp)			break;	}	/* Remove jobs after printing so there won't be multiple + or - jobs */	for (j = job_list; j; j = tmp) {		tmp = j->next;		if (j->flags & JF_REMOVE)			remove_job(j, "jobs");	}#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */	return 0;}/* list jobs for top-level notification */voidj_notify(){	Job	*j, *tmp;#ifdef JOB_SIGS	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);#endif /* JOB_SIGS */	for (j = job_list; j; j = j->next) {#ifdef JOBS		if (Flag(FMONITOR) && (j->flags & JF_CHANGED))			j_print(j, JP_MEDIUM, shl_out);#endif /* JOBS */		/* Remove job after doing reports so there aren't		 * multiple +/- jobs.		 */		if (j->state == PEXITED || j->state == PSIGNALLED)			j->flags |= JF_REMOVE;	}	for (j = job_list; j; j = tmp) {		tmp = j->next;		if (j->flags & JF_REMOVE)			remove_job(j, "notify");	}	shf_flush(shl_out);#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */}/* Return pid of last process in last asynchornous job */pid_tj_async(){#ifdef JOB_SIGS	sigset_t omask;	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);#endif /* JOB_SIGS */	if (async_job)		async_job->flags |= JF_KNOWN;#ifdef JOB_SIGS	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);#endif /* JOB_SIGS */	return async_pid;}/* Make j the last async process * * If jobs are compiled in then this routine expects sigchld to be blocked. */static voidj_set_async(j)	Job *j;{	Job	*jl, *oldest;	if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE)		remove_job(async_job, "async");	if (!(j->flags & JF_STARTED)) {		internal_errorf(0, "j_async: job not started");		return;	}	async_job = j;	async_pid = j->last_proc->pid;	while (nzombie > child_max) {		oldest = (Job *) 0;		for (jl = job_list; jl; jl = jl->next)			if (jl != async_job && (jl->flags & JF_ZOMBIE)			    && (!oldest || jl->age < oldest->age))				oldest = jl;		if (!oldest) {			/* XXX debugging */			if (!(async_job->flags & JF_ZOMBIE) || nzombie != 1) {				internal_errorf(0, "j_async: bad nzombie (%d)", nzombie);				nzombie = 0;			}			break;		}		remove_job(oldest, "zombie");	}}/* Start a job: set STARTED, check for held signals and set j->last_proc * * If jobs are compiled in then this routine expects sigchld to be blocked. */static voidj_startjob(j)	Job *j;{	Proc	*p;	j->flags |= JF_STARTED;	for (p = j->proc_list; p->next; p = p->next)		;	j->last_proc = p;#ifdef NEED_PGRP_SYNC	if (j_sync_open) {		j_sync_open = 0;		closepipe(j_sync_pipe);	}#endif /* NEED_PGRP_SYNC */#ifdef JOB_SIGS	if (held_sigchld) {		held_sigchld = 0;		/* Don't call j_sigchld() as it may remove job... */		kill(procpid, SIGCHLD);	}#endif /* JOB_SIGS */}/* * wait for job to complete or change state * * If jobs are compiled in then this routine expects sigchld to be blocked. */static intj_waitj(j, flags, where)	Job	*j;	int	flags;		/* see JW_* */	const char *where;{	int	rv;	/*	 * No auto-notify on the job we are waiting on.	 */	j->flags |= JF_WAITING;	if (flags & JW_ASYNCNOTIFY)		j->flags |= JF_W_ASYNCNOTIFY;	if (!Flag(FMONITOR))		flags |= JW_STOPPEDWAIT;	while ((volatile int) j->state == PRUNNING		|| ((flags & JW_STOPPEDWAIT)		    && (volatile int) j->state == PSTOPPED))	{#ifdef JOB_SIGS		sigsuspend(&sm_default);#else /* JOB_SIGS */		j_sigchld(SIGCHLD);#endif /* JOB_SIGS */		if (fatal_trap) {			int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY);			j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);			runtraps(TF_FATAL);			j->flags |= oldf; /* not reached... */		}		if ((flags & JW_INTERRUPT) && (rv = trap_pending())) {			j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);			return -rv;		}	}	j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);	if (j->flags & JF_FG) {		WAIT_T	status;		j->flags &= ~JF_FG;#ifdef TTY_PGRP		if (Flag(FMONITOR) && ttypgrp_ok && j->pgrp) {			/*			 * Save the tty's current pgrp so it can be restored			 * when the job is foregrounded.  This is to			 * deal with things like the GNU su which does			 * a fork/exec instead of an exec (the fork means			 * the execed shell gets a different pid from its			 * pgrp, so naturally it sets its pgrp and gets hosed			 * when it gets forgrounded by the parent shell, which			 * has restored the tty's pgrp to that of the su			 * process).			 */			if (j->state == PSTOPPED			    && (j->saved_ttypgrp = tcgetpgrp(tty_fd)) >= 0)				j->flags |= JF_SAVEDTTYPGRP;			if (tcsetpgrp(tty_fd, our_pgrp) < 0) {				warningf(TRUE,				"j_waitj: tcsetpgrp(%d, %d) failed: %s",					tty_fd, (int) our_pgrp,					strerror(errno));			}			if (j->state == PSTOPPED) {				j->flags |= JF_SAVEDTTY;				get_tty(tty_fd, &j->ttystate);			}		}#endif /* TTY_PGRP */		if (tty_fd >= 0) {			/* Only restore tty settings if job was originally			 * started in the foreground.  Problems can be			 * caused by things like `more foobar &' which will			 * typically get and save the shell's vi/emacs tty			 * settings before setting up the tty for itself;			 * when more exits, it restores the `original'			 * settings, and things go down hill from there...			 */			if (j->state == PEXITED && j->status == 0			    && (j->flags & JF_USETTYMODE))			{				get_tty(tty_fd, &tty_state);			} else {				set_tty(tty_fd, &tty_state,

⌨️ 快捷键说明

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