8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sh / jobs.c
blob5823122c935bf75e3b6f19a791c16a2c9724f083
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Job control for UNIX Shell
34 #include <sys/termio.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <sys/param.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <signal.h>
41 #include "defs.h"
44 * one of these for each active job
47 struct job
49 struct job *j_nxtp; /* next job in job ID order */
50 struct job *j_curp; /* next job in job currency order */
51 struct termios j_stty; /* termio save area when job stops */
52 pid_t j_pid; /* job leader's process ID */
53 pid_t j_pgid; /* job's process group ID */
54 pid_t j_tgid; /* job's foreground process group ID */
55 uint_t j_jid; /* job ID */
56 ushort_t j_xval; /* exit code, or exit or stop signal */
57 ushort_t j_flag; /* various status flags defined below */
58 char *j_pwd; /* job's working directory */
59 char *j_cmd; /* cmd used to invoke this job */
62 /* defines for j_flag */
64 #define J_DUMPED 0001 /* job has core dumped */
65 #define J_NOTIFY 0002 /* job has changed status */
66 #define J_SAVETTY 0004 /* job was stopped in foreground, and its */
67 /* termio settings were saved */
68 #define J_STOPPED 0010 /* job has been stopped */
69 #define J_SIGNALED 0020 /* job has received signal; j_xval has it */
70 #define J_DONE 0040 /* job has finished */
71 #define J_RUNNING 0100 /* job is currently running */
72 #define J_FOREGND 0200 /* job was put in foreground by shell */
74 /* options to the printjob() function defined below */
76 #define PR_CUR 00001 /* print job currency ('+', '-', or ' ') */
77 #define PR_JID 00002 /* print job ID */
78 #define PR_PGID 00004 /* print job's process group ID */
79 #define PR_STAT 00010 /* print status obtained from wait */
80 #define PR_CMD 00020 /* print cmd that invoked job */
81 #define PR_AMP 00040 /* print a '&' if in the background */
82 #define PR_PWD 00100 /* print jobs present working directory */
84 #define PR_DFL (PR_CUR|PR_JID|PR_STAT|PR_CMD) /* default options */
85 #define PR_LONG (PR_DFL|PR_PGID|PR_PWD) /* long options */
87 static struct termios mystty; /* default termio settings */
88 static int eofflg,
89 jobcnt, /* number of active jobs */
90 jobdone, /* number of active but finished jobs */
91 jobnote; /* jobs requiring notification */
92 static pid_t svpgid, /* saved process group ID */
93 svtgid; /* saved foreground process group ID */
94 static struct job *jobcur, /* active jobs listed in currency order */
95 **nextjob,
96 *thisjob,
97 *joblst; /* active jobs listed in job ID order */
99 static void printjob(struct job *, int);
101 static struct job *
102 pgid2job(pid_t pgid)
104 struct job *jp;
106 for (jp = joblst; jp != 0 && jp->j_pid != pgid; jp = jp->j_nxtp)
107 continue;
109 return (jp);
112 static struct job *
113 str2job(char *cmd, char *job, int mustbejob)
115 struct job *jp, *njp;
116 int i;
118 if (*job != '%')
119 jp = pgid2job(stoi(job));
120 else if (*++job == 0 || *job == '+' || *job == '%' || *job == '-') {
121 jp = jobcur;
122 if (*job == '-' && jp)
123 jp = jp->j_curp;
124 } else if (*job >= '0' && *job <= '9') {
125 i = stoi(job);
126 for (jp = joblst; jp && jp->j_jid != i; jp = jp->j_nxtp)
127 continue;
128 } else if (*job == '?') {
129 int j;
130 char *p;
131 i = strlen(++job);
132 jp = 0;
133 for (njp = jobcur; njp; njp = njp->j_curp) {
134 if (njp->j_jid == 0)
135 continue;
136 for (p = njp->j_cmd, j = strlen(p); j >= i; p++, j--) {
137 if (strncmp(job, p, i) == 0) {
138 if (jp != 0)
139 failed((unsigned char *)cmd,
140 ambiguous);
141 jp = njp;
142 break;
146 } else {
147 i = strlen(job);
148 jp = 0;
149 for (njp = jobcur; njp; njp = njp->j_curp) {
150 if (njp->j_jid == 0)
151 continue;
152 if (strncmp(job, njp->j_cmd, i) == 0) {
153 if (jp != 0)
154 failed((unsigned char *)cmd, ambiguous);
155 jp = njp;
160 if (mustbejob && (jp == 0 || jp->j_jid == 0))
161 failed((unsigned char *)cmd, nosuchjob);
163 return (jp);
166 static void
167 freejob(struct job *jp)
169 struct job **njp;
170 struct job **cjp;
172 for (njp = &joblst; *njp != jp; njp = &(*njp)->j_nxtp)
173 continue;
175 for (cjp = &jobcur; *cjp != jp; cjp = &(*cjp)->j_curp)
176 continue;
178 *njp = jp->j_nxtp;
179 *cjp = jp->j_curp;
180 free(jp);
181 jobcnt--;
182 jobdone--;
186 * Collect the foreground job.
187 * Used in the case where the subshell wants
188 * to exit, but needs to wait until the fg job
189 * is done.
191 void
192 collect_fg_job(void)
194 struct job *jp;
195 pid_t pid;
196 int stat;
198 for (jp = joblst; jp; jp = jp->j_nxtp)
199 if (jp->j_flag & J_FOREGND)
200 break;
202 if (!jp)
203 /* no foreground job */
204 return;
207 * Wait on fg job until wait succeeds
208 * or it fails due to no waitable children.
211 while (1) {
212 errno = 0;
213 pid = waitpid(jp->j_pid, &stat, 0);
214 if (pid == jp->j_pid || (pid == -1 && errno == ECHILD))
215 break;
220 * analyze the status of a job
223 static int
224 statjob(struct job *jp, int stat, int fg, int rc)
226 pid_t tgid;
227 int done = 0;
229 if (WIFCONTINUED(stat)) {
230 if (jp->j_flag & J_STOPPED) {
231 jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY);
232 jp->j_flag |= J_RUNNING;
233 if (!fg && jp->j_jid) {
234 jp->j_flag |= J_NOTIFY;
235 jobnote++;
238 } else if (WIFSTOPPED(stat)) {
239 jp->j_xval = WSTOPSIG(stat);
240 jp->j_flag &= ~J_RUNNING;
241 jp->j_flag |= (J_SIGNALED|J_STOPPED);
242 jp->j_pgid = getpgid(jp->j_pid);
243 jp->j_tgid = jp->j_pgid;
244 if (fg) {
245 if (tgid = settgid(mypgid, jp->j_pgid))
246 jp->j_tgid = tgid;
247 else {
248 jp->j_flag |= J_SAVETTY;
249 tcgetattr(0, &jp->j_stty);
250 (void) tcsetattr(0, TCSANOW, &mystty);
253 if (jp->j_jid) {
254 jp->j_flag |= J_NOTIFY;
255 jobnote++;
257 } else {
258 jp->j_flag &= ~J_RUNNING;
259 jp->j_flag |= J_DONE;
260 done++;
261 jobdone++;
262 if (WIFSIGNALED(stat)) {
263 jp->j_xval = WTERMSIG(stat);
264 jp->j_flag |= J_SIGNALED;
265 if (WCOREDUMP(stat))
266 jp->j_flag |= J_DUMPED;
267 if (!fg || jp->j_xval != SIGINT) {
268 jp->j_flag |= J_NOTIFY;
269 jobnote++;
271 } else { /* WIFEXITED */
272 jp->j_xval = WEXITSTATUS(stat);
273 jp->j_flag &= ~J_SIGNALED;
274 if (!fg && jp->j_jid) {
275 jp->j_flag |= J_NOTIFY;
276 jobnote++;
279 if (fg) {
280 if (!settgid(mypgid, jp->j_pgid) ||
281 !settgid(mypgid, getpgid(jp->j_pid)))
282 tcgetattr(0, &mystty);
285 if (rc) {
286 exitval = jp->j_xval;
287 if (jp->j_flag & J_SIGNALED)
288 exitval |= SIGFLG;
289 exitset();
291 if (done && !(jp->j_flag & J_NOTIFY))
292 freejob(jp);
293 return (done);
297 * collect the status of jobs that have recently exited or stopped -
298 * if wnohang == WNOHANG, wait until error, or all jobs are accounted for;
300 * called after each command is executed, with wnohang == 0, and as part
301 * of "wait" builtin with wnohang == WNOHANG
303 * We do not need to call chktrap here if waitpid(2) is called with
304 * wnohang == 0, because that only happens from syswait() which is called
305 * from builtin() where chktrap() is already called.
308 static void
309 collectjobs(wnohang)
311 pid_t pid;
312 struct job *jp;
313 int stat, n;
314 int wflags;
316 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
317 wflags = WUNTRACED|WCONTINUED;
318 else
319 wflags = 0;
321 for (n = jobcnt - jobdone; n > 0; n--) {
322 if ((pid = waitpid(-1, &stat, wnohang|wflags)) <= 0)
323 break;
324 if (jp = pgid2job(pid))
325 (void) statjob(jp, stat, 0, 0);
330 void
331 freejobs()
333 struct job *jp;
335 collectjobs(WNOHANG);
337 if (jobnote) {
338 int savefd = setb(2);
339 for (jp = joblst; jp; jp = jp->j_nxtp) {
340 if (jp->j_flag & J_NOTIFY) {
341 if (jp->j_jid)
342 printjob(jp, PR_DFL);
343 else if (jp->j_flag & J_FOREGND)
344 printjob(jp, PR_STAT);
345 else
346 printjob(jp, PR_STAT|PR_PGID);
349 (void) setb(savefd);
352 if (jobdone) {
353 for (jp = joblst; jp; jp = jp->j_nxtp) {
354 if (jp->j_flag & J_DONE)
355 freejob(jp);
360 static void
361 waitjob(struct job *jp)
363 int stat;
364 int done;
365 pid_t pid = jp->j_pid;
366 int wflags;
367 int ret = 0;
368 int err = 0;
370 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
371 wflags = WUNTRACED;
372 else
373 wflags = 0;
374 do {
375 errno = 0;
376 ret = waitpid(pid, &stat, wflags|WNOWAIT);
377 err = errno;
378 if (ret == -1 && err == ECHILD) {
379 stat = 0;
380 break;
382 } while (ret != pid);
384 done = statjob(jp, stat, 1, 1);
385 waitpid(pid, 0, wflags);
386 if (done && exitval && (flags & errflg))
387 exitsh(exitval);
388 flags |= eflag;
392 * modify the foreground process group to *new* only if the
393 * current foreground process group is equal to *expected*
397 settgid(new, expected)
398 pid_t new, expected;
400 pid_t current = tcgetpgrp(0);
402 if (current != expected)
403 return (current);
405 if (new != current)
406 tcsetpgrp(0, new);
408 return (0);
411 static void
412 restartjob(struct job *jp, int fg)
414 if (jp != jobcur) {
415 struct job *t;
417 for (t = jobcur; t->j_curp != jp; t = t->j_curp)
419 t->j_curp = jp->j_curp;
420 jp->j_curp = jobcur;
421 jobcur = jp;
423 if (fg) {
424 if (jp->j_flag & J_SAVETTY) {
425 jp->j_stty.c_lflag &= ~TOSTOP;
426 jp->j_stty.c_lflag |= (mystty.c_lflag&TOSTOP);
427 jp->j_stty.c_cc[VSUSP] = mystty.c_cc[VSUSP];
428 jp->j_stty.c_cc[VDSUSP] = mystty.c_cc[VDSUSP];
429 (void) tcsetattr(0, TCSADRAIN, &jp->j_stty);
431 (void) settgid(jp->j_tgid, mypgid);
433 (void) kill(-(jp->j_pgid), SIGCONT);
434 if (jp->j_tgid != jp->j_pgid)
435 (void) kill(-(jp->j_tgid), SIGCONT);
436 jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY);
437 jp->j_flag |= J_RUNNING;
438 if (fg) {
439 jp->j_flag |= J_FOREGND;
440 printjob(jp, PR_JID|PR_CMD);
441 waitjob(jp);
442 } else {
443 jp->j_flag &= ~J_FOREGND;
444 printjob(jp, PR_JID|PR_CMD|PR_AMP);
448 static void
449 printjob(struct job *jp, int propts)
451 int sp = 0;
453 if (jp->j_flag & J_NOTIFY) {
454 jobnote--;
455 jp->j_flag &= ~J_NOTIFY;
458 if (propts & PR_JID) {
459 prc_buff('[');
460 prn_buff(jp->j_jid);
461 prc_buff(']');
462 sp = 1;
465 if (propts & PR_CUR) {
466 while (sp-- > 0)
467 prc_buff(SPACE);
468 sp = 1;
469 if (jobcur == jp)
470 prc_buff('+');
471 else if (jobcur != 0 && jobcur->j_curp == jp)
472 prc_buff('-');
473 else
474 sp++;
477 if (propts & PR_PGID) {
478 while (sp-- > 0)
479 prc_buff(SPACE);
480 prn_buff(jp->j_pid);
481 sp = 1;
484 if (propts & PR_STAT) {
485 char *gmsg;
486 while (sp-- > 0)
487 prc_buff(SPACE);
488 sp = 28;
489 if (jp->j_flag & J_SIGNALED) {
490 char *sigstr, *strsignal();
491 if ((sigstr = strsignal(jp->j_xval)) != NULL) {
492 sp -= strlen(sigstr);
493 prs_buff(sigstr);
494 } else {
495 itos(jp->j_xval);
496 gmsg = gettext(signalnum);
497 sp -= strlen(numbuf) + strlen(gmsg);
498 prs_buff((unsigned char *)gmsg);
499 prs_buff(numbuf);
501 if (jp->j_flag & J_DUMPED) {
502 gmsg = gettext(coredump);
503 sp -= strlen(gmsg);
504 prs_buff((unsigned char *)gmsg);
506 } else if (jp->j_flag & J_DONE) {
507 itos(jp->j_xval);
508 gmsg = gettext(exited);
509 sp -= strlen(gmsg) + strlen(numbuf) + 2;
510 prs_buff((unsigned char *)gmsg);
511 prc_buff('(');
512 itos(jp->j_xval);
513 prs_buff(numbuf);
514 prc_buff(')');
515 } else {
516 gmsg = gettext(running);
517 sp -= strlen(gmsg);
518 prs_buff((unsigned char *)gmsg);
520 if (sp < 1)
521 sp = 1;
524 if (propts & PR_CMD) {
525 while (sp-- > 0)
526 prc_buff(SPACE);
527 prs_buff(jp->j_cmd);
528 sp = 1;
531 if (propts & PR_AMP) {
532 while (sp-- > 0)
533 prc_buff(SPACE);
534 prc_buff('&');
535 sp = 1;
538 if (propts & PR_PWD) {
539 while (sp-- > 0)
540 prc_buff(SPACE);
541 prs_buff("(wd: ");
542 prs_buff(jp->j_pwd);
543 prc_buff(')');
546 prc_buff(NL);
547 flushb();
553 * called to initialize job control for each new input file to the shell,
554 * and after the "exec" builtin
557 void
558 startjobs()
560 svpgid = mypgid;
562 if (tcgetattr(0, &mystty) == -1 || (svtgid = tcgetpgrp(0)) == -1) {
563 flags &= ~jcflg;
564 return;
567 flags |= jcflg;
569 handle(SIGTTOU, SIG_IGN);
570 handle(SIGTSTP, SIG_DFL);
572 if (mysid != mypgid) {
573 setpgid(0, 0);
574 mypgid = mypid;
575 (void) settgid(mypgid, svpgid);
581 endjobs(check_if)
582 int check_if;
584 if ((flags & (jcoff|jcflg)) != jcflg)
585 return (1);
587 if (check_if && jobcnt && eofflg++ == 0) {
588 struct job *jp;
589 if (check_if & JOB_STOPPED) {
590 for (jp = joblst; jp; jp = jp->j_nxtp) {
591 if (jp->j_jid && (jp->j_flag & J_STOPPED)) {
592 prs(_gettext(jobsstopped));
593 prc(NL);
594 return (0);
598 if (check_if & JOB_RUNNING) {
599 for (jp = joblst; jp; jp = jp->j_nxtp) {
600 if (jp->j_jid && (jp->j_flag & J_RUNNING)) {
601 prs(_gettext(jobsrunning));
602 prc(NL);
603 return (0);
609 if (svpgid != mypgid) {
610 (void) settgid(svtgid, mypgid);
611 setpgid(0, svpgid);
614 return (1);
619 * called by the shell to reserve a job slot for a job about to be spawned
622 void
623 deallocjob()
625 free(thisjob);
626 jobcnt--;
629 void
630 allocjob(char *cmd, uchar_t *cwd, int monitor)
632 struct job *jp, **jpp;
633 int jid, cmdlen, cwdlen;
635 cmdlen = strlen(cmd) + 1;
636 if (cmd[cmdlen-2] == '&') {
637 cmd[cmdlen-3] = 0;
638 cmdlen -= 2;
640 cwdlen = strlen(cwd) + 1;
641 jp = (struct job *) alloc(sizeof (struct job) + cmdlen + cwdlen);
642 if (jp == 0)
643 error(nostack);
644 jobcnt++;
645 jp->j_cmd = ((char *)jp) + sizeof (struct job);
646 strcpy(jp->j_cmd, cmd);
647 jp->j_pwd = jp->j_cmd + cmdlen;
648 strcpy(jp->j_pwd, cwd);
650 jpp = &joblst;
652 if (monitor) {
653 for (; *jpp; jpp = &(*jpp)->j_nxtp)
654 if ((*jpp)->j_jid != 0)
655 break;
656 for (jid = 1; *jpp; jpp = &(*jpp)->j_nxtp, jid++)
657 if ((*jpp)->j_jid != jid)
658 break;
659 } else
660 jid = 0;
662 jp->j_jid = jid;
663 nextjob = jpp;
664 thisjob = jp;
667 void
668 clearjobs(void)
670 struct job *jp, *sjp;
672 for (jp = joblst; jp; jp = sjp) {
673 sjp = jp->j_nxtp;
674 free(jp);
676 joblst = NULL;
677 jobcnt = 0;
678 jobnote = 0;
679 jobdone = 0;
683 void
684 makejob(int monitor, int fg)
686 if (monitor) {
687 mypgid = mypid;
688 setpgid(0, 0);
689 if (fg)
690 tcsetpgrp(0, mypid);
691 handle(SIGTTOU, SIG_DFL);
692 handle(SIGTSTP, SIG_DFL);
693 } else if (!fg) {
694 #ifdef NICE
695 nice(NICE);
696 #endif
697 handle(SIGTTIN, SIG_IGN);
698 handle(SIGINT, SIG_IGN);
699 handle(SIGQUIT, SIG_IGN);
700 if (!ioset)
701 renamef(chkopen(devnull, 0), 0);
706 * called by the shell after job has been spawned, to fill in the
707 * job slot, and wait for the job if in the foreground
710 void
711 postjob(pid, fg)
712 pid_t pid;
713 int fg;
716 int propts;
718 thisjob->j_nxtp = *nextjob;
719 *nextjob = thisjob;
720 thisjob->j_curp = jobcur;
721 jobcur = thisjob;
723 if (thisjob->j_jid) {
724 thisjob->j_pgid = pid;
725 propts = PR_JID|PR_PGID;
726 } else {
727 thisjob->j_pgid = mypgid;
728 propts = PR_PGID;
731 thisjob->j_flag = J_RUNNING;
732 thisjob->j_tgid = thisjob->j_pgid;
733 thisjob->j_pid = pid;
734 eofflg = 0;
736 if (fg) {
737 thisjob->j_flag |= J_FOREGND;
738 waitjob(thisjob);
739 } else {
740 if (flags & ttyflg)
741 printjob(thisjob, propts);
742 assnum(&pcsadr, (long)pid);
747 * the builtin "jobs" command
750 void
751 sysjobs(argc, argv)
752 int argc;
753 char *argv[];
755 char *cmd = *argv;
756 struct job *jp;
757 int propts, c;
758 extern int opterr, i;
759 int savoptind = optind;
760 int loptind = -1;
761 int savopterr = opterr;
762 int savsp = _sp;
763 char *savoptarg = optarg;
764 optind = 1;
765 opterr = 0;
766 _sp = 1;
767 propts = 0;
769 if ((flags & jcflg) == 0)
770 failed((unsigned char *)cmd, nojc);
772 while ((c = getopt(argc, argv, "lpx")) != -1) {
773 if (propts) {
774 gfailure(usage, jobsuse);
775 goto err;
777 switch (c) {
778 case 'x':
779 propts = -1;
780 break;
781 case 'p':
782 propts = PR_PGID;
783 break;
784 case 'l':
785 propts = PR_LONG;
786 break;
787 case '?':
788 gfailure(usage, jobsuse);
789 goto err;
793 loptind = optind;
794 err:
795 optind = savoptind;
796 optarg = savoptarg;
797 opterr = savopterr;
798 _sp = savsp;
799 if (loptind == -1)
800 return;
802 if (propts == -1) {
803 unsigned char *bp;
804 char *cp;
805 unsigned char *savebp;
806 for (savebp = bp = locstak(); loptind < argc; loptind++) {
807 cp = argv[loptind];
808 if (*cp == '%') {
809 jp = str2job(cmd, cp, 1);
810 itos(jp->j_pid);
811 cp = (char *)numbuf;
813 while (*cp) {
814 if (bp >= brkend)
815 growstak(bp);
816 *bp++ = *cp++;
818 if (bp >= brkend)
819 growstak(bp);
820 *bp++ = SPACE;
822 endstak(bp);
823 execexp(savebp, 0);
824 return;
827 collectjobs(WNOHANG);
829 if (propts == 0)
830 propts = PR_DFL;
832 if (loptind == argc) {
833 for (jp = joblst; jp; jp = jp->j_nxtp) {
834 if (jp->j_jid)
835 printjob(jp, propts);
837 } else do
838 printjob(str2job(cmd, argv[loptind++], 1), propts);
839 while (loptind < argc);
844 * the builtin "fg" and "bg" commands
846 void
847 sysfgbg(int argc, char *argv[])
849 char *cmd = *argv;
850 int fg;
852 if ((flags & jcflg) == 0)
853 failed((unsigned char *)cmd, nojc);
855 fg = eq("fg", cmd);
857 if (*++argv == 0) {
858 struct job *jp;
859 for (jp = jobcur; ; jp = jp->j_curp) {
860 if (jp == 0)
861 failed((unsigned char *)cmd, nocurjob);
862 if (jp->j_jid)
863 break;
865 restartjob(jp, fg);
866 } else {
867 do {
868 restartjob(str2job(cmd, *argv, 1), fg);
869 } while (*++argv);
874 * the builtin "wait" commands
877 void
878 syswait(argc, argv)
879 int argc;
880 char *argv[];
882 char *cmd = *argv;
883 struct job *jp;
884 int stat;
885 int wflags;
887 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
888 wflags = WUNTRACED;
889 else
890 wflags = 0;
892 if (argc == 1)
893 collectjobs(0);
894 else while (--argc) {
895 if ((jp = str2job(cmd, *++argv, 0)) == 0)
896 continue;
897 if (!(jp->j_flag & J_RUNNING))
898 continue;
899 if (waitpid(jp->j_pid, &stat, wflags) <= 0)
900 break;
901 (void) statjob(jp, stat, 0, 1);
905 static void
906 sigv(char *cmd, int sig, char *args)
908 int pgrp = 0;
909 int stopme = 0;
910 pid_t id;
912 if (*args == '%') {
913 struct job *jp;
914 jp = str2job(cmd, args, 1);
915 id = jp->j_pgid;
916 pgrp++;
917 } else {
918 if (*args == '-') {
919 pgrp++;
920 args++;
922 id = 0;
923 do {
924 if (*args < '0' || *args > '9') {
925 failure(cmd, badid);
926 return;
928 id = (id * 10) + (*args - '0');
929 } while (*++args);
930 if (id == 0) {
931 id = mypgid;
932 pgrp++;
936 if (sig == SIGSTOP) {
937 if (id == mysid || id == mypid && mypgid == mysid) {
938 failure(cmd, loginsh);
939 return;
941 if (id == mypgid && mypgid != svpgid) {
942 (void) settgid(svtgid, mypgid);
943 setpgid(0, svpgid);
944 stopme++;
948 if (pgrp)
949 id = -id;
951 if (kill(id, sig) < 0) {
953 switch (errno) {
954 case EPERM:
955 failure(cmd, eacces);
956 break;
958 case EINVAL:
959 failure(cmd, badsig);
960 break;
962 default:
963 if (pgrp)
964 failure(cmd, nosuchpgid);
965 else
966 failure(cmd, nosuchpid);
967 break;
970 } else if (sig == SIGTERM && pgrp)
971 (void) kill(id, SIGCONT);
973 if (stopme) {
974 setpgid(0, mypgid);
975 (void) settgid(mypgid, svpgid);
980 void
981 sysstop(int argc, char *argv[])
983 char *cmd = *argv;
984 if (argc <= 1) {
985 gfailure(usage, stopuse);
986 return;
988 while (*++argv)
989 sigv(cmd, SIGSTOP, *argv);
992 void
993 syskill(int argc, char *argv[])
995 char *cmd = *argv;
996 int sig = SIGTERM;
998 if (argc == 1) {
999 gfailure(usage, killuse);
1000 return;
1003 if (argv[1][0] == '-') {
1005 if (argc == 2) {
1007 int i;
1008 int cnt = 0;
1009 char sep = 0;
1010 char buf[12];
1012 if (!eq(argv[1], "-l")) {
1013 gfailure(usage, killuse);
1014 return;
1017 for (i = 1; i < MAXTRAP; i++) {
1018 if (sig2str(i, buf) < 0)
1019 continue;
1020 if (sep)
1021 prc_buff(sep);
1022 prs_buff(buf);
1023 if ((flags & ttyflg) && (++cnt % 10))
1024 sep = TAB;
1025 else
1026 sep = NL;
1028 prc_buff(NL);
1029 return;
1032 if (str2sig(&argv[1][1], &sig)) {
1033 failure(cmd, badsig);
1034 return;
1036 argv++;
1039 while (*++argv)
1040 sigv(cmd, sig, *argv);
1044 void
1045 syssusp(int argc, char *argv[])
1047 if (argc != 1)
1048 failed((unsigned char *)argv[0], badopt);
1049 sigv(argv[0], SIGSTOP, "0");
1052 void
1053 hupforegnd(void)
1055 struct job *jp;
1057 (void) sighold(SIGCHLD);
1058 for (jp = joblst; jp != NULL; jp = jp->j_nxtp) {
1059 if (jp->j_flag & J_FOREGND) {
1060 (void) kill(jp->j_pid, SIGHUP);
1061 break;
1064 (void) sigrelse(SIGCHLD);