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