Improve dangerous/undefined PID expansion behavior

1. Use Bash-like expansion for empty searches (when you just use a '%' by
itself).

'%' will now *only* match the last valid backgrounded process.
If there are no such processes, an expansion error will be generated.

'%' by itself would previously match either *all* backgrounded
processes, or failing that, all processes owned by your user. If you
ever tried to run `kill -9 %`, it would either kill all backgrounded
processes or *all* of your processes. I'm not sure why anyone would ever
want that to be a single keystroke away. You could almost typo it.

As a result, `fg %`, `bg %`, `kill %`, etc will all operate on the last
process touched by job control.

2. Don't run 'by-name' matches when the search term is numeric.

This prevents you from running a command like `kill %1` and accidentally
killing a process named something like "1Command". Overloaded behavior
can be dangerous, and we probably shouldn't play fast and loose with
expansion characters that generate process IDs.
This commit is contained in:
Ryan Hileman 2013-09-18 17:19:30 -07:00 committed by David Adam
parent 4ea92a97ea
commit f2a5237802

View File

@ -585,7 +585,30 @@ static int find_process(const wchar_t *proc,
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
const job_t *j; const job_t *j;
if (iswnumeric(proc) || (wcslen(proc)==0)) // do the empty param check first, because an empty string passes our 'numeric' check
if (wcslen(proc)==0)
{
/*
This is an empty job expansion: '%'
It expands to the last job backgrounded.
*/
job_iterator_t jobs;
while ((j = jobs.next()))
{
if (!j->command_is_empty())
{
append_completion(out, to_string<long>(j->pgid));
break;
}
}
/*
You don't *really* want to flip a coin between killing
the last process backgrounded and all processes, do you?
Let's not try other match methods with the solo '%' syntax.
*/
found = 1;
}
else if (iswnumeric(proc))
{ {
/* /*
This is a numeric job string, like '%2' This is a numeric job string, like '%2'
@ -611,11 +634,9 @@ static int find_process(const wchar_t *proc,
0); 0);
} }
} }
} }
else else
{ {
int jid; int jid;
wchar_t *end; wchar_t *end;
@ -624,15 +645,17 @@ static int find_process(const wchar_t *proc,
if (jid > 0 && !errno && !*end) if (jid > 0 && !errno && !*end)
{ {
j = job_get(jid); j = job_get(jid);
if ((j != 0) && (j->command_wcstr() != 0)) if ((j != 0) && (j->command_wcstr() != 0) && (!j->command_is_empty()))
{ {
{ append_completion(out, to_string<long>(j->pgid));
append_completion(out, to_string<long>(j->pgid));
found = 1;
}
} }
} }
} }
/*
Stop here so you can't match a random process name
when you're just trying to use job control.
*/
found = 1;
} }
if (found) if (found)
return 1; return 1;