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