~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to dash/jobs.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 1991, 1993
 
3
 *      The Regents of the University of California.  All rights reserved.
 
4
 * Copyright (c) 1997-2005
 
5
 *      Herbert Xu <herbert@gondor.apana.org.au>.  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. Neither the name of the University nor the names of its contributors
 
19
 *    may be used to endorse or promote products derived from this software
 
20
 *    without specific prior written permission.
 
21
 *
 
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
32
 * SUCH DAMAGE.
 
33
 */
 
34
 
 
35
#include <fcntl.h>
 
36
#include <signal.h>
 
37
#include <unistd.h>
 
38
#include <stdlib.h>
 
39
#include <paths.h>
 
40
#include <sys/types.h>
 
41
#include <sys/param.h>
 
42
#ifdef BSD
 
43
#include <sys/wait.h>
 
44
#include <sys/time.h>
 
45
#include <sys/resource.h>
 
46
#endif
 
47
#include <sys/ioctl.h>
 
48
 
 
49
#include "shell.h"
 
50
#if JOBS
 
51
#include <termios.h>
 
52
#undef CEOF                     /* syntax.h redefines this */
 
53
#endif
 
54
#include "redir.h"
 
55
#include "show.h"
 
56
#include "main.h"
 
57
#include "parser.h"
 
58
#include "nodes.h"
 
59
#include "jobs.h"
 
60
#include "options.h"
 
61
#include "trap.h"
 
62
#include "syntax.h"
 
63
#include "input.h"
 
64
#include "output.h"
 
65
#include "memalloc.h"
 
66
#include "error.h"
 
67
#include "mystring.h"
 
68
#include "system.h"
 
69
 
 
70
/* mode flags for set_curjob */
 
71
#define CUR_DELETE 2
 
72
#define CUR_RUNNING 1
 
73
#define CUR_STOPPED 0
 
74
 
 
75
/* mode flags for dowait */
 
76
#define DOWAIT_NORMAL 0
 
77
#define DOWAIT_BLOCK 1
 
78
 
 
79
/* array of jobs */
 
80
static struct job *jobtab;
 
81
/* size of array */
 
82
static unsigned njobs;
 
83
/* pid of last background process */
 
84
pid_t backgndpid;
 
85
 
 
86
#if JOBS
 
87
/* pgrp of shell on invocation */
 
88
static int initialpgrp;
 
89
/* control terminal */
 
90
static int ttyfd = -1;
 
91
#endif
 
92
 
 
93
/* current job */
 
94
static struct job *curjob;
 
95
/* number of presumed living untracked jobs */
 
96
static int jobless;
 
97
 
 
98
STATIC void set_curjob(struct job *, unsigned);
 
99
STATIC int jobno(const struct job *);
 
100
STATIC int sprint_status(char *, int, int);
 
101
STATIC void freejob(struct job *);
 
102
STATIC struct job *getjob(const char *, int);
 
103
STATIC struct job *growjobtab(void);
 
104
STATIC void forkchild(struct job *, union node *, int);
 
105
STATIC void forkparent(struct job *, union node *, int, pid_t);
 
106
STATIC int dowait(int, struct job *);
 
107
#ifdef SYSV
 
108
STATIC int onsigchild(void);
 
109
#endif
 
110
STATIC int waitproc(int, int *);
 
111
STATIC char *commandtext(union node *);
 
112
STATIC void cmdtxt(union node *);
 
113
STATIC void cmdlist(union node *, int);
 
114
STATIC void cmdputs(const char *);
 
115
STATIC void showpipe(struct job *, struct output *);
 
116
STATIC int getstatus(struct job *);
 
117
 
 
118
#if JOBS
 
119
static int restartjob(struct job *, int);
 
120
static void xtcsetpgrp(int, pid_t);
 
121
#endif
 
122
 
 
123
STATIC void
 
124
set_curjob(struct job *jp, unsigned mode)
 
125
{
 
126
        struct job *jp1;
 
127
        struct job **jpp, **curp;
 
128
 
 
129
        /* first remove from list */
 
130
        jpp = curp = &curjob;
 
131
        do {
 
132
                jp1 = *jpp;
 
133
                if (jp1 == jp)
 
134
                        break;
 
135
                jpp = &jp1->prev_job;
 
136
        } while (1);
 
137
        *jpp = jp1->prev_job;
 
138
 
 
139
        /* Then re-insert in correct position */
 
140
        jpp = curp;
 
141
        switch (mode) {
 
142
        default:
 
143
#ifdef DEBUG
 
144
                abort();
 
145
#endif
 
146
        case CUR_DELETE:
 
147
                /* job being deleted */
 
148
                break;
 
149
        case CUR_RUNNING:
 
150
                /* newly created job or backgrounded job,
 
151
                   put after all stopped jobs. */
 
152
                do {
 
153
                        jp1 = *jpp;
 
154
                        if (!JOBS || !jp1 || jp1->state != JOBSTOPPED)
 
155
                                break;
 
156
                        jpp = &jp1->prev_job;
 
157
                } while (1);
 
158
                /* FALLTHROUGH */
 
159
#if JOBS
 
160
        case CUR_STOPPED:
 
161
#endif
 
162
                /* newly stopped job - becomes curjob */
 
163
                jp->prev_job = *jpp;
 
164
                *jpp = jp;
 
165
                break;
 
166
        }
 
167
}
 
168
 
 
169
#if JOBS
 
170
/*
 
171
 * Turn job control on and off.
 
172
 *
 
173
 * Note:  This code assumes that the third arg to ioctl is a character
 
174
 * pointer, which is true on Berkeley systems but not System V.  Since
 
175
 * System V doesn't have job control yet, this isn't a problem now.
 
176
 *
 
177
 * Called with interrupts off.
 
178
 */
 
179
 
 
180
int jobctl;
 
181
 
 
182
void
 
183
setjobctl(int on)
 
184
{
 
185
        int fd;
 
186
        int pgrp;
 
187
 
 
188
        if (on == jobctl || rootshell == 0)
 
189
                return;
 
190
        if (on) {
 
191
                int ofd;
 
192
                ofd = fd = open(_PATH_TTY, O_RDWR);
 
193
                if (fd < 0) {
 
194
                        fd += 3;
 
195
                        while (!isatty(fd) && --fd >= 0)
 
196
                                ;
 
197
                }
 
198
                fd = fcntl(fd, F_DUPFD, 10);
 
199
                close(ofd);
 
200
                if (fd < 0)
 
201
                        goto out;
 
202
                fcntl(fd, F_SETFD, FD_CLOEXEC);
 
203
                do { /* while we are in the background */
 
204
                        if ((pgrp = tcgetpgrp(fd)) < 0) {
 
205
out:
 
206
                                sh_warnx("can't access tty; job control turned off");
 
207
                                mflag = on = 0;
 
208
                                goto close;
 
209
                        }
 
210
                        if (pgrp == getpgrp())
 
211
                                break;
 
212
                        killpg(0, SIGTTIN);
 
213
                } while (1);
 
214
                initialpgrp = pgrp;
 
215
 
 
216
                setsignal(SIGTSTP);
 
217
                setsignal(SIGTTOU);
 
218
                setsignal(SIGTTIN);
 
219
                pgrp = rootpid;
 
220
                setpgid(0, pgrp);
 
221
                xtcsetpgrp(fd, pgrp);
 
222
        } else {
 
223
                /* turning job control off */
 
224
                fd = ttyfd;
 
225
                pgrp = initialpgrp;
 
226
                xtcsetpgrp(fd, pgrp);
 
227
                setpgid(0, pgrp);
 
228
                setsignal(SIGTSTP);
 
229
                setsignal(SIGTTOU);
 
230
                setsignal(SIGTTIN);
 
231
close:
 
232
                close(fd);
 
233
                fd = -1;
 
234
        }
 
235
        ttyfd = fd;
 
236
        jobctl = on;
 
237
}
 
238
#endif
 
239
 
 
240
 
 
241
int
 
242
killcmd(argc, argv)
 
243
        int argc;
 
244
        char **argv;
 
245
{
 
246
        int signo = -1;
 
247
        int list = 0;
 
248
        int i;
 
249
        pid_t pid;
 
250
        struct job *jp;
 
251
 
 
252
        if (argc <= 1) {
 
253
usage:
 
254
                sh_error(
 
255
"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
 
256
"kill -l [exitstatus]"
 
257
                );
 
258
        }
 
259
 
 
260
        if (**++argv == '-') {
 
261
                signo = decode_signal(*argv + 1, 1);
 
262
                if (signo < 0) {
 
263
                        int c;
 
264
 
 
265
                        while ((c = nextopt("ls:")) != '\0')
 
266
                                switch (c) {
 
267
                                default:
 
268
#ifdef DEBUG
 
269
                                        abort();
 
270
#endif
 
271
                                case 'l':
 
272
                                        list = 1;
 
273
                                        break;
 
274
                                case 's':
 
275
                                        signo = decode_signal(optionarg, 1);
 
276
                                        if (signo < 0) {
 
277
                                                sh_error(
 
278
                                                        "invalid signal number or name: %s",
 
279
                                                        optionarg
 
280
                                                );
 
281
                                        }
 
282
                                        break;
 
283
                                }
 
284
                        argv = argptr;
 
285
                } else
 
286
                        argv++;
 
287
        }
 
288
 
 
289
        if (!list && signo < 0)
 
290
                signo = SIGTERM;
 
291
 
 
292
        if ((signo < 0 || !*argv) ^ list) {
 
293
                goto usage;
 
294
        }
 
295
 
 
296
        if (list) {
 
297
                struct output *out;
 
298
 
 
299
                out = out1;
 
300
                if (!*argv) {
 
301
                        outstr("0\n", out);
 
302
                        for (i = 1; i < NSIG; i++) {
 
303
                                outfmt(out, snlfmt, signal_name(i));
 
304
                        }
 
305
                        return 0;
 
306
                }
 
307
                signo = number(*argv);
 
308
                if (signo > 128)
 
309
                        signo -= 128;
 
310
                if (0 < signo && signo < NSIG)
 
311
                        outfmt(out, snlfmt, signal_name(signo));
 
312
                else
 
313
                        sh_error("invalid signal number or exit status: %s",
 
314
                                 *argv);
 
315
                return 0;
 
316
        }
 
317
 
 
318
        i = 0;
 
319
        do {
 
320
                if (**argv == '%') {
 
321
                        jp = getjob(*argv, 0);
 
322
                        pid = -jp->ps[0].pid;
 
323
                } else
 
324
                        pid = **argv == '-' ?
 
325
                                -number(*argv + 1) : number(*argv);
 
326
                if (kill(pid, signo) != 0) {
 
327
                        sh_warnx("%s\n", strerror(errno));
 
328
                        i = 1;
 
329
                }
 
330
        } while (*++argv);
 
331
 
 
332
        return i;
 
333
}
 
334
 
 
335
STATIC int
 
336
jobno(const struct job *jp)
 
337
{
 
338
        return jp - jobtab + 1;
 
339
}
 
340
 
 
341
#if JOBS
 
342
int
 
343
fgcmd(int argc, char **argv)
 
344
{
 
345
        struct job *jp;
 
346
        struct output *out;
 
347
        int mode;
 
348
        int retval;
 
349
 
 
350
        mode = (**argv == 'f') ? FORK_FG : FORK_BG;
 
351
        nextopt(nullstr);
 
352
        argv = argptr;
 
353
        out = out1;
 
354
        do {
 
355
                jp = getjob(*argv, 1);
 
356
                if (mode == FORK_BG) {
 
357
                        set_curjob(jp, CUR_RUNNING);
 
358
                        outfmt(out, "[%d] ", jobno(jp));
 
359
                }
 
360
                outstr(jp->ps->cmd, out);
 
361
                showpipe(jp, out);
 
362
                retval = restartjob(jp, mode);
 
363
        } while (*argv && *++argv);
 
364
        return retval;
 
365
}
 
366
 
 
367
int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
 
368
 
 
369
 
 
370
STATIC int
 
371
restartjob(struct job *jp, int mode)
 
372
{
 
373
        struct procstat *ps;
 
374
        int i;
 
375
        int status;
 
376
        pid_t pgid;
 
377
 
 
378
        INTOFF;
 
379
        if (jp->state == JOBDONE)
 
380
                goto out;
 
381
        jp->state = JOBRUNNING;
 
382
        pgid = jp->ps->pid;
 
383
        if (mode == FORK_FG)
 
384
                xtcsetpgrp(ttyfd, pgid);
 
385
        killpg(pgid, SIGCONT);
 
386
        ps = jp->ps;
 
387
        i = jp->nprocs;
 
388
        do {
 
389
                if (WIFSTOPPED(ps->status)) {
 
390
                        ps->status = -1;
 
391
                }
 
392
        } while (ps++, --i);
 
393
out:
 
394
        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
 
395
        INTON;
 
396
        return status;
 
397
}
 
398
#endif
 
399
 
 
400
STATIC int
 
401
sprint_status(char *s, int status, int sigonly)
 
402
{
 
403
        int col;
 
404
        int st;
 
405
 
 
406
        col = 0;
 
407
        st = WEXITSTATUS(status);
 
408
        if (!WIFEXITED(status)) {
 
409
#if JOBS
 
410
                st = WSTOPSIG(status);
 
411
                if (!WIFSTOPPED(status))
 
412
#endif
 
413
                        st = WTERMSIG(status);
 
414
                if (sigonly) {
 
415
                        if (st == SIGINT || st == SIGPIPE)
 
416
                                goto out;
 
417
#if JOBS
 
418
                        if (WIFSTOPPED(status))
 
419
                                goto out;
 
420
#endif
 
421
                }
 
422
                col = fmtstr(s, 32, strsignal(st));
 
423
                if (WCOREDUMP(status)) {
 
424
                        col += fmtstr(s + col, 16, " (core dumped)");
 
425
                }
 
426
        } else if (!sigonly) {
 
427
                if (st)
 
428
                        col = fmtstr(s, 16, "Done(%d)", st);
 
429
                else
 
430
                        col = fmtstr(s, 16, "Done");
 
431
        }
 
432
 
 
433
out:
 
434
        return col;
 
435
}
 
436
 
 
437
static void
 
438
showjob(struct output *out, struct job *jp, int mode)
 
439
{
 
440
        struct procstat *ps;
 
441
        struct procstat *psend;
 
442
        int col;
 
443
        int indent;
 
444
        char s[80];
 
445
 
 
446
        ps = jp->ps;
 
447
 
 
448
        if (mode & SHOW_PGID) {
 
449
                /* just output process (group) id of pipeline */
 
450
                outfmt(out, "%d\n", ps->pid);
 
451
                return;
 
452
        }
 
453
 
 
454
        col = fmtstr(s, 16, "[%d]   ", jobno(jp));
 
455
        indent = col;
 
456
 
 
457
        if (jp == curjob)
 
458
                s[col - 2] = '+';
 
459
        else if (curjob && jp == curjob->prev_job)
 
460
                s[col - 2] = '-';
 
461
 
 
462
        if (mode & SHOW_PID)
 
463
                col += fmtstr(s + col, 16, "%d ", ps->pid);
 
464
 
 
465
        psend = ps + jp->nprocs;
 
466
 
 
467
        if (jp->state == JOBRUNNING) {
 
468
                scopy("Running", s + col);
 
469
                col += strlen("Running");
 
470
        } else {
 
471
                int status = psend[-1].status;
 
472
#if JOBS
 
473
                if (jp->state == JOBSTOPPED)
 
474
                        status = jp->stopstatus;
 
475
#endif
 
476
                col += sprint_status(s + col, status, 0);
 
477
        }
 
478
 
 
479
        goto start;
 
480
 
 
481
        do {
 
482
                /* for each process */
 
483
                col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
 
484
 
 
485
start:
 
486
                outfmt(
 
487
                        out, "%s%*c%s",
 
488
                        s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
 
489
                );
 
490
                if (!(mode & SHOW_PID)) {
 
491
                        showpipe(jp, out);
 
492
                        break;
 
493
                }
 
494
                if (++ps == psend) {
 
495
                        outcslow('\n', out);
 
496
                        break;
 
497
                }
 
498
        } while (1);
 
499
 
 
500
        jp->changed = 0;
 
501
 
 
502
        if (jp->state == JOBDONE) {
 
503
                TRACE(("showjob: freeing job %d\n", jobno(jp)));
 
504
                freejob(jp);
 
505
        }
 
506
}
 
507
 
 
508
 
 
509
int
 
510
jobscmd(int argc, char **argv)
 
511
{
 
512
        int mode, m;
 
513
        struct output *out;
 
514
 
 
515
        mode = 0;
 
516
        while ((m = nextopt("lp")))
 
517
                if (m == 'l')
 
518
                        mode = SHOW_PID;
 
519
                else
 
520
                        mode = SHOW_PGID;
 
521
 
 
522
        out = out1;
 
523
        argv = argptr;
 
524
        if (*argv)
 
525
                do
 
526
                        showjob(out, getjob(*argv,0), mode);
 
527
                while (*++argv);
 
528
        else
 
529
                showjobs(out, mode);
 
530
 
 
531
        return 0;
 
532
}
 
533
 
 
534
 
 
535
/*
 
536
 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
 
537
 * statuses have changed since the last call to showjobs.
 
538
 */
 
539
 
 
540
void
 
541
showjobs(struct output *out, int mode)
 
542
{
 
543
        struct job *jp;
 
544
 
 
545
        TRACE(("showjobs(%x) called\n", mode));
 
546
 
 
547
        /* If not even one one job changed, there is nothing to do */
 
548
        while (dowait(DOWAIT_NORMAL, NULL) > 0)
 
549
                continue;
 
550
 
 
551
        for (jp = curjob; jp; jp = jp->prev_job) {
 
552
                if (!(mode & SHOW_CHANGED) || jp->changed)
 
553
                        showjob(out, jp, mode);
 
554
        }
 
555
}
 
556
 
 
557
/*
 
558
 * Mark a job structure as unused.
 
559
 */
 
560
 
 
561
STATIC void
 
562
freejob(struct job *jp)
 
563
{
 
564
        struct procstat *ps;
 
565
        int i;
 
566
 
 
567
        INTOFF;
 
568
        for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
 
569
                if (ps->cmd != nullstr)
 
570
                        ckfree(ps->cmd);
 
571
        }
 
572
        if (jp->ps != &jp->ps0)
 
573
                ckfree(jp->ps);
 
574
        jp->used = 0;
 
575
        set_curjob(jp, CUR_DELETE);
 
576
        INTON;
 
577
}
 
578
 
 
579
 
 
580
 
 
581
int
 
582
waitcmd(int argc, char **argv)
 
583
{
 
584
        struct job *job;
 
585
        int retval;
 
586
        struct job *jp;
 
587
 
 
588
        EXSIGON();
 
589
 
 
590
        nextopt(nullstr);
 
591
        retval = 0;
 
592
 
 
593
        argv = argptr;
 
594
        if (!*argv) {
 
595
                /* wait for all jobs */
 
596
                for (;;) {
 
597
                        jp = curjob;
 
598
                        while (1) {
 
599
                                if (!jp) {
 
600
                                        /* no running procs */
 
601
                                        goto out;
 
602
                                }
 
603
                                if (jp->state == JOBRUNNING)
 
604
                                        break;
 
605
                                jp->waited = 1;
 
606
                                jp = jp->prev_job;
 
607
                        }
 
608
                        dowait(DOWAIT_BLOCK, 0);
 
609
                }
 
610
        }
 
611
 
 
612
        retval = 127;
 
613
        do {
 
614
                if (**argv != '%') {
 
615
                        pid_t pid = number(*argv);
 
616
                        job = curjob;
 
617
                        goto start;
 
618
                        do {
 
619
                                if (job->ps[job->nprocs - 1].pid == pid)
 
620
                                        break;
 
621
                                job = job->prev_job;
 
622
start:
 
623
                                if (!job)
 
624
                                        goto repeat;
 
625
                        } while (1);
 
626
                } else
 
627
                        job = getjob(*argv, 0);
 
628
                /* loop until process terminated or stopped */
 
629
                while (job->state == JOBRUNNING)
 
630
                        dowait(DOWAIT_BLOCK, 0);
 
631
                job->waited = 1;
 
632
                retval = getstatus(job);
 
633
repeat:
 
634
                ;
 
635
        } while (*++argv);
 
636
 
 
637
out:
 
638
        return retval;
 
639
}
 
640
 
 
641
 
 
642
 
 
643
/*
 
644
 * Convert a job name to a job structure.
 
645
 */
 
646
 
 
647
STATIC struct job *
 
648
getjob(const char *name, int getctl)
 
649
{
 
650
        struct job *jp;
 
651
        struct job *found;
 
652
        const char *err_msg = "No such job: %s";
 
653
        unsigned num;
 
654
        int c;
 
655
        const char *p;
 
656
        char *(*match)(const char *, const char *);
 
657
 
 
658
        jp = curjob;
 
659
        p = name;
 
660
        if (!p)
 
661
                goto currentjob;
 
662
 
 
663
        if (*p != '%')
 
664
                goto err;
 
665
 
 
666
        c = *++p;
 
667
        if (!c)
 
668
                goto currentjob;
 
669
 
 
670
        if (!p[1]) {
 
671
                if (c == '+' || c == '%') {
 
672
currentjob:
 
673
                        err_msg = "No current job";
 
674
                        goto check;
 
675
                } else if (c == '-') {
 
676
                        if (jp)
 
677
                                jp = jp->prev_job;
 
678
                        err_msg = "No previous job";
 
679
check:
 
680
                        if (!jp)
 
681
                                goto err;
 
682
                        goto gotit;
 
683
                }
 
684
        }
 
685
 
 
686
        if (is_number(p)) {
 
687
                num = atoi(p);
 
688
                if (num < njobs) {
 
689
                        jp = jobtab + num - 1;
 
690
                        if (jp->used)
 
691
                                goto gotit;
 
692
                        goto err;
 
693
                }
 
694
        }
 
695
 
 
696
        match = prefix;
 
697
        if (*p == '?') {
 
698
                match = strstr;
 
699
                p++;
 
700
        }
 
701
 
 
702
        found = 0;
 
703
        while (1) {
 
704
                if (!jp)
 
705
                        goto err;
 
706
                if (match(jp->ps[0].cmd, p)) {
 
707
                        if (found)
 
708
                                goto err;
 
709
                        found = jp;
 
710
                        err_msg = "%s: ambiguous";
 
711
                }
 
712
                jp = jp->prev_job;
 
713
        }
 
714
 
 
715
gotit:
 
716
#if JOBS
 
717
        err_msg = "job %s not created under job control";
 
718
        if (getctl && jp->jobctl == 0)
 
719
                goto err;
 
720
#endif
 
721
        return jp;
 
722
err:
 
723
        sh_error(err_msg, name);
 
724
}
 
725
 
 
726
 
 
727
 
 
728
/*
 
729
 * Return a new job structure.
 
730
 * Called with interrupts off.
 
731
 */
 
732
 
 
733
struct job *
 
734
makejob(union node *node, int nprocs)
 
735
{
 
736
        int i;
 
737
        struct job *jp;
 
738
 
 
739
        for (i = njobs, jp = jobtab ; ; jp++) {
 
740
                if (--i < 0) {
 
741
                        jp = growjobtab();
 
742
                        break;
 
743
                }
 
744
                if (jp->used == 0)
 
745
                        break;
 
746
                if (jp->state != JOBDONE || !jp->waited)
 
747
                        continue;
 
748
                if (jobctl)
 
749
                        continue;
 
750
                freejob(jp);
 
751
                break;
 
752
        }
 
753
        memset(jp, 0, sizeof(*jp));
 
754
#if JOBS
 
755
        if (jobctl)
 
756
                jp->jobctl = 1;
 
757
#endif
 
758
        jp->prev_job = curjob;
 
759
        curjob = jp;
 
760
        jp->used = 1;
 
761
        jp->ps = &jp->ps0;
 
762
        if (nprocs > 1) {
 
763
                jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
 
764
        }
 
765
        TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
 
766
            jobno(jp)));
 
767
        return jp;
 
768
}
 
769
 
 
770
STATIC struct job *
 
771
growjobtab(void)
 
772
{
 
773
        size_t len;
 
774
        ptrdiff_t offset;
 
775
        struct job *jp, *jq;
 
776
 
 
777
        len = njobs * sizeof(*jp);
 
778
        jq = jobtab;
 
779
        jp = ckrealloc(jq, len + 4 * sizeof(*jp));
 
780
 
 
781
        offset = (char *)jp - (char *)jq;
 
782
        if (offset) {
 
783
                /* Relocate pointers */
 
784
                size_t l = len;
 
785
 
 
786
                jq = (struct job *)((char *)jq + l);
 
787
                while (l) {
 
788
                        l -= sizeof(*jp);
 
789
                        jq--;
 
790
#define joff(p) ((struct job *)((char *)(p) + l))
 
791
#define jmove(p) (p) = (void *)((char *)(p) + offset)
 
792
                        if (likely(joff(jp)->ps == &jq->ps0))
 
793
                                jmove(joff(jp)->ps);
 
794
                        if (joff(jp)->prev_job)
 
795
                                jmove(joff(jp)->prev_job);
 
796
                }
 
797
                if (curjob)
 
798
                        jmove(curjob);
 
799
#undef joff
 
800
#undef jmove
 
801
        }
 
802
 
 
803
        njobs += 4;
 
804
        jobtab = jp;
 
805
        jp = (struct job *)((char *)jp + len);
 
806
        jq = jp + 3;
 
807
        do {
 
808
                jq->used = 0;
 
809
        } while (--jq >= jp);
 
810
        return jp;
 
811
}
 
812
 
 
813
 
 
814
/*
 
815
 * Fork off a subshell.  If we are doing job control, give the subshell its
 
816
 * own process group.  Jp is a job structure that the job is to be added to.
 
817
 * N is the command that will be evaluated by the child.  Both jp and n may
 
818
 * be NULL.  The mode parameter can be one of the following:
 
819
 *      FORK_FG - Fork off a foreground process.
 
820
 *      FORK_BG - Fork off a background process.
 
821
 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
 
822
 *                   process group even if job control is on.
 
823
 *
 
824
 * When job control is turned off, background processes have their standard
 
825
 * input redirected to /dev/null (except for the second and later processes
 
826
 * in a pipeline).
 
827
 *
 
828
 * Called with interrupts off.
 
829
 */
 
830
 
 
831
STATIC inline void
 
832
forkchild(struct job *jp, union node *n, int mode)
 
833
{
 
834
        int oldlvl;
 
835
 
 
836
        TRACE(("Child shell %d\n", getpid()));
 
837
        oldlvl = shlvl;
 
838
        shlvl++;
 
839
 
 
840
        closescript();
 
841
        clear_traps();
 
842
#if JOBS
 
843
        /* do job control only in root shell */
 
844
        jobctl = 0;
 
845
        if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
 
846
                pid_t pgrp;
 
847
 
 
848
                if (jp->nprocs == 0)
 
849
                        pgrp = getpid();
 
850
                else
 
851
                        pgrp = jp->ps[0].pid;
 
852
                /* This can fail because we are doing it in the parent also */
 
853
                (void)setpgid(0, pgrp);
 
854
                if (mode == FORK_FG)
 
855
                        xtcsetpgrp(ttyfd, pgrp);
 
856
                setsignal(SIGTSTP);
 
857
                setsignal(SIGTTOU);
 
858
        } else
 
859
#endif
 
860
        if (mode == FORK_BG) {
 
861
                ignoresig(SIGINT);
 
862
                ignoresig(SIGQUIT);
 
863
                if (jp->nprocs == 0) {
 
864
                        close(0);
 
865
                        if (open(_PATH_DEVNULL, O_RDONLY) != 0)
 
866
                                sh_error("Can't open %s", _PATH_DEVNULL);
 
867
                }
 
868
        }
 
869
        if (!oldlvl && iflag) {
 
870
                setsignal(SIGINT);
 
871
                setsignal(SIGQUIT);
 
872
                setsignal(SIGTERM);
 
873
        }
 
874
        for (jp = curjob; jp; jp = jp->prev_job)
 
875
                freejob(jp);
 
876
        jobless = 0;
 
877
}
 
878
 
 
879
STATIC inline void
 
880
forkparent(struct job *jp, union node *n, int mode, pid_t pid)
 
881
{
 
882
        TRACE(("In parent shell:  child = %d\n", pid));
 
883
        if (!jp) {
 
884
                while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
 
885
                jobless++;
 
886
                return;
 
887
        }
 
888
#if JOBS
 
889
        if (mode != FORK_NOJOB && jp->jobctl) {
 
890
                int pgrp;
 
891
 
 
892
                if (jp->nprocs == 0)
 
893
                        pgrp = pid;
 
894
                else
 
895
                        pgrp = jp->ps[0].pid;
 
896
                /* This can fail because we are doing it in the child also */
 
897
                (void)setpgid(pid, pgrp);
 
898
        }
 
899
#endif
 
900
        if (mode == FORK_BG) {
 
901
                backgndpid = pid;               /* set $! */
 
902
                set_curjob(jp, CUR_RUNNING);
 
903
        }
 
904
        if (jp) {
 
905
                struct procstat *ps = &jp->ps[jp->nprocs++];
 
906
                ps->pid = pid;
 
907
                ps->status = -1;
 
908
                ps->cmd = nullstr;
 
909
                if (jobctl && n)
 
910
                        ps->cmd = commandtext(n);
 
911
        }
 
912
}
 
913
 
 
914
int
 
915
forkshell(struct job *jp, union node *n, int mode)
 
916
{
 
917
        int pid;
 
918
 
 
919
        TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
 
920
        pid = fork();
 
921
        if (pid < 0) {
 
922
                TRACE(("Fork failed, errno=%d", errno));
 
923
                if (jp)
 
924
                        freejob(jp);
 
925
                sh_error("Cannot fork");
 
926
        }
 
927
        if (pid == 0)
 
928
                forkchild(jp, n, mode);
 
929
        else
 
930
                forkparent(jp, n, mode, pid);
 
931
        return pid;
 
932
}
 
933
 
 
934
/*
 
935
 * Wait for job to finish.
 
936
 *
 
937
 * Under job control we have the problem that while a child process is
 
938
 * running interrupts generated by the user are sent to the child but not
 
939
 * to the shell.  This means that an infinite loop started by an inter-
 
940
 * active user may be hard to kill.  With job control turned off, an
 
941
 * interactive user may place an interactive program inside a loop.  If
 
942
 * the interactive program catches interrupts, the user doesn't want
 
943
 * these interrupts to also abort the loop.  The approach we take here
 
944
 * is to have the shell ignore interrupt signals while waiting for a
 
945
 * forground process to terminate, and then send itself an interrupt
 
946
 * signal if the child process was terminated by an interrupt signal.
 
947
 * Unfortunately, some programs want to do a bit of cleanup and then
 
948
 * exit on interrupt; unless these processes terminate themselves by
 
949
 * sending a signal to themselves (instead of calling exit) they will
 
950
 * confuse this approach.
 
951
 *
 
952
 * Called with interrupts off.
 
953
 */
 
954
 
 
955
int
 
956
waitforjob(struct job *jp)
 
957
{
 
958
        int st;
 
959
 
 
960
        TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
 
961
        while (jp->state == JOBRUNNING) {
 
962
                dowait(DOWAIT_BLOCK, jp);
 
963
        }
 
964
        st = getstatus(jp);
 
965
#if JOBS
 
966
        if (jp->jobctl) {
 
967
                xtcsetpgrp(ttyfd, rootpid);
 
968
                /*
 
969
                 * This is truly gross.
 
970
                 * If we're doing job control, then we did a TIOCSPGRP which
 
971
                 * caused us (the shell) to no longer be in the controlling
 
972
                 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
 
973
                 * intuit from the subprocess exit status whether a SIGINT
 
974
                 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
 
975
                 */
 
976
                if (jp->sigint)
 
977
                        raise(SIGINT);
 
978
        }
 
979
#endif
 
980
        if (! JOBS || jp->state == JOBDONE)
 
981
                freejob(jp);
 
982
        return st;
 
983
}
 
984
 
 
985
 
 
986
 
 
987
/*
 
988
 * Wait for a process to terminate.
 
989
 */
 
990
 
 
991
STATIC int
 
992
dowait(int block, struct job *job)
 
993
{
 
994
        int pid;
 
995
        int status;
 
996
        struct job *jp;
 
997
        struct job *thisjob;
 
998
        int state;
 
999
 
 
1000
        TRACE(("dowait(%d) called\n", block));
 
1001
        pid = waitproc(block, &status);
 
1002
        TRACE(("wait returns pid %d, status=%d\n", pid, status));
 
1003
        if (pid <= 0)
 
1004
                return pid;
 
1005
        INTOFF;
 
1006
        thisjob = NULL;
 
1007
        for (jp = curjob; jp; jp = jp->prev_job) {
 
1008
                struct procstat *sp;
 
1009
                struct procstat *spend;
 
1010
                if (jp->state == JOBDONE)
 
1011
                        continue;
 
1012
                state = JOBDONE;
 
1013
                spend = jp->ps + jp->nprocs;
 
1014
                sp = jp->ps;
 
1015
                do {
 
1016
                        if (sp->pid == pid) {
 
1017
                                TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
 
1018
                                sp->status = status;
 
1019
                                thisjob = jp;
 
1020
                        }
 
1021
                        if (sp->status == -1)
 
1022
                                state = JOBRUNNING;
 
1023
#if JOBS
 
1024
                        if (state == JOBRUNNING)
 
1025
                                continue;
 
1026
                        if (WIFSTOPPED(sp->status)) {
 
1027
                                jp->stopstatus = sp->status;
 
1028
                                state = JOBSTOPPED;
 
1029
                        }
 
1030
#endif
 
1031
                } while (++sp < spend);
 
1032
                if (thisjob)
 
1033
                        goto gotjob;
 
1034
        }
 
1035
        if (!JOBS || !WIFSTOPPED(status))
 
1036
                jobless--;
 
1037
        goto out;
 
1038
 
 
1039
gotjob:
 
1040
        if (state != JOBRUNNING) {
 
1041
                thisjob->changed = 1;
 
1042
 
 
1043
                if (thisjob->state != state) {
 
1044
                        TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
 
1045
                        thisjob->state = state;
 
1046
#if JOBS
 
1047
                        if (state == JOBSTOPPED) {
 
1048
                                set_curjob(thisjob, CUR_STOPPED);
 
1049
                        }
 
1050
#endif
 
1051
                }
 
1052
        }
 
1053
 
 
1054
out:
 
1055
        INTON;
 
1056
 
 
1057
        if (thisjob && thisjob == job) {
 
1058
                char s[48 + 1];
 
1059
                int len;
 
1060
 
 
1061
                len = sprint_status(s, status, 1);
 
1062
                if (len) {
 
1063
                        s[len] = '\n';
 
1064
                        s[len + 1] = 0;
 
1065
                        outstr(s, out2);
 
1066
                }
 
1067
        }
 
1068
        return pid;
 
1069
}
 
1070
 
 
1071
 
 
1072
 
 
1073
/*
 
1074
 * Do a wait system call.  If job control is compiled in, we accept
 
1075
 * stopped processes.  If block is zero, we return a value of zero
 
1076
 * rather than blocking.
 
1077
 *
 
1078
 * System V doesn't have a non-blocking wait system call.  It does
 
1079
 * have a SIGCLD signal that is sent to a process when one of it's
 
1080
 * children dies.  The obvious way to use SIGCLD would be to install
 
1081
 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
 
1082
 * was received, and have waitproc bump another counter when it got
 
1083
 * the status of a process.  Waitproc would then know that a wait
 
1084
 * system call would not block if the two counters were different.
 
1085
 * This approach doesn't work because if a process has children that
 
1086
 * have not been waited for, System V will send it a SIGCLD when it
 
1087
 * installs a signal handler for SIGCLD.  What this means is that when
 
1088
 * a child exits, the shell will be sent SIGCLD signals continuously
 
1089
 * until is runs out of stack space, unless it does a wait call before
 
1090
 * restoring the signal handler.  The code below takes advantage of
 
1091
 * this (mis)feature by installing a signal handler for SIGCLD and
 
1092
 * then checking to see whether it was called.  If there are any
 
1093
 * children to be waited for, it will be.
 
1094
 *
 
1095
 * If neither SYSV nor BSD is defined, we don't implement nonblocking
 
1096
 * waits at all.  In this case, the user will not be informed when
 
1097
 * a background process until the next time she runs a real program
 
1098
 * (as opposed to running a builtin command or just typing return),
 
1099
 * and the jobs command may give out of date information.
 
1100
 */
 
1101
 
 
1102
#ifdef SYSV
 
1103
STATIC int gotsigchild;
 
1104
 
 
1105
STATIC int onsigchild() {
 
1106
        gotsigchild = 1;
 
1107
}
 
1108
#endif
 
1109
 
 
1110
 
 
1111
STATIC int
 
1112
waitproc(int block, int *status)
 
1113
{
 
1114
#ifdef BSD
 
1115
        int flags = 0;
 
1116
 
 
1117
#if JOBS
 
1118
        if (jobctl)
 
1119
                flags |= WUNTRACED;
 
1120
#endif
 
1121
        if (block == 0)
 
1122
                flags |= WNOHANG;
 
1123
        return wait3(status, flags, (struct rusage *)NULL);
 
1124
#else
 
1125
#ifdef SYSV
 
1126
        int (*save)();
 
1127
 
 
1128
        if (block == 0) {
 
1129
                gotsigchild = 0;
 
1130
                save = signal(SIGCLD, onsigchild);
 
1131
                signal(SIGCLD, save);
 
1132
                if (gotsigchild == 0)
 
1133
                        return 0;
 
1134
        }
 
1135
        return wait(status);
 
1136
#else
 
1137
        if (block == 0)
 
1138
                return 0;
 
1139
        return wait(status);
 
1140
#endif
 
1141
#endif
 
1142
}
 
1143
 
 
1144
/*
 
1145
 * return 1 if there are stopped jobs, otherwise 0
 
1146
 */
 
1147
int job_warning;
 
1148
int
 
1149
stoppedjobs(void)
 
1150
{
 
1151
        struct job *jp;
 
1152
        int retval;
 
1153
 
 
1154
        retval = 0;
 
1155
        if (job_warning)
 
1156
                goto out;
 
1157
        jp = curjob;
 
1158
        if (jp && jp->state == JOBSTOPPED) {
 
1159
                out2str("You have stopped jobs.\n");
 
1160
                job_warning = 2;
 
1161
                retval++;
 
1162
        }
 
1163
 
 
1164
out:
 
1165
        return retval;
 
1166
}
 
1167
 
 
1168
/*
 
1169
 * Return a string identifying a command (to be printed by the
 
1170
 * jobs command).
 
1171
 */
 
1172
 
 
1173
STATIC char *cmdnextc;
 
1174
 
 
1175
STATIC char *
 
1176
commandtext(union node *n)
 
1177
{
 
1178
        char *name;
 
1179
 
 
1180
        STARTSTACKSTR(cmdnextc);
 
1181
        cmdtxt(n);
 
1182
        name = stackblock();
 
1183
        TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
 
1184
                name, cmdnextc, ps->cmd));
 
1185
        return savestr(name);
 
1186
}
 
1187
 
 
1188
 
 
1189
STATIC void
 
1190
cmdtxt(union node *n)
 
1191
{
 
1192
        union node *np;
 
1193
        struct nodelist *lp;
 
1194
        const char *p;
 
1195
        char s[2];
 
1196
 
 
1197
        if (!n)
 
1198
                return;
 
1199
        switch (n->type) {
 
1200
        default:
 
1201
#if DEBUG
 
1202
                abort();
 
1203
#endif
 
1204
        case NPIPE:
 
1205
                lp = n->npipe.cmdlist;
 
1206
                for (;;) {
 
1207
                        cmdtxt(lp->n);
 
1208
                        lp = lp->next;
 
1209
                        if (!lp)
 
1210
                                break;
 
1211
                        cmdputs(" | ");
 
1212
                }
 
1213
                break;
 
1214
        case NSEMI:
 
1215
                p = "; ";
 
1216
                goto binop;
 
1217
        case NAND:
 
1218
                p = " && ";
 
1219
                goto binop;
 
1220
        case NOR:
 
1221
                p = " || ";
 
1222
binop:
 
1223
                cmdtxt(n->nbinary.ch1);
 
1224
                cmdputs(p);
 
1225
                n = n->nbinary.ch2;
 
1226
                goto donode;
 
1227
        case NREDIR:
 
1228
        case NBACKGND:
 
1229
                n = n->nredir.n;
 
1230
                goto donode;
 
1231
        case NNOT:
 
1232
                cmdputs("!");
 
1233
                n = n->nnot.com;
 
1234
donode:
 
1235
                cmdtxt(n);
 
1236
                break;
 
1237
        case NIF:
 
1238
                cmdputs("if ");
 
1239
                cmdtxt(n->nif.test);
 
1240
                cmdputs("; then ");
 
1241
                n = n->nif.ifpart;
 
1242
                if (n->nif.elsepart) {
 
1243
                        cmdtxt(n);
 
1244
                        cmdputs("; else ");
 
1245
                        n = n->nif.elsepart;
 
1246
                }
 
1247
                p = "; fi";
 
1248
                goto dotail;
 
1249
        case NSUBSHELL:
 
1250
                cmdputs("(");
 
1251
                n = n->nredir.n;
 
1252
                p = ")";
 
1253
                goto dotail;
 
1254
        case NWHILE:
 
1255
                p = "while ";
 
1256
                goto until;
 
1257
        case NUNTIL:
 
1258
                p = "until ";
 
1259
until:
 
1260
                cmdputs(p);
 
1261
                cmdtxt(n->nbinary.ch1);
 
1262
                n = n->nbinary.ch2;
 
1263
                p = "; done";
 
1264
dodo:
 
1265
                cmdputs("; do ");
 
1266
dotail:
 
1267
                cmdtxt(n);
 
1268
                goto dotail2;
 
1269
        case NFOR:
 
1270
                cmdputs("for ");
 
1271
                cmdputs(n->nfor.var);
 
1272
                cmdputs(" in ");
 
1273
                cmdlist(n->nfor.args, 1);
 
1274
                n = n->nfor.body;
 
1275
                p = "; done";
 
1276
                goto dodo;
 
1277
        case NDEFUN:
 
1278
                cmdputs(n->narg.text);
 
1279
                p = "() { ... }";
 
1280
                goto dotail2;
 
1281
        case NCMD:
 
1282
                cmdlist(n->ncmd.args, 1);
 
1283
                cmdlist(n->ncmd.redirect, 0);
 
1284
                break;
 
1285
        case NARG:
 
1286
                p = n->narg.text;
 
1287
dotail2:
 
1288
                cmdputs(p);
 
1289
                break;
 
1290
        case NHERE:
 
1291
        case NXHERE:
 
1292
                p = "<<...";
 
1293
                goto dotail2;
 
1294
        case NCASE:
 
1295
                cmdputs("case ");
 
1296
                cmdputs(n->ncase.expr->narg.text);
 
1297
                cmdputs(" in ");
 
1298
                for (np = n->ncase.cases; np; np = np->nclist.next) {
 
1299
                        cmdtxt(np->nclist.pattern);
 
1300
                        cmdputs(") ");
 
1301
                        cmdtxt(np->nclist.body);
 
1302
                        cmdputs(";; ");
 
1303
                }
 
1304
                p = "esac";
 
1305
                goto dotail2;
 
1306
        case NTO:
 
1307
                p = ">";
 
1308
                goto redir;
 
1309
        case NCLOBBER:
 
1310
                p = ">|";
 
1311
                goto redir;
 
1312
        case NAPPEND:
 
1313
                p = ">>";
 
1314
                goto redir;
 
1315
        case NTOFD:
 
1316
                p = ">&";
 
1317
                goto redir;
 
1318
        case NFROM:
 
1319
                p = "<";
 
1320
                goto redir;
 
1321
        case NFROMFD:
 
1322
                p = "<&";
 
1323
                goto redir;
 
1324
        case NFROMTO:
 
1325
                p = "<>";
 
1326
redir:
 
1327
                s[0] = n->nfile.fd + '0';
 
1328
                s[1] = '\0';
 
1329
                cmdputs(s);
 
1330
                cmdputs(p);
 
1331
                if (n->type == NTOFD || n->type == NFROMFD) {
 
1332
                        s[0] = n->ndup.dupfd + '0';
 
1333
                        p = s;
 
1334
                        goto dotail2;
 
1335
                } else {
 
1336
                        n = n->nfile.fname;
 
1337
                        goto donode;
 
1338
                }
 
1339
        }
 
1340
}
 
1341
 
 
1342
STATIC void
 
1343
cmdlist(union node *np, int sep)
 
1344
{
 
1345
        for (; np; np = np->narg.next) {
 
1346
                if (!sep)
 
1347
                        cmdputs(spcstr);
 
1348
                cmdtxt(np);
 
1349
                if (sep && np->narg.next)
 
1350
                        cmdputs(spcstr);
 
1351
        }
 
1352
}
 
1353
 
 
1354
 
 
1355
STATIC void
 
1356
cmdputs(const char *s)
 
1357
{
 
1358
        const char *p, *str;
 
1359
        char c, cc[2] = " ";
 
1360
        char *nextc;
 
1361
        int subtype = 0;
 
1362
        int quoted = 0;
 
1363
        static const char vstype[VSTYPE + 1][4] = {
 
1364
                "", "}", "-", "+", "?", "=",
 
1365
                "%", "%%", "#", "##",
 
1366
        };
 
1367
 
 
1368
        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
 
1369
        p = s;
 
1370
        while ((c = *p++) != 0) {
 
1371
                str = 0;
 
1372
                switch (c) {
 
1373
                case CTLESC:
 
1374
                        c = *p++;
 
1375
                        break;
 
1376
                case CTLVAR:
 
1377
                        subtype = *p++;
 
1378
                        if ((subtype & VSTYPE) == VSLENGTH)
 
1379
                                str = "${#";
 
1380
                        else
 
1381
                                str = "${";
 
1382
                        if (!(subtype & VSQUOTE) != !(quoted & 1)) {
 
1383
                                quoted ^= 1;
 
1384
                                c = '"';
 
1385
                        } else
 
1386
                                goto dostr;
 
1387
                        break;
 
1388
                case CTLENDVAR:
 
1389
                        str = "\"}" + !(quoted & 1);
 
1390
                        quoted >>= 1;
 
1391
                        subtype = 0;
 
1392
                        goto dostr;
 
1393
                case CTLBACKQ:
 
1394
                        str = "$(...)";
 
1395
                        goto dostr;
 
1396
                case CTLBACKQ+CTLQUOTE:
 
1397
                        str = "\"$(...)\"";
 
1398
                        goto dostr;
 
1399
                case CTLARI:
 
1400
                        str = "$((";
 
1401
                        goto dostr;
 
1402
                case CTLENDARI:
 
1403
                        str = "))";
 
1404
                        goto dostr;
 
1405
                case CTLQUOTEMARK:
 
1406
                        quoted ^= 1;
 
1407
                        c = '"';
 
1408
                        break;
 
1409
                case '=':
 
1410
                        if (subtype == 0)
 
1411
                                break;
 
1412
                        if ((subtype & VSTYPE) != VSNORMAL)
 
1413
                                quoted <<= 1;
 
1414
                        str = vstype[subtype & VSTYPE];
 
1415
                        if (subtype & VSNUL)
 
1416
                                c = ':';
 
1417
                        else
 
1418
                                goto checkstr;
 
1419
                        break;
 
1420
                case '\'':
 
1421
                case '\\':
 
1422
                case '"':
 
1423
                case '$':
 
1424
                        /* These can only happen inside quotes */
 
1425
                        cc[0] = c;
 
1426
                        str = cc;
 
1427
                        c = '\\';
 
1428
                        break;
 
1429
                default:
 
1430
                        break;
 
1431
                }
 
1432
                USTPUTC(c, nextc);
 
1433
checkstr:
 
1434
                if (!str)
 
1435
                        continue;
 
1436
dostr:
 
1437
                while ((c = *str++)) {
 
1438
                        USTPUTC(c, nextc);
 
1439
                }
 
1440
        }
 
1441
        if (quoted & 1) {
 
1442
                USTPUTC('"', nextc);
 
1443
        }
 
1444
        *nextc = 0;
 
1445
        cmdnextc = nextc;
 
1446
}
 
1447
 
 
1448
 
 
1449
STATIC void
 
1450
showpipe(struct job *jp, struct output *out)
 
1451
{
 
1452
        struct procstat *sp;
 
1453
        struct procstat *spend;
 
1454
 
 
1455
        spend = jp->ps + jp->nprocs;
 
1456
        for (sp = jp->ps + 1; sp < spend; sp++)
 
1457
                outfmt(out, " | %s", sp->cmd);
 
1458
        outcslow('\n', out);
 
1459
        flushall();
 
1460
}
 
1461
 
 
1462
 
 
1463
#if JOBS
 
1464
STATIC void
 
1465
xtcsetpgrp(int fd, pid_t pgrp)
 
1466
{
 
1467
        if (tcsetpgrp(fd, pgrp))
 
1468
                sh_error("Cannot set tty process group (%s)", strerror(errno));
 
1469
}
 
1470
#endif
 
1471
 
 
1472
 
 
1473
STATIC int
 
1474
getstatus(struct job *job) {
 
1475
        int status;
 
1476
        int retval;
 
1477
 
 
1478
        status = job->ps[job->nprocs - 1].status;
 
1479
        retval = WEXITSTATUS(status);
 
1480
        if (!WIFEXITED(status)) {
 
1481
#if JOBS
 
1482
                retval = WSTOPSIG(status);
 
1483
                if (!WIFSTOPPED(status))
 
1484
#endif
 
1485
                {
 
1486
                        /* XXX: limits number of signals */
 
1487
                        retval = WTERMSIG(status);
 
1488
#if JOBS
 
1489
                        if (retval == SIGINT)
 
1490
                                job->sigint = 1;
 
1491
#endif
 
1492
                }
 
1493
                retval += 128;
 
1494
        }
 
1495
        TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
 
1496
                jobno(job), job->nprocs, status, retval));
 
1497
        return retval;
 
1498
}