Subversion Repositories HelenOS

Rev

Rev 2714 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2714 cejka 1
/*  $NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $  */
2
 
3
/*-
4
 * Copyright (c) 1991, 1993
5
 *  The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Kenneth Almquist.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. All advertising materials mentioning features or use of this software
19
 *    must display the following acknowledgement:
20
 *  This product includes software developed by the University of
21
 *  California, Berkeley and its contributors.
22
 * 4. Neither the name of the University nor the names of its contributors
23
 *    may be used to endorse or promote products derived from this software
24
 *    without specific prior written permission.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
 * SUCH DAMAGE.
37
 */
38
 
39
#include <sys/cdefs.h>
40
#ifndef lint
41
#if 0
42
static char sccsid[] = "@(#)jobs.c  8.5 (Berkeley) 5/4/95";
43
#else
44
__RCSID("$NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $");
45
#endif
46
#endif /* not lint */
47
 
48
#include <fcntl.h>
49
#include <signal.h>
50
#include <errno.h>
51
#include <unistd.h>
52
#include <stdlib.h>
53
#include <paths.h>
54
#include <sys/types.h>
55
#include <sys/param.h>
56
#ifdef BSD
57
#include <sys/wait.h>
58
#include <sys/time.h>
59
#include <sys/resource.h>
60
#endif
61
#include <sys/ioctl.h>
62
 
63
#include "shell.h"
64
#if JOBS
65
#if OLD_TTY_DRIVER
66
#include "sgtty.h"
67
#else
68
#include <termios.h>
69
#endif
70
#undef CEOF         /* syntax.h redefines this */
71
#endif
72
#include "redir.h"
73
#include "show.h"
74
#include "main.h"
75
#include "parser.h"
76
#include "nodes.h"
77
#include "jobs.h"
78
#include "options.h"
79
#include "trap.h"
80
#include "syntax.h"
81
#include "input.h"
82
#include "output.h"
83
#include "memalloc.h"
84
#include "error.h"
85
#include "mystring.h"
86
 
87
 
88
struct job *jobtab;     /* array of jobs */
89
int njobs;          /* size of array */
90
MKINIT short backgndpid = -1;   /* pid of last background process */
91
#if JOBS
92
int initialpgrp;        /* pgrp of shell on invocation */
93
short curjob;           /* current job */
94
#endif
95
STATIC int intreceived;
96
 
97
STATIC void restartjob (struct job *);
98
STATIC void freejob (struct job *);
99
STATIC struct job *getjob (char *);
100
STATIC int dowait (int, struct job *);
101
STATIC int onsigchild (void);
102
STATIC int waitproc (int, int *);
103
STATIC void cmdtxt (union node *);
104
STATIC void cmdputs (const char *);
105
STATIC void waitonint(int);
106
 
107
 
108
#if JOBS
109
/*
110
 * Turn job control on and off.
111
 *
112
 * Note:  This code assumes that the third arg to ioctl is a character
113
 * pointer, which is true on Berkeley systems but not System V.  Since
114
 * System V doesn't have job control yet, this isn't a problem now.
115
 */
116
 
117
MKINIT int jobctl;
118
 
119
void
120
setjobctl(on)
121
    int on;
122
{
123
#ifdef OLD_TTY_DRIVER
124
    int ldisc;
125
#endif
126
 
127
    if (on == jobctl || rootshell == 0)
128
        return;
129
    if (on) {
130
        do { /* while we are in the background */
131
#ifdef OLD_TTY_DRIVER
132
            if (ioctl(fd2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
133
#else
134
            initialpgrp = tcgetpgrp(fd2);
135
            if (initialpgrp < 0) {
136
#endif
137
                out2str("sh: can't access tty; job control turned off\n");
138
                mflag = 0;
139
                return;
140
            }
141
            if (initialpgrp == -1)
142
                initialpgrp = getpgrp();
143
            else if (initialpgrp != getpgrp()) {
144
                killpg(initialpgrp, SIGTTIN);
145
                continue;
146
            }
147
        } while (0);
148
#ifdef OLD_TTY_DRIVER
149
        if (ioctl(fd2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
150
            out2str("sh: need new tty driver to run job control; job control turned off\n");
151
            mflag = 0;
152
            return;
153
        }
154
#endif
155
        setsignal(SIGTSTP);
156
        setsignal(SIGTTOU);
157
        setsignal(SIGTTIN);
158
        setpgid(0, rootpid);
159
#ifdef OLD_TTY_DRIVER
160
        ioctl(fd2, TIOCSPGRP, (char *)&rootpid);
161
#else
162
        tcsetpgrp(fd2, rootpid);
163
#endif
164
    } else { /* turning job control off */
165
        setpgid(0, initialpgrp);
166
#ifdef OLD_TTY_DRIVER
167
        ioctl(fd2, TIOCSPGRP, (char *)&initialpgrp);
168
#else
169
        tcsetpgrp(fd2, initialpgrp);
170
#endif
171
        setsignal(SIGTSTP);
172
        setsignal(SIGTTOU);
173
        setsignal(SIGTTIN);
174
    }
175
    jobctl = on;
176
}
177
#endif
178
 
179
 
180
#ifdef mkinit
181
INCLUDE <stdlib.h>
182
 
183
SHELLPROC {
184
    backgndpid = -1;
185
#if JOBS
186
    jobctl = 0;
187
#endif
188
}
189
 
190
#endif
191
 
192
 
193
 
194
#if JOBS
195
int
196
killcmd(argc, argv)
197
    int argc;
198
    char **argv;
199
{
200
    extern char *signal_names[];
201
    int signo = -1;
202
    int list = 0;
203
    int i;
204
    pid_t pid;
205
    struct job *jp;
206
 
207
    if (argc <= 1) {
208
        error(
209
"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
210
"kill -l [exitstatus]"
211
        );
212
    }
213
 
214
    if (*argv[1] == '-') {
215
        signo = decode_signal(argv[1]+1);
216
        if (signo < 0) {
217
            int c;
218
 
219
            while ((c = nextopt("ls:")) != '\0')
220
                switch (c) {
221
                case 'l':
222
                    list = 1;
223
                    break;
224
                case 's':
225
                    signo = decode_signal(optarg);
226
                                break;
227
                default:
228
                    error(
229
    "nextopt returned character code 0%o", c);
230
            }
231
        } else
232
            argptr++;
233
    }
234
 
235
    if (!list && signo < 0)
236
        signo = SIGTERM;
237
 
238
    if ((signo < 0 || !*argptr) ^ list) {
239
        error(
240
"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
241
"kill -l [exitstatus]"
242
        );
243
    }
244
 
245
    if (list) {
246
        if (!*argptr) {
247
            out1fmt("0\n");
248
            for (i = 1; i < NSIG; i++) {
249
                if (strncmp(signal_names[i], "SIGJUNK(", 8)
250
                    == 0)
251
                    continue;
252
                out1fmt("%s\n", signal_names[i] + 3);
253
            }
254
            return 0;
255
        }
256
        signo = atoi(*argptr);
257
        if (signo > 128)
258
            signo -= 128;
259
        if (0 < signo && signo < NSIG)
260
            out1fmt("%s\n", signal_names[signo] + 3);
261
        else
262
            error("invalid signal number or exit status: %s",
263
                  *argptr);
264
        return 0;
265
    }
266
 
267
    do {
268
        if (**argptr == '%') {
269
            jp = getjob(*argptr);
270
            if (jp->jobctl == 0)
271
                error("job %s not created under job control",
272
                      *argptr);
273
            pid = -jp->ps[0].pid;
274
        } else
275
            pid = atoi(*argptr);
276
        if (kill(pid, signo) != 0)
277
            error("%s: %s", *argptr, strerror(errno));
278
    } while (*++argptr);
279
 
280
    return 0;
281
}
282
 
283
int
284
fgcmd(argc, argv)
285
    int argc;
286
    char **argv;
287
{
288
    struct job *jp;
289
    int pgrp;
290
    int status;
291
 
292
    jp = getjob(argv[1]);
293
    if (jp->jobctl == 0)
294
        error("job not created under job control");
295
    pgrp = jp->ps[0].pid;
296
#ifdef OLD_TTY_DRIVER
297
    ioctl(fd2, TIOCSPGRP, (char *)&pgrp);
298
#else
299
    tcsetpgrp(fd2, pgrp);
300
#endif
301
    restartjob(jp);
302
    INTOFF;
303
    status = waitforjob(jp);
304
    INTON;
305
    return status;
306
}
307
 
308
 
309
int
310
bgcmd(argc, argv)
311
    int argc;
312
    char **argv;
313
{
314
    struct job *jp;
315
 
316
    do {
317
        jp = getjob(*++argv);
318
        if (jp->jobctl == 0)
319
            error("job not created under job control");
320
        restartjob(jp);
321
    } while (--argc > 1);
322
    return 0;
323
}
324
 
325
 
326
STATIC void
327
restartjob(jp)
328
    struct job *jp;
329
{
330
    struct procstat *ps;
331
    int i;
332
 
333
    if (jp->state == JOBDONE)
334
        return;
335
    INTOFF;
336
    killpg(jp->ps[0].pid, SIGCONT);
337
    for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
338
        if (WIFSTOPPED(ps->status)) {
339
            ps->status = -1;
340
            jp->state = 0;
341
        }
342
    }
343
    INTON;
344
}
345
#endif
346
 
347
 
348
int
349
jobscmd(argc, argv)
350
    int argc;
351
    char **argv;
352
{
353
    showjobs(0);
354
    return 0;
355
}
356
 
357
 
358
/*
359
 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
360
 * statuses have changed since the last call to showjobs.
361
 *
362
 * If the shell is interrupted in the process of creating a job, the
363
 * result may be a job structure containing zero processes.  Such structures
364
 * will be freed here.
365
 */
366
 
367
void
368
showjobs(change)
369
    int change;
370
{
371
    int jobno;
372
    int procno;
373
    int i;
374
    struct job *jp;
375
    struct procstat *ps;
376
    int col;
377
    char s[64];
378
 
379
    TRACE(("showjobs(%d) called\n", change));
380
    while (dowait(0, (struct job *)NULL) > 0);
381
    for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
382
        if (! jp->used)
383
            continue;
384
        if (jp->nprocs == 0) {
385
            freejob(jp);
386
            continue;
387
        }
388
        if (change && ! jp->changed)
389
            continue;
390
        procno = jp->nprocs;
391
        for (ps = jp->ps ; ; ps++) {    /* for each process */
392
            if (ps == jp->ps)
393
                fmtstr(s, 64, "[%d] %ld ", jobno,
394
                    (long)ps->pid);
395
            else
396
                fmtstr(s, 64, "    %ld ",
397
                    (long)ps->pid);
398
            out1str(s);
399
            col = strlen(s);
400
            s[0] = '\0';
401
            if (ps->status == -1) {
402
                /* don't print anything */
403
            } else if (WIFEXITED(ps->status)) {
404
                fmtstr(s, 64, "Exit %d",
405
                       WEXITSTATUS(ps->status));
406
            } else {
407
#if JOBS
408
                if (WIFSTOPPED(ps->status))
409
                    i = WSTOPSIG(ps->status);
410
                else /* WIFSIGNALED(ps->status) */
411
#endif
412
                    i = WTERMSIG(ps->status);
413
                if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
414
                    scopy(sys_siglist[i & 0x7F], s);
415
                else
416
                    fmtstr(s, 64, "Signal %d", i & 0x7F);
417
                if (WCOREDUMP(ps->status))
418
                    strcat(s, " (core dumped)");
419
            }
420
            out1str(s);
421
            col += strlen(s);
422
            do {
423
                out1c(' ');
424
                col++;
425
            } while (col < 30);
426
            out1str(ps->cmd);
427
            out1c('\n');
428
            if (--procno <= 0)
429
                break;
430
        }
431
        jp->changed = 0;
432
        if (jp->state == JOBDONE) {
433
            freejob(jp);
434
        }
435
    }
436
}
437
 
438
 
439
/*
440
 * Mark a job structure as unused.
441
 */
442
 
443
STATIC void
444
freejob(jp)
445
    struct job *jp;
446
    {
447
    struct procstat *ps;
448
    int i;
449
 
450
    INTOFF;
451
    for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
452
        if (ps->cmd != nullstr)
453
            ckfree(ps->cmd);
454
    }
455
    if (jp->ps != &jp->ps0)
456
        ckfree(jp->ps);
457
    jp->used = 0;
458
#if JOBS
459
    if (curjob == jp - jobtab + 1)
460
        curjob = 0;
461
#endif
462
    INTON;
463
}
464
 
465
 
466
 
467
int
468
waitcmd(argc, argv)
469
    int argc;
470
    char **argv;
471
{
472
    struct job *job;
473
    int status, retval;
474
    struct job *jp;
475
 
476
    if (argc > 1) {
477
        job = getjob(argv[1]);
478
    } else {
479
        job = NULL;
480
    }
481
    for (;;) {  /* loop until process terminated or stopped */
482
        if (job != NULL) {
483
            if (job->state) {
484
                status = job->ps[job->nprocs - 1].status;
485
                if (WIFEXITED(status))
486
                    retval = WEXITSTATUS(status);
487
#if JOBS
488
                else if (WIFSTOPPED(status))
489
                    retval = WSTOPSIG(status) + 128;
490
#endif
491
                else {
492
                    /* XXX: limits number of signals */
493
                    retval = WTERMSIG(status) + 128;
494
                }
495
                if (! iflag)
496
                    freejob(job);
497
                return retval;
498
            }
499
        } else {
500
            for (jp = jobtab ; ; jp++) {
501
                if (jp >= jobtab + njobs) { /* no running procs */
502
                    return 0;
503
                }
504
                if (jp->used && jp->state == 0)
505
                    break;
506
            }
507
        }
508
        dowait(1, (struct job *)NULL);
509
    }
510
}
511
 
512
 
513
 
514
int
515
jobidcmd(argc, argv)
516
    int argc;
517
    char **argv;
518
{
519
    struct job *jp;
520
    int i;
521
 
522
    jp = getjob(argv[1]);
523
    for (i = 0 ; i < jp->nprocs ; ) {
524
        out1fmt("%ld", (long)jp->ps[i].pid);
525
        out1c(++i < jp->nprocs? ' ' : '\n');
526
    }
527
    return 0;
528
}
529
 
530
 
531
 
532
/*
533
 * Convert a job name to a job structure.
534
 */
535
 
536
STATIC struct job *
537
getjob(name)
538
    char *name;
539
    {
540
    int jobno;
541
    struct job *jp;
542
    int pid;
543
    int i;
544
 
545
    if (name == NULL) {
546
#if JOBS
547
currentjob:
548
        if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
549
            error("No current job");
550
        return &jobtab[jobno - 1];
551
#else
552
        error("No current job");
553
#endif
554
    } else if (name[0] == '%') {
555
        if (is_digit(name[1])) {
556
            jobno = number(name + 1);
557
            if (jobno > 0 && jobno <= njobs
558
             && jobtab[jobno - 1].used != 0)
559
                return &jobtab[jobno - 1];
560
#if JOBS
561
        } else if (name[1] == '%' && name[2] == '\0') {
562
            goto currentjob;
563
#endif
564
        } else {
565
            struct job *found = NULL;
566
            for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
567
                if (jp->used && jp->nprocs > 0
568
                 && prefix(name + 1, jp->ps[0].cmd)) {
569
                    if (found)
570
                        error("%s: ambiguous", name);
571
                    found = jp;
572
                }
573
            }
574
            if (found)
575
                return found;
576
        }
577
    } else if (is_number(name)) {
578
        pid = number(name);
579
        for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
580
            if (jp->used && jp->nprocs > 0
581
             && jp->ps[jp->nprocs - 1].pid == pid)
582
                return jp;
583
        }
584
    }
585
    error("No such job: %s", name);
586
    /* NOTREACHED */
587
}
588
 
589
 
590
 
591
/*
592
 * Return a new job structure,
593
 */
594
 
595
struct job *
596
makejob(node, nprocs)
597
    union node *node;
598
    int nprocs;
599
{
600
    int i;
601
    struct job *jp;
602
 
603
    for (i = njobs, jp = jobtab ; ; jp++) {
604
        if (--i < 0) {
605
            INTOFF;
606
            if (njobs == 0) {
607
                jobtab = ckmalloc(4 * sizeof jobtab[0]);
608
            } else {
609
                jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
610
                memcpy(jp, jobtab, njobs * sizeof jp[0]);
611
                /* Relocate `ps' pointers */
612
                for (i = 0; i < njobs; i++)
613
                    if (jp[i].ps == &jobtab[i].ps0)
614
                        jp[i].ps = &jp[i].ps0;
615
                ckfree(jobtab);
616
                jobtab = jp;
617
            }
618
            jp = jobtab + njobs;
619
            for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
620
            INTON;
621
            break;
622
        }
623
        if (jp->used == 0)
624
            break;
625
    }
626
    INTOFF;
627
    jp->state = 0;
628
    jp->used = 1;
629
    jp->changed = 0;
630
    jp->nprocs = 0;
631
#if JOBS
632
    jp->jobctl = jobctl;
633
#endif
634
    if (nprocs > 1) {
635
        jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
636
    } else {
637
        jp->ps = &jp->ps0;
638
    }
639
    INTON;
640
    TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
641
        jp - jobtab + 1));
642
    return jp;
643
}
644
 
645
 
646
/*
647
 * Fork of a subshell.  If we are doing job control, give the subshell its
648
 * own process group.  Jp is a job structure that the job is to be added to.
649
 * N is the command that will be evaluated by the child.  Both jp and n may
650
 * be NULL.  The mode parameter can be one of the following:
651
 *  FORK_FG - Fork off a foreground process.
652
 *  FORK_BG - Fork off a background process.
653
 *  FORK_NOJOB - Like FORK_FG, but don't give the process its own
654
 *           process group even if job control is on.
655
 *
656
 * When job control is turned off, background processes have their standard
657
 * input redirected to /dev/null (except for the second and later processes
658
 * in a pipeline).
659
 */
660
 
661
int
662
forkshell(jp, n, mode)
663
    union node *n;
664
    struct job *jp;
665
    int mode;
666
{
667
    int pid;
668
    int pgrp;
669
    const char *devnull = _PATH_DEVNULL;
670
    const char *nullerr = "Can't open %s";
671
 
672
    TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
673
        mode));
674
    INTOFF;
675
    pid = fork();
676
    if (pid == -1) {
677
        TRACE(("Fork failed, errno=%d\n", errno));
678
        INTON;
679
        error("Cannot fork");
680
    }
681
    if (pid == 0) {
682
        struct job *p;
683
        int wasroot;
684
        int i;
685
 
686
        TRACE(("Child shell %d\n", getpid()));
687
        wasroot = rootshell;
688
        rootshell = 0;
689
        closescript();
690
        INTON;
691
        clear_traps();
692
#if JOBS
693
        jobctl = 0;     /* do job control only in root shell */
694
        if (wasroot && mode != FORK_NOJOB && mflag) {
695
            if (jp == NULL || jp->nprocs == 0)
696
                pgrp = getpid();
697
            else
698
                pgrp = jp->ps[0].pid;
699
            setpgid(0, pgrp);
700
            if (mode == FORK_FG) {
701
                /*** this causes superfluous TIOCSPGRPS ***/
702
#ifdef OLD_TTY_DRIVER
703
                if (ioctl(fd2, TIOCSPGRP, (char *)&pgrp) < 0)
704
                    error("TIOCSPGRP failed, errno=%d", errno);
705
#else
706
                if (tcsetpgrp(fd2, pgrp) < 0)
707
                    error("tcsetpgrp failed, errno=%d", errno);
708
#endif
709
            }
710
            setsignal(SIGTSTP);
711
            setsignal(SIGTTOU);
712
        } else if (mode == FORK_BG) {
713
            ignoresig(SIGINT);
714
            ignoresig(SIGQUIT);
715
            ignoresig(SIGHUP);
716
            if ((jp == NULL || jp->nprocs == 0) &&
717
                ! fd0_redirected_p ()) {
718
                close(0);
719
                if (open(devnull, O_RDONLY) != 0)
720
                    error(nullerr, devnull);
721
            }
722
        }
723
#else
724
        if (mode == FORK_BG) {
725
            ignoresig(SIGINT);
726
            ignoresig(SIGQUIT);
727
            ignoresig(SIGHUP);
728
            if ((jp == NULL || jp->nprocs == 0) &&
729
                ! fd0_redirected_p ()) {
730
                close(0);
731
                if (open(devnull, O_RDONLY) != 0)
732
                    error(nullerr, devnull);
733
            }
734
        }
735
#endif
736
        for (i = njobs, p = jobtab ; --i >= 0 ; p++)
737
            if (p->used)
738
                freejob(p);
739
        if (wasroot && iflag) {
740
            setsignal(SIGINT);
741
            setsignal(SIGQUIT);
742
            setsignal(SIGTERM);
743
        }
744
        return pid;
745
    }
746
    if (rootshell && mode != FORK_NOJOB && mflag) {
747
        if (jp == NULL || jp->nprocs == 0)
748
            pgrp = pid;
749
        else
750
            pgrp = jp->ps[0].pid;
751
        setpgid(pid, pgrp);
752
    }
753
    if (mode == FORK_BG)
754
        backgndpid = pid;       /* set $! */
755
    if (jp) {
756
        struct procstat *ps = &jp->ps[jp->nprocs++];
757
        ps->pid = pid;
758
        ps->status = -1;
759
        ps->cmd = nullstr;
760
        if (iflag && rootshell && n)
761
            ps->cmd = commandtext(n);
762
    }
763
    INTON;
764
    TRACE(("In parent shell:  child = %d\n", pid));
765
    return pid;
766
}
767
 
768
 
769
 
770
/*
771
 * Wait for job to finish.
772
 *
773
 * Under job control we have the problem that while a child process is
774
 * running interrupts generated by the user are sent to the child but not
775
 * to the shell.  This means that an infinite loop started by an inter-
776
 * active user may be hard to kill.  With job control turned off, an
777
 * interactive user may place an interactive program inside a loop.  If
778
 * the interactive program catches interrupts, the user doesn't want
779
 * these interrupts to also abort the loop.  The approach we take here
780
 * is to have the shell ignore interrupt signals while waiting for a
781
 * forground process to terminate, and then send itself an interrupt
782
 * signal if the child process was terminated by an interrupt signal.
783
 * Unfortunately, some programs want to do a bit of cleanup and then
784
 * exit on interrupt; unless these processes terminate themselves by
785
 * sending a signal to themselves (instead of calling exit) they will
786
 * confuse this approach.
787
 */
788
 
789
int
790
waitforjob(jp)
791
    struct job *jp;
792
    {
793
#if JOBS
794
    int mypgrp = getpgrp();
795
#endif
796
    int status;
797
    int st;
798
    struct sigaction act, oact;
799
 
800
    INTOFF;
801
    intreceived = 0;
802
#if JOBS
803
    if (!jobctl) {
804
#else
805
    if (!iflag) {
806
#endif
807
        sigaction(SIGINT, 0, &act);
808
        act.sa_handler = waitonint;
809
        sigaction(SIGINT, &act, &oact);
810
    }
811
    TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
812
    while (jp->state == 0) {
813
        dowait(1, jp);
814
    }
815
#if JOBS
816
    if (!jobctl) {
817
#else
818
    if (!iflag) {
819
#endif
820
        extern char *trap[];
821
        sigaction(SIGINT, &oact, 0);
822
        if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
823
    }
824
#if JOBS
825
    if (jp->jobctl) {
826
#ifdef OLD_TTY_DRIVER
827
        if (ioctl(fd2, TIOCSPGRP, (char *)&mypgrp) < 0)
828
            error("TIOCSPGRP failed, errno=%d\n", errno);
829
#else
830
        if (tcsetpgrp(fd2, mypgrp) < 0)
831
            error("tcsetpgrp failed, errno=%d\n", errno);
832
#endif
833
    }
834
    if (jp->state == JOBSTOPPED)
835
        curjob = jp - jobtab + 1;
836
#endif
837
    status = jp->ps[jp->nprocs - 1].status;
838
    /* convert to 8 bits */
839
    if (WIFEXITED(status))
840
        st = WEXITSTATUS(status);
841
#if JOBS
842
    else if (WIFSTOPPED(status))
843
        st = WSTOPSIG(status) + 128;
844
#endif
845
    else
846
        st = WTERMSIG(status) + 128;
847
#if JOBS
848
    if (jp->jobctl) {
849
        /*
850
         * This is truly gross.
851
         * If we're doing job control, then we did a TIOCSPGRP which
852
         * caused us (the shell) to no longer be in the controlling
853
         * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
854
         * intuit from the subprocess exit status whether a SIGINT
855
         * occured, and if so interrupt ourselves.  Yuck.  - mycroft
856
         */
857
        if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
858
            raise(SIGINT);
859
    }
860
#endif
861
    if (! JOBS || jp->state == JOBDONE)
862
        freejob(jp);
863
    INTON;
864
    return st;
865
}
866
 
867
 
868
 
869
/*
870
 * Wait for a process to terminate.
871
 */
872
 
873
STATIC int
874
dowait(block, job)
875
    int block;
876
    struct job *job;
877
{
878
    int pid;
879
    int status;
880
    struct procstat *sp;
881
    struct job *jp;
882
    struct job *thisjob;
883
    int done;
884
    int stopped;
885
    int core;
886
    int sig;
887
 
888
    TRACE(("dowait(%d) called\n", block));
889
    do {
890
        pid = waitproc(block, &status);
891
        TRACE(("wait returns %d, status=%d\n", pid, status));
892
    } while (pid == -1 && errno == EINTR);
893
    if (pid <= 0)
894
        return pid;
895
    INTOFF;
896
    thisjob = NULL;
897
    for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
898
        if (jp->used) {
899
            done = 1;
900
            stopped = 1;
901
            for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
902
                if (sp->pid == -1)
903
                    continue;
904
                if (sp->pid == pid) {
905
                    TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
906
                    sp->status = status;
907
                    thisjob = jp;
908
                }
909
                if (sp->status == -1)
910
                    stopped = 0;
911
                else if (WIFSTOPPED(sp->status))
912
                    done = 0;
913
            }
914
            if (stopped) {      /* stopped or done */
915
                int state = done? JOBDONE : JOBSTOPPED;
916
                if (jp->state != state) {
917
                    TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
918
                    jp->state = state;
919
#if JOBS
920
                    if (done && curjob == jp - jobtab + 1)
921
                        curjob = 0;     /* no current job */
922
#endif
923
                }
924
            }
925
        }
926
    }
927
    INTON;
928
    if (! rootshell || ! iflag || (job && thisjob == job)) {
929
        core = WCOREDUMP(status);
930
#if JOBS
931
        if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
932
        else
933
#endif
934
        if (WIFEXITED(status)) sig = 0;
935
        else sig = WTERMSIG(status);
936
 
937
        if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
938
            if (thisjob != job)
939
                outfmt(out2, "%d: ", pid);
940
#if JOBS
941
            if (sig == SIGTSTP && rootshell && iflag)
942
                outfmt(out2, "%%%ld ",
943
                    (long)(job - jobtab + 1));
944
#endif
945
            if (sig < NSIG && sys_siglist[sig])
946
                out2str(sys_siglist[sig]);
947
            else
948
                outfmt(out2, "Signal %d", sig);
949
            if (core)
950
                out2str(" - core dumped");
951
            out2c('\n');
952
            flushout(&errout);
953
        } else {
954
            TRACE(("Not printing status: status=%d, sig=%d\n",
955
                   status, sig));
956
        }
957
    } else {
958
        TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
959
        if (thisjob)
960
            thisjob->changed = 1;
961
    }
962
    return pid;
963
}
964
 
965
 
966
 
967
/*
968
 * Do a wait system call.  If job control is compiled in, we accept
969
 * stopped processes.  If block is zero, we return a value of zero
970
 * rather than blocking.
971
 *
972
 * System V doesn't have a non-blocking wait system call.  It does
973
 * have a SIGCLD signal that is sent to a process when one of it's
974
 * children dies.  The obvious way to use SIGCLD would be to install
975
 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
976
 * was received, and have waitproc bump another counter when it got
977
 * the status of a process.  Waitproc would then know that a wait
978
 * system call would not block if the two counters were different.
979
 * This approach doesn't work because if a process has children that
980
 * have not been waited for, System V will send it a SIGCLD when it
981
 * installs a signal handler for SIGCLD.  What this means is that when
982
 * a child exits, the shell will be sent SIGCLD signals continuously
983
 * until is runs out of stack space, unless it does a wait call before
984
 * restoring the signal handler.  The code below takes advantage of
985
 * this (mis)feature by installing a signal handler for SIGCLD and
986
 * then checking to see whether it was called.  If there are any
987
 * children to be waited for, it will be.
988
 *
989
 * If neither SYSV nor BSD is defined, we don't implement nonblocking
990
 * waits at all.  In this case, the user will not be informed when
991
 * a background process until the next time she runs a real program
992
 * (as opposed to running a builtin command or just typing return),
993
 * and the jobs command may give out of date information.
994
 */
995
 
996
#ifdef SYSV
997
STATIC int gotsigchild;
998
 
999
STATIC int onsigchild() {
1000
    gotsigchild = 1;
1001
}
1002
#endif
1003
 
1004
 
1005
STATIC int
1006
waitproc(block, status)
1007
    int block;
1008
    int *status;
1009
{
1010
#ifdef BSD
1011
    int flags;
1012
 
1013
    flags = 0;
1014
#if JOBS
1015
    if (jobctl)
1016
        flags |= WUNTRACED;
1017
#endif
1018
    if (block == 0)
1019
        flags |= WNOHANG;
1020
    return wait3(status, flags, (struct rusage *)NULL);
1021
#else
1022
#ifdef SYSV
1023
    int (*save)();
1024
 
1025
    if (block == 0) {
1026
        gotsigchild = 0;
1027
        save = signal(SIGCLD, onsigchild);
1028
        signal(SIGCLD, save);
1029
        if (gotsigchild == 0)
1030
            return 0;
1031
    }
1032
    return wait(status);
1033
#else
1034
    if (block == 0)
1035
        return 0;
1036
    return wait(status);
1037
#endif
1038
#endif
1039
}
1040
 
1041
/*
1042
 * return 1 if there are stopped jobs, otherwise 0
1043
 */
1044
int job_warning = 0;
1045
int
1046
stoppedjobs()
1047
{
1048
    int jobno;
1049
    struct job *jp;
1050
 
1051
    if (job_warning)
1052
        return (0);
1053
    for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1054
        if (jp->used == 0)
1055
            continue;
1056
        if (jp->state == JOBSTOPPED) {
1057
            out2str("You have stopped jobs.\n");
1058
            job_warning = 2;
1059
            return (1);
1060
        }
1061
    }
1062
 
1063
    return (0);
1064
}
1065
 
1066
/*
1067
 * Return a string identifying a command (to be printed by the
1068
 * jobs command.
1069
 */
1070
 
1071
STATIC char *cmdnextc;
1072
STATIC int cmdnleft;
1073
#define MAXCMDTEXT  200
1074
 
1075
char *
1076
commandtext(n)
1077
    union node *n;
1078
    {
1079
    char *name;
1080
 
1081
    cmdnextc = name = ckmalloc(MAXCMDTEXT);
1082
    cmdnleft = MAXCMDTEXT - 4;
1083
    cmdtxt(n);
1084
    *cmdnextc = '\0';
1085
    return name;
1086
}
1087
 
1088
 
1089
STATIC void
1090
cmdtxt(n)
1091
    union node *n;
1092
    {
1093
    union node *np;
1094
    struct nodelist *lp;
1095
    const char *p;
1096
    int i;
1097
    char s[2];
1098
 
1099
    if (n == NULL)
1100
        return;
1101
    switch (n->type) {
1102
    case NSEMI:
1103
        cmdtxt(n->nbinary.ch1);
1104
        cmdputs("; ");
1105
        cmdtxt(n->nbinary.ch2);
1106
        break;
1107
    case NAND:
1108
        cmdtxt(n->nbinary.ch1);
1109
        cmdputs(" && ");
1110
        cmdtxt(n->nbinary.ch2);
1111
        break;
1112
    case NOR:
1113
        cmdtxt(n->nbinary.ch1);
1114
        cmdputs(" || ");
1115
        cmdtxt(n->nbinary.ch2);
1116
        break;
1117
    case NPIPE:
1118
        for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1119
            cmdtxt(lp->n);
1120
            if (lp->next)
1121
                cmdputs(" | ");
1122
        }
1123
        break;
1124
    case NSUBSHELL:
1125
        cmdputs("(");
1126
        cmdtxt(n->nredir.n);
1127
        cmdputs(")");
1128
        break;
1129
    case NREDIR:
1130
    case NBACKGND:
1131
        cmdtxt(n->nredir.n);
1132
        break;
1133
    case NIF:
1134
        cmdputs("if ");
1135
        cmdtxt(n->nif.test);
1136
        cmdputs("; then ");
1137
        cmdtxt(n->nif.ifpart);
1138
        cmdputs("...");
1139
        break;
1140
    case NWHILE:
1141
        cmdputs("while ");
1142
        goto until;
1143
    case NUNTIL:
1144
        cmdputs("until ");
1145
until:
1146
        cmdtxt(n->nbinary.ch1);
1147
        cmdputs("; do ");
1148
        cmdtxt(n->nbinary.ch2);
1149
        cmdputs("; done");
1150
        break;
1151
    case NFOR:
1152
        cmdputs("for ");
1153
        cmdputs(n->nfor.var);
1154
        cmdputs(" in ...");
1155
        break;
1156
    case NCASE:
1157
        cmdputs("case ");
1158
        cmdputs(n->ncase.expr->narg.text);
1159
        cmdputs(" in ...");
1160
        break;
1161
    case NDEFUN:
1162
        cmdputs(n->narg.text);
1163
        cmdputs("() ...");
1164
        break;
1165
    case NCMD:
1166
        for (np = n->ncmd.args ; np ; np = np->narg.next) {
1167
            cmdtxt(np);
1168
            if (np->narg.next)
1169
                cmdputs(" ");
1170
        }
1171
        for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1172
            cmdputs(" ");
1173
            cmdtxt(np);
1174
        }
1175
        break;
1176
    case NARG:
1177
        cmdputs(n->narg.text);
1178
        break;
1179
    case NTO:
1180
        p = ">";  i = 1;  goto redir;
1181
    case NAPPEND:
1182
        p = ">>";  i = 1;  goto redir;
1183
    case NTOFD:
1184
        p = ">&";  i = 1;  goto redir;
1185
    case NTOOV:
1186
        p = ">|";  i = 1;  goto redir;
1187
    case NFROM:
1188
        p = "<";  i = 0;  goto redir;
1189
    case NFROMFD:
1190
        p = "<&";  i = 0;  goto redir;
1191
    case NFROMTO:
1192
        p = "<>";  i = 0;  goto redir;
1193
redir:
1194
        if (n->nfile.fd != i) {
1195
            s[0] = n->nfile.fd + '0';
1196
            s[1] = '\0';
1197
            cmdputs(s);
1198
        }
1199
        cmdputs(p);
1200
        if (n->type == NTOFD || n->type == NFROMFD) {
1201
            s[0] = n->ndup.dupfd + '0';
1202
            s[1] = '\0';
1203
            cmdputs(s);
1204
        } else {
1205
            cmdtxt(n->nfile.fname);
1206
        }
1207
        break;
1208
    case NHERE:
1209
    case NXHERE:
1210
        cmdputs("<<...");
1211
        break;
1212
    default:
1213
        cmdputs("???");
1214
        break;
1215
    }
1216
}
1217
 
1218
 
1219
 
1220
STATIC void
1221
cmdputs(s)
1222
    const char *s;
1223
    {
1224
    const char *p;
1225
    char *q;
1226
    char c;
1227
    int subtype = 0;
1228
 
1229
    if (cmdnleft <= 0)
1230
        return;
1231
    p = s;
1232
    q = cmdnextc;
1233
    while ((c = *p++) != '\0') {
1234
        if (c == CTLESC)
1235
            *q++ = *p++;
1236
        else if (c == CTLVAR) {
1237
            *q++ = '$';
1238
            if (--cmdnleft > 0)
1239
                *q++ = '{';
1240
            subtype = *p++;
1241
        } else if (c == '=' && subtype != 0) {
1242
            *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1243
            subtype = 0;
1244
        } else if (c == CTLENDVAR) {
1245
            *q++ = '}';
1246
        } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1247
            cmdnleft++;     /* ignore it */
1248
        else
1249
            *q++ = c;
1250
        if (--cmdnleft <= 0) {
1251
            *q++ = '.';
1252
            *q++ = '.';
1253
            *q++ = '.';
1254
            break;
1255
        }
1256
    }
1257
    cmdnextc = q;
1258
}
1259
 
1260
STATIC void waitonint(int sig) {
1261
    intreceived = 1;
1262
    return;
1263
}