source: trunk/src/kash/jobs.c@ 3408

Last change on this file since 3408 was 3408, checked in by bird, 5 years ago

kash: Don't use sys_siglist, use strsignal instead. Should be present everywhere except when using VC++ on windows.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 31.2 KB
Line 
1/* $NetBSD: jobs.c,v 1.63 2005/06/01 15:41:19 lukem 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#if 0
36#ifndef lint
37static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
38#else
39__RCSID("$NetBSD: jobs.c,v 1.63 2005/06/01 15:41:19 lukem Exp $");
40#endif /* not lint */
41#endif
42
43#include <fcntl.h>
44#include <errno.h>
45#include <stdlib.h>
46#include <sys/types.h>
47
48#include "shell.h"
49#if JOBS && !defined(_MSC_VER)
50# include <termios.h>
51#endif
52#include "redir.h"
53#include "show.h"
54#include "main.h"
55#include "parser.h"
56#include "nodes.h"
57#include "jobs.h"
58#include "options.h"
59#include "trap.h"
60#include "syntax.h"
61#include "input.h"
62#include "output.h"
63#include "memalloc.h"
64#include "error.h"
65#include "mystring.h"
66#include "shinstance.h"
67
68//static struct job *jobtab; /* array of jobs */
69//static int njobs; /* size of array */
70//static int jobs_invalid; /* set in child */
71//MKINIT pid_t backgndpid = -1; /* pid of last background process */
72#if JOBS
73//int initialpgrp; /* pgrp of shell on invocation */
74//static int curjob = -1; /* current job */
75#endif
76//static int ttyfd = -1;
77
78STATIC void restartjob(shinstance *, struct job *);
79STATIC void freejob(shinstance *, struct job *);
80STATIC struct job *getjob(shinstance *, const char *, int);
81STATIC int dowait(shinstance *, int, struct job *);
82STATIC int waitproc(shinstance *, int, struct job *, int *);
83STATIC void cmdtxt(shinstance *, union node *);
84STATIC void cmdlist(shinstance *, union node *, int);
85STATIC void cmdputs(shinstance *, const char *);
86
87
88/*
89 * Turn job control on and off.
90 *
91 * Note: This code assumes that the third arg to ioctl is a character
92 * pointer, which is true on Berkeley systems but not System V. Since
93 * System V doesn't have job control yet, this isn't a problem now.
94 */
95
96//MKINIT int jobctl;
97
98void
99setjobctl(shinstance *psh, int on)
100{
101 if (on == psh->jobctl || psh->rootshell == 0)
102 return;
103 if (on) {
104 int err;
105 int i;
106 if (psh->ttyfd != -1)
107 shfile_close(&psh->fdtab, psh->ttyfd);
108 if ((psh->ttyfd = shfile_open(&psh->fdtab, "/dev/tty", O_RDWR, 0)) == -1) {
109 for (i = 0; i < 3; i++) {
110 if (shfile_isatty(&psh->fdtab, i)
111 && (psh->ttyfd = shfile_dup(&psh->fdtab, i)) != -1)
112 break;
113 }
114 if (i == 3)
115 goto out;
116 }
117 /* Move to a high fd */
118 for (i = 10; i > 2; i--) {
119 if ((err = shfile_fcntl(&psh->fdtab, psh->ttyfd, F_DUPFD, (1 << i) - 1)) != -1)
120 break;
121 }
122 if (err != -1) {
123 shfile_close(&psh->fdtab, psh->ttyfd);
124 psh->ttyfd = err;
125 }
126 err = shfile_cloexec(&psh->fdtab, psh->ttyfd, 1);
127 if (err == -1) {
128 shfile_close(&psh->fdtab, psh->ttyfd);
129 psh->ttyfd = -1;
130 goto out;
131 }
132 do { /* while we are in the background */
133 if ((psh->initialpgrp = sh_tcgetpgrp(psh, psh->ttyfd)) < 0) {
134out:
135 out2str(psh, "sh: can't access tty; job control turned off\n");
136 mflag(psh) = 0;
137 return;
138 }
139 if (psh->initialpgrp == -1)
140 psh->initialpgrp = sh_getpgrp(psh);
141 else if (psh->initialpgrp != sh_getpgrp(psh)) {
142 sh_killpg(psh, 0, SIGTTIN);
143 continue;
144 }
145 } while (0);
146
147 setsignal(psh, SIGTSTP, 0);
148 setsignal(psh, SIGTTOU, 0);
149 setsignal(psh, SIGTTIN, 0);
150 if (sh_getpgid(psh, 0) != psh->rootpid && sh_setpgid(psh, 0, psh->rootpid) == -1)
151 error(psh, "Cannot set process group (%s) at %d",
152 sh_strerror(psh, errno), __LINE__);
153 if (sh_tcsetpgrp(psh, psh->ttyfd, psh->rootpid) == -1)
154 error(psh, "Cannot set tty process group (%s) at %d",
155 sh_strerror(psh, errno), __LINE__);
156 } else { /* turning job control off */
157 if (sh_getpgid(psh, 0) != psh->initialpgrp && sh_setpgid(psh, 0, psh->initialpgrp) == -1)
158 error(psh, "Cannot set process group (%s) at %d",
159 sh_strerror(psh, errno), __LINE__);
160 if (sh_tcsetpgrp(psh, psh->ttyfd, psh->initialpgrp) == -1)
161 error(psh, "Cannot set tty process group (%s) at %d",
162 sh_strerror(psh, errno), __LINE__);
163 shfile_close(&psh->fdtab, psh->ttyfd);
164 psh->ttyfd = -1;
165 setsignal(psh, SIGTSTP, 0);
166 setsignal(psh, SIGTTOU, 0);
167 setsignal(psh, SIGTTIN, 0);
168 }
169 psh->jobctl = on;
170}
171
172
173#ifdef mkinit
174INCLUDE <stdlib.h>
175
176SHELLPROC {
177 psh->backgndpid = -1;
178#if JOBS
179 psh->jobctl = 0;
180#endif
181}
182
183#endif
184
185
186
187#if JOBS
188int
189fgcmd(shinstance *psh, int argc, char **argv)
190{
191 struct job *jp;
192 int i;
193 int status;
194
195 nextopt(psh, "");
196 jp = getjob(psh, *psh->argptr, 0);
197 if (jp->jobctl == 0)
198 error(psh, "job not created under job control");
199 out1fmt(psh, "%s", jp->ps[0].cmd);
200 for (i = 1; i < jp->nprocs; i++)
201 out1fmt(psh, " | %s", jp->ps[i].cmd );
202 out1c(psh, '\n');
203 output_flushall(psh);
204
205 for (i = 0; i < jp->nprocs; i++)
206 if (sh_tcsetpgrp(psh, psh->ttyfd, jp->ps[i].pid) != -1)
207 break;
208
209 if (i >= jp->nprocs) {
210 error(psh, "Cannot set tty process group (%s) at %d",
211 sh_strerror(psh, errno), __LINE__);
212 }
213 restartjob(psh, jp);
214 INTOFF;
215 status = waitforjob(psh, jp);
216 INTON;
217 return status;
218}
219
220static void
221set_curjob(shinstance *psh, struct job *jp, int mode)
222{
223 struct job *jp1, *jp2;
224 int i, ji;
225
226 ji = (int)(jp - psh->jobtab);
227
228 /* first remove from list */
229 if (ji == psh->curjob)
230 psh->curjob = jp->prev_job;
231 else {
232 for (i = 0; i < psh->njobs; i++) {
233 if (psh->jobtab[i].prev_job != ji)
234 continue;
235 psh->jobtab[i].prev_job = jp->prev_job;
236 break;
237 }
238 }
239
240 /* Then re-insert in correct position */
241 switch (mode) {
242 case 0: /* job being deleted */
243 jp->prev_job = -1;
244 break;
245 case 1: /* newly created job or backgrounded job,
246 put after all stopped jobs. */
247 if (psh->curjob != -1 && psh->jobtab[psh->curjob].state == JOBSTOPPED) {
248 for (jp1 = psh->jobtab + psh->curjob; ; jp1 = jp2) {
249 if (jp1->prev_job == -1)
250 break;
251 jp2 = psh->jobtab + jp1->prev_job;
252 if (jp2->state != JOBSTOPPED)
253 break;
254 }
255 jp->prev_job = jp1->prev_job;
256 jp1->prev_job = ji;
257 break;
258 }
259 /* FALLTHROUGH */
260 case 2: /* newly stopped job - becomes psh->curjob */
261 jp->prev_job = psh->curjob;
262 psh->curjob = ji;
263 break;
264 }
265}
266
267int
268bgcmd(shinstance *psh, int argc, char **argv)
269{
270 struct job *jp;
271 int i;
272
273 nextopt(psh, "");
274 do {
275 jp = getjob(psh, *psh->argptr, 0);
276 if (jp->jobctl == 0)
277 error(psh, "job not created under job control");
278 set_curjob(psh, jp, 1);
279 out1fmt(psh, "[%ld] %s", (long)(jp - psh->jobtab + 1), jp->ps[0].cmd);
280 for (i = 1; i < jp->nprocs; i++)
281 out1fmt(psh, " | %s", jp->ps[i].cmd );
282 out1c(psh, '\n');
283 output_flushall(psh);
284 restartjob(psh, jp);
285 } while (*psh->argptr && *++psh->argptr);
286 return 0;
287}
288
289
290STATIC void
291restartjob(shinstance *psh, struct job *jp)
292{
293 struct procstat *ps;
294 int i;
295
296 if (jp->state == JOBDONE)
297 return;
298 INTOFF;
299 for (i = 0; i < jp->nprocs; i++)
300 if (sh_killpg(psh, jp->ps[i].pid, SIGCONT) != -1)
301 break;
302 if (i >= jp->nprocs)
303 error(psh, "Cannot continue job (%s)", sh_strerror(psh, errno));
304 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
305 if (WIFSTOPPED(ps->status)) {
306 ps->status = -1;
307 jp->state = JOBRUNNING;
308 }
309 }
310 INTON;
311}
312#endif
313
314static void
315showjob(shinstance *psh, struct output *out, struct job *jp, int mode)
316{
317 int procno;
318 int st;
319 struct procstat *ps;
320 size_t col;
321 char s[64];
322
323#if JOBS
324 if (mode & SHOW_PGID) {
325 /* just output process (group) id of pipeline */
326 outfmt(out, "%ld\n", (long)jp->ps->pid);
327 return;
328 }
329#endif
330
331 procno = jp->nprocs;
332 if (!procno)
333 return;
334
335 if (mode & SHOW_PID)
336 mode |= SHOW_MULTILINE;
337
338 if ((procno > 1 && !(mode & SHOW_MULTILINE))
339 || (mode & SHOW_SIGNALLED)) {
340 /* See if we have more than one status to report */
341 ps = jp->ps;
342 st = ps->status;
343 do {
344 int st1 = ps->status;
345 if (st1 != st)
346 /* yes - need multi-line output */
347 mode |= SHOW_MULTILINE;
348 if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1))
349 continue;
350 if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f)
351 && st1 != SIGINT && st1 != SIGPIPE))
352 mode |= SHOW_ISSIG;
353
354 } while (ps++, --procno);
355 procno = jp->nprocs;
356 }
357
358 if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) {
359 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) {
360 TRACE((psh, "showjob: freeing job %d\n", jp - psh->jobtab + 1));
361 freejob(psh, jp);
362 }
363 return;
364 }
365
366 for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */
367 if (ps == jp->ps)
368 fmtstr(s, 16, "[%ld] %c ",
369 (long)(jp - psh->jobtab + 1),
370#if JOBS
371 jp == psh->jobtab + psh->curjob ? '+' :
372 psh->curjob != -1 && jp == psh->jobtab +
373 psh->jobtab[psh->curjob].prev_job ? '-' :
374#endif
375 ' ');
376 else
377 fmtstr(s, 16, " " );
378 col = strlen(s);
379 if (mode & SHOW_PID) {
380 fmtstr(s + col, 16, "%ld ", (long)ps->pid);
381 col += strlen(s + col);
382 }
383 if (ps->status == -1) {
384 scopy("Running", s + col);
385 } else if (WIFEXITED(ps->status)) {
386 st = WEXITSTATUS(ps->status);
387 if (st)
388 fmtstr(s + col, 16, "Done(%d)", st);
389 else
390 fmtstr(s + col, 16, "Done");
391 } else {
392 const char *pszSigNm;
393#if JOBS
394 if (WIFSTOPPED(ps->status))
395 st = WSTOPSIG(ps->status);
396 else /* WIFSIGNALED(ps->status) */
397#endif
398 st = WTERMSIG(ps->status);
399 st &= 0x7f;
400 pszSigNm = st < NSIG ? strsignal(st) : NULL;
401 if (pszSigNm)
402 scopyn(pszSigNm, s + col, 32);
403 else
404 fmtstr(s + col, 16, "Signal %d", st);
405 if (WCOREDUMP(ps->status)) {
406 col += strlen(s + col);
407 scopyn(" (core dumped)", s + col, 64 - col);
408 }
409 }
410 col += strlen(s + col);
411 outstr(s, out);
412 do {
413 outc(' ', out);
414 col++;
415 } while (col < 30);
416 outstr(ps->cmd, out);
417 if (mode & SHOW_MULTILINE) {
418 if (procno > 0) {
419 outc(' ', out);
420 outc('|', out);
421 }
422 } else {
423 while (--procno >= 0)
424 outfmt(out, " | %s", (++ps)->cmd );
425 }
426 outc('\n', out);
427 }
428 flushout(out);
429 jp->changed = 0;
430 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
431 freejob(psh, jp);
432}
433
434
435int
436jobscmd(shinstance *psh, int argc, char **argv)
437{
438 int mode, m;
439 int sv = psh->jobs_invalid;
440
441 psh->jobs_invalid = 0;
442 mode = 0;
443 while ((m = nextopt(psh, "lp")))
444 if (m == 'l')
445 mode = SHOW_PID;
446 else
447 mode = SHOW_PGID;
448 if (*psh->argptr)
449 do
450 showjob(psh, psh->out1, getjob(psh, *psh->argptr,0), mode);
451 while (*++psh->argptr);
452 else
453 showjobs(psh, psh->out1, mode);
454 psh->jobs_invalid = sv;
455 return 0;
456}
457
458
459/*
460 * Print a list of jobs. If "change" is nonzero, only print jobs whose
461 * statuses have changed since the last call to showjobs.
462 *
463 * If the shell is interrupted in the process of creating a job, the
464 * result may be a job structure containing zero processes. Such structures
465 * will be freed here.
466 */
467
468void
469showjobs(shinstance *psh, struct output *out, int mode)
470{
471 int jobno;
472 struct job *jp;
473 int silent = 0, gotpid;
474
475 TRACE((psh, "showjobs(%x) called\n", mode));
476
477 /* If not even one one job changed, there is nothing to do */
478 gotpid = dowait(psh, 0, NULL);
479 while (dowait(psh, 0, NULL) > 0)
480 continue;
481#ifdef JOBS
482 /*
483 * Check if we are not in our foreground group, and if not
484 * put us in it.
485 */
486 if (mflag(psh) && gotpid != -1 && sh_tcgetpgrp(psh, psh->ttyfd) != sh_getpid(psh)) {
487 if (sh_tcsetpgrp(psh, psh->ttyfd, sh_getpid(psh)) == -1)
488 error(psh, "Cannot set tty process group (%s) at %d",
489 sh_strerror(psh, errno), __LINE__);
490 TRACE((psh, "repaired tty process group\n"));
491 silent = 1;
492 }
493#endif
494 if (psh->jobs_invalid)
495 return;
496
497 for (jobno = 1, jp = psh->jobtab ; jobno <= psh->njobs ; jobno++, jp++) {
498 if (!jp->used)
499 continue;
500 if (jp->nprocs == 0) {
501 freejob(psh, jp);
502 continue;
503 }
504 if ((mode & SHOW_CHANGED) && !jp->changed)
505 continue;
506 if (silent && jp->changed) {
507 jp->changed = 0;
508 continue;
509 }
510 showjob(psh, out, jp, mode);
511 }
512}
513
514/*
515 * Mark a job structure as unused.
516 */
517
518STATIC void
519freejob(shinstance *psh, struct job *jp)
520{
521 INTOFF;
522 if (jp->ps != &jp->ps0) {
523 ckfree(psh, jp->ps);
524 jp->ps = &jp->ps0;
525 }
526 jp->nprocs = 0;
527 jp->used = 0;
528#if JOBS
529 set_curjob(psh, jp, 0);
530#endif
531 INTON;
532}
533
534
535
536int
537waitcmd(shinstance *psh, int argc, char **argv)
538{
539 struct job *job;
540 int status, retval;
541 struct job *jp;
542
543 nextopt(psh, "");
544
545 if (!*psh->argptr) {
546 /* wait for all jobs */
547 jp = psh->jobtab;
548 if (psh->jobs_invalid)
549 return 0;
550 for (;;) {
551 if (jp >= psh->jobtab + psh->njobs) {
552 /* no running procs */
553 return 0;
554 }
555 if (!jp->used || jp->state != JOBRUNNING) {
556 jp++;
557 continue;
558 }
559 if (dowait(psh, 1, (struct job *)NULL) == -1)
560 return 128 + SIGINT;
561 jp = psh->jobtab;
562 }
563 }
564
565 retval = 127; /* XXXGCC: -Wuninitialized */
566 for (; *psh->argptr; psh->argptr++) {
567 job = getjob(psh, *psh->argptr, 1);
568 if (!job) {
569 retval = 127;
570 continue;
571 }
572 /* loop until process terminated or stopped */
573 while (job->state == JOBRUNNING) {
574 if (dowait(psh, 1, (struct job *)NULL) == -1)
575 return 128 + SIGINT;
576 }
577 status = job->ps[job->nprocs].status;
578 if (WIFEXITED(status))
579 retval = WEXITSTATUS(status);
580#if JOBS
581 else if (WIFSTOPPED(status))
582 retval = WSTOPSIG(status) + 128;
583#endif
584 else {
585 /* XXX: limits number of signals */
586 retval = WTERMSIG(status) + 128;
587 }
588 if (!iflag(psh))
589 freejob(psh, job);
590 }
591 return retval;
592}
593
594
595
596int
597jobidcmd(shinstance *psh, int argc, char **argv)
598{
599 struct job *jp;
600 int i;
601
602 nextopt(psh, "");
603 jp = getjob(psh, *psh->argptr, 0);
604 for (i = 0 ; i < jp->nprocs ; ) {
605 out1fmt(psh, "%ld", (long)jp->ps[i].pid);
606 out1c(psh, ++i < jp->nprocs ? ' ' : '\n');
607 }
608 return 0;
609}
610
611int
612getjobpgrp(shinstance *psh, const char *name)
613{
614 struct job *jp;
615
616 jp = getjob(psh, name, 1);
617 if (jp == 0)
618 return 0;
619 return -jp->ps[0].pid;
620}
621
622/*
623 * Convert a job name to a job structure.
624 */
625
626STATIC struct job *
627getjob(shinstance *psh, const char *name, int noerror)
628{
629 int jobno = -1;
630 struct job *jp;
631 int pid;
632 int i;
633 const char *err_msg = "No such job: %s";
634
635 if (name == NULL) {
636#if JOBS
637 jobno = psh->curjob;
638#endif
639 err_msg = "No current job";
640 } else if (name[0] == '%') {
641 if (is_number(name + 1)) {
642 jobno = number(psh, name + 1) - 1;
643 } else if (!name[2]) {
644 switch (name[1]) {
645#if JOBS
646 case 0:
647 case '+':
648 case '%':
649 jobno = psh->curjob;
650 err_msg = "No current job";
651 break;
652 case '-':
653 jobno = psh->curjob;
654 if (jobno != -1)
655 jobno = psh->jobtab[jobno].prev_job;
656 err_msg = "No previous job";
657 break;
658#endif
659 default:
660 goto check_pattern;
661 }
662 } else {
663 struct job *found;
664 check_pattern:
665 found = NULL;
666 for (jp = psh->jobtab, i = psh->njobs ; --i >= 0 ; jp++) {
667 if (!jp->used || jp->nprocs <= 0)
668 continue;
669 if ((name[1] == '?'
670 && strstr(jp->ps[0].cmd, name + 2))
671 || prefix(name + 1, jp->ps[0].cmd)) {
672 if (found) {
673 err_msg = "%s: ambiguous";
674 found = 0;
675 break;
676 }
677 found = jp;
678 }
679 }
680 if (found)
681 return found;
682 }
683
684 } else if (is_number(name)) {
685 pid = number(psh, name);
686 for (jp = psh->jobtab, i = psh->njobs ; --i >= 0 ; jp++) {
687 if (jp->used && jp->nprocs > 0
688 && jp->ps[jp->nprocs - 1].pid == pid)
689 return jp;
690 }
691 }
692
693 if (!psh->jobs_invalid && jobno >= 0 && jobno < psh->njobs) {
694 jp = psh->jobtab + jobno;
695 if (jp->used)
696 return jp;
697 }
698 if (!noerror)
699 error(psh, err_msg, name);
700 return 0;
701}
702
703
704
705/*
706 * Return a new job structure,
707 */
708
709struct job *
710makejob(shinstance *psh, union node *node, int nprocs)
711{
712 int i;
713 struct job *jp;
714
715 if (psh->jobs_invalid) {
716 for (i = psh->njobs, jp = psh->jobtab ; --i >= 0 ; jp++) {
717 if (jp->used)
718 freejob(psh, jp);
719 }
720 psh->jobs_invalid = 0;
721 }
722
723 for (i = psh->njobs, jp = psh->jobtab ; ; jp++) {
724 if (--i < 0) {
725 INTOFF;
726 if (psh->njobs == 0) {
727 psh->jobtab = ckmalloc(psh, 4 * sizeof psh->jobtab[0]);
728 } else {
729 jp = ckmalloc(psh, (psh->njobs + 4) * sizeof psh->jobtab[0]);
730 memcpy(jp, psh->jobtab, psh->njobs * sizeof jp[0]);
731 /* Relocate `ps' pointers */
732 for (i = 0; i < psh->njobs; i++)
733 if (jp[i].ps == &psh->jobtab[i].ps0)
734 jp[i].ps = &jp[i].ps0;
735 ckfree(psh, psh->jobtab);
736 psh->jobtab = jp;
737 }
738 jp = psh->jobtab + psh->njobs;
739 for (i = 4 ; --i >= 0 ; psh->jobtab[psh->njobs++].used = 0);
740 INTON;
741 break;
742 }
743 if (jp->used == 0)
744 break;
745 }
746 INTOFF;
747 jp->state = JOBRUNNING;
748 jp->used = 1;
749 jp->changed = 0;
750 jp->nprocs = 0;
751#if JOBS
752 jp->jobctl = psh->jobctl;
753 set_curjob(psh, jp, 1);
754#endif
755 if (nprocs > 1) {
756 jp->ps = ckmalloc(psh, nprocs * sizeof (struct procstat));
757 } else {
758 jp->ps = &jp->ps0;
759 }
760 INTON;
761 TRACE((psh, "makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
762 jp - psh->jobtab + 1));
763 return jp;
764}
765
766
767/*
768 * Fork off a subshell. If we are doing job control, give the subshell its
769 * own process group. Jp is a job structure that the job is to be added to.
770 * N is the command that will be evaluated by the child. Both jp and n may
771 * be NULL. The mode parameter can be one of the following:
772 * FORK_FG - Fork off a foreground process.
773 * FORK_BG - Fork off a background process.
774 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
775 * process group even if job control is on.
776 *
777 * When job control is turned off, background processes have their standard
778 * input redirected to /dev/null (except for the second and later processes
779 * in a pipeline).
780 */
781
782int
783forkshell(shinstance *psh, struct job *jp, union node *n, int mode)
784{
785 int pid;
786
787 TRACE((psh, "forkshell(%%%d, %p, %d) called\n", jp - psh->jobtab, n, mode));
788 switch ((pid = sh_fork(psh))) {
789 case -1:
790 TRACE((psh, "Fork failed, errno=%d\n", errno));
791 INTON;
792 error(psh, "Cannot fork");
793 return -1; /* won't get here */
794 case 0:
795 forkchild(psh, jp, n, mode, 0);
796 return 0;
797 default:
798 return forkparent(psh, jp, n, mode, pid);
799 }
800}
801
802int
803forkparent(shinstance *psh, struct job *jp, union node *n, int mode, pid_t pid)
804{
805 int pgrp;
806
807 if (psh->rootshell && mode != FORK_NOJOB && mflag(psh)) {
808 if (jp == NULL || jp->nprocs == 0)
809 pgrp = pid;
810 else
811 pgrp = jp->ps[0].pid;
812 /* This can fail because we are doing it in the child also */
813 (void)sh_setpgid(psh, pid, pgrp);
814 }
815 if (mode == FORK_BG)
816 psh->backgndpid = pid; /* set $! */
817 if (jp) {
818 struct procstat *ps = &jp->ps[jp->nprocs++];
819 ps->pid = pid;
820 ps->status = -1;
821 ps->cmd[0] = 0;
822 if (/* iflag && rootshell && */ n)
823 commandtext(psh, ps, n);
824 }
825 TRACE((psh, "In parent shell: child = %d\n", pid));
826 return pid;
827}
828
829void
830forkchild(shinstance *psh, struct job *jp, union node *n, int mode, int vforked)
831{
832 int wasroot;
833 int pgrp;
834 const char *devnull = _PATH_DEVNULL;
835 const char *nullerr = "Can't open %s";
836
837 wasroot = psh->rootshell;
838 TRACE((psh, "Child shell %d\n", sh_getpid(psh)));
839 if (!vforked)
840 psh->rootshell = 0;
841
842 closescript(psh, vforked);
843 clear_traps(psh, vforked);
844#if JOBS
845 if (!vforked)
846 psh->jobctl = 0; /* do job control only in root shell */
847 if (wasroot && mode != FORK_NOJOB && mflag(psh)) {
848 if (jp == NULL || jp->nprocs == 0)
849 pgrp = sh_getpid(psh);
850 else
851 pgrp = jp->ps[0].pid;
852 /* This can fail because we are doing it in the parent also.
853 And we must ignore SIGTTOU at this point or we'll be stopped! */
854 (void)sh_setpgid(psh, 0, pgrp);
855 if (mode == FORK_FG) {
856 if (sh_tcsetpgrp(psh, psh->ttyfd, pgrp) == -1)
857 error(psh, "Cannot set tty process group (%s) at %d",
858 sh_strerror(psh, errno), __LINE__);
859 }
860 setsignal(psh, SIGTSTP, vforked);
861 setsignal(psh, SIGTTOU, vforked);
862 } else if (mode == FORK_BG) {
863 ignoresig(psh, SIGINT, vforked);
864 ignoresig(psh, SIGQUIT, vforked);
865 if ((jp == NULL || jp->nprocs == 0) &&
866 ! fd0_redirected_p(psh)) {
867 shfile_close(&psh->fdtab, 0);
868 if (shfile_open(&psh->fdtab, devnull, O_RDONLY, 0) != 0)
869 error(psh, nullerr, devnull);
870 }
871 }
872#else
873 if (mode == FORK_BG) {
874 ignoresig(psh, SIGINT, vforked);
875 ignoresig(psh, SIGQUIT, vforked);
876 if ((jp == NULL || jp->nprocs == 0) &&
877 ! fd0_redirected_p(psh)) {
878 shfile_close(&psh->fdtab, 0);
879 if (shfile_open(&psh->fdtab, devnull, O_RDONLY, 0) != 0)
880 error(psh, nullerr, devnull);
881 }
882 }
883#endif
884 if (wasroot && iflag(psh)) {
885 setsignal(psh, SIGINT, vforked);
886 setsignal(psh, SIGQUIT, vforked);
887 setsignal(psh, SIGTERM, vforked);
888 }
889
890 if (!vforked)
891 psh->jobs_invalid = 1;
892}
893
894/*
895 * Wait for job to finish.
896 *
897 * Under job control we have the problem that while a child process is
898 * running interrupts generated by the user are sent to the child but not
899 * to the shell. This means that an infinite loop started by an inter-
900 * active user may be hard to kill. With job control turned off, an
901 * interactive user may place an interactive program inside a loop. If
902 * the interactive program catches interrupts, the user doesn't want
903 * these interrupts to also abort the loop. The approach we take here
904 * is to have the shell ignore interrupt signals while waiting for a
905 * forground process to terminate, and then send itself an interrupt
906 * signal if the child process was terminated by an interrupt signal.
907 * Unfortunately, some programs want to do a bit of cleanup and then
908 * exit on interrupt; unless these processes terminate themselves by
909 * sending a signal to themselves (instead of calling exit) they will
910 * confuse this approach.
911 */
912
913int
914waitforjob(shinstance *psh, struct job *jp)
915{
916#if JOBS
917 int mypgrp = sh_getpgrp(psh);
918#endif
919 int status;
920 int st;
921
922 INTOFF;
923 TRACE((psh, "waitforjob(%%%d) called\n", jp - psh->jobtab + 1));
924 while (jp->state == JOBRUNNING) {
925 dowait(psh, 1, jp);
926 }
927#if JOBS
928 if (jp->jobctl) {
929 if (sh_tcsetpgrp(psh, psh->ttyfd, mypgrp) == -1)
930 error(psh, "Cannot set tty process group (%s) at %d",
931 sh_strerror(psh, errno), __LINE__);
932 }
933 if (jp->state == JOBSTOPPED && psh->curjob != jp - psh->jobtab)
934 set_curjob(psh, jp, 2);
935#endif
936 status = jp->ps[jp->nprocs - 1].status;
937 /* convert to 8 bits */
938 if (WIFEXITED(status))
939 st = WEXITSTATUS(status);
940#if JOBS
941 else if (WIFSTOPPED(status))
942 st = WSTOPSIG(status) + 128;
943#endif
944 else
945 st = WTERMSIG(status) + 128;
946 TRACE((psh, "waitforjob: job %d, nproc %d, status %x, st %x\n",
947 jp - psh->jobtab + 1, jp->nprocs, status, st ));
948#if JOBS
949 if (jp->jobctl) {
950 /*
951 * This is truly gross.
952 * If we're doing job control, then we did a TIOCSPGRP which
953 * caused us (the shell) to no longer be in the controlling
954 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
955 * intuit from the subprocess exit status whether a SIGINT
956 * occurred, and if so interrupt ourselves. Yuck. - mycroft
957 */
958 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
959 sh_raise_sigint(psh);/*raise(SIGINT);*/
960 }
961#endif
962 if (! JOBS || jp->state == JOBDONE)
963 freejob(psh, jp);
964 INTON;
965 return st;
966}
967
968
969
970/*
971 * Wait for a process to terminate.
972 */
973
974STATIC int
975dowait(shinstance *psh, int block, struct job *job)
976{
977 int pid;
978 int status;
979 struct procstat *sp;
980 struct job *jp;
981 struct job *thisjob;
982 int done;
983 int stopped;
984
985 TRACE((psh, "dowait(%d) called\n", block));
986 do {
987 pid = waitproc(psh, block, job, &status);
988 TRACE((psh, "wait returns pid %d, status %d\n", pid, status));
989 } while (pid == -1 && errno == EINTR && psh->gotsig[SIGINT - 1] == 0);
990 if (pid <= 0)
991 return pid;
992 INTOFF;
993 thisjob = NULL;
994 for (jp = psh->jobtab ; jp < psh->jobtab + psh->njobs ; jp++) {
995 if (jp->used) {
996 done = 1;
997 stopped = 1;
998 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
999 if (sp->pid == -1)
1000 continue;
1001 if (sp->pid == pid) {
1002 TRACE((psh, "Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp - psh->jobtab + 1, pid, sp->status, status));
1003 sp->status = status;
1004 thisjob = jp;
1005 }
1006 if (sp->status == -1)
1007 stopped = 0;
1008 else if (WIFSTOPPED(sp->status))
1009 done = 0;
1010 }
1011 if (stopped) { /* stopped or done */
1012 int state = done ? JOBDONE : JOBSTOPPED;
1013 if (jp->state != state) {
1014 TRACE((psh, "Job %d: changing state from %d to %d\n", jp - psh->jobtab + 1, jp->state, state));
1015 jp->state = state;
1016#if JOBS
1017 if (done)
1018 set_curjob(psh, jp, 0);
1019#endif
1020 }
1021 }
1022 }
1023 }
1024
1025 if (thisjob && thisjob->state != JOBRUNNING) {
1026 int mode = 0;
1027 if (!psh->rootshell || !iflag(psh))
1028 mode = SHOW_SIGNALLED;
1029 if (job == thisjob)
1030 mode = SHOW_SIGNALLED | SHOW_NO_FREE;
1031 if (mode)
1032 showjob(psh, psh->out2, thisjob, mode);
1033 else {
1034 TRACE((psh, "Not printing status, rootshell=%d, job=%p\n",
1035 psh->rootshell, job));
1036 thisjob->changed = 1;
1037 }
1038 }
1039
1040 INTON;
1041 return pid;
1042}
1043
1044
1045
1046/*
1047 * Do a wait system call. If job control is compiled in, we accept
1048 * stopped processes. If block is zero, we return a value of zero
1049 * rather than blocking.
1050 */
1051STATIC int
1052waitproc(shinstance *psh, int block, struct job *jp, int *status)
1053{
1054 int flags = 0;
1055
1056#if JOBS
1057 if (jp != NULL && jp->jobctl)
1058 flags |= WUNTRACED;
1059#endif
1060 if (block == 0)
1061 flags |= WNOHANG;
1062 return sh_waitpid(psh, -1, status, flags);
1063}
1064
1065/*
1066 * return 1 if there are stopped jobs, otherwise 0
1067 */
1068//int job_warning = 0;
1069int
1070stoppedjobs(shinstance *psh)
1071{
1072 int jobno;
1073 struct job *jp;
1074
1075 if (psh->job_warning || psh->jobs_invalid)
1076 return (0);
1077 for (jobno = 1, jp = psh->jobtab; jobno <= psh->njobs; jobno++, jp++) {
1078 if (jp->used == 0)
1079 continue;
1080 if (jp->state == JOBSTOPPED) {
1081 out2str(psh, "You have stopped jobs.\n");
1082 psh->job_warning = 2;
1083 return (1);
1084 }
1085 }
1086
1087 return (0);
1088}
1089
1090/*
1091 * Return a string identifying a command (to be printed by the
1092 * jobs command).
1093 */
1094
1095//STATIC char *cmdnextc;
1096//STATIC int cmdnleft;
1097
1098void
1099commandtext(shinstance *psh, struct procstat *ps, union node *n)
1100{
1101 int len;
1102
1103 psh->cmdnextc = ps->cmd;
1104 if (iflag(psh) || mflag(psh) || sizeof(ps->cmd) < 100)
1105 len = sizeof(ps->cmd);
1106 else
1107 len = sizeof(ps->cmd) / 10;
1108 psh->cmdnleft = len;
1109 cmdtxt(psh, n);
1110 if (psh->cmdnleft <= 0) {
1111 char *p = ps->cmd + len - 4;
1112 p[0] = '.';
1113 p[1] = '.';
1114 p[2] = '.';
1115 p[3] = 0;
1116 } else
1117 *psh->cmdnextc = '\0';
1118 TRACE((psh, "commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n",
1119 ps->cmd, psh->cmdnextc, psh->cmdnleft, ps->cmd));
1120}
1121
1122
1123STATIC void
1124cmdtxt(shinstance *psh, union node *n)
1125{
1126 union node *np;
1127 struct nodelist *lp;
1128 const char *p;
1129 int i;
1130 char s[2];
1131
1132 if (n == NULL || psh->cmdnleft <= 0)
1133 return;
1134 switch (n->type) {
1135 case NSEMI:
1136 cmdtxt(psh, n->nbinary.ch1);
1137 cmdputs(psh, "; ");
1138 cmdtxt(psh, n->nbinary.ch2);
1139 break;
1140 case NAND:
1141 cmdtxt(psh, n->nbinary.ch1);
1142 cmdputs(psh, " && ");
1143 cmdtxt(psh, n->nbinary.ch2);
1144 break;
1145 case NOR:
1146 cmdtxt(psh, n->nbinary.ch1);
1147 cmdputs(psh, " || ");
1148 cmdtxt(psh, n->nbinary.ch2);
1149 break;
1150 case NPIPE:
1151 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1152 cmdtxt(psh, lp->n);
1153 if (lp->next)
1154 cmdputs(psh, " | ");
1155 }
1156 break;
1157 case NSUBSHELL:
1158 cmdputs(psh, "(");
1159 cmdtxt(psh, n->nredir.n);
1160 cmdputs(psh, ")");
1161 break;
1162 case NREDIR:
1163 case NBACKGND:
1164 cmdtxt(psh, n->nredir.n);
1165 break;
1166 case NIF:
1167 cmdputs(psh, "if ");
1168 cmdtxt(psh, n->nif.test);
1169 cmdputs(psh, "; then ");
1170 cmdtxt(psh, n->nif.ifpart);
1171 if (n->nif.elsepart) {
1172 cmdputs(psh, "; else ");
1173 cmdtxt(psh, n->nif.elsepart);
1174 }
1175 cmdputs(psh, "; fi");
1176 break;
1177 case NWHILE:
1178 cmdputs(psh, "while ");
1179 goto until;
1180 case NUNTIL:
1181 cmdputs(psh, "until ");
1182until:
1183 cmdtxt(psh, n->nbinary.ch1);
1184 cmdputs(psh, "; do ");
1185 cmdtxt(psh, n->nbinary.ch2);
1186 cmdputs(psh, "; done");
1187 break;
1188 case NFOR:
1189 cmdputs(psh, "for ");
1190 cmdputs(psh, n->nfor.var);
1191 cmdputs(psh, " in ");
1192 cmdlist(psh, n->nfor.args, 1);
1193 cmdputs(psh, "; do ");
1194 cmdtxt(psh, n->nfor.body);
1195 cmdputs(psh, "; done");
1196 break;
1197 case NCASE:
1198 cmdputs(psh, "case ");
1199 cmdputs(psh, n->ncase.expr->narg.text);
1200 cmdputs(psh, " in ");
1201 for (np = n->ncase.cases; np; np = np->nclist.next) {
1202 cmdtxt(psh, np->nclist.pattern);
1203 cmdputs(psh, ") ");
1204 cmdtxt(psh, np->nclist.body);
1205 cmdputs(psh, ";; ");
1206 }
1207 cmdputs(psh, "esac");
1208 break;
1209 case NDEFUN:
1210 cmdputs(psh, n->narg.text);
1211 cmdputs(psh, "() { ... }");
1212 break;
1213 case NCMD:
1214 cmdlist(psh, n->ncmd.args, 1);
1215 cmdlist(psh, n->ncmd.redirect, 0);
1216 break;
1217 case NARG:
1218 cmdputs(psh, n->narg.text);
1219 break;
1220 case NTO:
1221 p = ">"; i = 1; goto redir;
1222 case NCLOBBER:
1223 p = ">|"; i = 1; goto redir;
1224 case NAPPEND:
1225 p = ">>"; i = 1; goto redir;
1226 case NTOFD:
1227 p = ">&"; i = 1; goto redir;
1228 case NFROM:
1229 p = "<"; i = 0; goto redir;
1230 case NFROMFD:
1231 p = "<&"; i = 0; goto redir;
1232 case NFROMTO:
1233 p = "<>"; i = 0; goto redir;
1234redir:
1235 if (n->nfile.fd != i) {
1236 s[0] = n->nfile.fd + '0';
1237 s[1] = '\0';
1238 cmdputs(psh, s);
1239 }
1240 cmdputs(psh, p);
1241 if (n->type == NTOFD || n->type == NFROMFD) {
1242 s[0] = n->ndup.dupfd + '0';
1243 s[1] = '\0';
1244 cmdputs(psh, s);
1245 } else {
1246 cmdtxt(psh, n->nfile.fname);
1247 }
1248 break;
1249 case NHERE:
1250 case NXHERE:
1251 cmdputs(psh, "<<...");
1252 break;
1253 default:
1254 cmdputs(psh, "???");
1255 break;
1256 }
1257}
1258
1259STATIC void
1260cmdlist(shinstance *psh, union node *np, int sep)
1261{
1262 for (; np; np = np->narg.next) {
1263 if (!sep)
1264 cmdputs(psh, " ");
1265 cmdtxt(psh, np);
1266 if (sep && np->narg.next)
1267 cmdputs(psh, " ");
1268 }
1269}
1270
1271
1272STATIC void
1273cmdputs(shinstance *psh, const char *s)
1274{
1275 const char *p, *str = 0;
1276 char c, cc[2] = " ";
1277 char *nextc;
1278 int nleft;
1279 int subtype = 0;
1280 int quoted = 0;
1281 static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
1282 "#", "##", "%", "%%" };
1283
1284 p = s;
1285 nextc = psh->cmdnextc;
1286 nleft = psh->cmdnleft;
1287 while (nleft > 0 && (c = *p++) != 0) {
1288 switch (c) {
1289 case CTLESC:
1290 c = *p++;
1291 break;
1292 case CTLVAR:
1293 subtype = *p++;
1294 if ((subtype & VSTYPE) == VSLENGTH)
1295 str = "${#";
1296 else
1297 str = "${";
1298 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
1299 quoted ^= 1;
1300 c = '"';
1301 } else
1302 c = *str++;
1303 break;
1304 case CTLENDVAR:
1305 if (quoted & 1) {
1306 c = '"';
1307 str = "}";
1308 } else
1309 c = '}';
1310 quoted >>= 1;
1311 subtype = 0;
1312 break;
1313 case CTLBACKQ:
1314 c = '$';
1315 str = "(...)";
1316 break;
1317 case CTLBACKQ+CTLQUOTE:
1318 c = '"';
1319 str = "$(...)\"";
1320 break;
1321 case CTLARI:
1322 c = '$';
1323 str = "((";
1324 break;
1325 case CTLENDARI:
1326 c = ')';
1327 str = ")";
1328 break;
1329 case CTLQUOTEMARK:
1330 quoted ^= 1;
1331 c = '"';
1332 break;
1333 case '=':
1334 if (subtype == 0)
1335 break;
1336 str = vstype[subtype & VSTYPE];
1337 if (subtype & VSNUL)
1338 c = ':';
1339 else
1340 c = *str++;
1341 if (c != '}')
1342 quoted <<= 1;
1343 break;
1344 case '\'':
1345 case '\\':
1346 case '"':
1347 case '$':
1348 /* These can only happen inside quotes */
1349 cc[0] = c;
1350 str = cc;
1351 c = '\\';
1352 break;
1353 default:
1354 break;
1355 }
1356 do {
1357 *nextc++ = c;
1358 } while (--nleft > 0 && str && (c = *str++));
1359 str = 0;
1360 }
1361 if ((quoted & 1) && nleft) {
1362 *nextc++ = '"';
1363 nleft--;
1364 }
1365 psh->cmdnleft = nleft;
1366 psh->cmdnextc = nextc;
1367}
Note: See TracBrowser for help on using the repository browser.