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