1This file is jobs.def, from which is created jobs.c. 2It implements the builtins "jobs" and "disown" in Bash. 3 4Copyright (C) 1987-2020 Free Software Foundation, Inc. 5 6This file is part of GNU Bash, the Bourne Again SHell. 7 8Bash is free software: you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation, either version 3 of the License, or 11(at your option) any later version. 12 13Bash is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with Bash. If not, see <http://www.gnu.org/licenses/>. 20 21$PRODUCES jobs.c 22 23$BUILTIN jobs 24$FUNCTION jobs_builtin 25$DEPENDS_ON JOB_CONTROL 26$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args] 27Display status of jobs. 28 29Lists the active jobs. JOBSPEC restricts output to that job. 30Without options, the status of all active jobs is displayed. 31 32Options: 33 -l lists process IDs in addition to the normal information 34 -n lists only processes that have changed status since the last 35 notification 36 -p lists process IDs only 37 -r restrict output to running jobs 38 -s restrict output to stopped jobs 39 40If -x is supplied, COMMAND is run after all job specifications that 41appear in ARGS have been replaced with the process ID of that job's 42process group leader. 43 44Exit Status: 45Returns success unless an invalid option is given or an error occurs. 46If -x is used, returns the exit status of COMMAND. 47$END 48 49#include <config.h> 50 51#if defined (JOB_CONTROL) 52#include "../bashtypes.h" 53#include <signal.h> 54#if defined (HAVE_UNISTD_H) 55# include <unistd.h> 56#endif 57 58#include "../bashansi.h" 59#include "../bashintl.h" 60 61#include "../shell.h" 62#include "../jobs.h" 63#include "../execute_cmd.h" 64#include "bashgetopt.h" 65#include "common.h" 66 67#define JSTATE_ANY 0x0 68#define JSTATE_RUNNING 0x1 69#define JSTATE_STOPPED 0x2 70 71static int execute_list_with_replacements PARAMS((WORD_LIST *)); 72 73/* The `jobs' command. Prints outs a list of active jobs. If the 74 argument `-l' is given, then the process id's are printed also. 75 If the argument `-p' is given, print the process group leader's 76 pid only. If `-n' is given, only processes that have changed 77 status since the last notification are printed. If -x is given, 78 replace all job specs with the pid of the appropriate process 79 group leader and execute the command. The -r and -s options mean 80 to print info about running and stopped jobs only, respectively. */ 81int 82jobs_builtin (list) 83 WORD_LIST *list; 84{ 85 int form, execute, state, opt, any_failed, job; 86 sigset_t set, oset; 87 88 execute = any_failed = 0; 89 form = JLIST_STANDARD; 90 state = JSTATE_ANY; 91 92 reset_internal_getopt (); 93 while ((opt = internal_getopt (list, "lpnxrs")) != -1) 94 { 95 switch (opt) 96 { 97 case 'l': 98 form = JLIST_LONG; 99 break; 100 case 'p': 101 form = JLIST_PID_ONLY; 102 break; 103 case 'n': 104 form = JLIST_CHANGED_ONLY; 105 break; 106 case 'x': 107 if (form != JLIST_STANDARD) 108 { 109 builtin_error (_("no other options allowed with `-x'")); 110 return (EXECUTION_FAILURE); 111 } 112 execute++; 113 break; 114 case 'r': 115 state = JSTATE_RUNNING; 116 break; 117 case 's': 118 state = JSTATE_STOPPED; 119 break; 120 121 CASE_HELPOPT; 122 default: 123 builtin_usage (); 124 return (EX_USAGE); 125 } 126 } 127 128 list = loptend; 129 130 if (execute) 131 return (execute_list_with_replacements (list)); 132 133 if (!list) 134 { 135 switch (state) 136 { 137 case JSTATE_ANY: 138 list_all_jobs (form); 139 break; 140 case JSTATE_RUNNING: 141 list_running_jobs (form); 142 break; 143 case JSTATE_STOPPED: 144 list_stopped_jobs (form); 145 break; 146 } 147 return (EXECUTION_SUCCESS); 148 } 149 150 while (list) 151 { 152 BLOCK_CHILD (set, oset); 153 job = get_job_spec (list); 154 155 if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0) 156 { 157 sh_badjob (list->word->word); 158 any_failed++; 159 } 160 else if (job != DUP_JOB) 161 list_one_job ((JOB *)NULL, form, 0, job); 162 163 UNBLOCK_CHILD (oset); 164 list = list->next; 165 } 166 return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); 167} 168 169static int 170execute_list_with_replacements (list) 171 WORD_LIST *list; 172{ 173 register WORD_LIST *l; 174 int job, result; 175 COMMAND *command; 176 JOB *j; 177 178 /* First do the replacement of job specifications with pids. */ 179 for (l = list; l; l = l->next) 180 { 181 if (l->word->word[0] == '%') /* we have a winner */ 182 { 183 job = get_job_spec (l); 184 185 /* A bad job spec is not really a job spec! Pass it through. */ 186 if (INVALID_JOB (job)) 187 continue; 188 189 j = get_job_by_jid (job); 190 free (l->word->word); 191 l->word->word = itos (j->pgrp); 192 } 193 } 194 195 /* Next make a new simple command and execute it. */ 196 begin_unwind_frame ("jobs_builtin"); 197 198 command = make_bare_simple_command (); 199 command->value.Simple->words = copy_word_list (list); 200 command->value.Simple->redirects = (REDIRECT *)NULL; 201 command->flags |= CMD_INHIBIT_EXPANSION; 202 command->value.Simple->flags |= CMD_INHIBIT_EXPANSION; 203 204 add_unwind_protect (dispose_command, command); 205 result = execute_command (command); 206 dispose_command (command); 207 208 discard_unwind_frame ("jobs_builtin"); 209 return (result); 210} 211#endif /* JOB_CONTROL */ 212 213$BUILTIN disown 214$FUNCTION disown_builtin 215$DEPENDS_ON JOB_CONTROL 216$SHORT_DOC disown [-h] [-ar] [jobspec ... | pid ...] 217Remove jobs from current shell. 218 219Removes each JOBSPEC argument from the table of active jobs. Without 220any JOBSPECs, the shell uses its notion of the current job. 221 222Options: 223 -a remove all jobs if JOBSPEC is not supplied 224 -h mark each JOBSPEC so that SIGHUP is not sent to the job if the 225 shell receives a SIGHUP 226 -r remove only running jobs 227 228Exit Status: 229Returns success unless an invalid option or JOBSPEC is given. 230$END 231 232#if defined (JOB_CONTROL) 233int 234disown_builtin (list) 235 WORD_LIST *list; 236{ 237 int opt, job, retval, nohup_only, running_jobs, all_jobs; 238 sigset_t set, oset; 239 intmax_t pid_value; 240 241 nohup_only = running_jobs = all_jobs = 0; 242 reset_internal_getopt (); 243 while ((opt = internal_getopt (list, "ahr")) != -1) 244 { 245 switch (opt) 246 { 247 case 'a': 248 all_jobs = 1; 249 break; 250 case 'h': 251 nohup_only = 1; 252 break; 253 case 'r': 254 running_jobs = 1; 255 break; 256 CASE_HELPOPT; 257 default: 258 builtin_usage (); 259 return (EX_USAGE); 260 } 261 } 262 list = loptend; 263 retval = EXECUTION_SUCCESS; 264 265 /* `disown -a' or `disown -r' */ 266 if (list == 0 && (all_jobs || running_jobs)) 267 { 268 if (nohup_only) 269 nohup_all_jobs (running_jobs); 270 else 271 delete_all_jobs (running_jobs); 272 return (EXECUTION_SUCCESS); 273 } 274 275 do 276 { 277 BLOCK_CHILD (set, oset); 278 job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value) 279 ? get_job_by_pid ((pid_t) pid_value, 0, 0) 280 : get_job_spec (list); 281 282 if (job == NO_JOB || jobs == 0 || INVALID_JOB (job)) 283 { 284 sh_badjob (list ? list->word->word : _("current")); 285 retval = EXECUTION_FAILURE; 286 } 287 else if (nohup_only) 288 nohup_job (job); 289 else 290 delete_job (job, 1); 291 UNBLOCK_CHILD (oset); 292 293 if (list) 294 list = list->next; 295 } 296 while (list); 297 298 return (retval); 299} 300#endif /* JOB_CONTROL */ 301