VirtualBox

source: kBuild/trunk/src/kash/jobs.c@ 2386

Last change on this file since 2386 was 2290, checked in by bird, 16 years ago

kash: malloc/free/friends gets a psh.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 31.0 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 strerror(errno), __LINE__);
153 if (sh_tcsetpgrp(psh, psh->ttyfd, psh->rootpid) == -1)
154 error(psh, "Cannot set tty process group (%s) at %d",
155 strerror(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 strerror(errno), __LINE__);
160 if (sh_tcsetpgrp(psh, psh->ttyfd, psh->initialpgrp) == -1)
161 error(psh, "Cannot set tty process group (%s) at %d",
162 strerror(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 strerror(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)", strerror(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#if JOBS
393 if (WIFSTOPPED(ps->status))
394 st = WSTOPSIG(ps->status);
395 else /* WIFSIGNALED(ps->status) */
396#endif
397 st = WTERMSIG(ps->status);
398 st &= 0x7f;
399 if (st < NSIG && sys_siglist[st])
400 scopyn(sys_siglist[st], s + col, 32);
401 else
402 fmtstr(s + col, 16, "Signal %d", st);
403 if (WCOREDUMP(ps->status)) {
404 col += strlen(s + col);
405 scopyn(" (core dumped)", s + col, 64 - col);
406 }
407 }
408 col += strlen(s + col);
409 outstr(s, out);
410 do {
411 outc(' ', out);
412 col++;
413 } while (col < 30);
414 outstr(ps->cmd, out);
415 if (mode & SHOW_MULTILINE) {
416 if (procno > 0) {
417 outc(' ', out);
418 outc('|', out);
419 }
420 } else {
421 while (--procno >= 0)
422 outfmt(out, " | %s", (++ps)->cmd );
423 }
424 outc('\n', out);
425 }
426 flushout(out);
427 jp->changed = 0;
428 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
429 freejob(psh, jp);
430}
431
432
433int
434jobscmd(shinstance *psh, int argc, char **argv)
435{
436 int mode, m;
437 int sv = psh->jobs_invalid;
438
439 psh->jobs_invalid = 0;
440 mode = 0;
441 while ((m = nextopt(psh, "lp")))
442 if (m == 'l')
443 mode = SHOW_PID;
444 else
445 mode = SHOW_PGID;
446 if (*psh->argptr)
447 do
448 showjob(psh, psh->out1, getjob(psh, *psh->argptr,0), mode);
449 while (*++psh->argptr);
450 else
451 showjobs(psh, psh->out1, mode);
452 psh->jobs_invalid = sv;
453 return 0;
454}
455
456
457/*
458 * Print a list of jobs. If "change" is nonzero, only print jobs whose
459 * statuses have changed since the last call to showjobs.
460 *
461 * If the shell is interrupted in the process of creating a job, the
462 * result may be a job structure containing zero processes. Such structures
463 * will be freed here.
464 */
465
466void
467showjobs(shinstance *psh, struct output *out, int mode)
468{
469 int jobno;
470 struct job *jp;
471 int silent = 0, gotpid;
472
473 TRACE((psh, "showjobs(%x) called\n", mode));
474
475 /* If not even one one job changed, there is nothing to do */
476 gotpid = dowait(psh, 0, NULL);
477 while (dowait(psh, 0, NULL) > 0)
478 continue;
479#ifdef JOBS
480 /*
481 * Check if we are not in our foreground group, and if not
482 * put us in it.
483 */
484 if (mflag(psh) && gotpid != -1 && sh_tcgetpgrp(psh, psh->ttyfd) != sh_getpid(psh)) {
485 if (sh_tcsetpgrp(psh, psh->ttyfd, sh_getpid(psh)) == -1)
486 error(psh, "Cannot set tty process group (%s) at %d",
487 strerror(errno), __LINE__);
488 TRACE((psh, "repaired tty process group\n"));
489 silent = 1;
490 }
491#endif
492 if (psh->jobs_invalid)
493 return;
494
495 for (jobno = 1, jp = psh->jobtab ; jobno <= psh->njobs ; jobno++, jp++) {
496 if (!jp->used)
497 continue;
498 if (jp->nprocs == 0) {
499 freejob(psh, jp);
500 continue;
501 }
502 if ((mode & SHOW_CHANGED) && !jp->changed)
503 continue;
504 if (silent && jp->changed) {
505 jp->changed = 0;
506 continue;
507 }
508 showjob(psh, out, jp, mode);
509 }
510}
511
512/*
513 * Mark a job structure as unused.
514 */
515
516STATIC void
517freejob(shinstance *psh, struct job *jp)
518{
519 INTOFF;
520 if (jp->ps != &jp->ps0) {
521 ckfree(psh, jp->ps);
522 jp->ps = &jp->ps0;
523 }
524 jp->nprocs = 0;
525 jp->used = 0;
526#if JOBS
527 set_curjob(psh, jp, 0);
528#endif
529 INTON;
530}
531
532
533
534int
535waitcmd(shinstance *psh, int argc, char **argv)
536{
537 struct job *job;
538 int status, retval;
539 struct job *jp;
540
541 nextopt(psh, "");
542
543 if (!*psh->argptr) {
544 /* wait for all jobs */
545 jp = psh->jobtab;
546 if (psh->jobs_invalid)
547 return 0;
548 for (;;) {
549 if (jp >= psh->jobtab + psh->njobs) {
550 /* no running procs */
551 return 0;
552 }
553 if (!jp->used || jp->state != JOBRUNNING) {
554 jp++;
555 continue;
556 }
557 if (dowait(psh, 1, (struct job *)NULL) == -1)
558 return 128 + SIGINT;
559 jp = psh->jobtab;
560 }
561 }
562
563 retval = 127; /* XXXGCC: -Wuninitialized */
564 for (; *psh->argptr; psh->argptr++) {
565 job = getjob(psh, *psh->argptr, 1);
566 if (!job) {
567 retval = 127;
568 continue;
569 }
570 /* loop until process terminated or stopped */
571 while (job->state == JOBRUNNING) {
572 if (dowait(psh, 1, (struct job *)NULL) == -1)
573 return 128 + SIGINT;
574 }
575 status = job->ps[job->nprocs].status;
576 if (WIFEXITED(status))
577 retval = WEXITSTATUS(status);
578#if JOBS
579 else if (WIFSTOPPED(status))
580 retval = WSTOPSIG(status) + 128;
581#endif
582 else {
583 /* XXX: limits number of signals */
584 retval = WTERMSIG(status) + 128;
585 }
586 if (!iflag(psh))
587 freejob(psh, job);
588 }
589 return retval;
590}
591
592
593
594int
595jobidcmd(shinstance *psh, int argc, char **argv)
596{
597 struct job *jp;
598 int i;
599
600 nextopt(psh, "");
601 jp = getjob(psh, *psh->argptr, 0);
602 for (i = 0 ; i < jp->nprocs ; ) {
603 out1fmt(psh, "%ld", (long)jp->ps[i].pid);
604 out1c(psh, ++i < jp->nprocs ? ' ' : '\n');
605 }
606 return 0;
607}
608
609int
610getjobpgrp(shinstance *psh, const char *name)
611{
612 struct job *jp;
613
614 jp = getjob(psh, name, 1);
615 if (jp == 0)
616 return 0;
617 return -jp->ps[0].pid;
618}
619
620/*
621 * Convert a job name to a job structure.
622 */
623
624STATIC struct job *
625getjob(shinstance *psh, const char *name, int noerror)
626{
627 int jobno = -1;
628 struct job *jp;
629 int pid;
630 int i;
631 const char *err_msg = "No such job: %s";
632
633 if (name == NULL) {
634#if JOBS
635 jobno = psh->curjob;
636#endif
637 err_msg = "No current job";
638 } else if (name[0] == '%') {
639 if (is_number(name + 1)) {
640 jobno = number(psh, name + 1) - 1;
641 } else if (!name[2]) {
642 switch (name[1]) {
643#if JOBS
644 case 0:
645 case '+':
646 case '%':
647 jobno = psh->curjob;
648 err_msg = "No current job";
649 break;
650 case '-':
651 jobno = psh->curjob;
652 if (jobno != -1)
653 jobno = psh->jobtab[jobno].prev_job;
654 err_msg = "No previous job";
655 break;
656#endif
657 default:
658 goto check_pattern;
659 }
660 } else {
661 struct job *found;
662 check_pattern:
663 found = NULL;
664 for (jp = psh->jobtab, i = psh->njobs ; --i >= 0 ; jp++) {
665 if (!jp->used || jp->nprocs <= 0)
666 continue;
667 if ((name[1] == '?'
668 && strstr(jp->ps[0].cmd, name + 2))
669 || prefix(name + 1, jp->ps[0].cmd)) {
670 if (found) {
671 err_msg = "%s: ambiguous";
672 found = 0;
673 break;
674 }
675 found = jp;
676 }
677 }
678 if (found)
679 return found;
680 }
681
682 } else if (is_number(name)) {
683 pid = number(psh, name);
684 for (jp = psh->jobtab, i = psh->njobs ; --i >= 0 ; jp++) {
685 if (jp->used && jp->nprocs > 0
686 && jp->ps[jp->nprocs - 1].pid == pid)
687 return jp;
688 }
689 }
690
691 if (!psh->jobs_invalid && jobno >= 0 && jobno < psh->njobs) {
692 jp = psh->jobtab + jobno;
693 if (jp->used)
694 return jp;
695 }
696 if (!noerror)
697 error(psh, err_msg, name);
698 return 0;
699}
700
701
702
703/*
704 * Return a new job structure,
705 */
706
707struct job *
708makejob(shinstance *psh, union node *node, int nprocs)
709{
710 int i;
711 struct job *jp;
712
713 if (psh->jobs_invalid) {
714 for (i = psh->njobs, jp = psh->jobtab ; --i >= 0 ; jp++) {
715 if (jp->used)
716 freejob(psh, jp);
717 }
718 psh->jobs_invalid = 0;
719 }
720
721 for (i = psh->njobs, jp = psh->jobtab ; ; jp++) {
722 if (--i < 0) {
723 INTOFF;
724 if (psh->njobs == 0) {
725 psh->jobtab = ckmalloc(psh, 4 * sizeof psh->jobtab[0]);
726 } else {
727 jp = ckmalloc(psh, (psh->njobs + 4) * sizeof psh->jobtab[0]);
728 memcpy(jp, psh->jobtab, psh->njobs * sizeof jp[0]);
729 /* Relocate `ps' pointers */
730 for (i = 0; i < psh->njobs; i++)
731 if (jp[i].ps == &psh->jobtab[i].ps0)
732 jp[i].ps = &jp[i].ps0;
733 ckfree(psh, psh->jobtab);
734 psh->jobtab = jp;
735 }
736 jp = psh->jobtab + psh->njobs;
737 for (i = 4 ; --i >= 0 ; psh->jobtab[psh->njobs++].used = 0);
738 INTON;
739 break;
740 }
741 if (jp->used == 0)
742 break;
743 }
744 INTOFF;
745 jp->state = JOBRUNNING;
746 jp->used = 1;
747 jp->changed = 0;
748 jp->nprocs = 0;
749#if JOBS
750 jp->jobctl = psh->jobctl;
751 set_curjob(psh, jp, 1);
752#endif
753 if (nprocs > 1) {
754 jp->ps = ckmalloc(psh, nprocs * sizeof (struct procstat));
755 } else {
756 jp->ps = &jp->ps0;
757 }
758 INTON;
759 TRACE((psh, "makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
760 jp - psh->jobtab + 1));
761 return jp;
762}
763
764
765/*
766 * Fork off a subshell. If we are doing job control, give the subshell its
767 * own process group. Jp is a job structure that the job is to be added to.
768 * N is the command that will be evaluated by the child. Both jp and n may
769 * be NULL. The mode parameter can be one of the following:
770 * FORK_FG - Fork off a foreground process.
771 * FORK_BG - Fork off a background process.
772 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
773 * process group even if job control is on.
774 *
775 * When job control is turned off, background processes have their standard
776 * input redirected to /dev/null (except for the second and later processes
777 * in a pipeline).
778 */
779
780int
781forkshell(shinstance *psh, struct job *jp, union node *n, int mode)
782{
783 int pid;
784
785 TRACE((psh, "forkshell(%%%d, %p, %d) called\n", jp - psh->jobtab, n, mode));
786 switch ((pid = sh_fork(psh))) {
787 case -1:
788 TRACE((psh, "Fork failed, errno=%d\n", errno));
789 INTON;
790 error(psh, "Cannot fork");
791 return -1; /* won't get here */
792 case 0:
793 forkchild(psh, jp, n, mode, 0);
794 return 0;
795 default:
796 return forkparent(psh, jp, n, mode, pid);
797 }
798}
799
800int
801forkparent(shinstance *psh, struct job *jp, union node *n, int mode, pid_t pid)
802{
803 int pgrp;
804
805 if (psh->rootshell && mode != FORK_NOJOB && mflag(psh)) {
806 if (jp == NULL || jp->nprocs == 0)
807 pgrp = pid;
808 else
809 pgrp = jp->ps[0].pid;
810 /* This can fail because we are doing it in the child also */
811 (void)sh_setpgid(psh, pid, pgrp);
812 }
813 if (mode == FORK_BG)
814 psh->backgndpid = pid; /* set $! */
815 if (jp) {
816 struct procstat *ps = &jp->ps[jp->nprocs++];
817 ps->pid = pid;
818 ps->status = -1;
819 ps->cmd[0] = 0;
820 if (/* iflag && rootshell && */ n)
821 commandtext(psh, ps, n);
822 }
823 TRACE((psh, "In parent shell: child = %d\n", pid));
824 return pid;
825}
826
827void
828forkchild(shinstance *psh, struct job *jp, union node *n, int mode, int vforked)
829{
830 int wasroot;
831 int pgrp;
832 const char *devnull = _PATH_DEVNULL;
833 const char *nullerr = "Can't open %s";
834
835 wasroot = psh->rootshell;
836 TRACE((psh, "Child shell %d\n", sh_getpid(psh)));
837 if (!vforked)
838 psh->rootshell = 0;
839
840 closescript(psh, vforked);
841 clear_traps(psh, vforked);
842#if JOBS
843 if (!vforked)
844 psh->jobctl = 0; /* do job control only in root shell */
845 if (wasroot && mode != FORK_NOJOB && mflag(psh)) {
846 if (jp == NULL || jp->nprocs == 0)
847 pgrp = sh_getpid(psh);
848 else
849 pgrp = jp->ps[0].pid;
850 /* This can fail because we are doing it in the parent also.
851 And we must ignore SIGTTOU at this point or we'll be stopped! */
852 (void)sh_setpgid(psh, 0, pgrp);
853 if (mode == FORK_FG) {
854 if (sh_tcsetpgrp(psh, psh->ttyfd, pgrp) == -1)
855 error(psh, "Cannot set tty process group (%s) at %d",
856 strerror(errno), __LINE__);
857 }
858 setsignal(psh, SIGTSTP, vforked);
859 setsignal(psh, SIGTTOU, vforked);
860 } else if (mode == FORK_BG) {
861 ignoresig(psh, SIGINT, vforked);
862 ignoresig(psh, SIGQUIT, vforked);
863 if ((jp == NULL || jp->nprocs == 0) &&
864 ! fd0_redirected_p(psh)) {
865 shfile_close(&psh->fdtab, 0);
866 if (shfile_open(&psh->fdtab, devnull, O_RDONLY, 0) != 0)
867 error(psh, nullerr, devnull);
868 }
869 }
870#else
871 if (mode == FORK_BG) {
872 ignoresig(psh, SIGINT, vforked);
873 ignoresig(psh, SIGQUIT, vforked);
874 if ((jp == NULL || jp->nprocs == 0) &&
875 ! fd0_redirected_p(psh)) {
876 shfile_close(&psh->fdtab, 0);
877 if (shfile_open(&psh->fdtab, devnull, O_RDONLY, 0) != 0)
878 error(psh, nullerr, devnull);
879 }
880 }
881#endif
882 if (wasroot && iflag(psh)) {
883 setsignal(psh, SIGINT, vforked);
884 setsignal(psh, SIGQUIT, vforked);
885 setsignal(psh, SIGTERM, vforked);
886 }
887
888 if (!vforked)
889 psh->jobs_invalid = 1;
890}
891
892/*
893 * Wait for job to finish.
894 *
895 * Under job control we have the problem that while a child process is
896 * running interrupts generated by the user are sent to the child but not
897 * to the shell. This means that an infinite loop started by an inter-
898 * active user may be hard to kill. With job control turned off, an
899 * interactive user may place an interactive program inside a loop. If
900 * the interactive program catches interrupts, the user doesn't want
901 * these interrupts to also abort the loop. The approach we take here
902 * is to have the shell ignore interrupt signals while waiting for a
903 * forground process to terminate, and then send itself an interrupt
904 * signal if the child process was terminated by an interrupt signal.
905 * Unfortunately, some programs want to do a bit of cleanup and then
906 * exit on interrupt; unless these processes terminate themselves by
907 * sending a signal to themselves (instead of calling exit) they will
908 * confuse this approach.
909 */
910
911int
912waitforjob(shinstance *psh, struct job *jp)
913{
914#if JOBS
915 int mypgrp = sh_getpgrp(psh);
916#endif
917 int status;
918 int st;
919
920 INTOFF;
921 TRACE((psh, "waitforjob(%%%d) called\n", jp - psh->jobtab + 1));
922 while (jp->state == JOBRUNNING) {
923 dowait(psh, 1, jp);
924 }
925#if JOBS
926 if (jp->jobctl) {
927 if (sh_tcsetpgrp(psh, psh->ttyfd, mypgrp) == -1)
928 error(psh, "Cannot set tty process group (%s) at %d",
929 strerror(errno), __LINE__);
930 }
931 if (jp->state == JOBSTOPPED && psh->curjob != jp - psh->jobtab)
932 set_curjob(psh, jp, 2);
933#endif
934 status = jp->ps[jp->nprocs - 1].status;
935 /* convert to 8 bits */
936 if (WIFEXITED(status))
937 st = WEXITSTATUS(status);
938#if JOBS
939 else if (WIFSTOPPED(status))
940 st = WSTOPSIG(status) + 128;
941#endif
942 else
943 st = WTERMSIG(status) + 128;
944 TRACE((psh, "waitforjob: job %d, nproc %d, status %x, st %x\n",
945 jp - psh->jobtab + 1, jp->nprocs, status, st ));
946#if JOBS
947 if (jp->jobctl) {
948 /*
949 * This is truly gross.
950 * If we're doing job control, then we did a TIOCSPGRP which
951 * caused us (the shell) to no longer be in the controlling
952 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
953 * intuit from the subprocess exit status whether a SIGINT
954 * occurred, and if so interrupt ourselves. Yuck. - mycroft
955 */
956 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
957 sh_raise_sigint(psh);/*raise(SIGINT);*/
958 }
959#endif
960 if (! JOBS || jp->state == JOBDONE)
961 freejob(psh, jp);
962 INTON;
963 return st;
964}
965
966
967
968/*
969 * Wait for a process to terminate.
970 */
971
972STATIC int
973dowait(shinstance *psh, int block, struct job *job)
974{
975 int pid;
976 int status;
977 struct procstat *sp;
978 struct job *jp;
979 struct job *thisjob;
980 int done;
981 int stopped;
982
983 TRACE((psh, "dowait(%d) called\n", block));
984 do {
985 pid = waitproc(psh, block, job, &status);
986 TRACE((psh, "wait returns pid %d, status %d\n", pid, status));
987 } while (pid == -1 && errno == EINTR && psh->gotsig[SIGINT - 1] == 0);
988 if (pid <= 0)
989 return pid;
990 INTOFF;
991 thisjob = NULL;
992 for (jp = psh->jobtab ; jp < psh->jobtab + psh->njobs ; jp++) {
993 if (jp->used) {
994 done = 1;
995 stopped = 1;
996 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
997 if (sp->pid == -1)
998 continue;
999 if (sp->pid == pid) {
1000 TRACE((psh, "Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp - psh->jobtab + 1, pid, sp->status, status));
1001 sp->status = status;
1002 thisjob = jp;
1003 }
1004 if (sp->status == -1)
1005 stopped = 0;
1006 else if (WIFSTOPPED(sp->status))
1007 done = 0;
1008 }
1009 if (stopped) { /* stopped or done */
1010 int state = done ? JOBDONE : JOBSTOPPED;
1011 if (jp->state != state) {
1012 TRACE((psh, "Job %d: changing state from %d to %d\n", jp - psh->jobtab + 1, jp->state, state));
1013 jp->state = state;
1014#if JOBS
1015 if (done)
1016 set_curjob(psh, jp, 0);
1017#endif
1018 }
1019 }
1020 }
1021 }
1022
1023 if (thisjob && thisjob->state != JOBRUNNING) {
1024 int mode = 0;
1025 if (!psh->rootshell || !iflag(psh))
1026 mode = SHOW_SIGNALLED;
1027 if (job == thisjob)
1028 mode = SHOW_SIGNALLED | SHOW_NO_FREE;
1029 if (mode)
1030 showjob(psh, psh->out2, thisjob, mode);
1031 else {
1032 TRACE((psh, "Not printing status, rootshell=%d, job=%p\n",
1033 psh->rootshell, job));
1034 thisjob->changed = 1;
1035 }
1036 }
1037
1038 INTON;
1039 return pid;
1040}
1041
1042
1043
1044/*
1045 * Do a wait system call. If job control is compiled in, we accept
1046 * stopped processes. If block is zero, we return a value of zero
1047 * rather than blocking.
1048 */
1049STATIC int
1050waitproc(shinstance *psh, int block, struct job *jp, int *status)
1051{
1052 int flags = 0;
1053
1054#if JOBS
1055 if (jp != NULL && jp->jobctl)
1056 flags |= WUNTRACED;
1057#endif
1058 if (block == 0)
1059 flags |= WNOHANG;
1060 return sh_waitpid(psh, -1, status, flags);
1061}
1062
1063/*
1064 * return 1 if there are stopped jobs, otherwise 0
1065 */
1066//int job_warning = 0;
1067int
1068stoppedjobs(shinstance *psh)
1069{
1070 int jobno;
1071 struct job *jp;
1072
1073 if (psh->job_warning || psh->jobs_invalid)
1074 return (0);
1075 for (jobno = 1, jp = psh->jobtab; jobno <= psh->njobs; jobno++, jp++) {
1076 if (jp->used == 0)
1077 continue;
1078 if (jp->state == JOBSTOPPED) {
1079 out2str(psh, "You have stopped jobs.\n");
1080 psh->job_warning = 2;
1081 return (1);
1082 }
1083 }
1084
1085 return (0);
1086}
1087
1088/*
1089 * Return a string identifying a command (to be printed by the
1090 * jobs command).
1091 */
1092
1093//STATIC char *cmdnextc;
1094//STATIC int cmdnleft;
1095
1096void
1097commandtext(shinstance *psh, struct procstat *ps, union node *n)
1098{
1099 int len;
1100
1101 psh->cmdnextc = ps->cmd;
1102 if (iflag(psh) || mflag(psh) || sizeof(ps->cmd) < 100)
1103 len = sizeof(ps->cmd);
1104 else
1105 len = sizeof(ps->cmd) / 10;
1106 psh->cmdnleft = len;
1107 cmdtxt(psh, n);
1108 if (psh->cmdnleft <= 0) {
1109 char *p = ps->cmd + len - 4;
1110 p[0] = '.';
1111 p[1] = '.';
1112 p[2] = '.';
1113 p[3] = 0;
1114 } else
1115 *psh->cmdnextc = '\0';
1116 TRACE((psh, "commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n",
1117 ps->cmd, psh->cmdnextc, psh->cmdnleft, ps->cmd));
1118}
1119
1120
1121STATIC void
1122cmdtxt(shinstance *psh, union node *n)
1123{
1124 union node *np;
1125 struct nodelist *lp;
1126 const char *p;
1127 int i;
1128 char s[2];
1129
1130 if (n == NULL || psh->cmdnleft <= 0)
1131 return;
1132 switch (n->type) {
1133 case NSEMI:
1134 cmdtxt(psh, n->nbinary.ch1);
1135 cmdputs(psh, "; ");
1136 cmdtxt(psh, n->nbinary.ch2);
1137 break;
1138 case NAND:
1139 cmdtxt(psh, n->nbinary.ch1);
1140 cmdputs(psh, " && ");
1141 cmdtxt(psh, n->nbinary.ch2);
1142 break;
1143 case NOR:
1144 cmdtxt(psh, n->nbinary.ch1);
1145 cmdputs(psh, " || ");
1146 cmdtxt(psh, n->nbinary.ch2);
1147 break;
1148 case NPIPE:
1149 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1150 cmdtxt(psh, lp->n);
1151 if (lp->next)
1152 cmdputs(psh, " | ");
1153 }
1154 break;
1155 case NSUBSHELL:
1156 cmdputs(psh, "(");
1157 cmdtxt(psh, n->nredir.n);
1158 cmdputs(psh, ")");
1159 break;
1160 case NREDIR:
1161 case NBACKGND:
1162 cmdtxt(psh, n->nredir.n);
1163 break;
1164 case NIF:
1165 cmdputs(psh, "if ");
1166 cmdtxt(psh, n->nif.test);
1167 cmdputs(psh, "; then ");
1168 cmdtxt(psh, n->nif.ifpart);
1169 if (n->nif.elsepart) {
1170 cmdputs(psh, "; else ");
1171 cmdtxt(psh, n->nif.elsepart);
1172 }
1173 cmdputs(psh, "; fi");
1174 break;
1175 case NWHILE:
1176 cmdputs(psh, "while ");
1177 goto until;
1178 case NUNTIL:
1179 cmdputs(psh, "until ");
1180until:
1181 cmdtxt(psh, n->nbinary.ch1);
1182 cmdputs(psh, "; do ");
1183 cmdtxt(psh, n->nbinary.ch2);
1184 cmdputs(psh, "; done");
1185 break;
1186 case NFOR:
1187 cmdputs(psh, "for ");
1188 cmdputs(psh, n->nfor.var);
1189 cmdputs(psh, " in ");
1190 cmdlist(psh, n->nfor.args, 1);
1191 cmdputs(psh, "; do ");
1192 cmdtxt(psh, n->nfor.body);
1193 cmdputs(psh, "; done");
1194 break;
1195 case NCASE:
1196 cmdputs(psh, "case ");
1197 cmdputs(psh, n->ncase.expr->narg.text);
1198 cmdputs(psh, " in ");
1199 for (np = n->ncase.cases; np; np = np->nclist.next) {
1200 cmdtxt(psh, np->nclist.pattern);
1201 cmdputs(psh, ") ");
1202 cmdtxt(psh, np->nclist.body);
1203 cmdputs(psh, ";; ");
1204 }
1205 cmdputs(psh, "esac");
1206 break;
1207 case NDEFUN:
1208 cmdputs(psh, n->narg.text);
1209 cmdputs(psh, "() { ... }");
1210 break;
1211 case NCMD:
1212 cmdlist(psh, n->ncmd.args, 1);
1213 cmdlist(psh, n->ncmd.redirect, 0);
1214 break;
1215 case NARG:
1216 cmdputs(psh, n->narg.text);
1217 break;
1218 case NTO:
1219 p = ">"; i = 1; goto redir;
1220 case NCLOBBER:
1221 p = ">|"; i = 1; goto redir;
1222 case NAPPEND:
1223 p = ">>"; i = 1; goto redir;
1224 case NTOFD:
1225 p = ">&"; i = 1; goto redir;
1226 case NFROM:
1227 p = "<"; i = 0; goto redir;
1228 case NFROMFD:
1229 p = "<&"; i = 0; goto redir;
1230 case NFROMTO:
1231 p = "<>"; i = 0; goto redir;
1232redir:
1233 if (n->nfile.fd != i) {
1234 s[0] = n->nfile.fd + '0';
1235 s[1] = '\0';
1236 cmdputs(psh, s);
1237 }
1238 cmdputs(psh, p);
1239 if (n->type == NTOFD || n->type == NFROMFD) {
1240 s[0] = n->ndup.dupfd + '0';
1241 s[1] = '\0';
1242 cmdputs(psh, s);
1243 } else {
1244 cmdtxt(psh, n->nfile.fname);
1245 }
1246 break;
1247 case NHERE:
1248 case NXHERE:
1249 cmdputs(psh, "<<...");
1250 break;
1251 default:
1252 cmdputs(psh, "???");
1253 break;
1254 }
1255}
1256
1257STATIC void
1258cmdlist(shinstance *psh, union node *np, int sep)
1259{
1260 for (; np; np = np->narg.next) {
1261 if (!sep)
1262 cmdputs(psh, " ");
1263 cmdtxt(psh, np);
1264 if (sep && np->narg.next)
1265 cmdputs(psh, " ");
1266 }
1267}
1268
1269
1270STATIC void
1271cmdputs(shinstance *psh, const char *s)
1272{
1273 const char *p, *str = 0;
1274 char c, cc[2] = " ";
1275 char *nextc;
1276 int nleft;
1277 int subtype = 0;
1278 int quoted = 0;
1279 static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
1280 "#", "##", "%", "%%" };
1281
1282 p = s;
1283 nextc = psh->cmdnextc;
1284 nleft = psh->cmdnleft;
1285 while (nleft > 0 && (c = *p++) != 0) {
1286 switch (c) {
1287 case CTLESC:
1288 c = *p++;
1289 break;
1290 case CTLVAR:
1291 subtype = *p++;
1292 if ((subtype & VSTYPE) == VSLENGTH)
1293 str = "${#";
1294 else
1295 str = "${";
1296 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
1297 quoted ^= 1;
1298 c = '"';
1299 } else
1300 c = *str++;
1301 break;
1302 case CTLENDVAR:
1303 if (quoted & 1) {
1304 c = '"';
1305 str = "}";
1306 } else
1307 c = '}';
1308 quoted >>= 1;
1309 subtype = 0;
1310 break;
1311 case CTLBACKQ:
1312 c = '$';
1313 str = "(...)";
1314 break;
1315 case CTLBACKQ+CTLQUOTE:
1316 c = '"';
1317 str = "$(...)\"";
1318 break;
1319 case CTLARI:
1320 c = '$';
1321 str = "((";
1322 break;
1323 case CTLENDARI:
1324 c = ')';
1325 str = ")";
1326 break;
1327 case CTLQUOTEMARK:
1328 quoted ^= 1;
1329 c = '"';
1330 break;
1331 case '=':
1332 if (subtype == 0)
1333 break;
1334 str = vstype[subtype & VSTYPE];
1335 if (subtype & VSNUL)
1336 c = ':';
1337 else
1338 c = *str++;
1339 if (c != '}')
1340 quoted <<= 1;
1341 break;
1342 case '\'':
1343 case '\\':
1344 case '"':
1345 case '$':
1346 /* These can only happen inside quotes */
1347 cc[0] = c;
1348 str = cc;
1349 c = '\\';
1350 break;
1351 default:
1352 break;
1353 }
1354 do {
1355 *nextc++ = c;
1356 } while (--nleft > 0 && str && (c = *str++));
1357 str = 0;
1358 }
1359 if ((quoted & 1) && nleft) {
1360 *nextc++ = '"';
1361 nleft--;
1362 }
1363 psh->cmdnleft = nleft;
1364 psh->cmdnextc = nextc;
1365}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette