17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*965005c8Schin * Copyright 2001 Sun Microsystems, Inc. All rights reserved. 24*965005c8Schin * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 26*965005c8Schin /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27*965005c8Schin /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Job control for UNIX Shell 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/termio.h> 357c478bd9Sstevel@tonic-gate #include <sys/types.h> 367c478bd9Sstevel@tonic-gate #include <sys/wait.h> 377c478bd9Sstevel@tonic-gate #include <sys/param.h> 387c478bd9Sstevel@tonic-gate #include <fcntl.h> 397c478bd9Sstevel@tonic-gate #include <errno.h> 407c478bd9Sstevel@tonic-gate #include "defs.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * one of these for each active job 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate struct job 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate struct job *j_nxtp; /* next job in job ID order */ 497c478bd9Sstevel@tonic-gate struct job *j_curp; /* next job in job currency order */ 507c478bd9Sstevel@tonic-gate struct termios j_stty; /* termio save area when job stops */ 517c478bd9Sstevel@tonic-gate pid_t j_pid; /* job leader's process ID */ 527c478bd9Sstevel@tonic-gate pid_t j_pgid; /* job's process group ID */ 537c478bd9Sstevel@tonic-gate pid_t j_tgid; /* job's foreground process group ID */ 547c478bd9Sstevel@tonic-gate uint j_jid; /* job ID */ 557c478bd9Sstevel@tonic-gate ushort j_xval; /* exit code, or exit or stop signal */ 567c478bd9Sstevel@tonic-gate ushort j_flag; /* various status flags defined below */ 577c478bd9Sstevel@tonic-gate char *j_pwd; /* job's working directory */ 587c478bd9Sstevel@tonic-gate char *j_cmd; /* cmd used to invoke this job */ 597c478bd9Sstevel@tonic-gate }; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* defines for j_flag */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #define J_DUMPED 0001 /* job has core dumped */ 647c478bd9Sstevel@tonic-gate #define J_NOTIFY 0002 /* job has changed status */ 657c478bd9Sstevel@tonic-gate #define J_SAVETTY 0004 /* job was stopped in foreground, and its */ 667c478bd9Sstevel@tonic-gate /* termio settings were saved */ 677c478bd9Sstevel@tonic-gate #define J_STOPPED 0010 /* job has been stopped */ 687c478bd9Sstevel@tonic-gate #define J_SIGNALED 0020 /* job has received signal; j_xval has it */ 697c478bd9Sstevel@tonic-gate #define J_DONE 0040 /* job has finished */ 707c478bd9Sstevel@tonic-gate #define J_RUNNING 0100 /* job is currently running */ 717c478bd9Sstevel@tonic-gate #define J_FOREGND 0200 /* job was put in foreground by shell */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* options to the printjob() function defined below */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #define PR_CUR 00001 /* print job currency ('+', '-', or ' ') */ 767c478bd9Sstevel@tonic-gate #define PR_JID 00002 /* print job ID */ 777c478bd9Sstevel@tonic-gate #define PR_PGID 00004 /* print job's process group ID */ 787c478bd9Sstevel@tonic-gate #define PR_STAT 00010 /* print status obtained from wait */ 797c478bd9Sstevel@tonic-gate #define PR_CMD 00020 /* print cmd that invoked job */ 807c478bd9Sstevel@tonic-gate #define PR_AMP 00040 /* print a '&' if in the background */ 817c478bd9Sstevel@tonic-gate #define PR_PWD 00100 /* print jobs present working directory */ 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #define PR_DFL (PR_CUR|PR_JID|PR_STAT|PR_CMD) /* default options */ 847c478bd9Sstevel@tonic-gate #define PR_LONG (PR_DFL|PR_PGID|PR_PWD) /* long options */ 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate static struct termios mystty; /* default termio settings */ 877c478bd9Sstevel@tonic-gate static int eofflg, 887c478bd9Sstevel@tonic-gate jobcnt, /* number of active jobs */ 897c478bd9Sstevel@tonic-gate jobdone, /* number of active but finished jobs */ 907c478bd9Sstevel@tonic-gate jobnote; /* jobs requiring notification */ 917c478bd9Sstevel@tonic-gate static pid_t svpgid, /* saved process group ID */ 927c478bd9Sstevel@tonic-gate svtgid; /* saved foreground process group ID */ 937c478bd9Sstevel@tonic-gate static struct job *jobcur, /* active jobs listed in currency order */ 947c478bd9Sstevel@tonic-gate **nextjob, 957c478bd9Sstevel@tonic-gate *thisjob, 967c478bd9Sstevel@tonic-gate *joblst; /* active jobs listed in job ID order */ 977c478bd9Sstevel@tonic-gate 98*965005c8Schin static void printjob(struct job *, int); 99*965005c8Schin 1007c478bd9Sstevel@tonic-gate pid_t 1017c478bd9Sstevel@tonic-gate tcgetpgrp(fd) 1027c478bd9Sstevel@tonic-gate { 1037c478bd9Sstevel@tonic-gate pid_t pgid; 1047c478bd9Sstevel@tonic-gate if (ioctl(fd, TIOCGPGRP, &pgid) == 0) 1057c478bd9Sstevel@tonic-gate return (pgid); 1067c478bd9Sstevel@tonic-gate return ((pid_t)-1); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate int 1107c478bd9Sstevel@tonic-gate tcsetpgrp(fd, pgid) 1117c478bd9Sstevel@tonic-gate int fd; 1127c478bd9Sstevel@tonic-gate pid_t pgid; 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate return (ioctl(fd, TIOCSPGRP, &pgid)); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate static struct job * 118*965005c8Schin pgid2job(pid_t pgid) 1197c478bd9Sstevel@tonic-gate { 120*965005c8Schin struct job *jp; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate for (jp = joblst; jp != 0 && jp->j_pid != pgid; jp = jp->j_nxtp) 1237c478bd9Sstevel@tonic-gate continue; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate return (jp); 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate static struct job * 129*965005c8Schin str2job(char *cmd, char *job, int mustbejob) 1307c478bd9Sstevel@tonic-gate { 131*965005c8Schin struct job *jp, *njp; 132*965005c8Schin int i; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate if (*job != '%') 1357c478bd9Sstevel@tonic-gate jp = pgid2job(stoi(job)); 1367c478bd9Sstevel@tonic-gate else if (*++job == 0 || *job == '+' || *job == '%' || *job == '-') { 1377c478bd9Sstevel@tonic-gate jp = jobcur; 1387c478bd9Sstevel@tonic-gate if (*job == '-' && jp) 1397c478bd9Sstevel@tonic-gate jp = jp->j_curp; 1407c478bd9Sstevel@tonic-gate } else if (*job >= '0' && *job <= '9') { 1417c478bd9Sstevel@tonic-gate i = stoi(job); 1427c478bd9Sstevel@tonic-gate for (jp = joblst; jp && jp->j_jid != i; jp = jp->j_nxtp) 1437c478bd9Sstevel@tonic-gate continue; 1447c478bd9Sstevel@tonic-gate } else if (*job == '?') { 145*965005c8Schin int j; 146*965005c8Schin char *p; 1477c478bd9Sstevel@tonic-gate i = strlen(++job); 1487c478bd9Sstevel@tonic-gate jp = 0; 1497c478bd9Sstevel@tonic-gate for (njp = jobcur; njp; njp = njp->j_curp) { 1507c478bd9Sstevel@tonic-gate if (njp->j_jid == 0) 1517c478bd9Sstevel@tonic-gate continue; 1527c478bd9Sstevel@tonic-gate for (p = njp->j_cmd, j = strlen(p); j >= i; p++, j--) { 1537c478bd9Sstevel@tonic-gate if (strncmp(job, p, i) == 0) { 1547c478bd9Sstevel@tonic-gate if (jp != 0) 155*965005c8Schin failed((unsigned char *)cmd, 156*965005c8Schin ambiguous); 1577c478bd9Sstevel@tonic-gate jp = njp; 1587c478bd9Sstevel@tonic-gate break; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate } else { 1637c478bd9Sstevel@tonic-gate i = strlen(job); 1647c478bd9Sstevel@tonic-gate jp = 0; 1657c478bd9Sstevel@tonic-gate for (njp = jobcur; njp; njp = njp->j_curp) { 1667c478bd9Sstevel@tonic-gate if (njp->j_jid == 0) 1677c478bd9Sstevel@tonic-gate continue; 1687c478bd9Sstevel@tonic-gate if (strncmp(job, njp->j_cmd, i) == 0) { 1697c478bd9Sstevel@tonic-gate if (jp != 0) 170*965005c8Schin failed((unsigned char *)cmd, ambiguous); 1717c478bd9Sstevel@tonic-gate jp = njp; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if (mustbejob && (jp == 0 || jp->j_jid == 0)) 177*965005c8Schin failed((unsigned char *)cmd, nosuchjob); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate return (jp); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate static void 183*965005c8Schin freejob(struct job *jp) 1847c478bd9Sstevel@tonic-gate { 185*965005c8Schin struct job **njp; 186*965005c8Schin struct job **cjp; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate for (njp = &joblst; *njp != jp; njp = &(*njp)->j_nxtp) 1897c478bd9Sstevel@tonic-gate continue; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate for (cjp = &jobcur; *cjp != jp; cjp = &(*cjp)->j_curp) 1927c478bd9Sstevel@tonic-gate continue; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate *njp = jp->j_nxtp; 1957c478bd9Sstevel@tonic-gate *cjp = jp->j_curp; 1967c478bd9Sstevel@tonic-gate free(jp); 1977c478bd9Sstevel@tonic-gate jobcnt--; 1987c478bd9Sstevel@tonic-gate jobdone--; 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Collect the foreground job. 2037c478bd9Sstevel@tonic-gate * Used in the case where the subshell wants 2047c478bd9Sstevel@tonic-gate * to exit, but needs to wait until the fg job 2057c478bd9Sstevel@tonic-gate * is done. 2067c478bd9Sstevel@tonic-gate */ 207*965005c8Schin void 208*965005c8Schin collect_fg_job(void) 2097c478bd9Sstevel@tonic-gate { 210*965005c8Schin struct job *jp; 211*965005c8Schin pid_t pid; 2127c478bd9Sstevel@tonic-gate int stat; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate for (jp = joblst; jp; jp = jp->j_nxtp) 2157c478bd9Sstevel@tonic-gate if (jp->j_flag & J_FOREGND) 2167c478bd9Sstevel@tonic-gate break; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate if (!jp) 2197c478bd9Sstevel@tonic-gate /* no foreground job */ 2207c478bd9Sstevel@tonic-gate return; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * Wait on fg job until wait succeeds 2247c478bd9Sstevel@tonic-gate * or it fails due to no waitable children. 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate while (1) { 2287c478bd9Sstevel@tonic-gate errno = 0; 2297c478bd9Sstevel@tonic-gate pid = waitpid(jp->j_pid, &stat, 0); 2307c478bd9Sstevel@tonic-gate if (pid == jp->j_pid || (pid == -1 && errno == ECHILD)) 2317c478bd9Sstevel@tonic-gate break; 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * analyze the status of a job 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate static int 240*965005c8Schin statjob(struct job *jp, int stat, int fg, int rc) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate pid_t tgid; 2437c478bd9Sstevel@tonic-gate int done = 0; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (WIFCONTINUED(stat)) { 2467c478bd9Sstevel@tonic-gate if (jp->j_flag & J_STOPPED) { 2477c478bd9Sstevel@tonic-gate jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); 2487c478bd9Sstevel@tonic-gate jp->j_flag |= J_RUNNING; 2497c478bd9Sstevel@tonic-gate if (!fg && jp->j_jid) { 2507c478bd9Sstevel@tonic-gate jp->j_flag |= J_NOTIFY; 2517c478bd9Sstevel@tonic-gate jobnote++; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate } else if (WIFSTOPPED(stat)) { 2557c478bd9Sstevel@tonic-gate jp->j_xval = WSTOPSIG(stat); 2567c478bd9Sstevel@tonic-gate jp->j_flag &= ~J_RUNNING; 2577c478bd9Sstevel@tonic-gate jp->j_flag |= (J_SIGNALED|J_STOPPED); 2587c478bd9Sstevel@tonic-gate jp->j_pgid = getpgid(jp->j_pid); 2597c478bd9Sstevel@tonic-gate jp->j_tgid = jp->j_pgid; 2607c478bd9Sstevel@tonic-gate if (fg) { 2617c478bd9Sstevel@tonic-gate if (tgid = settgid(mypgid, jp->j_pgid)) 2627c478bd9Sstevel@tonic-gate jp->j_tgid = tgid; 2637c478bd9Sstevel@tonic-gate else { 2647c478bd9Sstevel@tonic-gate jp->j_flag |= J_SAVETTY; 2657c478bd9Sstevel@tonic-gate tcgetattr(0, &jp->j_stty); 2667c478bd9Sstevel@tonic-gate (void) tcsetattr(0, TCSANOW, &mystty); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate if (jp->j_jid) { 2707c478bd9Sstevel@tonic-gate jp->j_flag |= J_NOTIFY; 2717c478bd9Sstevel@tonic-gate jobnote++; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate } else { 2747c478bd9Sstevel@tonic-gate jp->j_flag &= ~J_RUNNING; 2757c478bd9Sstevel@tonic-gate jp->j_flag |= J_DONE; 2767c478bd9Sstevel@tonic-gate done++; 2777c478bd9Sstevel@tonic-gate jobdone++; 2787c478bd9Sstevel@tonic-gate if (WIFSIGNALED(stat)) { 2797c478bd9Sstevel@tonic-gate jp->j_xval = WTERMSIG(stat); 2807c478bd9Sstevel@tonic-gate jp->j_flag |= J_SIGNALED; 2817c478bd9Sstevel@tonic-gate if (WCOREDUMP(stat)) 2827c478bd9Sstevel@tonic-gate jp->j_flag |= J_DUMPED; 2837c478bd9Sstevel@tonic-gate if (!fg || jp->j_xval != SIGINT) { 2847c478bd9Sstevel@tonic-gate jp->j_flag |= J_NOTIFY; 2857c478bd9Sstevel@tonic-gate jobnote++; 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate } else { /* WIFEXITED */ 2887c478bd9Sstevel@tonic-gate jp->j_xval = WEXITSTATUS(stat); 2897c478bd9Sstevel@tonic-gate jp->j_flag &= ~J_SIGNALED; 2907c478bd9Sstevel@tonic-gate if (!fg && jp->j_jid) { 2917c478bd9Sstevel@tonic-gate jp->j_flag |= J_NOTIFY; 2927c478bd9Sstevel@tonic-gate jobnote++; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate if (fg) { 2967c478bd9Sstevel@tonic-gate if (!settgid(mypgid, jp->j_pgid) || 2977c478bd9Sstevel@tonic-gate !settgid(mypgid, getpgid(jp->j_pid))) 2987c478bd9Sstevel@tonic-gate tcgetattr(0, &mystty); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate if (rc) { 3027c478bd9Sstevel@tonic-gate exitval = jp->j_xval; 3037c478bd9Sstevel@tonic-gate if (jp->j_flag & J_SIGNALED) 3047c478bd9Sstevel@tonic-gate exitval |= SIGFLG; 3057c478bd9Sstevel@tonic-gate exitset(); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate if (done && !(jp->j_flag & J_NOTIFY)) 3087c478bd9Sstevel@tonic-gate freejob(jp); 3097c478bd9Sstevel@tonic-gate return (done); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * collect the status of jobs that have recently exited or stopped - 3147c478bd9Sstevel@tonic-gate * if wnohang == WNOHANG, wait until error, or all jobs are accounted for; 3157c478bd9Sstevel@tonic-gate * 3167c478bd9Sstevel@tonic-gate * called after each command is executed, with wnohang == 0, and as part 3177c478bd9Sstevel@tonic-gate * of "wait" builtin with wnohang == WNOHANG 3187c478bd9Sstevel@tonic-gate * 3197c478bd9Sstevel@tonic-gate * We do not need to call chktrap here if waitpid(2) is called with 3207c478bd9Sstevel@tonic-gate * wnohang == 0, because that only happens from syswait() which is called 3217c478bd9Sstevel@tonic-gate * from builtin() where chktrap() is already called. 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate static void 3257c478bd9Sstevel@tonic-gate collectjobs(wnohang) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate pid_t pid; 328*965005c8Schin struct job *jp; 3297c478bd9Sstevel@tonic-gate int stat, n; 3307c478bd9Sstevel@tonic-gate int wflags; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) 3337c478bd9Sstevel@tonic-gate wflags = WUNTRACED|WCONTINUED; 3347c478bd9Sstevel@tonic-gate else 3357c478bd9Sstevel@tonic-gate wflags = 0; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate for (n = jobcnt - jobdone; n > 0; n--) { 3387c478bd9Sstevel@tonic-gate if ((pid = waitpid(-1, &stat, wnohang|wflags)) <= 0) 3397c478bd9Sstevel@tonic-gate break; 3407c478bd9Sstevel@tonic-gate if (jp = pgid2job(pid)) 3417c478bd9Sstevel@tonic-gate (void) statjob(jp, stat, 0, 0); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate void 3477c478bd9Sstevel@tonic-gate freejobs() 3487c478bd9Sstevel@tonic-gate { 349*965005c8Schin struct job *jp; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate collectjobs(WNOHANG); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if (jobnote) { 354*965005c8Schin int savefd = setb(2); 3557c478bd9Sstevel@tonic-gate for (jp = joblst; jp; jp = jp->j_nxtp) { 3567c478bd9Sstevel@tonic-gate if (jp->j_flag & J_NOTIFY) { 3577c478bd9Sstevel@tonic-gate if (jp->j_jid) 3587c478bd9Sstevel@tonic-gate printjob(jp, PR_DFL); 3597c478bd9Sstevel@tonic-gate else if (jp->j_flag & J_FOREGND) 3607c478bd9Sstevel@tonic-gate printjob(jp, PR_STAT); 3617c478bd9Sstevel@tonic-gate else 3627c478bd9Sstevel@tonic-gate printjob(jp, PR_STAT|PR_PGID); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate (void) setb(savefd); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate if (jobdone) { 3697c478bd9Sstevel@tonic-gate for (jp = joblst; jp; jp = jp->j_nxtp) { 3707c478bd9Sstevel@tonic-gate if (jp->j_flag & J_DONE) 3717c478bd9Sstevel@tonic-gate freejob(jp); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate static void 377*965005c8Schin waitjob(struct job *jp) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate int stat; 3807c478bd9Sstevel@tonic-gate int done; 3817c478bd9Sstevel@tonic-gate pid_t pid = jp->j_pid; 3827c478bd9Sstevel@tonic-gate int wflags; 3837c478bd9Sstevel@tonic-gate int ret = 0; 3847c478bd9Sstevel@tonic-gate int err = 0; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) 3877c478bd9Sstevel@tonic-gate wflags = WUNTRACED; 3887c478bd9Sstevel@tonic-gate else 3897c478bd9Sstevel@tonic-gate wflags = 0; 3907c478bd9Sstevel@tonic-gate do { 3917c478bd9Sstevel@tonic-gate errno = 0; 3927c478bd9Sstevel@tonic-gate ret = waitpid(pid, &stat, wflags|WNOWAIT); 3937c478bd9Sstevel@tonic-gate err = errno; 3947c478bd9Sstevel@tonic-gate if (ret == -1 && err == ECHILD) { 3957c478bd9Sstevel@tonic-gate stat = 0; 3967c478bd9Sstevel@tonic-gate break; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate } while (ret != pid); 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate done = statjob(jp, stat, 1, 1); 4017c478bd9Sstevel@tonic-gate waitpid(pid, 0, wflags); 4027c478bd9Sstevel@tonic-gate if (done && exitval && (flags & errflg)) 4037c478bd9Sstevel@tonic-gate exitsh(exitval); 4047c478bd9Sstevel@tonic-gate flags |= eflag; 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * modify the foreground process group to *new* only if the 4097c478bd9Sstevel@tonic-gate * current foreground process group is equal to *expected* 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate int 4137c478bd9Sstevel@tonic-gate settgid(new, expected) 4147c478bd9Sstevel@tonic-gate pid_t new, expected; 4157c478bd9Sstevel@tonic-gate { 416*965005c8Schin pid_t current = tcgetpgrp(0); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if (current != expected) 4197c478bd9Sstevel@tonic-gate return (current); 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate if (new != current) 4227c478bd9Sstevel@tonic-gate tcsetpgrp(0, new); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate return (0); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate static void 428*965005c8Schin restartjob(struct job *jp, int fg) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate if (jp != jobcur) { 431*965005c8Schin struct job *t; 4327c478bd9Sstevel@tonic-gate for (t = jobcur; t->j_curp != jp; t = t->j_curp); 4337c478bd9Sstevel@tonic-gate t->j_curp = jp->j_curp; 4347c478bd9Sstevel@tonic-gate jp->j_curp = jobcur; 4357c478bd9Sstevel@tonic-gate jobcur = jp; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate if (fg) { 4387c478bd9Sstevel@tonic-gate if (jp->j_flag & J_SAVETTY) { 4397c478bd9Sstevel@tonic-gate jp->j_stty.c_lflag &= ~TOSTOP; 4407c478bd9Sstevel@tonic-gate jp->j_stty.c_lflag |= (mystty.c_lflag&TOSTOP); 4417c478bd9Sstevel@tonic-gate jp->j_stty.c_cc[VSUSP] = mystty.c_cc[VSUSP]; 4427c478bd9Sstevel@tonic-gate jp->j_stty.c_cc[VDSUSP] = mystty.c_cc[VDSUSP]; 4437c478bd9Sstevel@tonic-gate (void) tcsetattr(0, TCSADRAIN, &jp->j_stty); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate (void) settgid(jp->j_tgid, mypgid); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate (void) kill(-(jp->j_pgid), SIGCONT); 4487c478bd9Sstevel@tonic-gate if (jp->j_tgid != jp->j_pgid) 4497c478bd9Sstevel@tonic-gate (void) kill(-(jp->j_tgid), SIGCONT); 4507c478bd9Sstevel@tonic-gate jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); 4517c478bd9Sstevel@tonic-gate jp->j_flag |= J_RUNNING; 4527c478bd9Sstevel@tonic-gate if (fg) { 4537c478bd9Sstevel@tonic-gate jp->j_flag |= J_FOREGND; 4547c478bd9Sstevel@tonic-gate printjob(jp, PR_JID|PR_CMD); 4557c478bd9Sstevel@tonic-gate waitjob(jp); 4567c478bd9Sstevel@tonic-gate } else { 4577c478bd9Sstevel@tonic-gate jp->j_flag &= ~J_FOREGND; 4587c478bd9Sstevel@tonic-gate printjob(jp, PR_JID|PR_CMD|PR_AMP); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 462*965005c8Schin static void 463*965005c8Schin printjob(struct job *jp, int propts) 4647c478bd9Sstevel@tonic-gate { 4657c478bd9Sstevel@tonic-gate int sp = 0; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (jp->j_flag & J_NOTIFY) { 4687c478bd9Sstevel@tonic-gate jobnote--; 4697c478bd9Sstevel@tonic-gate jp->j_flag &= ~J_NOTIFY; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (propts & PR_JID) { 4737c478bd9Sstevel@tonic-gate prc_buff('['); 4747c478bd9Sstevel@tonic-gate prn_buff(jp->j_jid); 4757c478bd9Sstevel@tonic-gate prc_buff(']'); 4767c478bd9Sstevel@tonic-gate sp = 1; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate if (propts & PR_CUR) { 4807c478bd9Sstevel@tonic-gate while (sp-- > 0) 4817c478bd9Sstevel@tonic-gate prc_buff(SPACE); 4827c478bd9Sstevel@tonic-gate sp = 1; 4837c478bd9Sstevel@tonic-gate if (jobcur == jp) 4847c478bd9Sstevel@tonic-gate prc_buff('+'); 4857c478bd9Sstevel@tonic-gate else if (jobcur != 0 && jobcur->j_curp == jp) 4867c478bd9Sstevel@tonic-gate prc_buff('-'); 4877c478bd9Sstevel@tonic-gate else 4887c478bd9Sstevel@tonic-gate sp++; 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (propts & PR_PGID) { 4927c478bd9Sstevel@tonic-gate while (sp-- > 0) 4937c478bd9Sstevel@tonic-gate prc_buff(SPACE); 4947c478bd9Sstevel@tonic-gate prn_buff(jp->j_pid); 4957c478bd9Sstevel@tonic-gate sp = 1; 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate if (propts & PR_STAT) { 4997c478bd9Sstevel@tonic-gate while (sp-- > 0) 5007c478bd9Sstevel@tonic-gate prc_buff(SPACE); 5017c478bd9Sstevel@tonic-gate sp = 28; 5027c478bd9Sstevel@tonic-gate if (jp->j_flag & J_SIGNALED) { 5037c478bd9Sstevel@tonic-gate char *sigstr, *strsignal(); 5047c478bd9Sstevel@tonic-gate if ((sigstr = strsignal(jp->j_xval)) != NULL) { 5057c478bd9Sstevel@tonic-gate sp -= strlen(sigstr); 5067c478bd9Sstevel@tonic-gate prs_buff(sigstr); 5077c478bd9Sstevel@tonic-gate } else { 5087c478bd9Sstevel@tonic-gate itos(jp->j_xval); 5097c478bd9Sstevel@tonic-gate sp -= strlen(numbuf) + 7; 5107c478bd9Sstevel@tonic-gate prs_buff("Signal "); 5117c478bd9Sstevel@tonic-gate prs_buff(numbuf); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate if (jp->j_flag & J_DUMPED) { 5147c478bd9Sstevel@tonic-gate sp -= strlen(coredump); 5157c478bd9Sstevel@tonic-gate prs_buff(coredump); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate } else if (jp->j_flag & J_DONE) { 5187c478bd9Sstevel@tonic-gate itos(jp->j_xval); 5197c478bd9Sstevel@tonic-gate sp -= strlen(exited) + strlen(numbuf) + 2; 5207c478bd9Sstevel@tonic-gate prs_buff(exited); 5217c478bd9Sstevel@tonic-gate prc_buff('('); 5227c478bd9Sstevel@tonic-gate itos(jp->j_xval); 5237c478bd9Sstevel@tonic-gate prs_buff(numbuf); 5247c478bd9Sstevel@tonic-gate prc_buff(')'); 5257c478bd9Sstevel@tonic-gate } else { 5267c478bd9Sstevel@tonic-gate sp -= strlen(running); 5277c478bd9Sstevel@tonic-gate prs_buff(running); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate if (sp < 1) 5307c478bd9Sstevel@tonic-gate sp = 1; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (propts & PR_CMD) { 5347c478bd9Sstevel@tonic-gate while (sp-- > 0) 5357c478bd9Sstevel@tonic-gate prc_buff(SPACE); 5367c478bd9Sstevel@tonic-gate prs_buff(jp->j_cmd); 5377c478bd9Sstevel@tonic-gate sp = 1; 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate if (propts & PR_AMP) { 5417c478bd9Sstevel@tonic-gate while (sp-- > 0) 5427c478bd9Sstevel@tonic-gate prc_buff(SPACE); 5437c478bd9Sstevel@tonic-gate prc_buff('&'); 5447c478bd9Sstevel@tonic-gate sp = 1; 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate if (propts & PR_PWD) { 5487c478bd9Sstevel@tonic-gate while (sp-- > 0) 5497c478bd9Sstevel@tonic-gate prc_buff(SPACE); 5507c478bd9Sstevel@tonic-gate prs_buff("(wd: "); 5517c478bd9Sstevel@tonic-gate prs_buff(jp->j_pwd); 5527c478bd9Sstevel@tonic-gate prc_buff(')'); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate prc_buff(NL); 5567c478bd9Sstevel@tonic-gate flushb(); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate /* 5627c478bd9Sstevel@tonic-gate * called to initialize job control for each new input file to the shell, 5637c478bd9Sstevel@tonic-gate * and after the "exec" builtin 5647c478bd9Sstevel@tonic-gate */ 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate void 5677c478bd9Sstevel@tonic-gate startjobs() 5687c478bd9Sstevel@tonic-gate { 5697c478bd9Sstevel@tonic-gate svpgid = mypgid; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate if (tcgetattr(0, &mystty) == -1 || (svtgid = tcgetpgrp(0)) == -1) { 5727c478bd9Sstevel@tonic-gate flags &= ~jcflg; 5737c478bd9Sstevel@tonic-gate return; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate flags |= jcflg; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate handle(SIGTTOU, SIG_IGN); 5797c478bd9Sstevel@tonic-gate handle(SIGTSTP, SIG_DFL); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if (mysid != mypgid) { 5827c478bd9Sstevel@tonic-gate setpgid(0, 0); 5837c478bd9Sstevel@tonic-gate mypgid = mypid; 5847c478bd9Sstevel@tonic-gate (void) settgid(mypgid, svpgid); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate int 5907c478bd9Sstevel@tonic-gate endjobs(check_if) 5917c478bd9Sstevel@tonic-gate int check_if; 5927c478bd9Sstevel@tonic-gate { 5937c478bd9Sstevel@tonic-gate if ((flags & (jcoff|jcflg)) != jcflg) 5947c478bd9Sstevel@tonic-gate return (1); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate if (check_if && jobcnt && eofflg++ == 0) { 597*965005c8Schin struct job *jp; 5987c478bd9Sstevel@tonic-gate if (check_if & JOB_STOPPED) { 5997c478bd9Sstevel@tonic-gate for (jp = joblst; jp; jp = jp->j_nxtp) { 6007c478bd9Sstevel@tonic-gate if (jp->j_jid && (jp->j_flag & J_STOPPED)) { 6017c478bd9Sstevel@tonic-gate prs(jobsstopped); 6027c478bd9Sstevel@tonic-gate prc(NL); 6037c478bd9Sstevel@tonic-gate return (0); 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate if (check_if & JOB_RUNNING) { 6087c478bd9Sstevel@tonic-gate for (jp = joblst; jp; jp = jp->j_nxtp) { 6097c478bd9Sstevel@tonic-gate if (jp->j_jid && (jp->j_flag & J_RUNNING)) { 6107c478bd9Sstevel@tonic-gate prs(jobsrunning); 6117c478bd9Sstevel@tonic-gate prc(NL); 6127c478bd9Sstevel@tonic-gate return (0); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate if (svpgid != mypgid) { 6197c478bd9Sstevel@tonic-gate (void) settgid(svtgid, mypgid); 6207c478bd9Sstevel@tonic-gate setpgid(0, svpgid); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate return (1); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /* 6287c478bd9Sstevel@tonic-gate * called by the shell to reserve a job slot for a job about to be spawned 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate void 6327c478bd9Sstevel@tonic-gate deallocjob() 6337c478bd9Sstevel@tonic-gate { 6347c478bd9Sstevel@tonic-gate free(thisjob); 6357c478bd9Sstevel@tonic-gate jobcnt--; 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 638*965005c8Schin void 639*965005c8Schin allocjob(char *cmd, unchar *cwd, int monitor) 6407c478bd9Sstevel@tonic-gate { 641*965005c8Schin struct job *jp, **jpp; 642*965005c8Schin int jid, cmdlen, cwdlen; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate cmdlen = strlen(cmd) + 1; 6457c478bd9Sstevel@tonic-gate if (cmd[cmdlen-2] == '&') { 6467c478bd9Sstevel@tonic-gate cmd[cmdlen-3] = 0; 6477c478bd9Sstevel@tonic-gate cmdlen -= 2; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate cwdlen = strlen(cwd) + 1; 6507c478bd9Sstevel@tonic-gate jp = (struct job *) alloc(sizeof (struct job) + cmdlen + cwdlen); 6517c478bd9Sstevel@tonic-gate if (jp == 0) 6527c478bd9Sstevel@tonic-gate error(nostack); 6537c478bd9Sstevel@tonic-gate jobcnt++; 6547c478bd9Sstevel@tonic-gate jp->j_cmd = ((char *)jp) + sizeof (struct job); 6557c478bd9Sstevel@tonic-gate strcpy(jp->j_cmd, cmd); 6567c478bd9Sstevel@tonic-gate jp->j_pwd = jp->j_cmd + cmdlen; 6577c478bd9Sstevel@tonic-gate strcpy(jp->j_pwd, cwd); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate jpp = &joblst; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (monitor) { 6627c478bd9Sstevel@tonic-gate for (; *jpp; jpp = &(*jpp)->j_nxtp) 6637c478bd9Sstevel@tonic-gate if ((*jpp)->j_jid != 0) 6647c478bd9Sstevel@tonic-gate break; 6657c478bd9Sstevel@tonic-gate for (jid = 1; *jpp; jpp = &(*jpp)->j_nxtp, jid++) 6667c478bd9Sstevel@tonic-gate if ((*jpp)->j_jid != jid) 6677c478bd9Sstevel@tonic-gate break; 6687c478bd9Sstevel@tonic-gate } else 6697c478bd9Sstevel@tonic-gate jid = 0; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate jp->j_jid = jid; 6727c478bd9Sstevel@tonic-gate nextjob = jpp; 6737c478bd9Sstevel@tonic-gate thisjob = jp; 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 676*965005c8Schin void 677*965005c8Schin clearjobs(void) 6787c478bd9Sstevel@tonic-gate { 679*965005c8Schin struct job *jp, *sjp; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate for (jp = joblst; jp; jp = sjp) { 6827c478bd9Sstevel@tonic-gate sjp = jp->j_nxtp; 6837c478bd9Sstevel@tonic-gate free(jp); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate joblst = NULL; 6867c478bd9Sstevel@tonic-gate jobcnt = 0; 6877c478bd9Sstevel@tonic-gate jobnote = 0; 6887c478bd9Sstevel@tonic-gate jobdone = 0; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 692*965005c8Schin void 693*965005c8Schin makejob(int monitor, int fg) 6947c478bd9Sstevel@tonic-gate { 6957c478bd9Sstevel@tonic-gate if (monitor) { 6967c478bd9Sstevel@tonic-gate mypgid = mypid; 6977c478bd9Sstevel@tonic-gate setpgid(0, 0); 6987c478bd9Sstevel@tonic-gate if (fg) 6997c478bd9Sstevel@tonic-gate tcsetpgrp(0, mypid); 7007c478bd9Sstevel@tonic-gate handle(SIGTTOU, SIG_DFL); 7017c478bd9Sstevel@tonic-gate handle(SIGTSTP, SIG_DFL); 7027c478bd9Sstevel@tonic-gate } else if (!fg) { 7037c478bd9Sstevel@tonic-gate #ifdef NICE 7047c478bd9Sstevel@tonic-gate nice(NICE); 7057c478bd9Sstevel@tonic-gate #endif 7067c478bd9Sstevel@tonic-gate handle(SIGTTIN, SIG_IGN); 7077c478bd9Sstevel@tonic-gate handle(SIGINT, SIG_IGN); 7087c478bd9Sstevel@tonic-gate handle(SIGQUIT, SIG_IGN); 7097c478bd9Sstevel@tonic-gate if (!ioset) 7107c478bd9Sstevel@tonic-gate renamef(chkopen(devnull, 0), 0); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * called by the shell after job has been spawned, to fill in the 7167c478bd9Sstevel@tonic-gate * job slot, and wait for the job if in the foreground 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate void 7207c478bd9Sstevel@tonic-gate postjob(pid, fg) 7217c478bd9Sstevel@tonic-gate pid_t pid; 7227c478bd9Sstevel@tonic-gate int fg; 7237c478bd9Sstevel@tonic-gate { 7247c478bd9Sstevel@tonic-gate 725*965005c8Schin int propts; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate thisjob->j_nxtp = *nextjob; 7287c478bd9Sstevel@tonic-gate *nextjob = thisjob; 7297c478bd9Sstevel@tonic-gate thisjob->j_curp = jobcur; 7307c478bd9Sstevel@tonic-gate jobcur = thisjob; 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate if (thisjob->j_jid) { 7337c478bd9Sstevel@tonic-gate thisjob->j_pgid = pid; 7347c478bd9Sstevel@tonic-gate propts = PR_JID|PR_PGID; 7357c478bd9Sstevel@tonic-gate } else { 7367c478bd9Sstevel@tonic-gate thisjob->j_pgid = mypgid; 7377c478bd9Sstevel@tonic-gate propts = PR_PGID; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate thisjob->j_flag = J_RUNNING; 7417c478bd9Sstevel@tonic-gate thisjob->j_tgid = thisjob->j_pgid; 7427c478bd9Sstevel@tonic-gate thisjob->j_pid = pid; 7437c478bd9Sstevel@tonic-gate eofflg = 0; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if (fg) { 7467c478bd9Sstevel@tonic-gate thisjob->j_flag |= J_FOREGND; 7477c478bd9Sstevel@tonic-gate waitjob(thisjob); 7487c478bd9Sstevel@tonic-gate } else { 7497c478bd9Sstevel@tonic-gate if (flags & ttyflg) 7507c478bd9Sstevel@tonic-gate printjob(thisjob, propts); 7517c478bd9Sstevel@tonic-gate assnum(&pcsadr, (long)pid); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* 7567c478bd9Sstevel@tonic-gate * the builtin "jobs" command 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate void 7607c478bd9Sstevel@tonic-gate sysjobs(argc, argv) 7617c478bd9Sstevel@tonic-gate int argc; 7627c478bd9Sstevel@tonic-gate char *argv[]; 7637c478bd9Sstevel@tonic-gate { 764*965005c8Schin char *cmd = *argv; 765*965005c8Schin struct job *jp; 766*965005c8Schin int propts, c; 7677c478bd9Sstevel@tonic-gate extern int opterr, i; 7687c478bd9Sstevel@tonic-gate int savoptind = optind; 7697c478bd9Sstevel@tonic-gate int loptind = -1; 7707c478bd9Sstevel@tonic-gate int savopterr = opterr; 7717c478bd9Sstevel@tonic-gate int savsp = _sp; 7727c478bd9Sstevel@tonic-gate char *savoptarg = optarg; 7737c478bd9Sstevel@tonic-gate optind = 1; 7747c478bd9Sstevel@tonic-gate opterr = 0; 7757c478bd9Sstevel@tonic-gate _sp = 1; 7767c478bd9Sstevel@tonic-gate propts = 0; 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate if ((flags & jcflg) == 0) 779*965005c8Schin failed((unsigned char *)cmd, nojc); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "lpx")) != -1) { 7827c478bd9Sstevel@tonic-gate if (propts) { 7837c478bd9Sstevel@tonic-gate failure(usage, jobsuse); 7847c478bd9Sstevel@tonic-gate goto err; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate switch (c) { 7877c478bd9Sstevel@tonic-gate case 'x': 7887c478bd9Sstevel@tonic-gate propts = -1; 7897c478bd9Sstevel@tonic-gate break; 7907c478bd9Sstevel@tonic-gate case 'p': 7917c478bd9Sstevel@tonic-gate propts = PR_PGID; 7927c478bd9Sstevel@tonic-gate break; 7937c478bd9Sstevel@tonic-gate case 'l': 7947c478bd9Sstevel@tonic-gate propts = PR_LONG; 7957c478bd9Sstevel@tonic-gate break; 7967c478bd9Sstevel@tonic-gate case '?': 7977c478bd9Sstevel@tonic-gate failure(usage, jobsuse); 7987c478bd9Sstevel@tonic-gate goto err; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate loptind = optind; 8037c478bd9Sstevel@tonic-gate err: 8047c478bd9Sstevel@tonic-gate optind = savoptind; 8057c478bd9Sstevel@tonic-gate optarg = savoptarg; 8067c478bd9Sstevel@tonic-gate opterr = savopterr; 8077c478bd9Sstevel@tonic-gate _sp = savsp; 8087c478bd9Sstevel@tonic-gate if (loptind == -1) 8097c478bd9Sstevel@tonic-gate return; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate if (propts == -1) { 812*965005c8Schin unsigned char *bp; 813*965005c8Schin char *cp; 8147c478bd9Sstevel@tonic-gate unsigned char *savebp; 8157c478bd9Sstevel@tonic-gate for (savebp = bp = locstak(); loptind < argc; loptind++) { 8167c478bd9Sstevel@tonic-gate cp = argv[loptind]; 8177c478bd9Sstevel@tonic-gate if (*cp == '%') { 8187c478bd9Sstevel@tonic-gate jp = str2job(cmd, cp, 1); 8197c478bd9Sstevel@tonic-gate itos(jp->j_pid); 8207c478bd9Sstevel@tonic-gate cp = (char *)numbuf; 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate while (*cp) { 8237c478bd9Sstevel@tonic-gate if (bp >= brkend) 8247c478bd9Sstevel@tonic-gate growstak(bp); 8257c478bd9Sstevel@tonic-gate *bp++ = *cp++; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate if (bp >= brkend) 8287c478bd9Sstevel@tonic-gate growstak(bp); 8297c478bd9Sstevel@tonic-gate *bp++ = SPACE; 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate endstak(bp); 8327c478bd9Sstevel@tonic-gate execexp(savebp, 0); 8337c478bd9Sstevel@tonic-gate return; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate collectjobs(WNOHANG); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate if (propts == 0) 8397c478bd9Sstevel@tonic-gate propts = PR_DFL; 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate if (loptind == argc) { 8427c478bd9Sstevel@tonic-gate for (jp = joblst; jp; jp = jp->j_nxtp) { 8437c478bd9Sstevel@tonic-gate if (jp->j_jid) 8447c478bd9Sstevel@tonic-gate printjob(jp, propts); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate } else do 8477c478bd9Sstevel@tonic-gate printjob(str2job(cmd, argv[loptind++], 1), propts); 8487c478bd9Sstevel@tonic-gate while (loptind < argc); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate /* 8537c478bd9Sstevel@tonic-gate * the builtin "fg" and "bg" commands 8547c478bd9Sstevel@tonic-gate */ 855*965005c8Schin void 856*965005c8Schin sysfgbg(int argc, char *argv[]) 8577c478bd9Sstevel@tonic-gate { 858*965005c8Schin char *cmd = *argv; 859*965005c8Schin int fg; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate if ((flags & jcflg) == 0) 862*965005c8Schin failed((unsigned char *)cmd, nojc); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate fg = eq("fg", cmd); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate if (*++argv == 0) { 8677c478bd9Sstevel@tonic-gate struct job *jp; 8687c478bd9Sstevel@tonic-gate for (jp = jobcur; ; jp = jp->j_curp) { 8697c478bd9Sstevel@tonic-gate if (jp == 0) 870*965005c8Schin failed((unsigned char *)cmd, nocurjob); 8717c478bd9Sstevel@tonic-gate if (jp->j_jid) 8727c478bd9Sstevel@tonic-gate break; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate restartjob(jp, fg); 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate else do 8787c478bd9Sstevel@tonic-gate restartjob(str2job(cmd, *argv, 1), fg); 8797c478bd9Sstevel@tonic-gate while (*++argv); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate /* 8847c478bd9Sstevel@tonic-gate * the builtin "wait" commands 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate void 8887c478bd9Sstevel@tonic-gate syswait(argc, argv) 8897c478bd9Sstevel@tonic-gate int argc; 8907c478bd9Sstevel@tonic-gate char *argv[]; 8917c478bd9Sstevel@tonic-gate { 892*965005c8Schin char *cmd = *argv; 893*965005c8Schin struct job *jp; 8947c478bd9Sstevel@tonic-gate int stat; 8957c478bd9Sstevel@tonic-gate int wflags; 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) 8987c478bd9Sstevel@tonic-gate wflags = WUNTRACED; 8997c478bd9Sstevel@tonic-gate else 9007c478bd9Sstevel@tonic-gate wflags = 0; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate if (argc == 1) 9037c478bd9Sstevel@tonic-gate collectjobs(0); 9047c478bd9Sstevel@tonic-gate else while (--argc) { 9057c478bd9Sstevel@tonic-gate if ((jp = str2job(cmd, *++argv, 0)) == 0) 9067c478bd9Sstevel@tonic-gate continue; 9077c478bd9Sstevel@tonic-gate if (!(jp->j_flag & J_RUNNING)) 9087c478bd9Sstevel@tonic-gate continue; 9097c478bd9Sstevel@tonic-gate if (waitpid(jp->j_pid, &stat, wflags) <= 0) 9107c478bd9Sstevel@tonic-gate break; 9117c478bd9Sstevel@tonic-gate (void) statjob(jp, stat, 0, 1); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 915*965005c8Schin static void 916*965005c8Schin sigv(char *cmd, int sig, char *args) 9177c478bd9Sstevel@tonic-gate { 9187c478bd9Sstevel@tonic-gate int pgrp = 0; 9197c478bd9Sstevel@tonic-gate int stopme = 0; 9207c478bd9Sstevel@tonic-gate pid_t id; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate if (*args == '%') { 923*965005c8Schin struct job *jp; 9247c478bd9Sstevel@tonic-gate jp = str2job(cmd, args, 1); 9257c478bd9Sstevel@tonic-gate id = jp->j_pgid; 9267c478bd9Sstevel@tonic-gate pgrp++; 9277c478bd9Sstevel@tonic-gate } else { 9287c478bd9Sstevel@tonic-gate if (*args == '-') { 9297c478bd9Sstevel@tonic-gate pgrp++; 9307c478bd9Sstevel@tonic-gate args++; 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate id = 0; 9337c478bd9Sstevel@tonic-gate do { 9347c478bd9Sstevel@tonic-gate if (*args < '0' || *args > '9') { 9357c478bd9Sstevel@tonic-gate failure(cmd, badid); 9367c478bd9Sstevel@tonic-gate return; 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate id = (id * 10) + (*args - '0'); 9397c478bd9Sstevel@tonic-gate } while (*++args); 9407c478bd9Sstevel@tonic-gate if (id == 0) { 9417c478bd9Sstevel@tonic-gate id = mypgid; 9427c478bd9Sstevel@tonic-gate pgrp++; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate if (sig == SIGSTOP) { 9477c478bd9Sstevel@tonic-gate if (id == mysid || id == mypid && mypgid == mysid) { 9487c478bd9Sstevel@tonic-gate failure(cmd, loginsh); 9497c478bd9Sstevel@tonic-gate return; 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate if (id == mypgid && mypgid != svpgid) { 9527c478bd9Sstevel@tonic-gate (void) settgid(svtgid, mypgid); 9537c478bd9Sstevel@tonic-gate setpgid(0, svpgid); 9547c478bd9Sstevel@tonic-gate stopme++; 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (pgrp) 9597c478bd9Sstevel@tonic-gate id = -id; 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (kill(id, sig) < 0) { 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate switch (errno) { 9647c478bd9Sstevel@tonic-gate case EPERM: 9657c478bd9Sstevel@tonic-gate failure(cmd, eacces); 9667c478bd9Sstevel@tonic-gate break; 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate case EINVAL: 9697c478bd9Sstevel@tonic-gate failure(cmd, badsig); 9707c478bd9Sstevel@tonic-gate break; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate default: 9737c478bd9Sstevel@tonic-gate if (pgrp) 9747c478bd9Sstevel@tonic-gate failure(cmd, nosuchpgid); 9757c478bd9Sstevel@tonic-gate else 9767c478bd9Sstevel@tonic-gate failure(cmd, nosuchpid); 9777c478bd9Sstevel@tonic-gate break; 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate } else if (sig == SIGTERM && pgrp) 9817c478bd9Sstevel@tonic-gate (void) kill(id, SIGCONT); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate if (stopme) { 9847c478bd9Sstevel@tonic-gate setpgid(0, mypgid); 9857c478bd9Sstevel@tonic-gate (void) settgid(mypgid, svpgid); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 990*965005c8Schin void 991*965005c8Schin sysstop(int argc, char *argv[]) 9927c478bd9Sstevel@tonic-gate { 9937c478bd9Sstevel@tonic-gate char *cmd = *argv; 9947c478bd9Sstevel@tonic-gate if (argc <= 1) 995*965005c8Schin failed((unsigned char *)usage, stopuse); 9967c478bd9Sstevel@tonic-gate while (*++argv) 9977c478bd9Sstevel@tonic-gate sigv(cmd, SIGSTOP, *argv); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 1000*965005c8Schin void 1001*965005c8Schin syskill(int argc, char *argv[]) 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate char *cmd = *argv; 10047c478bd9Sstevel@tonic-gate int sig = SIGTERM; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (argc == 1) { 10077c478bd9Sstevel@tonic-gate failure(usage, killuse); 10087c478bd9Sstevel@tonic-gate return; 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate if (argv[1][0] == '-') { 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate if (argc == 2) { 10147c478bd9Sstevel@tonic-gate 1015*965005c8Schin int i; 1016*965005c8Schin int cnt = 0; 1017*965005c8Schin char sep = 0; 10187c478bd9Sstevel@tonic-gate char buf[12]; 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate if (!eq(argv[1], "-l")) { 10217c478bd9Sstevel@tonic-gate failure(usage, killuse); 10227c478bd9Sstevel@tonic-gate return; 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate for (i = 1; i < MAXTRAP; i++) { 10267c478bd9Sstevel@tonic-gate if (sig2str(i, buf) < 0) 10277c478bd9Sstevel@tonic-gate continue; 10287c478bd9Sstevel@tonic-gate if (sep) 10297c478bd9Sstevel@tonic-gate prc_buff(sep); 10307c478bd9Sstevel@tonic-gate prs_buff(buf); 10317c478bd9Sstevel@tonic-gate if ((flags & ttyflg) && (++cnt % 10)) 10327c478bd9Sstevel@tonic-gate sep = TAB; 10337c478bd9Sstevel@tonic-gate else 10347c478bd9Sstevel@tonic-gate sep = NL; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate prc_buff(NL); 10377c478bd9Sstevel@tonic-gate return; 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate if (str2sig(&argv[1][1], &sig)) { 10417c478bd9Sstevel@tonic-gate failure(cmd, badsig); 10427c478bd9Sstevel@tonic-gate return; 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate argv++; 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate while (*++argv) 10487c478bd9Sstevel@tonic-gate sigv(cmd, sig, *argv); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 1052*965005c8Schin void 1053*965005c8Schin syssusp(int argc, char *argv[]) 10547c478bd9Sstevel@tonic-gate { 10557c478bd9Sstevel@tonic-gate if (argc != 1) 1056*965005c8Schin failed((unsigned char *)argv[0], badopt); 10577c478bd9Sstevel@tonic-gate sigv(argv[0], SIGSTOP, "0"); 10587c478bd9Sstevel@tonic-gate } 1059