Exemplo n.º 1
0
/* list jobs for top-level notification */
void
j_notify(void)
{
	Job	*j, *tmp;
	sigset_t omask;

	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
	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);
	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
}
Exemplo n.º 2
0
Arquivo: jobs.c Projeto: adtools/abcsh
/* list jobs for jobs built-in */
int
j_jobs(const char *cp, int slp,
        int nflag)       /* 0: short, 1: long, 2: pgrp */ 
{
        Job     *j, *tmp;
        int     how;
        int     zflag = 0;
        sigset_t omask;

        sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);

        if (nflag < 0) { /* kludge: print zombies */
                nflag = 0;
                zflag = 1;
        }
        if (cp) {
                int     ecode;

                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;
                }
        } 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");
        }
        sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
        return 0;
}
Exemplo n.º 3
0
/*
 * wait for job to complete or change state
 *
 * If jobs are compiled in then this routine expects sigchld to be blocked.
 */
static int
j_waitj(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)) {
		sigsuspend(&sm_default);
		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) {
		int	status;

		j->flags &= ~JF_FG;
#ifdef JOBS
		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 foregrounded 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;
				tcgetattr(tty_fd, &j->ttystate);
			}
		}
#endif /* JOBS */
		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)) {
				tcgetattr(tty_fd, &tty_state);
			} else {
				tcsetattr(tty_fd, TCSADRAIN, &tty_state);
				/* 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;
}
Exemplo n.º 4
0
/*
 * 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 void
check_job(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;
	}

	/* 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 least, 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);
	}

	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");
	}
}
Exemplo n.º 5
0
Arquivo: jobs.c Projeto: adtools/abcsh
/*
 * wait for job to complete or change state
 *
 * If jobs are compiled in then this routine expects sigchld to be blocked.
 */
static int
j_waitj(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;

                flags |= JW_STOPPEDWAIT;

        while ((volatile int) j->state == PRUNNING ||
                ((flags & JW_STOPPEDWAIT) && (volatile int) j->state == PSTOPPED))
        {
                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) {
                j->flags &= ~JF_FG;
                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))
                        {
                                tcgetattr(tty_fd, &tty_state);
                        } else {
                                tcsetattr(tty_fd, TCSADRAIN, &tty_state);
                                /* 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;
                        }
                }
        }

        j_usrtime = j->usrtime;
        j_systime = j->systime;
        rv = j->status;

        if (!(flags & JW_ASYNCNOTIFY) &&
                (j->state != PSTOPPED))
        {
                j_print(j, JP_SHORT, shl_out);
                shf_flush(shl_out);
        }
        if (j->state != PSTOPPED &&
                (!(flags & JW_ASYNCNOTIFY)))
                        remove_job(j, where);

        return rv;
}