]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/jobs.def
Bash-5.2 patch 17: fix for optimizing forks when using the . builtin in a subshell
[thirdparty/bash.git] / builtins / jobs.def
CommitLineData
726f6388 1This file is jobs.def, from which is created jobs.c.
ccc6cda3 2It implements the builtins "jobs" and "disown" in Bash.
726f6388 3
8868edaf 4Copyright (C) 1987-2020 Free Software Foundation, Inc.
726f6388
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
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.
726f6388 12
3185942a
JA
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.
726f6388 17
3185942a
JA
18You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
726f6388
JA
20
21$PRODUCES jobs.c
22
23$BUILTIN jobs
24$FUNCTION jobs_builtin
25$DEPENDS_ON JOB_CONTROL
ccc6cda3 26$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args]
3185942a
JA
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
ac50fbac 34 -n lists only processes that have changed status since the last
a0c0a00f 35 notification
3185942a
JA
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
ccc6cda3 42process group leader.
3185942a
JA
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.
726f6388
JA
47$END
48
ccc6cda3 49#include <config.h>
726f6388
JA
50
51#if defined (JOB_CONTROL)
ccc6cda3 52#include "../bashtypes.h"
726f6388 53#include <signal.h>
ccc6cda3
JA
54#if defined (HAVE_UNISTD_H)
55# include <unistd.h>
56#endif
57
58#include "../bashansi.h"
b80f6443 59#include "../bashintl.h"
726f6388 60
ccc6cda3
JA
61#include "../shell.h"
62#include "../jobs.h"
63#include "../execute_cmd.h"
726f6388 64#include "bashgetopt.h"
ccc6cda3
JA
65#include "common.h"
66
67#define JSTATE_ANY 0x0
68#define JSTATE_RUNNING 0x1
69#define JSTATE_STOPPED 0x2
726f6388 70
8868edaf 71static int execute_list_with_replacements PARAMS((WORD_LIST *));
726f6388
JA
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
ccc6cda3
JA
79 group leader and execute the command. The -r and -s options mean
80 to print info about running and stopped jobs only, respectively. */
726f6388
JA
81int
82jobs_builtin (list)
83 WORD_LIST *list;
84{
ccc6cda3
JA
85 int form, execute, state, opt, any_failed, job;
86 sigset_t set, oset;
726f6388 87
ccc6cda3
JA
88 execute = any_failed = 0;
89 form = JLIST_STANDARD;
90 state = JSTATE_ANY;
91
726f6388 92 reset_internal_getopt ();
ccc6cda3 93 while ((opt = internal_getopt (list, "lpnxrs")) != -1)
726f6388
JA
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 {
b80f6443 109 builtin_error (_("no other options allowed with `-x'"));
726f6388
JA
110 return (EXECUTION_FAILURE);
111 }
112 execute++;
113 break;
ccc6cda3
JA
114 case 'r':
115 state = JSTATE_RUNNING;
116 break;
117 case 's':
118 state = JSTATE_STOPPED;
119 break;
726f6388 120
a0c0a00f 121 CASE_HELPOPT;
726f6388 122 default:
ccc6cda3 123 builtin_usage ();
726f6388
JA
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 {
ccc6cda3
JA
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 }
726f6388
JA
147 return (EXECUTION_SUCCESS);
148 }
149
150 while (list)
151 {
726f6388
JA
152 BLOCK_CHILD (set, oset);
153 job = get_job_spec (list);
154
95732b49 155 if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
726f6388 156 {
7117c2d2 157 sh_badjob (list->word->word);
726f6388
JA
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;
b80f6443 175 COMMAND *command;
95732b49 176 JOB *j;
726f6388
JA
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. */
95732b49 186 if (INVALID_JOB (job))
726f6388
JA
187 continue;
188
95732b49 189 j = get_job_by_jid (job);
726f6388 190 free (l->word->word);
95732b49 191 l->word->word = itos (j->pgrp);
726f6388
JA
192 }
193 }
194
195 /* Next make a new simple command and execute it. */
196 begin_unwind_frame ("jobs_builtin");
726f6388 197
b80f6443
JA
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;
726f6388 203
b80f6443
JA
204 add_unwind_protect (dispose_command, command);
205 result = execute_command (command);
206 dispose_command (command);
726f6388 207
b80f6443 208 discard_unwind_frame ("jobs_builtin");
726f6388
JA
209 return (result);
210}
211#endif /* JOB_CONTROL */
ccc6cda3
JA
212
213$BUILTIN disown
214$FUNCTION disown_builtin
215$DEPENDS_ON JOB_CONTROL
a0c0a00f 216$SHORT_DOC disown [-h] [-ar] [jobspec ... | pid ...]
3185942a
JA
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
a0c0a00f 225 shell receives a SIGHUP
3185942a
JA
226 -r remove only running jobs
227
228Exit Status:
229Returns success unless an invalid option or JOBSPEC is given.
ccc6cda3
JA
230$END
231
232#if defined (JOB_CONTROL)
233int
234disown_builtin (list)
235 WORD_LIST *list;
236{
cce855bc 237 int opt, job, retval, nohup_only, running_jobs, all_jobs;
ccc6cda3 238 sigset_t set, oset;
7117c2d2 239 intmax_t pid_value;
ccc6cda3 240
cce855bc 241 nohup_only = running_jobs = all_jobs = 0;
ccc6cda3 242 reset_internal_getopt ();
cce855bc 243 while ((opt = internal_getopt (list, "ahr")) != -1)
ccc6cda3
JA
244 {
245 switch (opt)
246 {
cce855bc
JA
247 case 'a':
248 all_jobs = 1;
249 break;
ccc6cda3
JA
250 case 'h':
251 nohup_only = 1;
252 break;
cce855bc
JA
253 case 'r':
254 running_jobs = 1;
255 break;
a0c0a00f 256 CASE_HELPOPT;
ccc6cda3
JA
257 default:
258 builtin_usage ();
259 return (EX_USAGE);
260 }
261 }
262 list = loptend;
263 retval = EXECUTION_SUCCESS;
264
cce855bc
JA
265 /* `disown -a' or `disown -r' */
266 if (list == 0 && (all_jobs || running_jobs))
d166f048
JA
267 {
268 if (nohup_only)
cce855bc 269 nohup_all_jobs (running_jobs);
d166f048 270 else
cce855bc 271 delete_all_jobs (running_jobs);
d166f048
JA
272 return (EXECUTION_SUCCESS);
273 }
d166f048 274
ccc6cda3
JA
275 do
276 {
277 BLOCK_CHILD (set, oset);
f73dda09 278 job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
8868edaf 279 ? get_job_by_pid ((pid_t) pid_value, 0, 0)
d166f048 280 : get_job_spec (list);
ccc6cda3 281
95732b49 282 if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
ccc6cda3 283 {
3185942a 284 sh_badjob (list ? list->word->word : _("current"));
ccc6cda3
JA
285 retval = EXECUTION_FAILURE;
286 }
287 else if (nohup_only)
288 nohup_job (job);
289 else
cce855bc 290 delete_job (job, 1);
ccc6cda3
JA
291 UNBLOCK_CHILD (oset);
292
293 if (list)
294 list = list->next;
295 }
296 while (list);
d166f048 297
ccc6cda3
JA
298 return (retval);
299}
300#endif /* JOB_CONTROL */