No specific user configuration
[platform/upstream/bash.git] / builtins / wait.def
1 This file is wait.def, from which is created wait.c.
2 It implements the builtin "wait" in Bash.
3
4 Copyright (C) 1987-2013 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 $BUILTIN wait
22 $FUNCTION wait_builtin
23 $DEPENDS_ON JOB_CONTROL
24 $PRODUCES wait.c
25 $SHORT_DOC wait [-n] [id ...]
26 Wait for job completion and return exit status.
27
28 Waits for each process identified by an ID, which may be a process ID or a
29 job specification, and reports its termination status.  If ID is not
30 given, waits for all currently active child processes, and the return
31 status is zero.  If ID is a a job specification, waits for all processes
32 in that job's pipeline.
33
34 If the -n option is supplied, waits for the next job to terminate and
35 returns its exit status.
36
37 Exit Status:
38 Returns the status of the last ID; fails if ID is invalid or an invalid
39 option is given.
40 $END
41
42 $BUILTIN wait
43 $FUNCTION wait_builtin
44 $DEPENDS_ON !JOB_CONTROL
45 $SHORT_DOC wait [pid ...]
46 Wait for process completion and return exit status.
47
48 Waits for each process specified by a PID and reports its termination status.
49 If PID is not given, waits for all currently active child processes,
50 and the return status is zero.  PID must be a process ID.
51
52 Exit Status:
53 Returns the status of the last PID; fails if PID is invalid or an invalid
54 option is given.
55 $END
56
57 #include <config.h>
58
59 #include "../bashtypes.h"
60 #include <signal.h>
61
62 #if defined (HAVE_UNISTD_H)
63 #  include <unistd.h>
64 #endif
65
66 #include <chartypes.h>
67
68 #include "../bashansi.h"
69
70 #include "../shell.h"
71 #include "../jobs.h"
72 #include "common.h"
73 #include "bashgetopt.h"
74
75 extern int wait_signal_received;
76
77 procenv_t wait_intr_buf;
78
79 /* Wait for the pid in LIST to stop or die.  If no arguments are given, then
80    wait for all of the active background processes of the shell and return
81    0.  If a list of pids or job specs are given, return the exit status of
82    the last one waited for. */
83
84 #define WAIT_RETURN(s) \
85   do \
86     { \
87       interrupt_immediately = old_interrupt_immediately;\
88       wait_signal_received = 0; \
89       return (s);\
90     } \
91   while (0)
92
93 int
94 wait_builtin (list)
95      WORD_LIST *list;
96 {
97   int status, code, opt, nflag;
98   volatile int old_interrupt_immediately;
99
100   USE_VAR(list);
101
102   nflag = 0;
103   reset_internal_getopt ();
104   while ((opt = internal_getopt (list, "n")) != -1)
105     {
106       switch (opt)
107         {
108 #if defined (JOB_CONTROL)
109         case 'n':
110           nflag = 1;
111           break;
112 #endif
113         default:
114           builtin_usage ();
115           return (EX_USAGE);
116         }
117     }
118   list = loptend;
119
120   old_interrupt_immediately = interrupt_immediately;
121 #if 0
122   interrupt_immediately++;
123 #endif
124
125   /* POSIX.2 says:  When the shell is waiting (by means of the wait utility)
126      for asynchronous commands to complete, the reception of a signal for
127      which a trap has been set shall cause the wait utility to return
128      immediately with an exit status greater than 128, after which the trap
129      associated with the signal shall be taken.
130
131      We handle SIGINT here; it's the only one that needs to be treated
132      specially (I think), since it's handled specially in {no,}jobs.c. */
133   code = setjmp (wait_intr_buf);
134   if (code)
135     {
136       status = 128 + wait_signal_received;
137       WAIT_RETURN (status);
138     }
139
140   /* We support jobs or pids.
141      wait <pid-or-job> [pid-or-job ...] */
142
143 #if defined (JOB_CONTROL)
144   if (nflag)
145     {
146       status = wait_for_any_job ();
147       if (status < 0)
148         status = 127;
149       WAIT_RETURN (status);
150     }
151 #endif
152       
153   /* But wait without any arguments means to wait for all of the shell's
154      currently active background processes. */
155   if (list == 0)
156     {
157       wait_for_background_pids ();
158       WAIT_RETURN (EXECUTION_SUCCESS);
159     }
160
161   status = EXECUTION_SUCCESS;
162   while (list)
163     {
164       pid_t pid;
165       char *w;
166       intmax_t pid_value;
167
168       w = list->word->word;
169       if (DIGIT (*w))
170         {
171           if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
172             {
173               pid = (pid_t)pid_value;
174               status = wait_for_single_pid (pid);
175             }
176           else
177             {
178               sh_badpid (w);
179               WAIT_RETURN (EXECUTION_FAILURE);
180             }
181         }
182 #if defined (JOB_CONTROL)
183       else if (*w && *w == '%')
184         /* Must be a job spec.  Check it out. */
185         {
186           int job;
187           sigset_t set, oset;
188
189           BLOCK_CHILD (set, oset);
190           job = get_job_spec (list);
191
192           if (INVALID_JOB (job))
193             {
194               if (job != DUP_JOB)
195                 sh_badjob (list->word->word);
196               UNBLOCK_CHILD (oset);
197               status = 127;     /* As per Posix.2, section 4.70.2 */
198               list = list->next;
199               continue;
200             }
201
202           /* Job spec used.  Wait for the last pid in the pipeline. */
203           UNBLOCK_CHILD (oset);
204           status = wait_for_job (job);
205         }
206 #endif /* JOB_CONTROL */
207       else
208         {
209           sh_badpid (w);
210           status = EXECUTION_FAILURE;
211         }
212       list = list->next;
213     }
214
215   WAIT_RETURN (status);
216 }