]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | /* The thing that makes children, remembers them, and contains wait loops. */ |
2 | ||
ccc6cda3 JA |
3 | /* This file works under BSD, System V, minix, and Posix systems. It does |
4 | not implement job control. */ | |
726f6388 JA |
5 | |
6 | /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. | |
7 | ||
8 | This file is part of GNU Bash, the Bourne Again SHell. | |
9 | ||
10 | Bash is free software; you can redistribute it and/or modify it under | |
11 | the terms of the GNU General Public License as published by the Free | |
12 | Software Foundation; either version 1, or (at your option) any later | |
13 | version. | |
14 | ||
15 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY | |
16 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 | for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License along | |
21 | with Bash; see the file COPYING. If not, write to the Free Software | |
22 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
23 | ||
ccc6cda3 JA |
24 | #include "config.h" |
25 | ||
726f6388 | 26 | #include "bashtypes.h" |
ccc6cda3 JA |
27 | #include "filecntl.h" |
28 | ||
29 | #if defined (HAVE_UNISTD_H) | |
30 | # include <unistd.h> | |
31 | #endif | |
32 | ||
33 | #include <stdio.h> | |
726f6388 | 34 | #include <signal.h> |
726f6388 JA |
35 | #include <errno.h> |
36 | ||
ccc6cda3 JA |
37 | #include "bashjmp.h" |
38 | ||
726f6388 JA |
39 | #include "command.h" |
40 | #include "general.h" | |
726f6388 JA |
41 | #include "jobs.h" |
42 | #include "externs.h" | |
ccc6cda3 | 43 | #include "sig.h" |
726f6388 | 44 | #include "error.h" |
ccc6cda3 | 45 | #include "bashtty.h" |
726f6388 JA |
46 | |
47 | #if defined (BUFFERED_INPUT) | |
48 | # include "input.h" | |
49 | #endif | |
50 | ||
ccc6cda3 JA |
51 | #if defined (TERMIOS_TTY_DRIVER) |
52 | # include <termios.h> | |
726f6388 | 53 | #else |
ccc6cda3 | 54 | # if defined (TERMIO_TTY_DRIVER) |
726f6388 | 55 | # include <termio.h> |
ccc6cda3 JA |
56 | # else |
57 | # include <sgtty.h> | |
58 | # endif /* !TERMIO_TTY_DRIVER */ | |
59 | #endif /* TERMIOS_TTY_DRIVER */ | |
60 | ||
d166f048 | 61 | #if !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) |
ccc6cda3 JA |
62 | /* For struct winsize on SCO */ |
63 | /* sys/ptem.h has winsize but needs mblk_t from sys/stream.h */ | |
d166f048 JA |
64 | # if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH) |
65 | # if defined (HAVE_SYS_STREAM_H) | |
66 | # include <sys/stream.h> | |
67 | # endif | |
68 | # include <sys/ptem.h> | |
69 | # endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */ | |
70 | #endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */ | |
726f6388 | 71 | |
ccc6cda3 | 72 | #if defined (_POSIX_VERSION) || !defined (HAVE_KILLPG) |
726f6388 JA |
73 | # define killpg(pg, sig) kill(-(pg),(sig)) |
74 | #endif /* USG || _POSIX_VERSION */ | |
75 | ||
ccc6cda3 | 76 | #if !defined (HAVE_SIGINTERRUPT) |
726f6388 JA |
77 | # define siginterrupt(sig, code) |
78 | #endif /* USG */ | |
79 | ||
ccc6cda3 | 80 | #if defined (HAVE_WAITPID) |
726f6388 JA |
81 | # define WAITPID(pid, statusp, options) waitpid (pid, statusp, options) |
82 | #else | |
83 | # define WAITPID(pid, statusp, options) wait (statusp) | |
ccc6cda3 | 84 | #endif /* !HAVE_WAITPID */ |
726f6388 | 85 | |
d166f048 JA |
86 | /* Return the fd from which we are actually getting input. */ |
87 | #define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) | |
88 | ||
726f6388 JA |
89 | #if !defined (errno) |
90 | extern int errno; | |
91 | #endif /* !errno */ | |
92 | ||
d166f048 JA |
93 | #if defined (READLINE) |
94 | extern void _rl_set_screen_size (); | |
95 | #endif | |
96 | ||
726f6388 JA |
97 | extern int interactive, interactive_shell, login_shell; |
98 | extern int subshell_environment; | |
99 | extern int last_command_exit_value; | |
ccc6cda3 | 100 | #if defined (HAVE_POSIX_SIGNALS) |
726f6388 JA |
101 | extern sigset_t top_level_mask; |
102 | #endif | |
103 | ||
104 | pid_t last_made_pid = NO_PID; | |
105 | pid_t last_asynchronous_pid = NO_PID; | |
106 | ||
107 | /* Call this when you start making children. */ | |
108 | int already_making_children = 0; | |
109 | ||
d166f048 JA |
110 | /* The controlling tty for this shell. */ |
111 | int shell_tty = -1; | |
112 | ||
ccc6cda3 JA |
113 | /* If this is non-zero, $LINES and $COLUMNS are reset after every process |
114 | exits from get_tty_state(). */ | |
115 | int check_window_size; | |
116 | ||
117 | #if defined (HAVE_WAITPID) | |
726f6388 JA |
118 | static void reap_zombie_children (); |
119 | #endif | |
120 | ||
121 | struct proc_status { | |
122 | pid_t pid; | |
123 | int status; /* Exit status of PID or 128 + fatal signal number */ | |
124 | }; | |
125 | ||
126 | static struct proc_status *pid_list = (struct proc_status *)NULL; | |
ccc6cda3 | 127 | static int pid_list_size; |
726f6388 JA |
128 | |
129 | #define PROC_BAD -1 | |
130 | #define PROC_STILL_ALIVE -2 | |
131 | ||
132 | /* Allocate new, or grow existing PID_LIST. */ | |
133 | static void | |
134 | alloc_pid_list () | |
135 | { | |
136 | register int i; | |
137 | int old = pid_list_size; | |
138 | ||
139 | pid_list_size += 10; | |
140 | pid_list = (struct proc_status *) | |
141 | xrealloc (pid_list, pid_list_size * sizeof (struct proc_status)); | |
142 | ||
143 | /* None of the newly allocated slots have process id's yet. */ | |
144 | for (i = old; i < pid_list_size; i++) | |
ccc6cda3 | 145 | pid_list[i].pid = NO_PID; |
726f6388 JA |
146 | } |
147 | ||
148 | /* Return the offset within the PID_LIST array of an empty slot. This can | |
149 | create new slots if all of the existing slots are taken. */ | |
150 | static int | |
151 | find_proc_slot () | |
152 | { | |
153 | register int i; | |
154 | ||
155 | for (i = 0; i < pid_list_size; i++) | |
156 | if (pid_list[i].pid == NO_PID) | |
157 | return (i); | |
158 | ||
159 | if (i == pid_list_size) | |
160 | alloc_pid_list (); | |
161 | ||
162 | return (i); | |
163 | } | |
164 | ||
165 | /* Return the offset within the PID_LIST array of a slot containing PID, | |
166 | or the value NO_PID if the pid wasn't found. */ | |
167 | static int | |
168 | find_index_by_pid (pid) | |
169 | pid_t pid; | |
170 | { | |
171 | register int i; | |
172 | ||
173 | for (i = 0; i < pid_list_size; i++) | |
174 | if (pid_list[i].pid == pid) | |
175 | return (i); | |
176 | ||
177 | return (NO_PID); | |
178 | } | |
179 | ||
180 | /* Return the status of PID as looked up in the PID_LIST array. A | |
181 | return value of PROC_BAD indicates that PID wasn't found. */ | |
182 | static int | |
183 | find_status_by_pid (pid) | |
184 | pid_t pid; | |
185 | { | |
186 | int i; | |
187 | ||
188 | i = find_index_by_pid (pid); | |
189 | if (i == NO_PID) | |
190 | return (PROC_BAD); | |
191 | return (pid_list[i].status); | |
192 | } | |
193 | ||
194 | /* Give PID the status value STATUS in the PID_LIST array. */ | |
195 | static void | |
196 | set_pid_status (pid, status) | |
197 | pid_t pid; | |
198 | WAIT status; | |
199 | { | |
200 | int slot; | |
201 | ||
202 | slot = find_index_by_pid (pid); | |
203 | if (slot == NO_PID) | |
204 | return; | |
205 | ||
206 | if (WIFSIGNALED (status)) | |
207 | pid_list[slot].status = 128 + WTERMSIG (status); | |
208 | else | |
209 | pid_list[slot].status = WEXITSTATUS (status); | |
210 | } | |
211 | ||
212 | static void | |
213 | add_pid (pid) | |
214 | pid_t pid; | |
215 | { | |
216 | int slot; | |
217 | ||
218 | slot = find_proc_slot (); | |
219 | pid_list[slot].pid = pid; | |
220 | pid_list[slot].status = PROC_STILL_ALIVE; | |
221 | } | |
222 | ||
223 | int | |
224 | cleanup_dead_jobs () | |
225 | { | |
226 | register int i; | |
227 | ||
ccc6cda3 | 228 | #if defined (HAVE_WAITPID) |
726f6388 JA |
229 | reap_zombie_children (); |
230 | #endif | |
231 | ||
232 | for (i = 0; i < pid_list_size; i++) | |
233 | if (pid_list[i].status != PROC_STILL_ALIVE) | |
234 | pid_list[i].pid = NO_PID; | |
235 | } | |
236 | ||
237 | /* Initialize the job control mechanism, and set up the tty stuff. */ | |
d166f048 JA |
238 | initialize_job_control (force) |
239 | int force; | |
726f6388 | 240 | { |
d166f048 JA |
241 | shell_tty = fileno (stderr); |
242 | ||
243 | if (interactive) | |
244 | get_tty_state (); | |
726f6388 JA |
245 | } |
246 | ||
ccc6cda3 JA |
247 | #if defined (TIOCGWINSZ) && defined (SIGWINCH) |
248 | static SigHandler *old_winch = (SigHandler *)SIG_DFL; | |
249 | ||
250 | static void | |
251 | get_new_window_size (from_sig) | |
252 | int from_sig; | |
253 | { | |
254 | struct winsize win; | |
255 | int tty; | |
256 | ||
d166f048 | 257 | tty = input_tty (); |
ccc6cda3 JA |
258 | if (tty >= 0 && (ioctl (tty, TIOCGWINSZ, &win) == 0) && |
259 | win.ws_row > 0 && win.ws_col > 0) | |
260 | { | |
261 | #if defined (aixpc) | |
262 | shell_tty_info.c_winsize = win; /* structure copying */ | |
263 | #endif | |
264 | set_lines_and_columns (win.ws_row, win.ws_col); | |
265 | #if defined (READLINE) | |
266 | _rl_set_screen_size (win.ws_row, win.ws_col); | |
267 | #endif | |
268 | } | |
ccc6cda3 | 269 | } |
726f6388 JA |
270 | |
271 | static sighandler | |
272 | sigwinch_sighandler (sig) | |
273 | int sig; | |
274 | { | |
ccc6cda3 | 275 | #if defined (MUST_REINSTALL_SIGHANDLERS) |
726f6388 | 276 | set_signal_handler (SIGWINCH, sigwinch_sighandler); |
ccc6cda3 JA |
277 | #endif /* MUST_REINSTALL_SIGHANDLERS */ |
278 | get_new_window_size (1); | |
279 | } | |
280 | #else | |
281 | static void | |
282 | get_new_window_size (from_sig) | |
283 | int from_sig; | |
284 | { | |
285 | } | |
286 | #endif /* TIOCGWINSZ && SIGWINCH */ | |
287 | ||
288 | void | |
289 | set_sigwinch_handler () | |
290 | { | |
291 | #if defined (TIOCGWINSZ) && defined (SIGWINCH) | |
292 | old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); | |
293 | #endif | |
294 | } | |
295 | ||
296 | void | |
297 | unset_sigwinch_handler () | |
298 | { | |
299 | #if defined (TIOCGWINSZ) && defined (SIGWINCH) | |
300 | set_signal_handler (SIGWINCH, old_winch); | |
301 | #endif | |
726f6388 | 302 | } |
726f6388 JA |
303 | |
304 | /* Setup this shell to handle C-C, etc. */ | |
305 | void | |
306 | initialize_job_signals () | |
307 | { | |
308 | set_signal_handler (SIGINT, sigint_sighandler); | |
ccc6cda3 | 309 | set_sigwinch_handler (); |
726f6388 JA |
310 | |
311 | /* If this is a login shell we don't wish to be disturbed by | |
312 | stop signals. */ | |
313 | if (login_shell) | |
ccc6cda3 | 314 | ignore_tty_job_signals (); |
726f6388 JA |
315 | } |
316 | ||
ccc6cda3 | 317 | #if defined (HAVE_WAITPID) |
726f6388 JA |
318 | /* Collect the status of all zombie children so that their system |
319 | resources can be deallocated. */ | |
320 | static void | |
321 | reap_zombie_children () | |
322 | { | |
323 | #if defined (WNOHANG) | |
324 | pid_t pid; | |
325 | WAIT status; | |
326 | ||
327 | while ((pid = waitpid (-1, (int *)&status, WNOHANG)) > 0) | |
328 | set_pid_status (pid, status); | |
ccc6cda3 | 329 | #endif |
726f6388 | 330 | } |
ccc6cda3 | 331 | #endif /* WAITPID && WNOHANG */ |
726f6388 JA |
332 | |
333 | /* Fork, handling errors. Returns the pid of the newly made child, or 0. | |
334 | COMMAND is just for remembering the name of the command; we don't do | |
335 | anything else with it. ASYNC_P says what to do with the tty. If | |
336 | non-zero, then don't give it away. */ | |
337 | pid_t | |
338 | make_child (command, async_p) | |
339 | char *command; | |
340 | int async_p; | |
341 | { | |
342 | pid_t pid; | |
ccc6cda3 | 343 | #if defined (HAVE_WAITPID) |
726f6388 | 344 | int retry = 1; |
ccc6cda3 | 345 | #endif /* HAVE_WAITPID */ |
726f6388 JA |
346 | |
347 | /* Discard saved memory. */ | |
ccc6cda3 | 348 | if (command) |
726f6388 JA |
349 | free (command); |
350 | ||
351 | start_pipeline (); | |
352 | ||
353 | #if defined (BUFFERED_INPUT) | |
354 | /* If default_buffered_input is active, we are reading a script. If | |
355 | the command is asynchronous, we have already duplicated /dev/null | |
356 | as fd 0, but have not changed the buffered stream corresponding to | |
357 | the old fd 0. We don't want to sync the stream in this case. */ | |
358 | if (default_buffered_input != -1 && | |
359 | (!async_p || default_buffered_input > 0)) | |
360 | sync_buffered_stream (default_buffered_input); | |
361 | #endif /* BUFFERED_INPUT */ | |
362 | ||
363 | /* Create the child, handle severe errors. */ | |
ccc6cda3 | 364 | #if defined (HAVE_WAITPID) |
726f6388 | 365 | retry_fork: |
ccc6cda3 | 366 | #endif /* HAVE_WAITPID */ |
726f6388 JA |
367 | |
368 | if ((pid = fork ()) < 0) | |
369 | { | |
ccc6cda3 | 370 | #if defined (HAVE_WAITPID) |
726f6388 JA |
371 | /* Posix systems with a non-blocking waitpid () system call available |
372 | get another chance after zombies are reaped. */ | |
373 | if (errno == EAGAIN && retry) | |
374 | { | |
375 | reap_zombie_children (); | |
376 | retry = 0; | |
377 | goto retry_fork; | |
378 | } | |
ccc6cda3 | 379 | #endif /* HAVE_WAITPID */ |
726f6388 | 380 | |
ccc6cda3 | 381 | sys_error ("fork"); |
726f6388 JA |
382 | |
383 | throw_to_top_level (); | |
384 | } | |
ccc6cda3 | 385 | |
726f6388 JA |
386 | if (pid == 0) |
387 | { | |
388 | #if defined (BUFFERED_INPUT) | |
389 | if (default_buffered_input > 0) | |
390 | { | |
391 | close_buffered_fd (default_buffered_input); | |
392 | default_buffered_input = bash_input.location.buffered_fd = -1; | |
393 | } | |
394 | #endif /* BUFFERED_INPUT */ | |
395 | ||
ccc6cda3 | 396 | #if defined (HAVE_POSIX_SIGNALS) |
726f6388 JA |
397 | /* Restore top-level signal mask. */ |
398 | sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); | |
399 | #endif | |
400 | ||
401 | /* Ignore INT and QUIT in asynchronous children. */ | |
402 | if (async_p) | |
ccc6cda3 | 403 | last_asynchronous_pid = getpid (); |
726f6388 | 404 | |
ccc6cda3 | 405 | default_tty_job_signals (); |
726f6388 JA |
406 | } |
407 | else | |
408 | { | |
409 | /* In the parent. */ | |
410 | ||
411 | last_made_pid = pid; | |
412 | ||
413 | if (async_p) | |
414 | last_asynchronous_pid = pid; | |
415 | ||
416 | add_pid (pid); | |
417 | } | |
418 | return (pid); | |
419 | } | |
420 | ||
ccc6cda3 JA |
421 | void |
422 | ignore_tty_job_signals () | |
423 | { | |
424 | #if defined (SIGTSTP) | |
425 | set_signal_handler (SIGTSTP, SIG_IGN); | |
426 | set_signal_handler (SIGTTIN, SIG_IGN); | |
427 | set_signal_handler (SIGTTOU, SIG_IGN); | |
428 | #endif | |
429 | } | |
430 | ||
431 | void | |
432 | default_tty_job_signals () | |
433 | { | |
434 | #if defined (SIGTSTP) | |
435 | set_signal_handler (SIGTSTP, SIG_DFL); | |
436 | set_signal_handler (SIGTTIN, SIG_DFL); | |
437 | set_signal_handler (SIGTTOU, SIG_DFL); | |
438 | #endif | |
439 | } | |
440 | ||
726f6388 JA |
441 | /* Wait for a single pid (PID) and return its exit status. */ |
442 | wait_for_single_pid (pid) | |
443 | pid_t pid; | |
444 | { | |
445 | pid_t got_pid; | |
446 | WAIT status; | |
447 | int pstatus; | |
448 | ||
449 | pstatus = find_status_by_pid (pid); | |
450 | ||
451 | if (pstatus == PROC_BAD) | |
ccc6cda3 JA |
452 | { |
453 | internal_error ("wait: pid %d is not a child of this shell", pid); | |
454 | return (127); | |
455 | } | |
726f6388 JA |
456 | |
457 | if (pstatus != PROC_STILL_ALIVE) | |
458 | return (pstatus); | |
459 | ||
460 | siginterrupt (SIGINT, 1); | |
461 | while ((got_pid = WAITPID (pid, &status, 0)) != pid) | |
462 | { | |
463 | if (got_pid < 0) | |
464 | { | |
465 | if (errno != EINTR && errno != ECHILD) | |
466 | { | |
467 | siginterrupt (SIGINT, 0); | |
ccc6cda3 | 468 | sys_error ("wait"); |
726f6388 JA |
469 | } |
470 | break; | |
471 | } | |
472 | else if (got_pid > 0) | |
473 | set_pid_status (got_pid, status); | |
474 | } | |
475 | ||
476 | set_pid_status (got_pid, status); | |
477 | siginterrupt (SIGINT, 0); | |
478 | QUIT; | |
479 | ||
480 | if (WIFSIGNALED (status)) | |
481 | return (128 + WTERMSIG (status)); | |
482 | else | |
483 | return (WEXITSTATUS (status)); | |
484 | } | |
485 | ||
486 | /* Wait for all of the shell's children to exit. */ | |
487 | void | |
488 | wait_for_background_pids () | |
489 | { | |
490 | pid_t got_pid; | |
491 | WAIT status; | |
492 | ||
493 | /* If we aren't using job control, we let the kernel take care of the | |
ccc6cda3 | 494 | bookkeeping for us. wait () will return -1 and set errno to ECHILD |
726f6388 JA |
495 | when there are no more unwaited-for child processes on both |
496 | 4.2 BSD-based and System V-based systems. */ | |
497 | ||
498 | siginterrupt (SIGINT, 1); | |
499 | ||
500 | /* Wait for ECHILD */ | |
501 | while ((got_pid = WAITPID (-1, &status, 0)) != -1) | |
502 | set_pid_status (got_pid, status); | |
503 | ||
504 | if (errno != EINTR && errno != ECHILD) | |
505 | { | |
506 | siginterrupt (SIGINT, 0); | |
ccc6cda3 | 507 | sys_error("wait"); |
726f6388 JA |
508 | } |
509 | ||
510 | siginterrupt (SIGINT, 0); | |
511 | QUIT; | |
512 | } | |
513 | ||
514 | /* Handle SIGINT while we are waiting for children in a script to exit. | |
515 | All interrupts are effectively ignored by the shell, but allowed to | |
516 | kill a running job. */ | |
517 | static sighandler | |
518 | wait_sigint_handler (sig) | |
519 | int sig; | |
520 | { | |
521 | #if 0 | |
522 | /* Run a trap handler if one has been defined. */ | |
523 | maybe_call_trap_handler (sig); | |
524 | #endif | |
525 | ||
ccc6cda3 | 526 | SIGRETURN (0); |
726f6388 JA |
527 | } |
528 | ||
529 | /* Wait for pid (one of our children) to terminate. This is called only | |
530 | by the execution code in execute_cmd.c. */ | |
531 | int | |
532 | wait_for (pid) | |
533 | pid_t pid; | |
534 | { | |
535 | int return_val, pstatus; | |
536 | pid_t got_pid; | |
537 | WAIT status; | |
538 | SigHandler *old_sigint_handler; | |
539 | ||
540 | pstatus = find_status_by_pid (pid); | |
541 | ||
542 | if (pstatus == PROC_BAD) | |
543 | return (0); | |
544 | ||
545 | if (pstatus != PROC_STILL_ALIVE) | |
546 | return (pstatus); | |
547 | ||
548 | /* If we are running a script, ignore SIGINT while we're waiting for | |
549 | a child to exit. The loop below does some of this, but not all. */ | |
550 | if (!interactive_shell) | |
551 | old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); | |
552 | ||
553 | while ((got_pid = WAITPID (-1, &status, 0)) != pid) /* XXX was pid now -1 */ | |
554 | { | |
555 | if (got_pid < 0 && errno == ECHILD) | |
556 | { | |
557 | #if !defined (_POSIX_VERSION) | |
558 | status.w_termsig = status.w_retcode = 0; | |
559 | #else | |
560 | status = 0; | |
561 | #endif /* _POSIX_VERSION */ | |
562 | break; | |
563 | } | |
564 | else if (got_pid < 0 && errno != EINTR) | |
ccc6cda3 | 565 | programming_error ("wait_for(%d): %s", pid, strerror(errno)); |
726f6388 JA |
566 | else if (got_pid > 0) |
567 | set_pid_status (got_pid, status); | |
568 | } | |
569 | ||
570 | set_pid_status (got_pid, status); | |
571 | ||
ccc6cda3 | 572 | #if defined (HAVE_WAITPID) |
726f6388 JA |
573 | if (got_pid >= 0) |
574 | reap_zombie_children (); | |
ccc6cda3 | 575 | #endif /* HAVE_WAITPID */ |
726f6388 | 576 | |
ccc6cda3 | 577 | if (interactive_shell == 0) |
726f6388 JA |
578 | { |
579 | set_signal_handler (SIGINT, old_sigint_handler); | |
580 | /* If the job exited because of SIGINT, make sure the shell acts as if | |
581 | it had received one also. */ | |
582 | if (WIFSIGNALED (status) && (WTERMSIG (status) == SIGINT)) | |
583 | { | |
584 | if (maybe_call_trap_handler (SIGINT) == 0) | |
585 | (*old_sigint_handler) (SIGINT); | |
586 | } | |
587 | } | |
ccc6cda3 | 588 | |
726f6388 JA |
589 | /* Default return value. */ |
590 | /* ``a full 8 bits of status is returned'' */ | |
591 | if (WIFSIGNALED (status)) | |
592 | return_val = 128 + WTERMSIG (status); | |
593 | else | |
594 | return_val = WEXITSTATUS (status); | |
ccc6cda3 | 595 | |
d166f048 JA |
596 | #if !defined (DONT_REPORT_SIGPIPE) |
597 | if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) && | |
598 | (WTERMSIG (status) != SIGINT)) | |
599 | #else | |
600 | if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) && | |
601 | (WTERMSIG (status) != SIGINT) && (WTERMSIG (status) != SIGPIPE)) | |
602 | #endif | |
726f6388 JA |
603 | { |
604 | fprintf (stderr, "%s", strsignal (WTERMSIG (status))); | |
605 | if (WIFCORED (status)) | |
606 | fprintf (stderr, " (core dumped)"); | |
607 | fprintf (stderr, "\n"); | |
608 | } | |
609 | ||
ccc6cda3 | 610 | if (interactive_shell && subshell_environment == 0) |
726f6388 JA |
611 | { |
612 | if (WIFSIGNALED (status) || WIFSTOPPED (status)) | |
613 | set_tty_state (); | |
614 | else | |
615 | get_tty_state (); | |
616 | } | |
617 | ||
618 | return (return_val); | |
619 | } | |
620 | ||
621 | /* Give PID SIGNAL. This determines what job the pid belongs to (if any). | |
622 | If PID does belong to a job, and the job is stopped, then CONTinue the | |
623 | job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, | |
624 | then kill the process group associated with PID. */ | |
625 | int | |
626 | kill_pid (pid, signal, group) | |
627 | pid_t pid; | |
628 | int signal, group; | |
629 | { | |
630 | int result; | |
631 | ||
632 | if (group) | |
633 | result = killpg (pid, signal); | |
634 | else | |
635 | result = kill (pid, signal); | |
636 | ||
637 | return (result); | |
638 | } | |
639 | ||
ccc6cda3 | 640 | #if defined (TERMIOS_TTY_DRIVER) |
726f6388 | 641 | static struct termios shell_tty_info; |
ccc6cda3 JA |
642 | #else /* !TERMIOS_TTY_DRIVER */ |
643 | # if defined (TERMIO_TTY_DRIVER) | |
726f6388 JA |
644 | static struct termio shell_tty_info; |
645 | # else | |
646 | static struct sgttyb shell_tty_info; | |
ccc6cda3 JA |
647 | # endif /* !TERMIO_TTY_DRIVER */ |
648 | #endif /* !TERMIOS_TTY_DRIVER */ | |
726f6388 | 649 | |
ccc6cda3 | 650 | static int got_tty_state; |
726f6388 JA |
651 | |
652 | /* Fill the contents of shell_tty_info with the current tty info. */ | |
653 | get_tty_state () | |
654 | { | |
ccc6cda3 JA |
655 | int tty; |
656 | ||
d166f048 | 657 | tty = input_tty (); |
726f6388 JA |
658 | if (tty != -1) |
659 | { | |
ccc6cda3 | 660 | #if defined (TERMIOS_TTY_DRIVER) |
726f6388 JA |
661 | tcgetattr (tty, &shell_tty_info); |
662 | #else | |
ccc6cda3 | 663 | # if defined (TERMIO_TTY_DRIVER) |
726f6388 JA |
664 | ioctl (tty, TCGETA, &shell_tty_info); |
665 | # else | |
666 | ioctl (tty, TIOCGETP, &shell_tty_info); | |
667 | # endif | |
668 | #endif | |
726f6388 | 669 | got_tty_state = 1; |
ccc6cda3 JA |
670 | if (check_window_size) |
671 | get_new_window_size (0); | |
726f6388 JA |
672 | } |
673 | } | |
674 | ||
675 | /* Make the current tty use the state in shell_tty_info. */ | |
676 | set_tty_state () | |
677 | { | |
ccc6cda3 JA |
678 | int tty; |
679 | ||
d166f048 | 680 | tty = input_tty (); |
726f6388 JA |
681 | if (tty != -1) |
682 | { | |
ccc6cda3 | 683 | if (got_tty_state == 0) |
d166f048 JA |
684 | return; |
685 | ||
ccc6cda3 | 686 | #if defined (TERMIOS_TTY_DRIVER) |
726f6388 JA |
687 | tcsetattr (tty, TCSADRAIN, &shell_tty_info); |
688 | #else | |
ccc6cda3 | 689 | # if defined (TERMIO_TTY_DRIVER) |
726f6388 JA |
690 | ioctl (tty, TCSETAW, &shell_tty_info); /* Wait for output, no flush */ |
691 | # else | |
692 | ioctl (tty, TIOCSETN, &shell_tty_info); | |
693 | # endif | |
694 | #endif | |
726f6388 JA |
695 | } |
696 | } | |
697 | ||
698 | /* Give the terminal to PGRP. */ | |
699 | give_terminal_to (pgrp) | |
700 | pid_t pgrp; | |
701 | { | |
702 | } | |
703 | ||
704 | /* Stop a pipeline. */ | |
705 | stop_pipeline (async, ignore) | |
706 | int async; | |
707 | COMMAND *ignore; | |
708 | { | |
709 | already_making_children = 0; | |
710 | } | |
711 | ||
712 | void | |
713 | start_pipeline () | |
714 | { | |
715 | already_making_children = 1; | |
716 | } | |
717 | ||
d166f048 JA |
718 | int |
719 | get_job_by_pid (pid, block) | |
720 | pid_t pid; | |
721 | int block; | |
722 | { | |
723 | int i; | |
724 | ||
725 | i = find_index_by_pid (pid); | |
726 | return ((i == NO_PID) ? PROC_BAD : i); | |
727 | } | |
728 | ||
726f6388 JA |
729 | /* Print descriptive information about the job with leader pid PID. */ |
730 | void | |
731 | describe_pid (pid) | |
732 | pid_t pid; | |
733 | { | |
734 | fprintf (stderr, "%d\n", (int) pid); | |
735 | } | |
ccc6cda3 JA |
736 | |
737 | void | |
738 | unfreeze_jobs_list () | |
739 | { | |
740 | } |