jobs.c revision 1.91 1 /* $NetBSD: jobs.c,v 1.91 2017/10/23 10:52:07 kre Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
39 #else
40 __RCSID("$NetBSD: jobs.c,v 1.91 2017/10/23 10:52:07 kre Exp $");
41 #endif
42 #endif /* not lint */
43
44 #include <fcntl.h>
45 #include <signal.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <paths.h>
50 #include <sys/types.h>
51 #include <sys/param.h>
52 #ifdef BSD
53 #include <sys/wait.h>
54 #include <sys/time.h>
55 #include <sys/resource.h>
56 #endif
57 #include <sys/ioctl.h>
58
59 #include "shell.h"
60 #if JOBS
61 #if OLD_TTY_DRIVER
62 #include "sgtty.h"
63 #else
64 #include <termios.h>
65 #endif
66 #undef CEOF /* syntax.h redefines this */
67 #endif
68 #include "redir.h"
69 #include "show.h"
70 #include "main.h"
71 #include "parser.h"
72 #include "nodes.h"
73 #include "jobs.h"
74 #include "options.h"
75 #include "builtins.h"
76 #include "trap.h"
77 #include "syntax.h"
78 #include "input.h"
79 #include "output.h"
80 #include "memalloc.h"
81 #include "error.h"
82 #include "mystring.h"
83
84
85 #ifndef WCONTINUED
86 #define WCONTINUED 0 /* So we can compile on old systems */
87 #endif
88 #ifndef WIFCONTINUED
89 #define WIFCONTINUED(x) (0) /* ditto */
90 #endif
91
92
93 static struct job *jobtab; /* array of jobs */
94 static int njobs; /* size of array */
95 static int jobs_invalid; /* set in child */
96 MKINIT pid_t backgndpid = -1; /* pid of last background process */
97 #if JOBS
98 int initialpgrp; /* pgrp of shell on invocation */
99 static int curjob = -1; /* current job */
100 #endif
101 static int ttyfd = -1;
102
103 STATIC void restartjob(struct job *);
104 STATIC void freejob(struct job *);
105 STATIC struct job *getjob(const char *, int);
106 STATIC int dowait(int, struct job *);
107 #define WBLOCK 1
108 #define WNOFREE 2
109 #define WSILENT 4
110 STATIC int jobstatus(const struct job *, int);
111 STATIC int waitproc(int, struct job *, int *);
112 STATIC void cmdtxt(union node *);
113 STATIC void cmdlist(union node *, int);
114 STATIC void cmdputs(const char *);
115 inline static void cmdputi(int);
116
117 #ifdef SYSV
118 STATIC int onsigchild(void);
119 #endif
120
121 #ifdef OLD_TTY_DRIVER
122 static pid_t tcgetpgrp(int fd);
123 static int tcsetpgrp(int fd, pid_t pgrp);
124
125 static pid_t
126 tcgetpgrp(int fd)
127 {
128 pid_t pgrp;
129 if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1)
130 return -1;
131 else
132 return pgrp;
133 }
134
135 static int
136 tcsetpgrp(int fd, pid_tpgrp)
137 {
138 return ioctl(fd, TIOCSPGRP, (char *)&pgrp);
139 }
140 #endif
141
142 static void
143 ttyfd_change(int from, int to)
144 {
145 if (ttyfd == from)
146 ttyfd = to;
147 }
148
149 /*
150 * Turn job control on and off.
151 *
152 * Note: This code assumes that the third arg to ioctl is a character
153 * pointer, which is true on Berkeley systems but not System V. Since
154 * System V doesn't have job control yet, this isn't a problem now.
155 */
156
157 MKINIT int jobctl;
158
159 void
160 setjobctl(int on)
161 {
162 #ifdef OLD_TTY_DRIVER
163 int ldisc;
164 #endif
165
166 if (on == jobctl || rootshell == 0)
167 return;
168 if (on) {
169 #if defined(FIOCLEX) || defined(FD_CLOEXEC)
170 int i;
171
172 if (ttyfd != -1)
173 sh_close(ttyfd);
174 if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) {
175 for (i = 0; i < 3; i++) {
176 if (isatty(i) && (ttyfd = dup(i)) != -1)
177 break;
178 }
179 if (i == 3)
180 goto out;
181 }
182 ttyfd = to_upper_fd(ttyfd); /* Move to a high fd */
183 register_sh_fd(ttyfd, ttyfd_change);
184 #else
185 out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control");
186 goto out;
187 #endif
188 do { /* while we are in the background */
189 if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) {
190 out:
191 out2str("sh: can't access tty; job control turned off\n");
192 mflag = 0;
193 return;
194 }
195 if (initialpgrp == -1)
196 initialpgrp = getpgrp();
197 else if (initialpgrp != getpgrp()) {
198 killpg(0, SIGTTIN);
199 continue;
200 }
201 } while (0);
202
203 #ifdef OLD_TTY_DRIVER
204 if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0
205 || ldisc != NTTYDISC) {
206 out2str("sh: need new tty driver to run job control; job control turned off\n");
207 mflag = 0;
208 return;
209 }
210 #endif
211 setsignal(SIGTSTP, 0);
212 setsignal(SIGTTOU, 0);
213 setsignal(SIGTTIN, 0);
214 if (getpgrp() != rootpid && setpgid(0, rootpid) == -1)
215 error("Cannot set process group (%s) at %d",
216 strerror(errno), __LINE__);
217 if (tcsetpgrp(ttyfd, rootpid) == -1)
218 error("Cannot set tty process group (%s) at %d",
219 strerror(errno), __LINE__);
220 } else { /* turning job control off */
221 if (getpgrp() != initialpgrp && setpgid(0, initialpgrp) == -1)
222 error("Cannot set process group (%s) at %d",
223 strerror(errno), __LINE__);
224 if (tcsetpgrp(ttyfd, initialpgrp) == -1)
225 error("Cannot set tty process group (%s) at %d",
226 strerror(errno), __LINE__);
227 sh_close(ttyfd);
228 ttyfd = -1;
229 setsignal(SIGTSTP, 0);
230 setsignal(SIGTTOU, 0);
231 setsignal(SIGTTIN, 0);
232 }
233 jobctl = on;
234 }
235
236
237 #ifdef mkinit
238 INCLUDE <stdlib.h>
239
240 SHELLPROC {
241 backgndpid = -1;
242 #if JOBS
243 jobctl = 0;
244 #endif
245 }
246
247 #endif
248
249
250
251 #if JOBS
252 static int
253 do_fgcmd(const char *arg_ptr)
254 {
255 struct job *jp;
256 int i;
257 int status;
258
259 if (jobs_invalid)
260 error("No current jobs");
261 jp = getjob(arg_ptr, 0);
262 if (jp->jobctl == 0)
263 error("job not created under job control");
264 out1fmt("%s", jp->ps[0].cmd);
265 for (i = 1; i < jp->nprocs; i++)
266 out1fmt(" | %s", jp->ps[i].cmd );
267 out1c('\n');
268 flushall();
269
270 for (i = 0; i < jp->nprocs; i++)
271 if (tcsetpgrp(ttyfd, jp->ps[i].pid) != -1)
272 break;
273
274 if (i >= jp->nprocs) {
275 error("Cannot set tty process group (%s) at %d",
276 strerror(errno), __LINE__);
277 }
278 restartjob(jp);
279 INTOFF;
280 status = waitforjob(jp);
281 INTON;
282 return status;
283 }
284
285 int
286 fgcmd(int argc, char **argv)
287 {
288 nextopt("");
289 return do_fgcmd(*argptr);
290 }
291
292 int
293 fgcmd_percent(int argc, char **argv)
294 {
295 nextopt("");
296 return do_fgcmd(*argv);
297 }
298
299 static void
300 set_curjob(struct job *jp, int mode)
301 {
302 struct job *jp1, *jp2;
303 int i, ji;
304
305 ji = jp - jobtab;
306
307 /* first remove from list */
308 if (ji == curjob)
309 curjob = jp->prev_job;
310 else {
311 for (i = 0; i < njobs; i++) {
312 if (jobtab[i].prev_job != ji)
313 continue;
314 jobtab[i].prev_job = jp->prev_job;
315 break;
316 }
317 }
318
319 /* Then re-insert in correct position */
320 switch (mode) {
321 case 0: /* job being deleted */
322 jp->prev_job = -1;
323 break;
324 case 1: /* newly created job or backgrounded job,
325 put after all stopped jobs. */
326 if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) {
327 for (jp1 = jobtab + curjob; ; jp1 = jp2) {
328 if (jp1->prev_job == -1)
329 break;
330 jp2 = jobtab + jp1->prev_job;
331 if (jp2->state != JOBSTOPPED)
332 break;
333 }
334 jp->prev_job = jp1->prev_job;
335 jp1->prev_job = ji;
336 break;
337 }
338 /* FALLTHROUGH */
339 case 2: /* newly stopped job - becomes curjob */
340 jp->prev_job = curjob;
341 curjob = ji;
342 break;
343 }
344 }
345
346 int
347 bgcmd(int argc, char **argv)
348 {
349 struct job *jp;
350 int i;
351
352 nextopt("");
353 if (jobs_invalid)
354 error("No current jobs");
355 do {
356 jp = getjob(*argptr, 0);
357 if (jp->jobctl == 0)
358 error("job not created under job control");
359 set_curjob(jp, 1);
360 out1fmt("[%ld] %s", (long)(jp - jobtab + 1), jp->ps[0].cmd);
361 for (i = 1; i < jp->nprocs; i++)
362 out1fmt(" | %s", jp->ps[i].cmd );
363 out1c('\n');
364 flushall();
365 restartjob(jp);
366 } while (*argptr && *++argptr);
367 return 0;
368 }
369
370
371 STATIC void
372 restartjob(struct job *jp)
373 {
374 struct procstat *ps;
375 int i;
376
377 if (jp->state == JOBDONE)
378 return;
379 INTOFF;
380 for (i = 0; i < jp->nprocs; i++)
381 if (killpg(jp->ps[i].pid, SIGCONT) != -1)
382 break;
383 if (i >= jp->nprocs)
384 error("Cannot continue job (%s)", strerror(errno));
385 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
386 if (WIFSTOPPED(ps->status)) {
387 ps->status = -1;
388 jp->state = JOBRUNNING;
389 }
390 }
391 INTON;
392 }
393 #endif
394
395 inline static void
396 cmdputi(int n)
397 {
398 char str[20];
399
400 fmtstr(str, sizeof str, "%d", n);
401 cmdputs(str);
402 }
403
404 static void
405 showjob(struct output *out, struct job *jp, int mode)
406 {
407 int procno;
408 int st;
409 struct procstat *ps;
410 int col;
411 char s[64];
412
413 #if JOBS
414 if (mode & SHOW_PGID) {
415 /* just output process (group) id of pipeline */
416 outfmt(out, "%ld\n", (long)jp->ps->pid);
417 return;
418 }
419 #endif
420
421 procno = jp->nprocs;
422 if (!procno)
423 return;
424
425 if (mode & SHOW_PID)
426 mode |= SHOW_MULTILINE;
427
428 if ((procno > 1 && !(mode & SHOW_MULTILINE))
429 || (mode & SHOW_SIGNALLED)) {
430 /* See if we have more than one status to report */
431 ps = jp->ps;
432 st = ps->status;
433 do {
434 int st1 = ps->status;
435 if (st1 != st)
436 /* yes - need multi-line output */
437 mode |= SHOW_MULTILINE;
438 if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1))
439 continue;
440 if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f)
441 && st1 != SIGINT && st1 != SIGPIPE))
442 mode |= SHOW_ISSIG;
443
444 } while (ps++, --procno);
445 procno = jp->nprocs;
446 }
447
448 if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) {
449 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) {
450 VTRACE(DBG_JOBS, ("showjob: freeing job %d\n",
451 jp - jobtab + 1));
452 freejob(jp);
453 }
454 return;
455 }
456
457 for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */
458 if (ps == jp->ps)
459 fmtstr(s, 16, "[%ld] %c ",
460 (long)(jp - jobtab + 1),
461 #if JOBS
462 jp == jobtab + curjob ? '+' :
463 curjob != -1 && jp == jobtab +
464 jobtab[curjob].prev_job ? '-' :
465 #endif
466 ' ');
467 else
468 fmtstr(s, 16, " " );
469 col = strlen(s);
470 if (mode & SHOW_PID) {
471 fmtstr(s + col, 16, "%ld ", (long)ps->pid);
472 col += strlen(s + col);
473 }
474 if (ps->status == -1) {
475 scopy("Running", s + col);
476 } else if (WIFEXITED(ps->status)) {
477 st = WEXITSTATUS(ps->status);
478 if (st)
479 fmtstr(s + col, 16, "Done(%d)", st);
480 else
481 fmtstr(s + col, 16, "Done");
482 } else {
483 #if JOBS
484 if (WIFSTOPPED(ps->status))
485 st = WSTOPSIG(ps->status);
486 else /* WIFSIGNALED(ps->status) */
487 #endif
488 st = WTERMSIG(ps->status);
489 st &= 0x7f;
490 if (st < NSIG && sys_siglist[st])
491 scopyn(sys_siglist[st], s + col, 32);
492 else
493 fmtstr(s + col, 16, "Signal %d", st);
494 if (WCOREDUMP(ps->status)) {
495 col += strlen(s + col);
496 scopyn(" (core dumped)", s + col, 64 - col);
497 }
498 }
499 col += strlen(s + col);
500 outstr(s, out);
501 do {
502 outc(' ', out);
503 col++;
504 } while (col < 30);
505 outstr(ps->cmd, out);
506 if (mode & SHOW_MULTILINE) {
507 if (procno > 0) {
508 outc(' ', out);
509 outc('|', out);
510 }
511 } else {
512 while (--procno >= 0)
513 outfmt(out, " | %s", (++ps)->cmd );
514 }
515 outc('\n', out);
516 }
517 flushout(out);
518 jp->changed = 0;
519 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
520 freejob(jp);
521 }
522
523
524 int
525 jobscmd(int argc, char **argv)
526 {
527 int mode, m;
528
529 mode = 0;
530 while ((m = nextopt("lp")))
531 if (m == 'l')
532 mode = SHOW_PID;
533 else
534 mode = SHOW_PGID;
535 if (!iflag)
536 mode |= SHOW_NO_FREE;
537 if (*argptr)
538 do
539 showjob(out1, getjob(*argptr,0), mode);
540 while (*++argptr);
541 else
542 showjobs(out1, mode);
543 return 0;
544 }
545
546
547 /*
548 * Print a list of jobs. If "change" is nonzero, only print jobs whose
549 * statuses have changed since the last call to showjobs.
550 *
551 * If the shell is interrupted in the process of creating a job, the
552 * result may be a job structure containing zero processes. Such structures
553 * will be freed here.
554 */
555
556 void
557 showjobs(struct output *out, int mode)
558 {
559 int jobno;
560 struct job *jp;
561 int silent = 0, gotpid;
562
563 CTRACE(DBG_JOBS, ("showjobs(%x) called\n", mode));
564
565 /* If not even one one job changed, there is nothing to do */
566 gotpid = dowait(WSILENT, NULL);
567 while (dowait(WSILENT, NULL) > 0)
568 continue;
569 #ifdef JOBS
570 /*
571 * Check if we are not in our foreground group, and if not
572 * put us in it.
573 */
574 if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) {
575 if (tcsetpgrp(ttyfd, getpid()) == -1)
576 error("Cannot set tty process group (%s) at %d",
577 strerror(errno), __LINE__);
578 VTRACE(DBG_JOBS|DBG_INPUT, ("repaired tty process group\n"));
579 silent = 1;
580 }
581 #endif
582 if (jobs_invalid)
583 return;
584
585 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
586 if (!jp->used)
587 continue;
588 if (jp->nprocs == 0) {
589 freejob(jp);
590 continue;
591 }
592 if ((mode & SHOW_CHANGED) && !jp->changed)
593 continue;
594 if (silent && jp->changed) {
595 jp->changed = 0;
596 continue;
597 }
598 showjob(out, jp, mode);
599 }
600 }
601
602 /*
603 * Mark a job structure as unused.
604 */
605
606 STATIC void
607 freejob(struct job *jp)
608 {
609 INTOFF;
610 if (jp->ps != &jp->ps0) {
611 ckfree(jp->ps);
612 jp->ps = &jp->ps0;
613 }
614 jp->nprocs = 0;
615 jp->used = 0;
616 #if JOBS
617 set_curjob(jp, 0);
618 #endif
619 INTON;
620 }
621
622 /*
623 * Extract the status of a completed job (for $?)
624 */
625 STATIC int
626 jobstatus(const struct job *jp, int raw)
627 {
628 int status = 0;
629 int retval;
630
631 if (pipefail && jp->nprocs) {
632 int i;
633
634 for (i = 0; i < jp->nprocs; i++)
635 if (jp->ps[i].status != 0)
636 status = jp->ps[i].status;
637 } else
638 status = jp->ps[jp->nprocs ? jp->nprocs - 1 : 0].status;
639
640 if (raw)
641 return status;
642
643 if (WIFEXITED(status))
644 retval = WEXITSTATUS(status);
645 #if JOBS
646 else if (WIFSTOPPED(status))
647 retval = WSTOPSIG(status) + 128;
648 #endif
649 else {
650 /* XXX: limits number of signals */
651 retval = WTERMSIG(status) + 128;
652 }
653
654 return retval;
655 }
656
657
658
659 int
660 waitcmd(int argc, char **argv)
661 {
662 struct job *job;
663 int retval;
664 struct job *jp;
665
666 nextopt("");
667
668 /*
669 * If we have forked, and not yet created any new jobs, then
670 * we have no children, whatever jobtab claims,
671 * so simply return in that case.
672 *
673 * The return code is 127 if we had any pid args (none are found)
674 * but 0 for plain old "wait".
675 */
676 if (jobs_invalid)
677 return *argptr ? 127 : 0;
678
679 if (!*argptr) {
680 /* wait for all jobs */
681 jp = jobtab;
682 for (;;) {
683 if (jp >= jobtab + njobs) {
684 /* no running procs */
685 return 0;
686 }
687 if (!jp->used || jp->state != JOBRUNNING) {
688 jp++;
689 continue;
690 }
691 if (dowait(WBLOCK, NULL) == -1)
692 return 128 + lastsig();
693 jp = jobtab;
694 }
695 }
696
697 retval = 127; /* XXXGCC: -Wuninitialized */
698 for (; *argptr; argptr++) {
699 job = getjob(*argptr, 1);
700 if (!job) {
701 retval = 127;
702 continue;
703 }
704 /* loop until process terminated or stopped */
705 while (job->state == JOBRUNNING) {
706 if (dowait(WBLOCK|WNOFREE, job) == -1)
707 return 128 + lastsig();
708 }
709 retval = jobstatus(job, 0);
710 if (!iflag)
711 freejob(job);
712 }
713 return retval;
714 }
715
716
717
718 int
719 jobidcmd(int argc, char **argv)
720 {
721 struct job *jp;
722 int i;
723
724 nextopt("");
725 jp = getjob(*argptr, 0);
726 for (i = 0 ; i < jp->nprocs ; ) {
727 out1fmt("%ld", (long)jp->ps[i].pid);
728 out1c(++i < jp->nprocs ? ' ' : '\n');
729 }
730 return 0;
731 }
732
733 int
734 getjobpgrp(const char *name)
735 {
736 struct job *jp;
737
738 if (jobs_invalid)
739 error("No such job: %s", name);
740 jp = getjob(name, 1);
741 if (jp == 0)
742 return 0;
743 return -jp->ps[0].pid;
744 }
745
746 /*
747 * Convert a job name to a job structure.
748 */
749
750 STATIC struct job *
751 getjob(const char *name, int noerror)
752 {
753 int jobno = -1;
754 struct job *jp;
755 int pid;
756 int i;
757 const char *err_msg = "No such job: %s";
758
759 if (name == NULL) {
760 #if JOBS
761 jobno = curjob;
762 #endif
763 err_msg = "No current job";
764 } else if (name[0] == '%') {
765 if (is_number(name + 1)) {
766 jobno = number(name + 1) - 1;
767 } else if (!name[2]) {
768 switch (name[1]) {
769 #if JOBS
770 case 0:
771 case '+':
772 case '%':
773 jobno = curjob;
774 err_msg = "No current job";
775 break;
776 case '-':
777 jobno = curjob;
778 if (jobno != -1)
779 jobno = jobtab[jobno].prev_job;
780 err_msg = "No previous job";
781 break;
782 #endif
783 default:
784 goto check_pattern;
785 }
786 } else {
787 struct job *found;
788 check_pattern:
789 found = NULL;
790 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
791 if (!jp->used || jp->nprocs <= 0)
792 continue;
793 if ((name[1] == '?'
794 && strstr(jp->ps[0].cmd, name + 2))
795 || prefix(name + 1, jp->ps[0].cmd)) {
796 if (found) {
797 err_msg = "%s: ambiguous";
798 found = 0;
799 break;
800 }
801 found = jp;
802 }
803 }
804 if (found)
805 return found;
806 }
807
808 } else if (is_number(name)) {
809 pid = number(name);
810 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
811 if (jp->used && jp->nprocs > 0
812 && jp->ps[jp->nprocs - 1].pid == pid)
813 return jp;
814 }
815 }
816
817 if (jobno >= 0 && jobno < njobs) {
818 jp = jobtab + jobno;
819 if (jp->used)
820 return jp;
821 }
822 if (!noerror)
823 error(err_msg, name);
824 return 0;
825 }
826
827
828
829 /*
830 * Return a new job structure,
831 */
832
833 struct job *
834 makejob(union node *node, int nprocs)
835 {
836 int i;
837 struct job *jp;
838
839 if (jobs_invalid) {
840 for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) {
841 if (jp->used)
842 freejob(jp);
843 }
844 jobs_invalid = 0;
845 }
846
847 for (i = njobs, jp = jobtab ; ; jp++) {
848 if (--i < 0) {
849 INTOFF;
850 if (njobs == 0) {
851 jobtab = ckmalloc(4 * sizeof jobtab[0]);
852 } else {
853 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
854 memcpy(jp, jobtab, njobs * sizeof jp[0]);
855 /* Relocate `ps' pointers */
856 for (i = 0; i < njobs; i++)
857 if (jp[i].ps == &jobtab[i].ps0)
858 jp[i].ps = &jp[i].ps0;
859 ckfree(jobtab);
860 jobtab = jp;
861 }
862 jp = jobtab + njobs;
863 for (i = 4 ; --i >= 0 ; )
864 jobtab[njobs++].used = 0;
865 INTON;
866 break;
867 }
868 if (jp->used == 0)
869 break;
870 }
871 INTOFF;
872 jp->state = JOBRUNNING;
873 jp->used = 1;
874 jp->changed = 0;
875 jp->nprocs = 0;
876 #if JOBS
877 jp->jobctl = jobctl;
878 set_curjob(jp, 1);
879 #endif
880 if (nprocs > 1) {
881 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
882 } else {
883 jp->ps = &jp->ps0;
884 }
885 INTON;
886 VTRACE(DBG_JOBS, ("makejob(0x%lx, %d) returns %%%d\n",
887 (long)node, nprocs, jp - jobtab + 1));
888 return jp;
889 }
890
891
892 /*
893 * Fork off a subshell. If we are doing job control, give the subshell its
894 * own process group. Jp is a job structure that the job is to be added to.
895 * N is the command that will be evaluated by the child. Both jp and n may
896 * be NULL. The mode parameter can be one of the following:
897 * FORK_FG - Fork off a foreground process.
898 * FORK_BG - Fork off a background process.
899 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
900 * process group even if job control is on.
901 *
902 * When job control is turned off, background processes have their standard
903 * input redirected to /dev/null (except for the second and later processes
904 * in a pipeline).
905 */
906
907 int
908 forkshell(struct job *jp, union node *n, int mode)
909 {
910 pid_t pid;
911 int serrno;
912
913 CTRACE(DBG_JOBS, ("forkshell(%%%d, %p, %d) called\n",
914 jp - jobtab, n, mode));
915
916 switch ((pid = fork())) {
917 case -1:
918 serrno = errno;
919 VTRACE(DBG_JOBS, ("Fork failed, errno=%d\n", serrno));
920 INTON;
921 error("Cannot fork (%s)", strerror(serrno));
922 break;
923 case 0:
924 SHELL_FORKED();
925 forkchild(jp, n, mode, 0);
926 return 0;
927 default:
928 return forkparent(jp, n, mode, pid);
929 }
930 }
931
932 int
933 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
934 {
935 int pgrp;
936
937 if (rootshell && mode != FORK_NOJOB && mflag) {
938 if (jp == NULL || jp->nprocs == 0)
939 pgrp = pid;
940 else
941 pgrp = jp->ps[0].pid;
942 /* This can fail because we are doing it in the child also */
943 (void)setpgid(pid, pgrp);
944 }
945 if (mode == FORK_BG)
946 backgndpid = pid; /* set $! */
947 if (jp) {
948 struct procstat *ps = &jp->ps[jp->nprocs++];
949 ps->pid = pid;
950 ps->status = -1;
951 ps->cmd[0] = 0;
952 if (/* iflag && rootshell && */ n)
953 commandtext(ps, n);
954 }
955 CTRACE(DBG_JOBS, ("In parent shell: child = %d (mode %d)\n",pid,mode));
956 return pid;
957 }
958
959 void
960 forkchild(struct job *jp, union node *n, int mode, int vforked)
961 {
962 int wasroot;
963 int pgrp;
964 const char *devnull = _PATH_DEVNULL;
965 const char *nullerr = "Can't open %s";
966
967 wasroot = rootshell;
968 CTRACE(DBG_JOBS, ("Child shell %d %sforked from %d (mode %d)\n",
969 getpid(), vforked?"v":"", getppid(), mode));
970 if (!vforked)
971 rootshell = 0;
972
973 closescript(vforked);
974 clear_traps(vforked);
975 #if JOBS
976 if (!vforked)
977 jobctl = 0; /* do job control only in root shell */
978 if (wasroot && mode != FORK_NOJOB && mflag) {
979 if (jp == NULL || jp->nprocs == 0)
980 pgrp = getpid();
981 else
982 pgrp = jp->ps[0].pid;
983 /* This can fail because we are doing it in the parent also */
984 (void)setpgid(0, pgrp);
985 if (mode == FORK_FG) {
986 if (tcsetpgrp(ttyfd, pgrp) == -1)
987 error("Cannot set tty process group (%s) at %d",
988 strerror(errno), __LINE__);
989 }
990 setsignal(SIGTSTP, vforked);
991 setsignal(SIGTTOU, vforked);
992 } else if (mode == FORK_BG) {
993 ignoresig(SIGINT, vforked);
994 ignoresig(SIGQUIT, vforked);
995 if ((jp == NULL || jp->nprocs == 0) &&
996 ! fd0_redirected_p ()) {
997 close(0);
998 if (open(devnull, O_RDONLY) != 0)
999 error(nullerr, devnull);
1000 }
1001 }
1002 #else
1003 if (mode == FORK_BG) {
1004 ignoresig(SIGINT, vforked);
1005 ignoresig(SIGQUIT, vforked);
1006 if ((jp == NULL || jp->nprocs == 0) &&
1007 ! fd0_redirected_p ()) {
1008 close(0);
1009 if (open(devnull, O_RDONLY) != 0)
1010 error(nullerr, devnull);
1011 }
1012 }
1013 #endif
1014 if (wasroot && iflag) {
1015 setsignal(SIGINT, vforked);
1016 setsignal(SIGQUIT, vforked);
1017 setsignal(SIGTERM, vforked);
1018 }
1019
1020 if (!vforked)
1021 jobs_invalid = 1;
1022 }
1023
1024 /*
1025 * Wait for job to finish.
1026 *
1027 * Under job control we have the problem that while a child process is
1028 * running interrupts generated by the user are sent to the child but not
1029 * to the shell. This means that an infinite loop started by an inter-
1030 * active user may be hard to kill. With job control turned off, an
1031 * interactive user may place an interactive program inside a loop. If
1032 * the interactive program catches interrupts, the user doesn't want
1033 * these interrupts to also abort the loop. The approach we take here
1034 * is to have the shell ignore interrupt signals while waiting for a
1035 * forground process to terminate, and then send itself an interrupt
1036 * signal if the child process was terminated by an interrupt signal.
1037 * Unfortunately, some programs want to do a bit of cleanup and then
1038 * exit on interrupt; unless these processes terminate themselves by
1039 * sending a signal to themselves (instead of calling exit) they will
1040 * confuse this approach.
1041 */
1042
1043 int
1044 waitforjob(struct job *jp)
1045 {
1046 #if JOBS
1047 int mypgrp = getpgrp();
1048 #endif
1049 int status;
1050 int st;
1051
1052 INTOFF;
1053 VTRACE(DBG_JOBS, ("waitforjob(%%%d) called\n", jp - jobtab + 1));
1054 while (jp->state == JOBRUNNING) {
1055 dowait(WBLOCK, jp);
1056 }
1057 #if JOBS
1058 if (jp->jobctl) {
1059 if (tcsetpgrp(ttyfd, mypgrp) == -1)
1060 error("Cannot set tty process group (%s) at %d",
1061 strerror(errno), __LINE__);
1062 }
1063 if (jp->state == JOBSTOPPED && curjob != jp - jobtab)
1064 set_curjob(jp, 2);
1065 #endif
1066 status = jobstatus(jp, 1);
1067
1068 /* convert to 8 bits */
1069 if (WIFEXITED(status))
1070 st = WEXITSTATUS(status);
1071 #if JOBS
1072 else if (WIFSTOPPED(status))
1073 st = WSTOPSIG(status) + 128;
1074 #endif
1075 else
1076 st = WTERMSIG(status) + 128;
1077
1078 VTRACE(DBG_JOBS, ("waitforjob: job %d, nproc %d, status %d, st %x\n",
1079 jp - jobtab + 1, jp->nprocs, status, st));
1080 #if JOBS
1081 if (jp->jobctl) {
1082 /*
1083 * This is truly gross.
1084 * If we're doing job control, then we did a TIOCSPGRP which
1085 * caused us (the shell) to no longer be in the controlling
1086 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
1087 * intuit from the subprocess exit status whether a SIGINT
1088 * occurred, and if so interrupt ourselves. Yuck. - mycroft
1089 */
1090 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
1091 raise(SIGINT);
1092 }
1093 #endif
1094 if (! JOBS || jp->state == JOBDONE)
1095 freejob(jp);
1096 INTON;
1097 return st;
1098 }
1099
1100
1101
1102 /*
1103 * Wait for a process to terminate.
1104 */
1105
1106 STATIC int
1107 dowait(int flags, struct job *job)
1108 {
1109 int pid;
1110 int status;
1111 struct procstat *sp;
1112 struct job *jp;
1113 struct job *thisjob;
1114 int done;
1115 int stopped;
1116
1117 VTRACE(DBG_JOBS|DBG_PROCS, ("dowait(%x) called\n", flags));
1118 do {
1119 pid = waitproc(flags & WBLOCK, job, &status);
1120 VTRACE(DBG_JOBS|DBG_PROCS, ("wait returns pid %d, status %#x\n",
1121 pid, status));
1122 } while (pid == -1 && errno == EINTR && pendingsigs == 0);
1123 if (pid <= 0)
1124 return pid;
1125 INTOFF;
1126 thisjob = NULL;
1127 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
1128 if (jp->used) {
1129 done = 1;
1130 stopped = 1;
1131 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
1132 if (sp->pid == -1)
1133 continue;
1134 if (sp->pid == pid &&
1135 (sp->status==-1 || WIFSTOPPED(sp->status))) {
1136 VTRACE(DBG_JOBS | DBG_PROCS,
1137 ("Job %d: changing status of proc %d from %#x to %#x\n",
1138 jp - jobtab + 1, pid,
1139 sp->status, status));
1140 if (WIFCONTINUED(status)) {
1141 if (sp->status != -1)
1142 jp->changed = 1;
1143 sp->status = -1;
1144 jp->state = 0;
1145 } else
1146 sp->status = status;
1147 thisjob = jp;
1148 }
1149 if (sp->status == -1)
1150 stopped = 0;
1151 else if (WIFSTOPPED(sp->status))
1152 done = 0;
1153 }
1154 if (stopped) { /* stopped or done */
1155 int state = done ? JOBDONE : JOBSTOPPED;
1156
1157 if (jp->state != state) {
1158 VTRACE(DBG_JOBS,
1159 ("Job %d: changing state from %d to %d\n",
1160 jp - jobtab + 1, jp->state, state));
1161 jp->state = state;
1162 #if JOBS
1163 if (done)
1164 set_curjob(jp, 0);
1165 #endif
1166 }
1167 }
1168 }
1169 }
1170
1171 if (thisjob && (thisjob->state != JOBRUNNING || thisjob->changed)) {
1172 int mode = 0;
1173
1174 if (!rootshell || !iflag)
1175 mode = SHOW_SIGNALLED;
1176 if ((job == thisjob && (flags & WNOFREE) == 0) ||
1177 job != thisjob)
1178 mode = SHOW_SIGNALLED | SHOW_NO_FREE;
1179 if (mode && (flags & WSILENT) == 0)
1180 showjob(out2, thisjob, mode);
1181 else {
1182 VTRACE(DBG_JOBS,
1183 ("Not printing status, rootshell=%d, job=%p\n",
1184 rootshell, job));
1185 thisjob->changed = 1;
1186 }
1187 }
1188
1189 INTON;
1190 return pid;
1191 }
1192
1193
1194
1195 /*
1196 * Do a wait system call. If job control is compiled in, we accept
1197 * stopped processes. If block is zero, we return a value of zero
1198 * rather than blocking.
1199 *
1200 * System V doesn't have a non-blocking wait system call. It does
1201 * have a SIGCLD signal that is sent to a process when one of its
1202 * children dies. The obvious way to use SIGCLD would be to install
1203 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
1204 * was received, and have waitproc bump another counter when it got
1205 * the status of a process. Waitproc would then know that a wait
1206 * system call would not block if the two counters were different.
1207 * This approach doesn't work because if a process has children that
1208 * have not been waited for, System V will send it a SIGCLD when it
1209 * installs a signal handler for SIGCLD. What this means is that when
1210 * a child exits, the shell will be sent SIGCLD signals continuously
1211 * until is runs out of stack space, unless it does a wait call before
1212 * restoring the signal handler. The code below takes advantage of
1213 * this (mis)feature by installing a signal handler for SIGCLD and
1214 * then checking to see whether it was called. If there are any
1215 * children to be waited for, it will be.
1216 *
1217 * If neither SYSV nor BSD is defined, we don't implement nonblocking
1218 * waits at all. In this case, the user will not be informed when
1219 * a background process until the next time she runs a real program
1220 * (as opposed to running a builtin command or just typing return),
1221 * and the jobs command may give out of date information.
1222 */
1223
1224 #ifdef SYSV
1225 STATIC int gotsigchild;
1226
1227 STATIC int onsigchild() {
1228 gotsigchild = 1;
1229 }
1230 #endif
1231
1232
1233 STATIC int
1234 waitproc(int block, struct job *jp, int *status)
1235 {
1236 #ifdef BSD
1237 int flags = 0;
1238
1239 #if JOBS
1240 if (mflag || (jp != NULL && jp->jobctl))
1241 flags |= WUNTRACED | WCONTINUED;
1242 #endif
1243 if (block == 0)
1244 flags |= WNOHANG;
1245 VTRACE(DBG_WAIT, ("waitproc: doing waitpid(flags=%#x)\n", flags));
1246 return waitpid(-1, status, flags);
1247 #else
1248 #ifdef SYSV
1249 int (*save)();
1250
1251 if (block == 0) {
1252 gotsigchild = 0;
1253 save = signal(SIGCLD, onsigchild);
1254 signal(SIGCLD, save);
1255 if (gotsigchild == 0)
1256 return 0;
1257 }
1258 return wait(status);
1259 #else
1260 if (block == 0)
1261 return 0;
1262 return wait(status);
1263 #endif
1264 #endif
1265 }
1266
1267 /*
1268 * return 1 if there are stopped jobs, otherwise 0
1269 */
1270 int job_warning = 0;
1271 int
1272 stoppedjobs(void)
1273 {
1274 int jobno;
1275 struct job *jp;
1276
1277 if (job_warning || jobs_invalid)
1278 return (0);
1279 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1280 if (jp->used == 0)
1281 continue;
1282 if (jp->state == JOBSTOPPED) {
1283 out2str("You have stopped jobs.\n");
1284 job_warning = 2;
1285 return (1);
1286 }
1287 }
1288
1289 return (0);
1290 }
1291
1292 /*
1293 * Return a string identifying a command (to be printed by the
1294 * jobs command).
1295 */
1296
1297 STATIC char *cmdnextc;
1298 STATIC int cmdnleft;
1299
1300 void
1301 commandtext(struct procstat *ps, union node *n)
1302 {
1303 int len;
1304
1305 cmdnextc = ps->cmd;
1306 if (iflag || mflag || sizeof ps->cmd < 100)
1307 len = sizeof(ps->cmd);
1308 else
1309 len = sizeof(ps->cmd) / 10;
1310 cmdnleft = len;
1311 cmdtxt(n);
1312 if (cmdnleft <= 0) {
1313 char *p = ps->cmd + len - 4;
1314 p[0] = '.';
1315 p[1] = '.';
1316 p[2] = '.';
1317 p[3] = 0;
1318 } else
1319 *cmdnextc = '\0';
1320
1321 VTRACE(DBG_JOBS,
1322 ("commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n",
1323 ps->cmd, cmdnextc, cmdnleft, ps->cmd));
1324 }
1325
1326
1327 STATIC void
1328 cmdtxt(union node *n)
1329 {
1330 union node *np;
1331 struct nodelist *lp;
1332 const char *p;
1333 int i;
1334
1335 if (n == NULL || cmdnleft <= 0)
1336 return;
1337 switch (n->type) {
1338 case NSEMI:
1339 cmdtxt(n->nbinary.ch1);
1340 cmdputs("; ");
1341 cmdtxt(n->nbinary.ch2);
1342 break;
1343 case NAND:
1344 cmdtxt(n->nbinary.ch1);
1345 cmdputs(" && ");
1346 cmdtxt(n->nbinary.ch2);
1347 break;
1348 case NOR:
1349 cmdtxt(n->nbinary.ch1);
1350 cmdputs(" || ");
1351 cmdtxt(n->nbinary.ch2);
1352 break;
1353 case NDNOT:
1354 cmdputs("! ");
1355 /* FALLTHROUGH */
1356 case NNOT:
1357 cmdputs("! ");
1358 cmdtxt(n->nnot.com);
1359 break;
1360 case NPIPE:
1361 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1362 cmdtxt(lp->n);
1363 if (lp->next)
1364 cmdputs(" | ");
1365 }
1366 if (n->npipe.backgnd)
1367 cmdputs(" &");
1368 break;
1369 case NSUBSHELL:
1370 cmdputs("(");
1371 cmdtxt(n->nredir.n);
1372 cmdputs(")");
1373 break;
1374 case NREDIR:
1375 case NBACKGND:
1376 cmdtxt(n->nredir.n);
1377 break;
1378 case NIF:
1379 cmdputs("if ");
1380 cmdtxt(n->nif.test);
1381 cmdputs("; then ");
1382 cmdtxt(n->nif.ifpart);
1383 if (n->nif.elsepart) {
1384 cmdputs("; else ");
1385 cmdtxt(n->nif.elsepart);
1386 }
1387 cmdputs("; fi");
1388 break;
1389 case NWHILE:
1390 cmdputs("while ");
1391 goto until;
1392 case NUNTIL:
1393 cmdputs("until ");
1394 until:
1395 cmdtxt(n->nbinary.ch1);
1396 cmdputs("; do ");
1397 cmdtxt(n->nbinary.ch2);
1398 cmdputs("; done");
1399 break;
1400 case NFOR:
1401 cmdputs("for ");
1402 cmdputs(n->nfor.var);
1403 cmdputs(" in ");
1404 cmdlist(n->nfor.args, 1);
1405 cmdputs("; do ");
1406 cmdtxt(n->nfor.body);
1407 cmdputs("; done");
1408 break;
1409 case NCASE:
1410 cmdputs("case ");
1411 cmdputs(n->ncase.expr->narg.text);
1412 cmdputs(" in ");
1413 for (np = n->ncase.cases; np; np = np->nclist.next) {
1414 cmdtxt(np->nclist.pattern);
1415 cmdputs(") ");
1416 cmdtxt(np->nclist.body);
1417 switch (n->type) { /* switch (not if) for later */
1418 case NCLISTCONT:
1419 cmdputs(";& ");
1420 break;
1421 default:
1422 cmdputs(";; ");
1423 break;
1424 }
1425 }
1426 cmdputs("esac");
1427 break;
1428 case NDEFUN:
1429 cmdputs(n->narg.text);
1430 cmdputs("() { ... }");
1431 break;
1432 case NCMD:
1433 cmdlist(n->ncmd.args, 1);
1434 cmdlist(n->ncmd.redirect, 0);
1435 if (n->ncmd.backgnd)
1436 cmdputs(" &");
1437 break;
1438 case NARG:
1439 cmdputs(n->narg.text);
1440 break;
1441 case NTO:
1442 p = ">"; i = 1; goto redir;
1443 case NCLOBBER:
1444 p = ">|"; i = 1; goto redir;
1445 case NAPPEND:
1446 p = ">>"; i = 1; goto redir;
1447 case NTOFD:
1448 p = ">&"; i = 1; goto redir;
1449 case NFROM:
1450 p = "<"; i = 0; goto redir;
1451 case NFROMFD:
1452 p = "<&"; i = 0; goto redir;
1453 case NFROMTO:
1454 p = "<>"; i = 0; goto redir;
1455 redir:
1456 if (n->nfile.fd != i)
1457 cmdputi(n->nfile.fd);
1458 cmdputs(p);
1459 if (n->type == NTOFD || n->type == NFROMFD) {
1460 if (n->ndup.dupfd < 0)
1461 cmdputs("-");
1462 else
1463 cmdputi(n->ndup.dupfd);
1464 } else {
1465 cmdtxt(n->nfile.fname);
1466 }
1467 break;
1468 case NHERE:
1469 case NXHERE:
1470 cmdputs("<<...");
1471 break;
1472 default:
1473 cmdputs("???");
1474 break;
1475 }
1476 }
1477
1478 STATIC void
1479 cmdlist(union node *np, int sep)
1480 {
1481 for (; np; np = np->narg.next) {
1482 if (!sep)
1483 cmdputs(" ");
1484 cmdtxt(np);
1485 if (sep && np->narg.next)
1486 cmdputs(" ");
1487 }
1488 }
1489
1490
1491 STATIC void
1492 cmdputs(const char *s)
1493 {
1494 const char *p, *str = 0;
1495 char c, cc[2] = " ";
1496 char *nextc;
1497 int nleft;
1498 int subtype = 0;
1499 int quoted = 0;
1500 static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
1501 "#", "##", "%", "%%", "}" };
1502
1503 p = s;
1504 nextc = cmdnextc;
1505 nleft = cmdnleft;
1506 while (nleft > 0 && (c = *p++) != 0) {
1507 switch (c) {
1508 case CTLNONL:
1509 c = '\0';
1510 break;
1511 case CTLESC:
1512 c = *p++;
1513 break;
1514 case CTLVAR:
1515 subtype = *p++;
1516 if (subtype & VSLINENO) { /* undo LINENO hack */
1517 if ((subtype & VSTYPE) == VSLENGTH)
1518 str = "${#LINENO"; /*}*/
1519 else
1520 str = "${LINENO"; /*}*/
1521 while (is_digit(*p))
1522 p++;
1523 } else if ((subtype & VSTYPE) == VSLENGTH)
1524 str = "${#"; /*}*/
1525 else
1526 str = "${"; /*}*/
1527 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
1528 quoted ^= 1;
1529 c = '"';
1530 } else {
1531 c = *str++;
1532 }
1533 break;
1534 case CTLENDVAR: /*{*/
1535 c = '}';
1536 if (quoted & 1)
1537 str = "\"";
1538 quoted >>= 1;
1539 subtype = 0;
1540 break;
1541 case CTLBACKQ:
1542 c = '$';
1543 str = "(...)";
1544 break;
1545 case CTLBACKQ+CTLQUOTE:
1546 c = '"';
1547 str = "$(...)\"";
1548 break;
1549 case CTLARI:
1550 c = '$';
1551 if (*p == ' ')
1552 p++;
1553 str = "(("; /*))*/
1554 break;
1555 case CTLENDARI: /*((*/
1556 c = ')';
1557 str = ")";
1558 break;
1559 case CTLQUOTEMARK:
1560 quoted ^= 1;
1561 c = '"';
1562 break;
1563 case CTLQUOTEEND:
1564 quoted >>= 1;
1565 c = '"';
1566 break;
1567 case '=':
1568 if (subtype == 0)
1569 break;
1570 str = vstype[subtype & VSTYPE];
1571 if (subtype & VSNUL)
1572 c = ':';
1573 else
1574 c = *str++; /*{*/
1575 if (c != '}')
1576 quoted <<= 1;
1577 else if (*p == CTLENDVAR)
1578 c = *str++;
1579 subtype = 0;
1580 break;
1581 case '\'':
1582 case '\\':
1583 case '"':
1584 case '$':
1585 /* These can only happen inside quotes */
1586 cc[0] = c;
1587 str = cc;
1588 c = '\\';
1589 break;
1590 default:
1591 break;
1592 }
1593 if (c != '\0') do { /* c == 0 implies nothing in str */
1594 *nextc++ = c;
1595 } while (--nleft > 0 && str && (c = *str++));
1596 str = 0;
1597 }
1598 if ((quoted & 1) && nleft) {
1599 *nextc++ = '"';
1600 nleft--;
1601 }
1602 cmdnleft = nleft;
1603 cmdnextc = nextc;
1604 }
1605