sh(1): bring sh from freebsd
[dragonfly.git] / bin / sh / jobs.c
1 /*-
2  * Copyright (c) 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)jobs.c      8.5 (Berkeley) 5/4/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: head/bin/sh/jobs.c 361112 2020-05-16 16:29:23Z jilles $");
40
41 #include <sys/ioctl.h>
42 #include <sys/param.h>
43 #include <sys/resource.h>
44 #include <sys/time.h>
45 #include <sys/wait.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <paths.h>
49 #include <signal.h>
50 #include <stddef.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53
54 #include "shell.h"
55 #if JOBS
56 #include <termios.h>
57 #undef CEOF                     /* syntax.h redefines this */
58 #endif
59 #include "redir.h"
60 #include "exec.h"
61 #include "show.h"
62 #include "main.h"
63 #include "parser.h"
64 #include "nodes.h"
65 #include "jobs.h"
66 #include "options.h"
67 #include "trap.h"
68 #include "syntax.h"
69 #include "input.h"
70 #include "output.h"
71 #include "memalloc.h"
72 #include "error.h"
73 #include "mystring.h"
74 #include "var.h"
75 #include "builtins.h"
76 #include "eval.h"
77
78
79 /*
80  * A job structure contains information about a job.  A job is either a
81  * single process or a set of processes contained in a pipeline.  In the
82  * latter case, pidlist will be non-NULL, and will point to a -1 terminated
83  * array of pids.
84  */
85
86 struct procstat {
87         pid_t pid;              /* process id */
88         int status;             /* status flags (defined above) */
89         char *cmd;              /* text of command being run */
90 };
91
92
93 /* states */
94 #define JOBSTOPPED 1            /* all procs are stopped */
95 #define JOBDONE 2               /* all procs are completed */
96
97
98 struct job {
99         struct procstat ps0;    /* status of process */
100         struct procstat *ps;    /* status or processes when more than one */
101         short nprocs;           /* number of processes */
102         pid_t pgrp;             /* process group of this job */
103         char state;             /* true if job is finished */
104         char used;              /* true if this entry is in used */
105         char changed;           /* true if status has changed */
106         char foreground;        /* true if running in the foreground */
107         char remembered;        /* true if $! referenced */
108         char pipefail;          /* pass any non-zero status */
109 #if JOBS
110         char jobctl;            /* job running under job control */
111         struct job *next;       /* job used after this one */
112 #endif
113 };
114
115
116 static struct job *jobtab;      /* array of jobs */
117 static int njobs;               /* size of array */
118 static pid_t backgndpid = -1;   /* pid of last background process */
119 static struct job *bgjob = NULL; /* last background process */
120 #if JOBS
121 static struct job *jobmru;      /* most recently used job list */
122 static pid_t initialpgrp;       /* pgrp of shell on invocation */
123 #endif
124 static int ttyfd = -1;
125
126 /* mode flags for dowait */
127 #define DOWAIT_BLOCK    0x1 /* wait until a child exits */
128 #define DOWAIT_SIG      0x2 /* if DOWAIT_BLOCK, abort on signal */
129 #define DOWAIT_SIG_TRAP 0x4 /* if DOWAIT_SIG, abort on trapped signal only */
130
131 #if JOBS
132 static void restartjob(struct job *);
133 #endif
134 static void freejob(struct job *);
135 static int waitcmdloop(struct job *);
136 static struct job *getjob_nonotfound(const char *);
137 static struct job *getjob(const char *);
138 pid_t killjob(const char *, int);
139 static pid_t dowait(int, struct job *);
140 static void checkzombies(void);
141 static void cmdtxt(union node *);
142 static void cmdputs(const char *);
143 #if JOBS
144 static void setcurjob(struct job *);
145 static void deljob(struct job *);
146 static struct job *getcurjob(struct job *);
147 #endif
148 static int getjobstatus(const struct job *);
149 static void printjobcmd(struct job *);
150 static void showjob(struct job *, int);
151
152
153 /*
154  * Turn job control on and off.
155  */
156
157 static int jobctl;
158
159 #if JOBS
160 static void
161 jobctl_notty(void)
162 {
163         if (ttyfd >= 0) {
164                 close(ttyfd);
165                 ttyfd = -1;
166         }
167         if (!iflag) {
168                 setsignal(SIGTSTP);
169                 setsignal(SIGTTOU);
170                 setsignal(SIGTTIN);
171                 jobctl = 1;
172                 return;
173         }
174         out2fmt_flush("sh: can't access tty; job control turned off\n");
175         mflag = 0;
176 }
177
178 void
179 setjobctl(int on)
180 {
181         int i;
182
183         if (on == jobctl || rootshell == 0)
184                 return;
185         if (on) {
186                 if (ttyfd != -1)
187                         close(ttyfd);
188                 if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC_MAYBE)) < 0) {
189                         i = 0;
190                         while (i <= 2 && !isatty(i))
191                                 i++;
192                         if (i > 2 ||
193                             (ttyfd = fcntl(i, F_DUPFD_CLOEXEC_MAYBE, 10)) < 0) {
194                                 jobctl_notty();
195                                 return;
196                         }
197                 }
198                 if (ttyfd < 10) {
199                         /*
200                          * Keep our TTY file descriptor out of the way of
201                          * the user's redirections.
202                          */
203                         if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC_MAYBE, 10)) < 0) {
204                                 jobctl_notty();
205                                 return;
206                         }
207                         close(ttyfd);
208                         ttyfd = i;
209                 }
210 #if !defined(O_CLOEXEC) || !defined(F_DUPFD_CLOEXEC)
211                 if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
212                         close(ttyfd);
213                         ttyfd = -1;
214                         goto out;
215                 }
216 #endif
217                 do { /* while we are in the background */
218                         initialpgrp = tcgetpgrp(ttyfd);
219                         if (initialpgrp < 0) {
220 #if !defined(O_CLOEXEC) || !defined(F_DUPFD_CLOEXEC)
221 out:
222 #endif
223                                 jobctl_notty();
224                                 return;
225                         }
226                         if (initialpgrp != getpgrp()) {
227                                 if (!iflag) {
228                                         initialpgrp = -1;
229                                         jobctl_notty();
230                                         return;
231                                 }
232                                 kill(0, SIGTTIN);
233                                 continue;
234                         }
235                 } while (0);
236                 setsignal(SIGTSTP);
237                 setsignal(SIGTTOU);
238                 setsignal(SIGTTIN);
239                 setpgid(0, rootpid);
240                 tcsetpgrp(ttyfd, rootpid);
241         } else { /* turning job control off */
242                 setpgid(0, initialpgrp);
243                 if (ttyfd >= 0) {
244                         tcsetpgrp(ttyfd, initialpgrp);
245                         close(ttyfd);
246                         ttyfd = -1;
247                 }
248                 setsignal(SIGTSTP);
249                 setsignal(SIGTTOU);
250                 setsignal(SIGTTIN);
251         }
252         jobctl = on;
253 }
254 #endif
255
256
257 #if JOBS
258 int
259 fgcmd(int argc __unused, char **argv __unused)
260 {
261         struct job *jp;
262         pid_t pgrp;
263         int status;
264
265         nextopt("");
266         jp = getjob(*argptr);
267         if (jp->jobctl == 0)
268                 error("job not created under job control");
269         printjobcmd(jp);
270         flushout(&output);
271         pgrp = jp->ps[0].pid;
272         if (ttyfd >= 0)
273                 tcsetpgrp(ttyfd, pgrp);
274         restartjob(jp);
275         jp->foreground = 1;
276         INTOFF;
277         status = waitforjob(jp, (int *)NULL);
278         INTON;
279         return status;
280 }
281
282
283 int
284 bgcmd(int argc __unused, char **argv __unused)
285 {
286         struct job *jp;
287
288         nextopt("");
289         do {
290                 jp = getjob(*argptr);
291                 if (jp->jobctl == 0)
292                         error("job not created under job control");
293                 if (jp->state == JOBDONE)
294                         continue;
295                 restartjob(jp);
296                 jp->foreground = 0;
297                 out1fmt("[%td] ", jp - jobtab + 1);
298                 printjobcmd(jp);
299         } while (*argptr != NULL && *++argptr != NULL);
300         return 0;
301 }
302
303
304 static void
305 restartjob(struct job *jp)
306 {
307         struct procstat *ps;
308         int i;
309
310         if (jp->state == JOBDONE)
311                 return;
312         setcurjob(jp);
313         INTOFF;
314         kill(-jp->ps[0].pid, SIGCONT);
315         for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
316                 if (WIFSTOPPED(ps->status)) {
317                         ps->status = -1;
318                         jp->state = 0;
319                 }
320         }
321         INTON;
322 }
323 #endif
324
325
326 int
327 jobscmd(int argc __unused, char *argv[] __unused)
328 {
329         char *id;
330         int ch, mode;
331
332         mode = SHOWJOBS_DEFAULT;
333         while ((ch = nextopt("lps")) != '\0') {
334                 switch (ch) {
335                 case 'l':
336                         mode = SHOWJOBS_VERBOSE;
337                         break;
338                 case 'p':
339                         mode = SHOWJOBS_PGIDS;
340                         break;
341                 case 's':
342                         mode = SHOWJOBS_PIDS;
343                         break;
344                 }
345         }
346
347         if (*argptr == NULL)
348                 showjobs(0, mode);
349         else
350                 while ((id = *argptr++) != NULL)
351                         showjob(getjob(id), mode);
352
353         return (0);
354 }
355
356 static int getjobstatus(const struct job *jp)
357 {
358         int i, status;
359
360         if (!jp->pipefail)
361                 return (jp->ps[jp->nprocs - 1].status);
362         for (i = jp->nprocs - 1; i >= 0; i--) {
363                 status = jp->ps[i].status;
364                 if (status != 0)
365                         return (status);
366         }
367         return (0);
368 }
369
370 static void
371 printjobcmd(struct job *jp)
372 {
373         struct procstat *ps;
374         int i;
375
376         for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
377                 out1str(ps->cmd);
378                 if (i > 0)
379                         out1str(" | ");
380         }
381         out1c('\n');
382 }
383
384 static void
385 showjob(struct job *jp, int mode)
386 {
387         char s[64];
388         char statebuf[16];
389         const char *statestr, *coredump;
390         struct procstat *ps;
391         struct job *j;
392         int col, curr, i, jobno, prev, procno, status;
393         char c;
394
395         procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs;
396         jobno = jp - jobtab + 1;
397         curr = prev = 0;
398 #if JOBS
399         if ((j = getcurjob(NULL)) != NULL) {
400                 curr = j - jobtab + 1;
401                 if ((j = getcurjob(j)) != NULL)
402                         prev = j - jobtab + 1;
403         }
404 #endif
405         coredump = "";
406         status = getjobstatus(jp);
407         if (jp->state == 0) {
408                 statestr = "Running";
409 #if JOBS
410         } else if (jp->state == JOBSTOPPED) {
411                 ps = jp->ps + jp->nprocs - 1;
412                 while (!WIFSTOPPED(ps->status) && ps > jp->ps)
413                         ps--;
414                 if (WIFSTOPPED(ps->status))
415                         i = WSTOPSIG(ps->status);
416                 else
417                         i = -1;
418                 statestr = strsignal(i);
419                 if (statestr == NULL)
420                         statestr = "Suspended";
421 #endif
422         } else if (WIFEXITED(status)) {
423                 if (WEXITSTATUS(status) == 0)
424                         statestr = "Done";
425                 else {
426                         fmtstr(statebuf, sizeof(statebuf), "Done(%d)",
427                             WEXITSTATUS(status));
428                         statestr = statebuf;
429                 }
430         } else {
431                 i = WTERMSIG(status);
432                 statestr = strsignal(i);
433                 if (statestr == NULL)
434                         statestr = "Unknown signal";
435                 if (WCOREDUMP(status))
436                         coredump = " (core dumped)";
437         }
438
439         for (ps = jp->ps ; procno > 0 ; ps++, procno--) { /* for each process */
440                 if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
441                         out1fmt("%d\n", (int)ps->pid);
442                         continue;
443                 }
444                 if (mode != SHOWJOBS_VERBOSE && ps != jp->ps)
445                         continue;
446                 if (jobno == curr && ps == jp->ps)
447                         c = '+';
448                 else if (jobno == prev && ps == jp->ps)
449                         c = '-';
450                 else
451                         c = ' ';
452                 if (ps == jp->ps)
453                         fmtstr(s, 64, "[%d] %c ", jobno, c);
454                 else
455                         fmtstr(s, 64, "    %c ", c);
456                 out1str(s);
457                 col = strlen(s);
458                 if (mode == SHOWJOBS_VERBOSE) {
459                         fmtstr(s, 64, "%d ", (int)ps->pid);
460                         out1str(s);
461                         col += strlen(s);
462                 }
463                 if (ps == jp->ps) {
464                         out1str(statestr);
465                         out1str(coredump);
466                         col += strlen(statestr) + strlen(coredump);
467                 }
468                 do {
469                         out1c(' ');
470                         col++;
471                 } while (col < 30);
472                 if (mode == SHOWJOBS_VERBOSE) {
473                         out1str(ps->cmd);
474                         out1c('\n');
475                 } else
476                         printjobcmd(jp);
477         }
478 }
479
480 /*
481  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
482  * statuses have changed since the last call to showjobs.
483  *
484  * If the shell is interrupted in the process of creating a job, the
485  * result may be a job structure containing zero processes.  Such structures
486  * will be freed here.
487  */
488
489 void
490 showjobs(int change, int mode)
491 {
492         int jobno;
493         struct job *jp;
494
495         TRACE(("showjobs(%d) called\n", change));
496         checkzombies();
497         for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
498                 if (! jp->used)
499                         continue;
500                 if (jp->nprocs == 0) {
501                         freejob(jp);
502                         continue;
503                 }
504                 if (change && ! jp->changed)
505                         continue;
506                 showjob(jp, mode);
507                 if (mode == SHOWJOBS_DEFAULT || mode == SHOWJOBS_VERBOSE) {
508                         jp->changed = 0;
509                         /* Hack: discard jobs for which $! has not been
510                          * referenced in interactive mode when they terminate.
511                          */
512                         if (jp->state == JOBDONE && !jp->remembered &&
513                                         (iflag || jp != bgjob)) {
514                                 freejob(jp);
515                         }
516                 }
517         }
518 }
519
520
521 /*
522  * Mark a job structure as unused.
523  */
524
525 static void
526 freejob(struct job *jp)
527 {
528         struct procstat *ps;
529         int i;
530
531         INTOFF;
532         if (bgjob == jp)
533                 bgjob = NULL;
534         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
535                 if (ps->cmd != nullstr)
536                         ckfree(ps->cmd);
537         }
538         if (jp->ps != &jp->ps0)
539                 ckfree(jp->ps);
540         jp->used = 0;
541 #if JOBS
542         deljob(jp);
543 #endif
544         INTON;
545 }
546
547
548
549 int
550 waitcmd(int argc __unused, char **argv __unused)
551 {
552         struct job *job;
553         int retval;
554
555         nextopt("");
556         if (*argptr == NULL)
557                 return (waitcmdloop(NULL));
558
559         do {
560                 job = getjob_nonotfound(*argptr);
561                 if (job == NULL)
562                         retval = 127;
563                 else
564                         retval = waitcmdloop(job);
565                 argptr++;
566         } while (*argptr != NULL);
567
568         return (retval);
569 }
570
571 static int
572 waitcmdloop(struct job *job)
573 {
574         int status, retval, sig;
575         struct job *jp;
576
577         /*
578          * Loop until a process is terminated or stopped, or a SIGINT is
579          * received.
580          */
581
582         do {
583                 if (job != NULL) {
584                         if (job->state == JOBDONE) {
585                                 status = getjobstatus(job);
586                                 if (WIFEXITED(status))
587                                         retval = WEXITSTATUS(status);
588                                 else
589                                         retval = WTERMSIG(status) + 128;
590                                 if (! iflag || ! job->changed)
591                                         freejob(job);
592                                 else {
593                                         job->remembered = 0;
594                                         if (job == bgjob)
595                                                 bgjob = NULL;
596                                 }
597                                 return retval;
598                         }
599                 } else {
600                         for (jp = jobtab ; jp < jobtab + njobs; jp++)
601                                 if (jp->used && jp->state == JOBDONE) {
602                                         if (! iflag || ! jp->changed)
603                                                 freejob(jp);
604                                         else {
605                                                 jp->remembered = 0;
606                                                 if (jp == bgjob)
607                                                         bgjob = NULL;
608                                         }
609                                 }
610                         for (jp = jobtab ; ; jp++) {
611                                 if (jp >= jobtab + njobs) {     /* no running procs */
612                                         return 0;
613                                 }
614                                 if (jp->used && jp->state == 0)
615                                         break;
616                         }
617                 }
618         } while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1);
619
620         sig = pendingsig_waitcmd;
621         pendingsig_waitcmd = 0;
622         return sig + 128;
623 }
624
625
626
627 int
628 jobidcmd(int argc __unused, char **argv __unused)
629 {
630         struct job *jp;
631         int i;
632
633         nextopt("");
634         jp = getjob(*argptr);
635         for (i = 0 ; i < jp->nprocs ; ) {
636                 out1fmt("%d", (int)jp->ps[i].pid);
637                 out1c(++i < jp->nprocs? ' ' : '\n');
638         }
639         return 0;
640 }
641
642
643
644 /*
645  * Convert a job name to a job structure.
646  */
647
648 static struct job *
649 getjob_nonotfound(const char *name)
650 {
651         int jobno;
652         struct job *found, *jp;
653         size_t namelen;
654         pid_t pid;
655         int i;
656
657         if (name == NULL) {
658 #if JOBS
659                 name = "%+";
660 #else
661                 error("No current job");
662 #endif
663         }
664         if (name[0] == '%') {
665                 if (is_digit(name[1])) {
666                         jobno = number(name + 1);
667                         if (jobno > 0 && jobno <= njobs
668                          && jobtab[jobno - 1].used != 0)
669                                 return &jobtab[jobno - 1];
670 #if JOBS
671                 } else if ((name[1] == '%' || name[1] == '+') &&
672                     name[2] == '\0') {
673                         if ((jp = getcurjob(NULL)) == NULL)
674                                 error("No current job");
675                         return (jp);
676                 } else if (name[1] == '-' && name[2] == '\0') {
677                         if ((jp = getcurjob(NULL)) == NULL ||
678                             (jp = getcurjob(jp)) == NULL)
679                                 error("No previous job");
680                         return (jp);
681 #endif
682                 } else if (name[1] == '?') {
683                         found = NULL;
684                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
685                                 if (jp->used && jp->nprocs > 0
686                                  && strstr(jp->ps[0].cmd, name + 2) != NULL) {
687                                         if (found)
688                                                 error("%s: ambiguous", name);
689                                         found = jp;
690                                 }
691                         }
692                         if (found != NULL)
693                                 return (found);
694                 } else {
695                         namelen = strlen(name);
696                         found = NULL;
697                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
698                                 if (jp->used && jp->nprocs > 0
699                                  && strncmp(jp->ps[0].cmd, name + 1,
700                                  namelen - 1) == 0) {
701                                         if (found)
702                                                 error("%s: ambiguous", name);
703                                         found = jp;
704                                 }
705                         }
706                         if (found)
707                                 return found;
708                 }
709         } else if (is_number(name)) {
710                 pid = (pid_t)number(name);
711                 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
712                         if (jp->used && jp->nprocs > 0
713                          && jp->ps[jp->nprocs - 1].pid == pid)
714                                 return jp;
715                 }
716         }
717         return NULL;
718 }
719
720
721 static struct job *
722 getjob(const char *name)
723 {
724         struct job *jp;
725
726         jp = getjob_nonotfound(name);
727         if (jp == NULL)
728                 error("No such job: %s", name);
729         return (jp);
730 }
731
732
733 int
734 killjob(const char *name, int sig)
735 {
736         struct job *jp;
737         int i, ret;
738
739         jp = getjob(name);
740         if (jp->state == JOBDONE)
741                 return 0;
742         if (jp->jobctl)
743                 return kill(-jp->ps[0].pid, sig);
744         ret = -1;
745         errno = ESRCH;
746         for (i = 0; i < jp->nprocs; i++)
747                 if (jp->ps[i].status == -1 || WIFSTOPPED(jp->ps[i].status)) {
748                         if (kill(jp->ps[i].pid, sig) == 0)
749                                 ret = 0;
750                 } else
751                         ret = 0;
752         return ret;
753 }
754
755 /*
756  * Return a new job structure,
757  */
758
759 struct job *
760 makejob(union node *node __unused, int nprocs)
761 {
762         int i;
763         struct job *jp;
764
765         for (i = njobs, jp = jobtab ; ; jp++) {
766                 if (--i < 0) {
767                         INTOFF;
768                         if (njobs == 0) {
769                                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
770 #if JOBS
771                                 jobmru = NULL;
772 #endif
773                         } else {
774                                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
775                                 memcpy(jp, jobtab, njobs * sizeof jp[0]);
776 #if JOBS
777                                 /* Relocate `next' pointers and list head */
778                                 if (jobmru != NULL)
779                                         jobmru = &jp[jobmru - jobtab];
780                                 for (i = 0; i < njobs; i++)
781                                         if (jp[i].next != NULL)
782                                                 jp[i].next = &jp[jp[i].next -
783                                                     jobtab];
784 #endif
785                                 if (bgjob != NULL)
786                                         bgjob = &jp[bgjob - jobtab];
787                                 /* Relocate `ps' pointers */
788                                 for (i = 0; i < njobs; i++)
789                                         if (jp[i].ps == &jobtab[i].ps0)
790                                                 jp[i].ps = &jp[i].ps0;
791                                 ckfree(jobtab);
792                                 jobtab = jp;
793                         }
794                         jp = jobtab + njobs;
795                         for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0)
796                                 ;
797                         INTON;
798                         break;
799                 }
800                 if (jp->used == 0)
801                         break;
802         }
803         INTOFF;
804         jp->state = 0;
805         jp->used = 1;
806         jp->changed = 0;
807         jp->nprocs = 0;
808         jp->foreground = 0;
809         jp->remembered = 0;
810         jp->pipefail = pipefailflag;
811 #if JOBS
812         jp->jobctl = jobctl;
813         jp->next = NULL;
814 #endif
815         if (nprocs > 1) {
816                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
817         } else {
818                 jp->ps = &jp->ps0;
819         }
820         INTON;
821         TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node, nprocs,
822             jp - jobtab + 1));
823         return jp;
824 }
825
826 #if JOBS
827 static void
828 setcurjob(struct job *cj)
829 {
830         struct job *jp, *prev;
831
832         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
833                 if (jp == cj) {
834                         if (prev != NULL)
835                                 prev->next = jp->next;
836                         else
837                                 jobmru = jp->next;
838                         jp->next = jobmru;
839                         jobmru = cj;
840                         return;
841                 }
842         }
843         cj->next = jobmru;
844         jobmru = cj;
845 }
846
847 static void
848 deljob(struct job *j)
849 {
850         struct job *jp, *prev;
851
852         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
853                 if (jp == j) {
854                         if (prev != NULL)
855                                 prev->next = jp->next;
856                         else
857                                 jobmru = jp->next;
858                         return;
859                 }
860         }
861 }
862
863 /*
864  * Return the most recently used job that isn't `nj', and preferably one
865  * that is stopped.
866  */
867 static struct job *
868 getcurjob(struct job *nj)
869 {
870         struct job *jp;
871
872         /* Try to find a stopped one.. */
873         for (jp = jobmru; jp != NULL; jp = jp->next)
874                 if (jp->used && jp != nj && jp->state == JOBSTOPPED)
875                         return (jp);
876         /* Otherwise the most recently used job that isn't `nj' */
877         for (jp = jobmru; jp != NULL; jp = jp->next)
878                 if (jp->used && jp != nj)
879                         return (jp);
880
881         return (NULL);
882 }
883
884 #endif
885
886 /*
887  * Fork of a subshell.  If we are doing job control, give the subshell its
888  * own process group.  Jp is a job structure that the job is to be added to.
889  * N is the command that will be evaluated by the child.  Both jp and n may
890  * be NULL.  The mode parameter can be one of the following:
891  *      FORK_FG - Fork off a foreground process.
892  *      FORK_BG - Fork off a background process.
893  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
894  *                   process group even if job control is on.
895  *
896  * When job control is turned off, background processes have their standard
897  * input redirected to /dev/null (except for the second and later processes
898  * in a pipeline).
899  */
900
901 pid_t
902 forkshell(struct job *jp, union node *n, int mode)
903 {
904         pid_t pid;
905         pid_t pgrp;
906
907         TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
908             mode));
909         INTOFF;
910         if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0))
911                 checkzombies();
912         flushall();
913         pid = fork();
914         if (pid == -1) {
915                 TRACE(("Fork failed, errno=%d\n", errno));
916                 INTON;
917                 error("Cannot fork: %s", strerror(errno));
918         }
919         if (pid == 0) {
920                 struct job *p;
921                 int wasroot;
922                 int i;
923
924                 TRACE(("Child shell %d\n", (int)getpid()));
925                 wasroot = rootshell;
926                 rootshell = 0;
927                 handler = &main_handler;
928                 closescript();
929                 INTON;
930                 forcelocal = 0;
931                 clear_traps();
932 #if JOBS
933                 jobctl = 0;             /* do job control only in root shell */
934                 if (wasroot && mode != FORK_NOJOB && mflag) {
935                         if (jp == NULL || jp->nprocs == 0)
936                                 pgrp = getpid();
937                         else
938                                 pgrp = jp->ps[0].pid;
939                         if (setpgid(0, pgrp) == 0 && mode == FORK_FG &&
940                             ttyfd >= 0) {
941                                 /*** this causes superfluous TIOCSPGRPS ***/
942                                 if (tcsetpgrp(ttyfd, pgrp) < 0)
943                                         error("tcsetpgrp failed, errno=%d", errno);
944                         }
945                         setsignal(SIGTSTP);
946                         setsignal(SIGTTOU);
947                 } else if (mode == FORK_BG) {
948                         ignoresig(SIGINT);
949                         ignoresig(SIGQUIT);
950                         if ((jp == NULL || jp->nprocs == 0) &&
951                             ! fd0_redirected_p ()) {
952                                 close(0);
953                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
954                                         error("cannot open %s: %s",
955                                             _PATH_DEVNULL, strerror(errno));
956                         }
957                 }
958 #else
959                 if (mode == FORK_BG) {
960                         ignoresig(SIGINT);
961                         ignoresig(SIGQUIT);
962                         if ((jp == NULL || jp->nprocs == 0) &&
963                             ! fd0_redirected_p ()) {
964                                 close(0);
965                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
966                                         error("cannot open %s: %s",
967                                             _PATH_DEVNULL, strerror(errno));
968                         }
969                 }
970 #endif
971                 INTOFF;
972                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
973                         if (p->used)
974                                 freejob(p);
975                 INTON;
976                 if (wasroot && iflag) {
977                         setsignal(SIGINT);
978                         setsignal(SIGQUIT);
979                         setsignal(SIGTERM);
980                 }
981                 return pid;
982         }
983         if (rootshell && mode != FORK_NOJOB && mflag) {
984                 if (jp == NULL || jp->nprocs == 0)
985                         pgrp = pid;
986                 else
987                         pgrp = jp->ps[0].pid;
988                 setpgid(pid, pgrp);
989         }
990         if (mode == FORK_BG) {
991                 if (bgjob != NULL && bgjob->state == JOBDONE &&
992                     !bgjob->remembered && !iflag)
993                         freejob(bgjob);
994                 backgndpid = pid;               /* set $! */
995                 bgjob = jp;
996         }
997         if (jp) {
998                 struct procstat *ps = &jp->ps[jp->nprocs++];
999                 ps->pid = pid;
1000                 ps->status = -1;
1001                 ps->cmd = nullstr;
1002                 if (iflag && rootshell && n)
1003                         ps->cmd = commandtext(n);
1004                 jp->foreground = mode == FORK_FG;
1005 #if JOBS
1006                 setcurjob(jp);
1007 #endif
1008         }
1009         INTON;
1010         TRACE(("In parent shell:  child = %d\n", (int)pid));
1011         return pid;
1012 }
1013
1014
1015 pid_t
1016 vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
1017 {
1018         pid_t pid;
1019         struct jmploc jmploc;
1020         struct jmploc *savehandler;
1021         int inton;
1022
1023         TRACE(("vforkexecshell(%%%td, %s, %p) called\n", jp - jobtab, argv[0],
1024             (void *)pip));
1025         inton = is_int_on();
1026         INTOFF;
1027         flushall();
1028         savehandler = handler;
1029         pid = vfork();
1030         if (pid == -1) {
1031                 TRACE(("Vfork failed, errno=%d\n", errno));
1032                 INTON;
1033                 error("Cannot fork: %s", strerror(errno));
1034         }
1035         if (pid == 0) {
1036                 TRACE(("Child shell %d\n", (int)getpid()));
1037                 if (setjmp(jmploc.loc))
1038                         _exit(exitstatus);
1039                 if (pip != NULL) {
1040                         close(pip[0]);
1041                         if (pip[1] != 1) {
1042                                 dup2(pip[1], 1);
1043                                 close(pip[1]);
1044                         }
1045                 }
1046                 handler = &jmploc;
1047                 shellexec(argv, envp, path, idx);
1048         }
1049         handler = savehandler;
1050         if (jp) {
1051                 struct procstat *ps = &jp->ps[jp->nprocs++];
1052                 ps->pid = pid;
1053                 ps->status = -1;
1054                 ps->cmd = nullstr;
1055                 jp->foreground = 1;
1056 #if JOBS
1057                 setcurjob(jp);
1058 #endif
1059         }
1060         SETINTON(inton);
1061         TRACE(("In parent shell:  child = %d\n", (int)pid));
1062         return pid;
1063 }
1064
1065
1066 /*
1067  * Wait for job to finish.
1068  *
1069  * Under job control we have the problem that while a child process is
1070  * running interrupts generated by the user are sent to the child but not
1071  * to the shell.  This means that an infinite loop started by an inter-
1072  * active user may be hard to kill.  With job control turned off, an
1073  * interactive user may place an interactive program inside a loop.  If
1074  * the interactive program catches interrupts, the user doesn't want
1075  * these interrupts to also abort the loop.  The approach we take here
1076  * is to have the shell ignore interrupt signals while waiting for a
1077  * foreground process to terminate, and then send itself an interrupt
1078  * signal if the child process was terminated by an interrupt signal.
1079  * Unfortunately, some programs want to do a bit of cleanup and then
1080  * exit on interrupt; unless these processes terminate themselves by
1081  * sending a signal to themselves (instead of calling exit) they will
1082  * confuse this approach.
1083  */
1084
1085 int
1086 waitforjob(struct job *jp, int *signaled)
1087 {
1088 #if JOBS
1089         int propagate_int = jp->jobctl && jp->foreground;
1090 #endif
1091         int status;
1092         int st;
1093
1094         INTOFF;
1095         TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
1096         while (jp->state == 0)
1097                 if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG |
1098                     DOWAIT_SIG_TRAP : 0), jp) == -1)
1099                         dotrap();
1100 #if JOBS
1101         if (jp->jobctl) {
1102                 if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
1103                         error("tcsetpgrp failed, errno=%d\n", errno);
1104         }
1105         if (jp->state == JOBSTOPPED)
1106                 setcurjob(jp);
1107 #endif
1108         status = getjobstatus(jp);
1109         if (signaled != NULL)
1110                 *signaled = WIFSIGNALED(status);
1111         /* convert to 8 bits */
1112         if (WIFEXITED(status))
1113                 st = WEXITSTATUS(status);
1114 #if JOBS
1115         else if (WIFSTOPPED(status))
1116                 st = WSTOPSIG(status) + 128;
1117 #endif
1118         else
1119                 st = WTERMSIG(status) + 128;
1120         if (! JOBS || jp->state == JOBDONE)
1121                 freejob(jp);
1122         if (int_pending()) {
1123                 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGINT)
1124                         CLEAR_PENDING_INT;
1125         }
1126 #if JOBS
1127         else if (rootshell && propagate_int &&
1128                         WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
1129                 kill(getpid(), SIGINT);
1130 #endif
1131         INTON;
1132         return st;
1133 }
1134
1135
1136 static void
1137 dummy_handler(int sig __unused)
1138 {
1139 }
1140
1141 /*
1142  * Wait for a process to terminate.
1143  */
1144
1145 static pid_t
1146 dowait(int mode, struct job *job)
1147 {
1148         struct sigaction sa, osa;
1149         sigset_t mask, omask;
1150         pid_t pid;
1151         int status;
1152         struct procstat *sp;
1153         struct job *jp;
1154         struct job *thisjob;
1155         const char *sigstr;
1156         int done;
1157         int stopped;
1158         int sig;
1159         int coredump;
1160         int wflags;
1161         int restore_sigchld;
1162
1163         TRACE(("dowait(%d, %p) called\n", mode, job));
1164         restore_sigchld = 0;
1165         if ((mode & DOWAIT_SIG) != 0) {
1166                 sigfillset(&mask);
1167                 sigprocmask(SIG_BLOCK, &mask, &omask);
1168                 INTOFF;
1169                 if (!issigchldtrapped()) {
1170                         restore_sigchld = 1;
1171                         sa.sa_handler = dummy_handler;
1172                         sa.sa_flags = 0;
1173                         sigemptyset(&sa.sa_mask);
1174                         sigaction(SIGCHLD, &sa, &osa);
1175                 }
1176         }
1177         do {
1178 #if JOBS
1179                 if (iflag)
1180                         wflags = WUNTRACED | WCONTINUED;
1181                 else
1182 #endif
1183                         wflags = 0;
1184                 if ((mode & (DOWAIT_BLOCK | DOWAIT_SIG)) != DOWAIT_BLOCK)
1185                         wflags |= WNOHANG;
1186                 pid = wait3(&status, wflags, (struct rusage *)NULL);
1187                 TRACE(("wait returns %d, status=%d\n", (int)pid, status));
1188                 if (pid == 0 && (mode & DOWAIT_SIG) != 0) {
1189                         pid = -1;
1190                         if (((mode & DOWAIT_SIG_TRAP) != 0 ?
1191                             pendingsig : pendingsig_waitcmd) != 0) {
1192                                 errno = EINTR;
1193                                 break;
1194                         }
1195                         sigsuspend(&omask);
1196                         if (int_pending())
1197                                 break;
1198                 }
1199         } while (pid == -1 && errno == EINTR);
1200         if (pid == -1 && errno == ECHILD && job != NULL)
1201                 job->state = JOBDONE;
1202         if ((mode & DOWAIT_SIG) != 0) {
1203                 if (restore_sigchld)
1204                         sigaction(SIGCHLD, &osa, NULL);
1205                 sigprocmask(SIG_SETMASK, &omask, NULL);
1206                 INTON;
1207         }
1208         if (pid <= 0)
1209                 return pid;
1210         INTOFF;
1211         thisjob = NULL;
1212         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
1213                 if (jp->used && jp->nprocs > 0) {
1214                         done = 1;
1215                         stopped = 1;
1216                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
1217                                 if (sp->pid == -1)
1218                                         continue;
1219                                 if (sp->pid == pid && (sp->status == -1 ||
1220                                     WIFSTOPPED(sp->status))) {
1221                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
1222                                                    (int)pid, sp->status,
1223                                                    status));
1224                                         if (WIFCONTINUED(status)) {
1225                                                 sp->status = -1;
1226                                                 jp->state = 0;
1227                                         } else
1228                                                 sp->status = status;
1229                                         thisjob = jp;
1230                                 }
1231                                 if (sp->status == -1)
1232                                         stopped = 0;
1233                                 else if (WIFSTOPPED(sp->status))
1234                                         done = 0;
1235                         }
1236                         if (stopped) {          /* stopped or done */
1237                                 int state = done? JOBDONE : JOBSTOPPED;
1238                                 if (jp->state != state) {
1239                                         TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
1240                                         jp->state = state;
1241                                         if (jp != job) {
1242                                                 if (done && !jp->remembered &&
1243                                                     !iflag && jp != bgjob)
1244                                                         freejob(jp);
1245 #if JOBS
1246                                                 else if (done)
1247                                                         deljob(jp);
1248 #endif
1249                                         }
1250                                 }
1251                         }
1252                 }
1253         }
1254         INTON;
1255         if (!thisjob || thisjob->state == 0)
1256                 ;
1257         else if ((!rootshell || !iflag || thisjob == job) &&
1258             thisjob->foreground && thisjob->state != JOBSTOPPED) {
1259                 sig = 0;
1260                 coredump = 0;
1261                 for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++)
1262                         if (WIFSIGNALED(sp->status)) {
1263                                 sig = WTERMSIG(sp->status);
1264                                 coredump = WCOREDUMP(sp->status);
1265                         }
1266                 if (sig > 0 && sig != SIGINT && sig != SIGPIPE) {
1267                         sigstr = strsignal(sig);
1268                         if (sigstr != NULL)
1269                                 out2str(sigstr);
1270                         else
1271                                 out2str("Unknown signal");
1272                         if (coredump)
1273                                 out2str(" (core dumped)");
1274                         out2c('\n');
1275                         flushout(out2);
1276                 }
1277         } else {
1278                 TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
1279                 thisjob->changed = 1;
1280         }
1281         return pid;
1282 }
1283
1284
1285
1286 /*
1287  * return 1 if there are stopped jobs, otherwise 0
1288  */
1289 int job_warning = 0;
1290 int
1291 stoppedjobs(void)
1292 {
1293         int jobno;
1294         struct job *jp;
1295
1296         if (job_warning)
1297                 return (0);
1298         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1299                 if (jp->used == 0)
1300                         continue;
1301                 if (jp->state == JOBSTOPPED) {
1302                         out2fmt_flush("You have stopped jobs.\n");
1303                         job_warning = 2;
1304                         return (1);
1305                 }
1306         }
1307
1308         return (0);
1309 }
1310
1311
1312 static void
1313 checkzombies(void)
1314 {
1315         while (njobs > 0 && dowait(0, NULL) > 0)
1316                 ;
1317 }
1318
1319
1320 int
1321 backgndpidset(void)
1322 {
1323         return backgndpid != -1;
1324 }
1325
1326
1327 pid_t
1328 backgndpidval(void)
1329 {
1330         if (bgjob != NULL && !forcelocal)
1331                 bgjob->remembered = 1;
1332         return backgndpid;
1333 }
1334
1335 /*
1336  * Return a string identifying a command (to be printed by the
1337  * jobs command.
1338  */
1339
1340 static char *cmdnextc;
1341 static int cmdnleft;
1342 #define MAXCMDTEXT      200
1343
1344 char *
1345 commandtext(union node *n)
1346 {
1347         char *name;
1348
1349         cmdnextc = name = ckmalloc(MAXCMDTEXT);
1350         cmdnleft = MAXCMDTEXT - 4;
1351         cmdtxt(n);
1352         *cmdnextc = '\0';
1353         return name;
1354 }
1355
1356
1357 static void
1358 cmdtxtdogroup(union node *n)
1359 {
1360         cmdputs("; do ");
1361         cmdtxt(n);
1362         cmdputs("; done");
1363 }
1364
1365
1366 static void
1367 cmdtxtredir(union node *n, const char *op, int deffd)
1368 {
1369         char s[2];
1370
1371         if (n->nfile.fd != deffd) {
1372                 s[0] = n->nfile.fd + '0';
1373                 s[1] = '\0';
1374                 cmdputs(s);
1375         }
1376         cmdputs(op);
1377         if (n->type == NTOFD || n->type == NFROMFD) {
1378                 if (n->ndup.dupfd >= 0)
1379                         s[0] = n->ndup.dupfd + '0';
1380                 else
1381                         s[0] = '-';
1382                 s[1] = '\0';
1383                 cmdputs(s);
1384         } else {
1385                 cmdtxt(n->nfile.fname);
1386         }
1387 }
1388
1389
1390 static void
1391 cmdtxt(union node *n)
1392 {
1393         union node *np;
1394         struct nodelist *lp;
1395
1396         if (n == NULL)
1397                 return;
1398         switch (n->type) {
1399         case NSEMI:
1400                 cmdtxt(n->nbinary.ch1);
1401                 cmdputs("; ");
1402                 cmdtxt(n->nbinary.ch2);
1403                 break;
1404         case NAND:
1405                 cmdtxt(n->nbinary.ch1);
1406                 cmdputs(" && ");
1407                 cmdtxt(n->nbinary.ch2);
1408                 break;
1409         case NOR:
1410                 cmdtxt(n->nbinary.ch1);
1411                 cmdputs(" || ");
1412                 cmdtxt(n->nbinary.ch2);
1413                 break;
1414         case NPIPE:
1415                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1416                         cmdtxt(lp->n);
1417                         if (lp->next)
1418                                 cmdputs(" | ");
1419                 }
1420                 break;
1421         case NSUBSHELL:
1422                 cmdputs("(");
1423                 cmdtxt(n->nredir.n);
1424                 cmdputs(")");
1425                 break;
1426         case NREDIR:
1427         case NBACKGND:
1428                 cmdtxt(n->nredir.n);
1429                 break;
1430         case NIF:
1431                 cmdputs("if ");
1432                 cmdtxt(n->nif.test);
1433                 cmdputs("; then ");
1434                 cmdtxt(n->nif.ifpart);
1435                 cmdputs("...");
1436                 break;
1437         case NWHILE:
1438                 cmdputs("while ");
1439                 cmdtxt(n->nbinary.ch1);
1440                 cmdtxtdogroup(n->nbinary.ch2);
1441                 break;
1442         case NUNTIL:
1443                 cmdputs("until ");
1444                 cmdtxt(n->nbinary.ch1);
1445                 cmdtxtdogroup(n->nbinary.ch2);
1446                 break;
1447         case NFOR:
1448                 cmdputs("for ");
1449                 cmdputs(n->nfor.var);
1450                 cmdputs(" in ...");
1451                 break;
1452         case NCASE:
1453                 cmdputs("case ");
1454                 cmdputs(n->ncase.expr->narg.text);
1455                 cmdputs(" in ...");
1456                 break;
1457         case NDEFUN:
1458                 cmdputs(n->narg.text);
1459                 cmdputs("() ...");
1460                 break;
1461         case NNOT:
1462                 cmdputs("! ");
1463                 cmdtxt(n->nnot.com);
1464                 break;
1465         case NCMD:
1466                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
1467                         cmdtxt(np);
1468                         if (np->narg.next)
1469                                 cmdputs(" ");
1470                 }
1471                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1472                         cmdputs(" ");
1473                         cmdtxt(np);
1474                 }
1475                 break;
1476         case NARG:
1477                 cmdputs(n->narg.text);
1478                 break;
1479         case NTO:
1480                 cmdtxtredir(n, ">", 1);
1481                 break;
1482         case NAPPEND:
1483                 cmdtxtredir(n, ">>", 1);
1484                 break;
1485         case NTOFD:
1486                 cmdtxtredir(n, ">&", 1);
1487                 break;
1488         case NCLOBBER:
1489                 cmdtxtredir(n, ">|", 1);
1490                 break;
1491         case NFROM:
1492                 cmdtxtredir(n, "<", 0);
1493                 break;
1494         case NFROMTO:
1495                 cmdtxtredir(n, "<>", 0);
1496                 break;
1497         case NFROMFD:
1498                 cmdtxtredir(n, "<&", 0);
1499                 break;
1500         case NHERE:
1501         case NXHERE:
1502                 cmdputs("<<...");
1503                 break;
1504         default:
1505                 cmdputs("???");
1506                 break;
1507         }
1508 }
1509
1510
1511
1512 static void
1513 cmdputs(const char *s)
1514 {
1515         const char *p;
1516         char *q;
1517         char c;
1518         int subtype = 0;
1519
1520         if (cmdnleft <= 0)
1521                 return;
1522         p = s;
1523         q = cmdnextc;
1524         while ((c = *p++) != '\0') {
1525                 if (c == CTLESC)
1526                         *q++ = *p++;
1527                 else if (c == CTLVAR) {
1528                         *q++ = '$';
1529                         if (--cmdnleft > 0)
1530                                 *q++ = '{';
1531                         subtype = *p++;
1532                         if ((subtype & VSTYPE) == VSLENGTH && --cmdnleft > 0)
1533                                 *q++ = '#';
1534                 } else if (c == '=' && subtype != 0) {
1535                         *q = "}-+?=##%%\0X"[(subtype & VSTYPE) - VSNORMAL];
1536                         if (*q)
1537                                 q++;
1538                         else
1539                                 cmdnleft++;
1540                         if (((subtype & VSTYPE) == VSTRIMLEFTMAX ||
1541                             (subtype & VSTYPE) == VSTRIMRIGHTMAX) &&
1542                             --cmdnleft > 0)
1543                                 *q = q[-1], q++;
1544                         subtype = 0;
1545                 } else if (c == CTLENDVAR) {
1546                         *q++ = '}';
1547                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) {
1548                         cmdnleft -= 5;
1549                         if (cmdnleft > 0) {
1550                                 *q++ = '$';
1551                                 *q++ = '(';
1552                                 *q++ = '.';
1553                                 *q++ = '.';
1554                                 *q++ = '.';
1555                                 *q++ = ')';
1556                         }
1557                 } else if (c == CTLARI) {
1558                         cmdnleft -= 2;
1559                         if (cmdnleft > 0) {
1560                                 *q++ = '$';
1561                                 *q++ = '(';
1562                                 *q++ = '(';
1563                         }
1564                         p++;
1565                 } else if (c == CTLENDARI) {
1566                         if (--cmdnleft > 0) {
1567                                 *q++ = ')';
1568                                 *q++ = ')';
1569                         }
1570                 } else if (c == CTLQUOTEMARK || c == CTLQUOTEEND)
1571                         cmdnleft++; /* ignore */
1572                 else
1573                         *q++ = c;
1574                 if (--cmdnleft <= 0) {
1575                         *q++ = '.';
1576                         *q++ = '.';
1577                         *q++ = '.';
1578                         break;
1579                 }
1580         }
1581         cmdnextc = q;
1582 }