sh.proc.c revision 65b0c20e9bbaf87a200ce20a4decf18585e61a25
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley Software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "sh.h"
#include "sh.dir.h"
#include "sh.proc.h"
#include "wait.h"
#include "sh.tconst.h"
/*
* C Shell - functions that manage processes, handling hanging, termination
*/
void okpcntl(void);
/*
* pchild - called at interrupt level by the SIGCHLD signal
* indicating that at least one child has terminated or stopped
* thus at least one wait system call will definitely return a
* childs status. Top level routines (like pwait) must be sure
* to mask interrupts when playing with the proclist data structures!
*/
void
pchild(void)
{
int pid;
union wait w;
int jobflags;
#ifdef TRACE
tprintf("TRACE- pchile()\n");
#endif
loop:
/*
* SysV sends a SIGCHLD when the child process
* receives a SIGCONT, and result of that action is ignored here
*/
return;
if (pid <= 0) {
errno = 0;
goto loop;
}
return;
}
goto found;
goto loop;
if (WIFSTOPPED(w)) {
} else {
if (WIFSIGNALED(w)) {
else
if (w.w_coredump)
} else {
else
}
}
jobflags = 0;
do {
}
do {
} else
#ifdef IIASA
#endif
; /* print in pjwait */
}
} else {
write_string("\015\n");
flush();
} else {
neednote++;
}
}
}
goto loop;
}
void
pnote(void)
{
#ifdef TRACE
tprintf("TRACE- pnote()\n");
#endif
neednote = 0;
(void) sigsetmask(omask);
}
}
}
/*
* pwait - wait for current job to terminate, maintaining integrity
* of current and previous job indicators.
*/
void
pwait(void)
{
int omask;
#ifdef TRACE
tprintf("TRACE- pwait()\n");
#endif
/*
* Here's where dead procs get flushed.
*/
}
(void) sigsetmask(omask);
}
/*
* pjwait - wait for a job to finish or become stopped
* It is assumed to be in the foreground state (PFOREGND)
*/
void
{
#ifdef TRACE
tprintf("TRACE- pjwait()\n");
#endif
do {
printf("BUG: waiting for background job!\n");
/*
* Now keep pausing as long as we are not interrupted (SIGINT),
* and the target process, or any of its friends, are running
*/
for (;;) {
jobflags = 0;
do
break;
/*
* At this point, csh used to call:
* sigpause(sigblock(0) &~ sigmask(SIGCHLD));
* expecting to receive a SIGCHLD signal from the
* termination of the child and to invoke the
* signal handler, pchild(), as a result.
*
* However, vfork() now causes a vfork()'d child to
* have all of its active signal handlers reset to
* SIG_DFL, to forstall parent memory corruption due
* to race conditions with signal handling.
*
* If this instance of csh is itself a child of vfork(),
* which can happen when the top-level csh performs a
* command substitution inside an i/o redirection, like:
* then we will never receive SIGCHLD. To accommodate
* this, we wait until one of our children terminates
* (without actually reaping the child) and call the
* SIGCHLD signal handler (pchild()) directly.
*/
if (csh_wait_noreap() > 0)
pchild(); /* simulate receipt of SIGCHLD */
}
(void) sigsetmask(omask);
if (tpgrp > 0) /* get tty back */
printf("\n");
}
pintr1(0);
/*NOTREACHED*/
}
reason = 0;
do {
exitstat();
}
/*
* dowait - wait for all processes to finish
*/
void
dowait(void)
{
int omask;
#ifdef TRACE
tprintf("TRACE- dowait()\n");
#endif
pjobs++;
loop:
sigpause(0);
goto loop;
}
(void) sigsetmask(omask);
pjobs = 0;
}
/*
* pflushall - flush all jobs from list (e.g. at fork())
*/
void
pflushall(void)
{
#ifdef TRACE
tprintf("TRACE- pflush()\n");
#endif
}
/*
* pflush - flag all process structures in the same job as the
* the argument process for deletion. The actual free of the
* space is not done here since pflush is called at interrupt level.
*/
void
{
int index;
#ifdef TRACE
tprintf("TRACE- pflush()\n");
#endif
printf("BUG: process flushed twice");
return;
}
pcurrjob = 0;
do {
}
}
/*
* pclrcurr - make sure the given job is not the current or previous job;
* pp MUST be the job leader
*/
void
{
#ifdef TRACE
tprintf("TRACE- pclrcurr()\n");
#endif
} else {
}
}
/* +4 here is 1 for '\0', 1 ea for << >& >> */
int cmdlen;
/*
* palloc - allocate a process structure and fill it up.
* an important assumption is made that the process is running.
*/
void
{
int i;
#ifdef TRACE
tprintf("TRACE- palloc()\n");
#endif
cmdlen = 0;
padd(t);
*cmdp++ = 0;
}
if (pcurrjob) {
/* careful here with interrupt level */
;
} else {
else {
for (i = 1; ; i++) {
goto tryagain;
if (i > pmaxindex)
pmaxindex = i;
break;
tryagain:;
}
}
}
}
void
{
#ifdef TRACE
tprintf("TRACE- padd()\n");
#endif
if (t == 0)
return;
switch (t->t_dtyp) {
case TPAR:
break;
case TCOM:
if (argp[1])
}
break;
case TOR:
case TAND:
case TFIL:
case TLST:
switch (t->t_dtyp) {
case TOR:
break;
case TAND:
break;
case TFIL:
break;
case TLST:
break;
}
return;
}
}
}
}
void
{
#ifdef TRACE
tprintf("TRACE- pads()\n");
#endif
return;
cmdp += 4;
return;
}
cmdp += i;
cmdlen += i;
}
/*
* psavejob - temporarily save the current job on a one level stack
* so another job can be created. Used for { } in exp6
* and `` in globbing.
*/
void
psavejob(void)
{
#ifdef TRACE
tprintf("TRACE- psavejob()\n");
#endif
}
/*
* prestjob - opposite of psavejob. This may be missed if we are interrupted
* somewhere, but pendjob cleans up anyway.
*/
void
prestjob(void)
{
#ifdef TRACE
tprintf("TRACE- prestjob()\n");
#endif
}
/*
* pendjob - indicate that a job (set of commands) has been completed
* or is about to begin.
*/
void
pendjob(void)
{
#ifdef TRACE
tprintf("TRACE- pendjob()\n");
#endif
do {
printf("\n");
}
}
/*
* pprint - print a job
*/
int
{
char *format;
#ifdef TRACE
tprintf("TRACE- pprint()\n");
#endif
}
jobflags = 0;
do {
printf(" ");
else {
printf("\n");
: (tchar) ' '));
else
printf(" ");
format = "%-21s";
else
format = "%s";
goto prcomd;
} else
else {
}
switch (status) {
case PRUNNING:
break;
case PINTERRUPTED:
case PSTOPPED:
case PSIGNALED:
break;
case PNEXITED:
case PAEXITED:
else
break;
default:
}
}
}
printf(" |");
printf("&");
}
printf(" (core dumped)");
printf(" &");
printf(" (wd: ");
printf(")");
}
}
printf("\n\t");
}
}
printf("\n");
printf("(wd now: ");
printf(")\n");
}
}
printf(" ");
}
return (jobflags);
}
void
{
#ifdef TRACE
tprintf("TRACE- ptprint()\n");
#endif
do {
}
/*
* dojobs - print all jobs
*/
void
{
int i;
#ifdef TRACE
tprintf("TRACE- dojobs()\n");
#endif
if (chkstop)
chkstop = 2;
if (*++v) {
error("Usage: jobs [ -l ]");
}
for (i = 1; i <= pmaxindex; i++)
break;
}
}
/*
* dofg - builtin - put the job into the foreground
*/
void
{
#ifdef TRACE
tprintf("TRACE- dofg()\n");
#endif
okpcntl();
++v;
do {
} while (*v && *++v);
}
/*
* %... - builtin - put the job into the foreground
*/
void
{
#ifdef TRACE
tprintf("TRACE- untty()\n");
#endif
okpcntl();
}
/*
* dobg - builtin - put the job into the background
*/
void
{
#ifdef TRACE
tprintf("TRACE- dobg()\n");
#endif
okpcntl();
++v;
do {
} while (*v && *++v);
}
/*
* %... & - builtin - put the job into the background
*/
void
{
#ifdef TRACE
tprintf("TRACE- dobg1()\n");
#endif
}
/*
* dostop - builtin - stop the job
*/
void
{
#ifdef TRACE
tprintf("TRACE- dostop()\n");
#endif
}
/*
* dokill - builtin - superset of kill (1)
*/
void
{
int signum;
#ifdef TRACE
tprintf("TRACE- dokill()\n");
#endif
v++;
if (v[0] && v[0][0] == '-') {
if (v[0][1] == 'l') {
if (signum % 8 == 0)
Putchar('\n');
}
Putchar('\n');
return;
}
if (digit(v[0][1])) {
bferr("Bad signal number");
} else {
int signo;
name = &v[0][1];
goto gotsig;
}
goto gotsig;
}
bferr("Unknown signal; kill -l lists signals");
}
v++;
} else
}
void
{
int jobflags = 0;
#ifdef TRACE
tprintf("TRACE- pkill()\n");
#endif
if (setintr)
while (*v) {
if (*cp == '%') {
do
switch (signum) {
case SIGSTOP:
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
/* %s -> %t */
err++;
goto cont;
}
}
/* %s -> %t */
err++;
}
bferr("Arguments should be jobs or process id's");
else {
err++;
goto cont;
}
}
cont:
v++;
}
(void) sigsetmask(omask);
if (err)
}
/*
* pstart - start the job in foreground/background
*/
void
{
#ifdef TRACE
tprintf("TRACE- pstart()\n");
#endif
do {
if (foregnd)
else
}
if (foregnd)
else
{
{
}
else
{
else
}
}
if (foregnd)
(void) sigsetmask(omask);
}
void
{
#ifdef TRACE
tprintf("TRACE- panystop()\n");
#endif
chkstop = 2;
}
struct process *
{
#ifdef TRACE
tprintf("TRACE- pfind()\n");
#endif
bferr("No current job");
return (pcurrent);
}
bferr("No previous job");
return (pprevious);
}
return (pp);
bferr("No such job");
}
continue;
goto match;
}
if (np)
bferr("Ambiguous");
}
}
if (np)
return (np);
bferr("No job matches pattern");
else
bferr("No such job");
/*NOTREACHED*/
}
/*
* pgetcurr - find most recent job that is not pp, preferably stopped
*/
struct process *
{
#ifdef TRACE
tprintf("TRACE- pgetcurr()\n");
#endif
return (np);
}
return (xp);
}
/*
* donotify - flag the job so as to report termination asynchronously
*/
void
{
#ifdef TRACE
tprintf("TRACE- donotify()\n");
#endif
}
/*
* Do the fork and whatever should be done in the child side that
* should not be done if we are not forking at all (like for simple builtin's)
* Also do everything that needs any signals fiddled with in the parent side
*
* -1: leave tty alone; inherit pgrp from parent
* 0: already have tty; manipulate process pgrps only
* 1: want to claim tty; manipulate process and tty pgrps
* It is usually just the value of tpgrp.
*
* argument:
* t: command we are forking for
*/
int
{
int pid;
bool ignint = 0;
int child_pid;
#ifdef TRACE
tprintf("TRACE- pfork()\n");
#endif
/*
* A child will be uninterruptible only under very special
* conditions. Remember that the semantics of '&' is
* implemented by disconnecting the process from the tty so
* signals do not need to ignored just for '&'.
* Thus signals are set to default action for children unless:
* we have had an "onintr -" (then specifically ignored)
* we are not playing with signals (inherit action)
*/
if (setintr)
/*
* Hold SIGCHLD until we have the process installed in our table.
*/
if (setintr == 0)
else {
(void) sigsetmask(omask);
error("Fork failed");
}
/*
* setup the process group
*/
if (pid == 0)
else
if (pid == 0) {
int sigttou;
settimes();
pflushall();
child++;
if (setintr) {
setintr = 0; /* until I think otherwise */
/*
* Children just get blown away on SIGINT, SIGQUIT
* unless "onintr -" seen.
*/
if (wanttty >= 0) {
/* make stoppable */
}
}
if (wanttty > 0) {
}
if (tpgrp > 0)
tpgrp = 0; /* gave tty away */
/*
* Nohup and nice apply only to TCOM's but it would be
* nice (?!?) if you could say "nohup (foo;bar)"
*/
} else {
(void) sigsetmask(omask);
}
return (pid);
}
void
okpcntl(void)
{
#ifdef TRACE
tprintf("TRACE- okpcntl()\n");
#endif
if (tpgrp == -1)
error("No job control in this shell");
if (tpgrp == 0)
error("No job control in subshells");
}