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