b14e91f24b8b080a5f3dd61c222906a09a97bec2
[platform/upstream/bash.git] / builtins / jobs.def
1 This file is jobs.def, from which is created jobs.c.
2 It implements the builtins "jobs" and "disown" in Bash.
3
4 Copyright (C) 1987-2009 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along 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]
27 Display status of jobs.
28
29 Lists the active jobs.  JOBSPEC restricts output to that job.
30 Without options, the status of all active jobs is displayed.
31
32 Options:
33   -l    lists process IDs in addition to the normal information
34   -n    list 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
40 If -x is supplied, COMMAND is run after all job specifications that
41 appear in ARGS have been replaced with the process ID of that job's
42 process group leader.
43
44 Exit Status:
45 Returns success unless an invalid option is given or an error occurs.
46 If -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
71 static int execute_list_with_replacements __P((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. */
81 int
82 jobs_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         default:
122           builtin_usage ();
123           return (EX_USAGE);
124         }
125     }
126
127   list = loptend;
128
129   if (execute)
130     return (execute_list_with_replacements (list));
131
132   if (!list)
133     {
134       switch (state)
135         {
136         case JSTATE_ANY:
137           list_all_jobs (form);
138           break;
139         case JSTATE_RUNNING:
140           list_running_jobs (form);
141           break;
142         case JSTATE_STOPPED:
143           list_stopped_jobs (form);
144           break;
145         }
146       return (EXECUTION_SUCCESS);
147     }
148
149   while (list)
150     {
151       BLOCK_CHILD (set, oset);
152       job = get_job_spec (list);
153
154       if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
155         {
156           sh_badjob (list->word->word);
157           any_failed++;
158         }
159       else if (job != DUP_JOB)
160         list_one_job ((JOB *)NULL, form, 0, job);
161
162       UNBLOCK_CHILD (oset);
163       list = list->next;
164     }
165   return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
166 }
167
168 static int
169 execute_list_with_replacements (list)
170      WORD_LIST *list;
171 {
172   register WORD_LIST *l;
173   int job, result;
174   COMMAND *command;
175   JOB *j;
176
177   /* First do the replacement of job specifications with pids. */
178   for (l = list; l; l = l->next)
179     {
180       if (l->word->word[0] == '%')      /* we have a winner */
181         {
182           job = get_job_spec (l);
183
184           /* A bad job spec is not really a job spec! Pass it through. */
185           if (INVALID_JOB (job))
186             continue;
187
188           j = get_job_by_jid (job);
189           free (l->word->word);
190           l->word->word = itos (j->pgrp);
191         }
192     }
193
194   /* Next make a new simple command and execute it. */
195   begin_unwind_frame ("jobs_builtin");
196
197   command = make_bare_simple_command ();
198   command->value.Simple->words = copy_word_list (list);
199   command->value.Simple->redirects = (REDIRECT *)NULL;
200   command->flags |= CMD_INHIBIT_EXPANSION;
201   command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
202
203   add_unwind_protect (dispose_command, command);
204   result = execute_command (command);
205   dispose_command (command);
206
207   discard_unwind_frame ("jobs_builtin");
208   return (result);
209 }
210 #endif /* JOB_CONTROL */
211
212 $BUILTIN disown
213 $FUNCTION disown_builtin
214 $DEPENDS_ON JOB_CONTROL
215 $SHORT_DOC disown [-h] [-ar] [jobspec ...]
216 Remove jobs from current shell.
217
218 Removes each JOBSPEC argument from the table of active jobs.  Without
219 any JOBSPECs, the shell uses its notion of the current job.
220
221 Options:
222   -a    remove all jobs if JOBSPEC is not supplied
223   -h    mark each JOBSPEC so that SIGHUP is not sent to the job if the
224         shell receives a SIGHUP
225   -r    remove only running jobs
226
227 Exit Status:
228 Returns success unless an invalid option or JOBSPEC is given.
229 $END
230
231 #if defined (JOB_CONTROL)
232 int
233 disown_builtin (list)
234      WORD_LIST *list;
235 {
236   int opt, job, retval, nohup_only, running_jobs, all_jobs;
237   sigset_t set, oset;
238   intmax_t pid_value;
239
240   nohup_only = running_jobs = all_jobs = 0;
241   reset_internal_getopt ();
242   while ((opt = internal_getopt (list, "ahr")) != -1)
243     {
244       switch (opt)
245         {
246         case 'a':
247           all_jobs = 1;
248           break;
249         case 'h':
250           nohup_only = 1;
251           break;
252         case 'r':
253           running_jobs = 1;
254           break;
255         default:
256           builtin_usage ();
257           return (EX_USAGE);
258         }
259     }
260   list = loptend;
261   retval = EXECUTION_SUCCESS;
262
263   /* `disown -a' or `disown -r' */
264   if (list == 0 && (all_jobs || running_jobs))
265     {
266       if (nohup_only)
267         nohup_all_jobs (running_jobs);
268       else
269         delete_all_jobs (running_jobs);
270       return (EXECUTION_SUCCESS);
271     }
272
273   do
274     {
275       BLOCK_CHILD (set, oset);
276       job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
277                 ? get_job_by_pid ((pid_t) pid_value, 0)
278                 : get_job_spec (list);
279
280       if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
281         {
282           sh_badjob (list ? list->word->word : _("current"));
283           retval = EXECUTION_FAILURE;
284         }
285       else if (nohup_only)
286         nohup_job (job);
287       else
288         delete_job (job, 1);
289       UNBLOCK_CHILD (oset);
290
291       if (list)
292         list = list->next;
293     }
294   while (list);
295
296   return (retval);
297 }
298 #endif /* JOB_CONTROL */