| This file is kill.def, from which is created kill.c. |
| It implements the builtin "kill" in Bash. |
| |
| Copyright (C) 1987-2010 Free Software Foundation, Inc. |
| |
| This file is part of GNU Bash, the Bourne Again SHell. |
| |
| Bash is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| Bash is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with Bash. If not, see <http://www.gnu.org/licenses/>. |
| |
| $PRODUCES kill.c |
| |
| $BUILTIN kill |
| $FUNCTION kill_builtin |
| $SHORT_DOC kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec] |
| Send a signal to a job. |
| |
| Send the processes identified by PID or JOBSPEC the signal named by |
| SIGSPEC or SIGNUM. If neither SIGSPEC nor SIGNUM is present, then |
| SIGTERM is assumed. |
| |
| Options: |
| -s sig SIG is a signal name |
| -n sig SIG is a signal number |
| -l list the signal names; if arguments follow `-l' they are |
| assumed to be signal numbers for which names should be listed |
| |
| Kill is a shell builtin for two reasons: it allows job IDs to be used |
| instead of process IDs, and allows processes to be killed if the limit |
| on processes that you can create is reached. |
| |
| Exit Status: |
| Returns success unless an invalid option is given or an error occurs. |
| $END |
| |
| #include <config.h> |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #if defined (HAVE_UNISTD_H) |
| # ifdef _MINIX |
| # include <sys/types.h> |
| # endif |
| # include <unistd.h> |
| #endif |
| |
| #include "../bashansi.h" |
| #include "../bashintl.h" |
| |
| #include <signal.h> |
| |
| #include "../shell.h" |
| #include "../trap.h" |
| #include "../jobs.h" |
| #include "common.h" |
| |
| /* Not all systems declare ERRNO in errno.h... and some systems #define it! */ |
| #if !defined (errno) |
| #include <errno.h> |
| #endif /* !errno */ |
| |
| extern int posixly_correct; |
| |
| static void kill_error __P((pid_t, int)); |
| |
| #if !defined (CONTINUE_AFTER_KILL_ERROR) |
| # define CONTINUE_OR_FAIL return (EXECUTION_FAILURE) |
| #else |
| # define CONTINUE_OR_FAIL goto continue_killing |
| #endif /* CONTINUE_AFTER_KILL_ERROR */ |
| |
| /* Here is the kill builtin. We only have it so that people can type |
| kill -KILL %1? No, if you fill up the process table this way you |
| can still kill some. */ |
| int |
| kill_builtin (list) |
| WORD_LIST *list; |
| { |
| int sig, any_succeeded, listing, saw_signal, dflags; |
| char *sigspec, *word; |
| pid_t pid; |
| intmax_t pid_value; |
| |
| if (list == 0) |
| { |
| builtin_usage (); |
| return (EX_USAGE); |
| } |
| |
| any_succeeded = listing = saw_signal = 0; |
| sig = SIGTERM; |
| sigspec = "TERM"; |
| |
| dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0); |
| /* Process options. */ |
| while (list) |
| { |
| word = list->word->word; |
| |
| if (ISOPTION (word, 'l')) |
| { |
| listing++; |
| list = list->next; |
| } |
| else if (ISOPTION (word, 's') || ISOPTION (word, 'n')) |
| { |
| list = list->next; |
| if (list) |
| { |
| sigspec = list->word->word; |
| if (sigspec[0] == '0' && sigspec[1] == '\0') |
| sig = 0; |
| else |
| sig = decode_signal (sigspec, dflags); |
| list = list->next; |
| saw_signal++; |
| } |
| else |
| { |
| sh_needarg (word); |
| return (EXECUTION_FAILURE); |
| } |
| } |
| else if (ISOPTION (word, '-')) |
| { |
| list = list->next; |
| break; |
| } |
| else if (ISOPTION (word, '?')) |
| { |
| builtin_usage (); |
| return (EX_USAGE); |
| } |
| /* If this is a signal specification then process it. We only process |
| the first one seen; other arguments may signify process groups (e.g, |
| -num == process group num). */ |
| else if (*word == '-' && saw_signal == 0) |
| { |
| sigspec = word + 1; |
| sig = decode_signal (sigspec, dflags); |
| saw_signal++; |
| list = list->next; |
| } |
| else |
| break; |
| } |
| |
| if (listing) |
| return (display_signal_list (list, 0)); |
| |
| /* OK, we are killing processes. */ |
| if (sig == NO_SIG) |
| { |
| sh_invalidsig (sigspec); |
| return (EXECUTION_FAILURE); |
| } |
| |
| if (list == 0) |
| { |
| builtin_usage (); |
| return (EX_USAGE); |
| } |
| |
| while (list) |
| { |
| word = list->word->word; |
| |
| if (*word == '-') |
| word++; |
| |
| /* Use the entire argument in case of minus sign presence. */ |
| if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value)) |
| { |
| pid = (pid_t) pid_value; |
| |
| if (kill_pid (pid, sig, pid < -1) < 0) |
| { |
| if (errno == EINVAL) |
| sh_invalidsig (sigspec); |
| else |
| kill_error (pid, errno); |
| CONTINUE_OR_FAIL; |
| } |
| else |
| any_succeeded++; |
| } |
| #if defined (JOB_CONTROL) |
| else if (*list->word->word && *list->word->word != '%') |
| { |
| builtin_error (_("%s: arguments must be process or job IDs"), list->word->word); |
| CONTINUE_OR_FAIL; |
| } |
| else if (*word) |
| /* Posix.2 says you can kill without job control active (4.32.4) */ |
| { /* Must be a job spec. Check it out. */ |
| int job; |
| sigset_t set, oset; |
| JOB *j; |
| |
| BLOCK_CHILD (set, oset); |
| job = get_job_spec (list); |
| |
| if (INVALID_JOB (job)) |
| { |
| if (job != DUP_JOB) |
| sh_badjob (list->word->word); |
| UNBLOCK_CHILD (oset); |
| CONTINUE_OR_FAIL; |
| } |
| |
| j = get_job_by_jid (job); |
| /* Job spec used. Kill the process group. If the job was started |
| without job control, then its pgrp == shell_pgrp, so we have |
| to be careful. We take the pid of the first job in the pipeline |
| in that case. */ |
| pid = IS_JOBCONTROL (job) ? j->pgrp : j->pipe->pid; |
| |
| UNBLOCK_CHILD (oset); |
| |
| if (kill_pid (pid, sig, 1) < 0) |
| { |
| if (errno == EINVAL) |
| sh_invalidsig (sigspec); |
| else |
| kill_error (pid, errno); |
| CONTINUE_OR_FAIL; |
| } |
| else |
| any_succeeded++; |
| } |
| #endif /* !JOB_CONTROL */ |
| else |
| { |
| sh_badpid (list->word->word); |
| CONTINUE_OR_FAIL; |
| } |
| continue_killing: |
| list = list->next; |
| } |
| |
| return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE); |
| } |
| |
| static void |
| kill_error (pid, e) |
| pid_t pid; |
| int e; |
| { |
| char *x; |
| |
| x = strerror (e); |
| if (x == 0) |
| x = _("Unknown error"); |
| builtin_error ("(%ld) - %s", (long)pid, x); |
| } |