blob: 2a713ae958a45d77700b0e8e0392d582daf540e5 [file] [log] [blame]
Dan Pasanenc6e37862014-10-02 14:08:59 -05001/* wait.c, created from wait.def. */
2#line 41 "./wait.def"
3
4#line 56 "./wait.def"
5
6#include <config.h>
7
8#include "../bashtypes.h"
9#include <signal.h>
10
11#if defined (HAVE_UNISTD_H)
12# include <unistd.h>
13#endif
14
15#include <chartypes.h>
16
17#include "../bashansi.h"
18
19#include "../shell.h"
20#include "../jobs.h"
21#include "common.h"
22#include "bashgetopt.h"
23
24extern int wait_signal_received;
25
26procenv_t wait_intr_buf;
27
28/* Wait for the pid in LIST to stop or die. If no arguments are given, then
29 wait for all of the active background processes of the shell and return
30 0. If a list of pids or job specs are given, return the exit status of
31 the last one waited for. */
32
33#define WAIT_RETURN(s) \
34 do \
35 { \
36 interrupt_immediately = old_interrupt_immediately;\
37 wait_signal_received = 0; \
38 return (s);\
39 } \
40 while (0)
41
42int
43wait_builtin (list)
44 WORD_LIST *list;
45{
46 int status, code, opt, nflag;
47 volatile int old_interrupt_immediately;
48
49 USE_VAR(list);
50
51 nflag = 0;
52 reset_internal_getopt ();
53 while ((opt = internal_getopt (list, "n")) != -1)
54 {
55 switch (opt)
56 {
57#if defined (JOB_CONTROL)
58 case 'n':
59 nflag = 1;
60 break;
61#endif
62 default:
63 builtin_usage ();
64 return (EX_USAGE);
65 }
66 }
67 list = loptend;
68
69 old_interrupt_immediately = interrupt_immediately;
70#if 0
71 interrupt_immediately++;
72#endif
73
74 /* POSIX.2 says: When the shell is waiting (by means of the wait utility)
75 for asynchronous commands to complete, the reception of a signal for
76 which a trap has been set shall cause the wait utility to return
77 immediately with an exit status greater than 128, after which the trap
78 associated with the signal shall be taken.
79
80 We handle SIGINT here; it's the only one that needs to be treated
81 specially (I think), since it's handled specially in {no,}jobs.c. */
82 code = setjmp (wait_intr_buf);
83 if (code)
84 {
85 status = 128 + wait_signal_received;
86 WAIT_RETURN (status);
87 }
88
89 /* We support jobs or pids.
90 wait <pid-or-job> [pid-or-job ...] */
91
92#if defined (JOB_CONTROL)
93 if (nflag)
94 {
95 status = wait_for_any_job ();
96 if (status < 0)
97 status = 127;
98 WAIT_RETURN (status);
99 }
100#endif
101
102 /* But wait without any arguments means to wait for all of the shell's
103 currently active background processes. */
104 if (list == 0)
105 {
106 wait_for_background_pids ();
107 WAIT_RETURN (EXECUTION_SUCCESS);
108 }
109
110 status = EXECUTION_SUCCESS;
111 while (list)
112 {
113 pid_t pid;
114 char *w;
115 intmax_t pid_value;
116
117 w = list->word->word;
118 if (DIGIT (*w))
119 {
120 if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
121 {
122 pid = (pid_t)pid_value;
123 status = wait_for_single_pid (pid);
124 }
125 else
126 {
127 sh_badpid (w);
128 WAIT_RETURN (EXECUTION_FAILURE);
129 }
130 }
131#if defined (JOB_CONTROL)
132 else if (*w && *w == '%')
133 /* Must be a job spec. Check it out. */
134 {
135 int job;
136 sigset_t set, oset;
137
138 BLOCK_CHILD (set, oset);
139 job = get_job_spec (list);
140
141 if (INVALID_JOB (job))
142 {
143 if (job != DUP_JOB)
144 sh_badjob (list->word->word);
145 UNBLOCK_CHILD (oset);
146 status = 127; /* As per Posix.2, section 4.70.2 */
147 list = list->next;
148 continue;
149 }
150
151 /* Job spec used. Wait for the last pid in the pipeline. */
152 UNBLOCK_CHILD (oset);
153 status = wait_for_job (job);
154 }
155#endif /* JOB_CONTROL */
156 else
157 {
158 sh_badpid (w);
159 status = EXECUTION_FAILURE;
160 }
161 list = list->next;
162 }
163
164 WAIT_RETURN (status);
165}