kill: -l space between name parses correctly

This was supposed to be just a cherry-pick of the referenced
commit. However there were two problems:
 1. kill code was moved out to its own file
 2. strtosig() had a latent bug where signal numbers were not
 converted to names.

Original note:
kill -lHUP would work correctly, but kill -l HUP would not.

The list option in kill was hit by a quirk of getopt_long where an
option with an optional argument would not attempt to get the argument
beyond the space, even though a mandatory argument would do that.

The fix is a kludge to scan to the next argument and if it looks
like something we can use, use it. Lucky for us, the list option is
one where parsing can stop immediately.

Thanks to Brian Vandenberg for the way forward.

References:
 http://stackoverflow.com/questions/1052746/getopt-does-not-parse-optional-arguments-to-parameters
 https://bugs.debian.org/854407
 commit 537cea324b121f54744369425332c256aa84a181
This commit is contained in:
Craig Small 2017-05-22 22:15:59 +10:00
parent 3ad417c0c0
commit aa41c309dd
4 changed files with 31 additions and 8 deletions

1
NEWS
View File

@ -1,5 +1,6 @@
procps-ng-NEXT
----------------
* kill: -l space between name parses correctly Debian #854407
* library: dont use vm_min_free on non Linux Debian #831396
* library: dont use SIGPWR on FreeBSD Debian #832148
* library: don't strip off wchan prefixes (ps & top) Redhat #1322111

14
kill.c
View File

@ -53,6 +53,8 @@ int main(int argc, char **argv)
int signo, i, loop=1;
long pid;
int exitvalue = EXIT_SUCCESS;
int optindex;
char *sig_option;
static const struct option longopts[] = {
{"list", optional_argument, NULL, 'l'},
@ -77,17 +79,23 @@ int main(int argc, char **argv)
signo = SIGTERM;
opterr=0; /* suppress errors on -123 */
while (loop == 1 && (i = getopt_long(argc, argv, "l::Ls:hV", longopts, NULL)) != -1)
while (loop == 1 && (i = getopt_long(argc, argv, "l::Ls:hV", longopts, &optindex)) != -1)
switch (i) {
case 'l':
sig_option = NULL;
if (optarg) {
sig_option = optarg;
} else if (argv[optind] != NULL && argv[optind][0] != '-') {
sig_option = argv[optind];
}
if (sig_option) {
char *s;
s = strtosig(optarg);
s = strtosig(sig_option);
if (s)
printf("%s\n", s);
else
xwarnx(_("unknown signal name %s"),
optarg);
sig_option);
free(s);
} else {
unix_print_signals();

View File

@ -240,10 +240,11 @@ char *strtosig(const char *restrict s)
p += 3;
if (isdigit(*p)){
numsignal = strtol(s,&endp,10);
if(*endp || endp==s)
if(*endp || endp==s){
free(p);
return NULL; /* not valid */
}
}
if (numsignal){
for (i = 0; i < number_of_signals; i++){
if (numsignal == get_sigtable_num(i)){

View File

@ -20,15 +20,28 @@ set test "kill list signal names in table"
spawn $kill -L
expect_pass "$test" "^\(\\s+\\d+ \[A-Z12+-\]+\)+\\s*$"
set test "kill convert signal name to number"
set test "kill convert signal name to number no space"
spawn $kill -lHUP
expect_pass "$test" "^1\\s*"
set test "kill convert SIG-prefixed signal name to number"
set test "kill convert signal name to number with space"
spawn $kill -l HUP
expect_pass "$test" "^1\\s*"
set test "kill convert SIG-prefixed signal name to number no space"
spawn $kill -lSIGHUP
expect_pass "$test" "^1\\s*$"
set test "kill convert signal number to name"
set test "kill convert SIG-prefixed signal name to number with space"
spawn $kill -l SIGHUP
expect_pass "$test" "^1\\s*$"
set test "kill convert signal number to name no space"
spawn $kill -l1
expect_pass "$test" "^HUP\\s*"
set test "kill convert signal number to name with space"
spawn $kill -l 1
expect_pass "$test" "^HUP\\s*"