]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - bin/sh/jobs.c
sys/{x86,amd64}: remove one of doubled ;s
[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                                 /*** this causes superfluous TIOCSPGRPS ***/
932                                 if (tcsetpgrp(ttyfd, pgrp) < 0)
933                                         error("tcsetpgrp failed, errno=%d", errno);
934                         }
935                         setsignal(SIGTSTP);
936                         setsignal(SIGTTOU);
937                 } else if (mode == FORK_BG) {
938                         ignoresig(SIGINT);
939                         ignoresig(SIGQUIT);
940                         if ((jp == NULL || jp->nprocs == 0) &&
941                             ! fd0_redirected_p ()) {
942                                 close(0);
943                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
944                                         error("cannot open %s: %s",
945                                             _PATH_DEVNULL, strerror(errno));
946                         }
947                 }
948 #else
949                 if (mode == FORK_BG) {
950                         ignoresig(SIGINT);
951                         ignoresig(SIGQUIT);
952                         if ((jp == NULL || jp->nprocs == 0) &&
953                             ! fd0_redirected_p ()) {
954                                 close(0);
955                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
956                                         error("cannot open %s: %s",
957                                             _PATH_DEVNULL, strerror(errno));
958                         }
959                 }
960 #endif
961                 INTOFF;
962                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
963                         if (p->used)
964                                 freejob(p);
965                 INTON;
966                 if (wasroot && iflag) {
967                         setsignal(SIGINT);
968                         setsignal(SIGQUIT);
969                         setsignal(SIGTERM);
970                 }
971                 return pid;
972         }
973         if (rootshell && mode != FORK_NOJOB && mflag) {
974                 if (jp == NULL || jp->nprocs == 0)
975                         pgrp = pid;
976                 else
977                         pgrp = jp->ps[0].pid;
978                 setpgid(pid, pgrp);
979         }
980         if (mode == FORK_BG) {
981                 if (bgjob != NULL && bgjob->state == JOBDONE &&
982                     !bgjob->remembered && !iflag)
983                         freejob(bgjob);
984                 backgndpid = pid;               /* set $! */
985                 bgjob = jp;
986         }
987         if (jp) {
988                 struct procstat *ps = &jp->ps[jp->nprocs++];
989                 ps->pid = pid;
990                 ps->status = -1;
991                 ps->cmd = nullstr;
992                 if (iflag && rootshell && n)
993                         ps->cmd = commandtext(n);
994                 jp->foreground = mode == FORK_FG;
995 #if JOBS
996                 setcurjob(jp);
997 #endif
998         }
999         INTON;
1000         TRACE(("In parent shell:  child = %d\n", (int)pid));
1001         return pid;
1002 }
1003
1004
1005 pid_t
1006 vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
1007 {
1008         pid_t pid;
1009         struct jmploc jmploc;
1010         struct jmploc *savehandler;
1011
1012         TRACE(("vforkexecshell(%%%td, %s, %p) called\n", jp - jobtab, argv[0],
1013             (void *)pip));
1014         INTOFF;
1015         flushall();
1016         savehandler = handler;
1017         pid = vfork();
1018         if (pid == -1) {
1019                 TRACE(("Vfork failed, errno=%d\n", errno));
1020                 INTON;
1021                 error("Cannot fork: %s", strerror(errno));
1022         }
1023         if (pid == 0) {
1024                 TRACE(("Child shell %d\n", (int)getpid()));
1025                 if (setjmp(jmploc.loc))
1026                         _exit(exitstatus);
1027                 if (pip != NULL) {
1028                         close(pip[0]);
1029                         if (pip[1] != 1) {
1030                                 dup2(pip[1], 1);
1031                                 close(pip[1]);
1032                         }
1033                 }
1034                 handler = &jmploc;
1035                 shellexec(argv, envp, path, idx);
1036         }
1037         handler = savehandler;
1038         if (jp) {
1039                 struct procstat *ps = &jp->ps[jp->nprocs++];
1040                 ps->pid = pid;
1041                 ps->status = -1;
1042                 ps->cmd = nullstr;
1043                 jp->foreground = 1;
1044 #if JOBS
1045                 setcurjob(jp);
1046 #endif
1047         }
1048         INTON;
1049         TRACE(("In parent shell:  child = %d\n", (int)pid));
1050         return pid;
1051 }
1052
1053
1054 /*
1055  * Wait for job to finish.
1056  *
1057  * Under job control we have the problem that while a child process is
1058  * running interrupts generated by the user are sent to the child but not
1059  * to the shell.  This means that an infinite loop started by an inter-
1060  * active user may be hard to kill.  With job control turned off, an
1061  * interactive user may place an interactive program inside a loop.  If
1062  * the interactive program catches interrupts, the user doesn't want
1063  * these interrupts to also abort the loop.  The approach we take here
1064  * is to have the shell ignore interrupt signals while waiting for a
1065  * foreground process to terminate, and then send itself an interrupt
1066  * signal if the child process was terminated by an interrupt signal.
1067  * Unfortunately, some programs want to do a bit of cleanup and then
1068  * exit on interrupt; unless these processes terminate themselves by
1069  * sending a signal to themselves (instead of calling exit) they will
1070  * confuse this approach.
1071  */
1072
1073 int
1074 waitforjob(struct job *jp, int *signaled)
1075 {
1076 #if JOBS
1077         int propagate_int = jp->jobctl && jp->foreground;
1078 #endif
1079         int status;
1080         int st;
1081
1082         INTOFF;
1083         TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
1084         while (jp->state == 0)
1085                 if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG |
1086                     DOWAIT_SIG_TRAP : 0), jp) == -1)
1087                         dotrap();
1088 #if JOBS
1089         if (jp->jobctl) {
1090                 if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
1091                         error("tcsetpgrp failed, errno=%d\n", errno);
1092         }
1093         if (jp->state == JOBSTOPPED)
1094                 setcurjob(jp);
1095 #endif
1096         status = getjobstatus(jp);
1097         if (signaled != NULL)
1098                 *signaled = WIFSIGNALED(status);
1099         /* convert to 8 bits */
1100         if (WIFEXITED(status))
1101                 st = WEXITSTATUS(status);
1102 #if JOBS
1103         else if (WIFSTOPPED(status))
1104                 st = WSTOPSIG(status) + 128;
1105 #endif
1106         else
1107                 st = WTERMSIG(status) + 128;
1108         if (! JOBS || jp->state == JOBDONE)
1109                 freejob(jp);
1110         if (int_pending()) {
1111                 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGINT)
1112                         CLEAR_PENDING_INT;
1113         }
1114 #if JOBS
1115         else if (rootshell && propagate_int &&
1116                         WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
1117                 kill(getpid(), SIGINT);
1118 #endif
1119         INTON;
1120         return st;
1121 }
1122
1123
1124 static void
1125 dummy_handler(int sig __unused)
1126 {
1127 }
1128
1129 /*
1130  * Wait for a process to terminate.
1131  */
1132
1133 static pid_t
1134 dowait(int mode, struct job *job)
1135 {
1136         struct sigaction sa, osa;
1137         sigset_t mask, omask;
1138         pid_t pid;
1139         int status;
1140         struct procstat *sp;
1141         struct job *jp;
1142         struct job *thisjob;
1143         const char *sigstr;
1144         int done;
1145         int stopped;
1146         int sig;
1147         int coredump;
1148         int wflags;
1149         int restore_sigchld;
1150
1151         TRACE(("dowait(%d, %p) called\n", mode, job));
1152         restore_sigchld = 0;
1153         if ((mode & DOWAIT_SIG) != 0) {
1154                 sigfillset(&mask);
1155                 sigprocmask(SIG_BLOCK, &mask, &omask);
1156                 INTOFF;
1157                 if (!issigchldtrapped()) {
1158                         restore_sigchld = 1;
1159                         sa.sa_handler = dummy_handler;
1160                         sa.sa_flags = 0;
1161                         sigemptyset(&sa.sa_mask);
1162                         sigaction(SIGCHLD, &sa, &osa);
1163                 }
1164         }
1165         do {
1166 #if JOBS
1167                 if (iflag)
1168                         wflags = WUNTRACED | WCONTINUED;
1169                 else
1170 #endif
1171                         wflags = 0;
1172                 if ((mode & (DOWAIT_BLOCK | DOWAIT_SIG)) != DOWAIT_BLOCK)
1173                         wflags |= WNOHANG;
1174                 pid = wait3(&status, wflags, (struct rusage *)NULL);
1175                 TRACE(("wait returns %d, status=%d\n", (int)pid, status));
1176                 if (pid == 0 && (mode & DOWAIT_SIG) != 0) {
1177                         pid = -1;
1178                         if (((mode & DOWAIT_SIG_TRAP) != 0 ?
1179                             pendingsig : pendingsig_waitcmd) != 0) {
1180                                 errno = EINTR;
1181                                 break;
1182                         }
1183                         sigsuspend(&omask);
1184                         if (int_pending())
1185                                 break;
1186                 }
1187         } while (pid == -1 && errno == EINTR);
1188         if (pid == -1 && errno == ECHILD && job != NULL)
1189                 job->state = JOBDONE;
1190         if ((mode & DOWAIT_SIG) != 0) {
1191                 if (restore_sigchld)
1192                         sigaction(SIGCHLD, &osa, NULL);
1193                 sigprocmask(SIG_SETMASK, &omask, NULL);
1194                 INTON;
1195         }
1196         if (pid <= 0)
1197                 return pid;
1198         INTOFF;
1199         thisjob = NULL;
1200         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
1201                 if (jp->used && jp->nprocs > 0) {
1202                         done = 1;
1203                         stopped = 1;
1204                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
1205                                 if (sp->pid == -1)
1206                                         continue;
1207                                 if (sp->pid == pid && (sp->status == -1 ||
1208                                     WIFSTOPPED(sp->status))) {
1209                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
1210                                                    (int)pid, sp->status,
1211                                                    status));
1212                                         if (WIFCONTINUED(status)) {
1213                                                 sp->status = -1;
1214                                                 jp->state = 0;
1215                                         } else
1216                                                 sp->status = status;
1217                                         thisjob = jp;
1218                                 }
1219                                 if (sp->status == -1)
1220                                         stopped = 0;
1221                                 else if (WIFSTOPPED(sp->status))
1222                                         done = 0;
1223                         }
1224                         if (stopped) {          /* stopped or done */
1225                                 int state = done? JOBDONE : JOBSTOPPED;
1226                                 if (jp->state != state) {
1227                                         TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
1228                                         jp->state = state;
1229                                         if (jp != job) {
1230                                                 if (done && !jp->remembered &&
1231                                                     !iflag && jp != bgjob)
1232                                                         freejob(jp);
1233 #if JOBS
1234                                                 else if (done)
1235                                                         deljob(jp);
1236 #endif
1237                                         }
1238                                 }
1239                         }
1240                 }
1241         }
1242         INTON;
1243         if (!thisjob || thisjob->state == 0)
1244                 ;
1245         else if ((!rootshell || !iflag || thisjob == job) &&
1246             thisjob->foreground && thisjob->state != JOBSTOPPED) {
1247                 sig = 0;
1248                 coredump = 0;
1249                 for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++)
1250                         if (WIFSIGNALED(sp->status)) {
1251                                 sig = WTERMSIG(sp->status);
1252                                 coredump = WCOREDUMP(sp->status);
1253                         }
1254                 if (sig > 0 && sig != SIGINT && sig != SIGPIPE) {
1255                         sigstr = strsignal(sig);
1256                         if (sigstr != NULL)
1257                                 out2str(sigstr);
1258                         else
1259                                 out2str("Unknown signal");
1260                         if (coredump)
1261                                 out2str(" (core dumped)");
1262                         out2c('\n');
1263                         flushout(out2);
1264                 }
1265         } else {
1266                 TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
1267                 thisjob->changed = 1;
1268         }
1269         return pid;
1270 }
1271
1272
1273
1274 /*
1275  * return 1 if there are stopped jobs, otherwise 0
1276  */
1277 int job_warning = 0;
1278 int
1279 stoppedjobs(void)
1280 {
1281         int jobno;
1282         struct job *jp;
1283
1284         if (job_warning)
1285                 return (0);
1286         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1287                 if (jp->used == 0)
1288                         continue;
1289                 if (jp->state == JOBSTOPPED) {
1290                         out2fmt_flush("You have stopped jobs.\n");
1291                         job_warning = 2;
1292                         return (1);
1293                 }
1294         }
1295
1296         return (0);
1297 }
1298
1299
1300 static void
1301 checkzombies(void)
1302 {
1303         while (njobs > 0 && dowait(0, NULL) > 0)
1304                 ;
1305 }
1306
1307
1308 int
1309 backgndpidset(void)
1310 {
1311         return backgndpid != -1;
1312 }
1313
1314
1315 pid_t
1316 backgndpidval(void)
1317 {
1318         if (bgjob != NULL && !forcelocal)
1319                 bgjob->remembered = 1;
1320         return backgndpid;
1321 }
1322
1323 /*
1324  * Return a string identifying a command (to be printed by the
1325  * jobs command.
1326  */
1327
1328 static char *cmdnextc;
1329 static int cmdnleft;
1330 #define MAXCMDTEXT      200
1331
1332 char *
1333 commandtext(union node *n)
1334 {
1335         char *name;
1336
1337         cmdnextc = name = ckmalloc(MAXCMDTEXT);
1338         cmdnleft = MAXCMDTEXT - 4;
1339         cmdtxt(n);
1340         *cmdnextc = '\0';
1341         return name;
1342 }
1343
1344
1345 static void
1346 cmdtxtdogroup(union node *n)
1347 {
1348         cmdputs("; do ");
1349         cmdtxt(n);
1350         cmdputs("; done");
1351 }
1352
1353
1354 static void
1355 cmdtxtredir(union node *n, const char *op, int deffd)
1356 {
1357         char s[2];
1358
1359         if (n->nfile.fd != deffd) {
1360                 s[0] = n->nfile.fd + '0';
1361                 s[1] = '\0';
1362                 cmdputs(s);
1363         }
1364         cmdputs(op);
1365         if (n->type == NTOFD || n->type == NFROMFD) {
1366                 if (n->ndup.dupfd >= 0)
1367                         s[0] = n->ndup.dupfd + '0';
1368                 else
1369                         s[0] = '-';
1370                 s[1] = '\0';
1371                 cmdputs(s);
1372         } else {
1373                 cmdtxt(n->nfile.fname);
1374         }
1375 }
1376
1377
1378 static void
1379 cmdtxt(union node *n)
1380 {
1381         union node *np;
1382         struct nodelist *lp;
1383
1384         if (n == NULL)
1385                 return;
1386         switch (n->type) {
1387         case NSEMI:
1388                 cmdtxt(n->nbinary.ch1);
1389                 cmdputs("; ");
1390                 cmdtxt(n->nbinary.ch2);
1391                 break;
1392         case NAND:
1393                 cmdtxt(n->nbinary.ch1);
1394                 cmdputs(" && ");
1395                 cmdtxt(n->nbinary.ch2);
1396                 break;
1397         case NOR:
1398                 cmdtxt(n->nbinary.ch1);
1399                 cmdputs(" || ");
1400                 cmdtxt(n->nbinary.ch2);
1401                 break;
1402         case NPIPE:
1403                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1404                         cmdtxt(lp->n);
1405                         if (lp->next)
1406                                 cmdputs(" | ");
1407                 }
1408                 break;
1409         case NSUBSHELL:
1410                 cmdputs("(");
1411                 cmdtxt(n->nredir.n);
1412                 cmdputs(")");
1413                 break;
1414         case NREDIR:
1415         case NBACKGND:
1416                 cmdtxt(n->nredir.n);
1417                 break;
1418         case NIF:
1419                 cmdputs("if ");
1420                 cmdtxt(n->nif.test);
1421                 cmdputs("; then ");
1422                 cmdtxt(n->nif.ifpart);
1423                 cmdputs("...");
1424                 break;
1425         case NWHILE:
1426                 cmdputs("while ");
1427                 cmdtxt(n->nbinary.ch1);
1428                 cmdtxtdogroup(n->nbinary.ch2);
1429                 break;
1430         case NUNTIL:
1431                 cmdputs("until ");
1432                 cmdtxt(n->nbinary.ch1);
1433                 cmdtxtdogroup(n->nbinary.ch2);
1434                 break;
1435         case NFOR:
1436                 cmdputs("for ");
1437                 cmdputs(n->nfor.var);
1438                 cmdputs(" in ...");
1439                 break;
1440         case NCASE:
1441                 cmdputs("case ");
1442                 cmdputs(n->ncase.expr->narg.text);
1443                 cmdputs(" in ...");
1444                 break;
1445         case NDEFUN:
1446                 cmdputs(n->narg.text);
1447                 cmdputs("() ...");
1448                 break;
1449         case NNOT:
1450                 cmdputs("! ");
1451                 cmdtxt(n->nnot.com);
1452                 break;
1453         case NCMD:
1454                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
1455                         cmdtxt(np);
1456                         if (np->narg.next)
1457                                 cmdputs(" ");
1458                 }
1459                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1460                         cmdputs(" ");
1461                         cmdtxt(np);
1462                 }
1463                 break;
1464         case NARG:
1465                 cmdputs(n->narg.text);
1466                 break;
1467         case NTO:
1468                 cmdtxtredir(n, ">", 1);
1469                 break;
1470         case NAPPEND:
1471                 cmdtxtredir(n, ">>", 1);
1472                 break;
1473         case NTOFD:
1474                 cmdtxtredir(n, ">&", 1);
1475                 break;
1476         case NCLOBBER:
1477                 cmdtxtredir(n, ">|", 1);
1478                 break;
1479         case NFROM:
1480                 cmdtxtredir(n, "<", 0);
1481                 break;
1482         case NFROMTO:
1483                 cmdtxtredir(n, "<>", 0);
1484                 break;
1485         case NFROMFD:
1486                 cmdtxtredir(n, "<&", 0);
1487                 break;
1488         case NHERE:
1489         case NXHERE:
1490                 cmdputs("<<...");
1491                 break;
1492         default:
1493                 cmdputs("???");
1494                 break;
1495         }
1496 }
1497
1498
1499
1500 static void
1501 cmdputs(const char *s)
1502 {
1503         const char *p;
1504         char *q;
1505         char c;
1506         int subtype = 0;
1507
1508         if (cmdnleft <= 0)
1509                 return;
1510         p = s;
1511         q = cmdnextc;
1512         while ((c = *p++) != '\0') {
1513                 if (c == CTLESC)
1514                         *q++ = *p++;
1515                 else if (c == CTLVAR) {
1516                         *q++ = '$';
1517                         if (--cmdnleft > 0)
1518                                 *q++ = '{';
1519                         subtype = *p++;
1520                         if ((subtype & VSTYPE) == VSLENGTH && --cmdnleft > 0)
1521                                 *q++ = '#';
1522                 } else if (c == '=' && subtype != 0) {
1523                         *q = "}-+?=##%%\0X"[(subtype & VSTYPE) - VSNORMAL];
1524                         if (*q)
1525                                 q++;
1526                         else
1527                                 cmdnleft++;
1528                         if (((subtype & VSTYPE) == VSTRIMLEFTMAX ||
1529                             (subtype & VSTYPE) == VSTRIMRIGHTMAX) &&
1530                             --cmdnleft > 0)
1531                                 *q = q[-1], q++;
1532                         subtype = 0;
1533                 } else if (c == CTLENDVAR) {
1534                         *q++ = '}';
1535                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) {
1536                         cmdnleft -= 5;
1537                         if (cmdnleft > 0) {
1538                                 *q++ = '$';
1539                                 *q++ = '(';
1540                                 *q++ = '.';
1541                                 *q++ = '.';
1542                                 *q++ = '.';
1543                                 *q++ = ')';
1544                         }
1545                 } else if (c == CTLARI) {
1546                         cmdnleft -= 2;
1547                         if (cmdnleft > 0) {
1548                                 *q++ = '$';
1549                                 *q++ = '(';
1550                                 *q++ = '(';
1551                         }
1552                         p++;
1553                 } else if (c == CTLENDARI) {
1554                         if (--cmdnleft > 0) {
1555                                 *q++ = ')';
1556                                 *q++ = ')';
1557                         }
1558                 } else if (c == CTLQUOTEMARK || c == CTLQUOTEEND)
1559                         cmdnleft++; /* ignore */
1560                 else
1561                         *q++ = c;
1562                 if (--cmdnleft <= 0) {
1563                         *q++ = '.';
1564                         *q++ = '.';
1565                         *q++ = '.';
1566                         break;
1567                 }
1568         }
1569         cmdnextc = q;
1570 }