Cygwin: kill(1): introduce a -W option

Allow to kill processes using Windows PIDs on the command line.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2019-02-02 21:02:00 +01:00
parent 3a3934252c
commit 658f939003
4 changed files with 59 additions and 20 deletions

View File

@ -322,6 +322,15 @@ cygwin_internal (cygwin_getinfo_types t, ...)
res = p ? p->dwProcessId : 0; res = p ? p->dwProcessId : 0;
} }
break; break;
case CW_WINPID_TO_CYGWIN_PID:
{
DWORD winpid = va_arg (arg, DWORD);
pid_t pid = cygwin_pid (winpid);
res = pid ?: winpid + MAX_PID;
}
break;
case CW_EXTRACT_DOMAIN_AND_USER: case CW_EXTRACT_DOMAIN_AND_USER:
{ {
WCHAR nt_domain[MAX_DOMAIN_NAME_LEN + 1]; WCHAR nt_domain[MAX_DOMAIN_NAME_LEN + 1];

View File

@ -158,6 +158,7 @@ typedef enum
CW_GETNSS_GRP_SRC, CW_GETNSS_GRP_SRC,
CW_EXCEPTION_RECORD_FROM_SIGINFO_T, CW_EXCEPTION_RECORD_FROM_SIGINFO_T,
CW_CYGHEAP_PROFTHR_ALL, CW_CYGHEAP_PROFTHR_ALL,
CW_WINPID_TO_CYGWIN_PID,
} cygwin_getinfo_types; } cygwin_getinfo_types;
#define CW_LOCK_PINFO CW_LOCK_PINFO #define CW_LOCK_PINFO CW_LOCK_PINFO
@ -220,6 +221,7 @@ typedef enum
#define CW_GETNSS_GRP_SRC CW_GETNSS_GRP_SRC #define CW_GETNSS_GRP_SRC CW_GETNSS_GRP_SRC
#define CW_EXCEPTION_RECORD_FROM_SIGINFO_T CW_EXCEPTION_RECORD_FROM_SIGINFO_T #define CW_EXCEPTION_RECORD_FROM_SIGINFO_T CW_EXCEPTION_RECORD_FROM_SIGINFO_T
#define CW_CYGHEAP_PROFTHR_ALL CW_CYGHEAP_PROFTHR_ALL #define CW_CYGHEAP_PROFTHR_ALL CW_CYGHEAP_PROFTHR_ALL
#define CW_WINPID_TO_CYGWIN_PID CW_WINPID_TO_CYGWIN_PID
/* Token type for CW_SET_EXTERNAL_TOKEN */ /* Token type for CW_SET_EXTERNAL_TOKEN */
enum enum

View File

@ -692,6 +692,8 @@ kill -l [signal]
-f, --force force, using win32 interface if necessary -f, --force force, using win32 interface if necessary
-l, --list print a list of signal names -l, --list print a list of signal names
-s, --signal send signal (use kill --list for a list) -s, --signal send signal (use kill --list for a list)
-W, --winpid specified pids are windows PIDs, not Cygwin PIDs
(use with extrem caution!)
-h, --help output usage information and exit -h, --help output usage information and exit
-V, --version output version information and exit -V, --version output version information and exit
</screen> </screen>
@ -717,7 +719,13 @@ $ /bin/kill --version
</screen> which should give the Cygwin </screen> which should give the Cygwin
<command>kill</command> version number and copyright information. </para> <command>kill</command> version number and copyright information. </para>
<para>Unless you specific the <literal>-f</literal> option, the "pid" <para>The <literal>-f</literal> option uses Windows functions to
terminate processes forcefully. Use <literal>-f</literal> to
terminate native Windows processes not started by Cygwin processes.
<literal>-f</literal> can also be useful to terminate Cygwin processes
not answering to SIGKILL.</para>
<para>Unless you specific the <literal>-W</literal> option, the "pid"
values used by <command>kill</command> are the Cygwin pids, not the values used by <command>kill</command> are the Cygwin pids, not the
Windows pids. To get a list of running programs and their Cygwin pids, Windows pids. To get a list of running programs and their Cygwin pids,
use the Cygwin <command>ps</command> program. <command>ps -W</command> use the Cygwin <command>ps</command> program. <command>ps -W</command>

View File

@ -26,17 +26,18 @@ static struct option longopts[] =
{"list", optional_argument, NULL, 'l'}, {"list", optional_argument, NULL, 'l'},
{"force", no_argument, NULL, 'f'}, {"force", no_argument, NULL, 'f'},
{"signal", required_argument, NULL, 's'}, {"signal", required_argument, NULL, 's'},
{"winpid", no_argument, NULL, 'W'},
{"version", no_argument, NULL, 'V'}, {"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
static char opts[] = "hl::fs:V"; static char opts[] = "hl::fs:WV";
static void static void
usage (FILE *where = stderr) usage (FILE *where = stderr)
{ {
fprintf (where , "" fprintf (where , ""
"Usage: %1$s [-f] [-signal] [-s signal] pid1 [pid2 ...]\n" "Usage: %1$s [-fW] [-signal] [-s signal] pid1 [pid2 ...]\n"
" %1$s -l [signal]\n" " %1$s -l [signal]\n"
"\n" "\n"
"Send signals to processes\n" "Send signals to processes\n"
@ -44,6 +45,8 @@ usage (FILE *where = stderr)
" -f, --force force, using win32 interface if necessary\n" " -f, --force force, using win32 interface if necessary\n"
" -l, --list print a list of signal names\n" " -l, --list print a list of signal names\n"
" -s, --signal send signal (use %1$s --list for a list)\n" " -s, --signal send signal (use %1$s --list for a list)\n"
" -W, --winpid specified pids are windows PIDs, not Cygwin PIDs\n"
" (use with extrem caution!)\n"
" -h, --help output usage information and exit\n" " -h, --help output usage information and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
"\n", prog_name); "\n", prog_name);
@ -152,19 +155,28 @@ get_debug_priv (void)
} }
static void __stdcall static void __stdcall
forcekill (pid_t pid, int sig, int wait) forcekill (pid_t pid, DWORD winpid, int sig, int wait)
{ {
DWORD dwpid;
/* try to acquire SeDebugPrivilege */ /* try to acquire SeDebugPrivilege */
get_debug_priv(); get_debug_priv();
external_pinfo *p = NULL; if (!winpid)
p = (external_pinfo *) cygwin_internal (CW_GETPINFO_FULL, pid); {
external_pinfo *p = (external_pinfo *)
cygwin_internal (CW_GETPINFO_FULL, pid);
if (!p) if (!p)
{ {
fprintf (stderr, "%s: %d: No such process\n", prog_name, pid); fprintf (stderr, "%s: %d: No such process\n", prog_name, pid);
return; return;
} }
DWORD dwpid = p->dwProcessId; dwpid = p->dwProcessId;
}
else
/* pid is used for printing only after this point */
pid = dwpid = winpid;
HANDLE h = OpenProcess (PROCESS_TERMINATE, FALSE, dwpid); HANDLE h = OpenProcess (PROCESS_TERMINATE, FALSE, dwpid);
if (!h) if (!h)
{ {
@ -186,6 +198,7 @@ main (int argc, char **argv)
{ {
int sig = SIGTERM; int sig = SIGTERM;
int force = 0; int force = 0;
int winpids = 0;
int ret = 0; int ret = 0;
char *gotasig = NULL; char *gotasig = NULL;
@ -197,7 +210,6 @@ main (int argc, char **argv)
opterr = 0; opterr = 0;
char *p; char *p;
long long int pid = 0;
for (;;) for (;;)
{ {
@ -228,6 +240,9 @@ main (int argc, char **argv)
case 'f': case 'f':
force = 1; force = 1;
break; break;
case 'W':
winpids = 1;
break;
case 'h': case 'h':
usage (stdout); usage (stdout);
break; break;
@ -257,32 +272,37 @@ out:
fprintf (stderr, "%s: not enough arguments\n", prog_name); fprintf (stderr, "%s: not enough arguments\n", prog_name);
return 1; return 1;
} }
while (*argv != NULL) for (long long int pid = 0; *argv != NULL; argv++)
{ {
if (!pid) DWORD dwpid = 0;
pid = strtoll (*argv, &p, 10); pid = strtoll (*argv, &p, 10);
/* INT_MIN <= pid <= INT_MAX. -f only takes positive pids. */ /* INT_MIN <= pid <= INT_MAX. -f only takes positive pids. */
if (*p != '\0' || pid < (force ? 1 : INT_MIN) || pid > INT_MAX) if (*p != '\0' || pid < (force ? 1 : INT_MIN) || pid > INT_MAX)
{ {
fprintf (stderr, "%s: illegal pid: %s\n", prog_name, *argv); fprintf (stderr, "%s: illegal pid: %s\n", prog_name, *argv);
ret = 1; ret = 1;
continue;
} }
else if (kill ((pid_t) pid, sig) == 0) if (winpids)
{
dwpid = pid;
pid = (pid_t) cygwin_internal (CW_WINPID_TO_CYGWIN_PID, dwpid);
}
if (kill ((pid_t) pid, sig) == 0)
{ {
if (force) if (force)
forcekill ((pid_t) pid, sig, 1); forcekill ((pid_t) pid, dwpid, sig, 1);
} }
else if (force) else if (force)
forcekill ((pid_t) pid, sig, 0); forcekill ((pid_t) pid, dwpid, sig, 0);
else else
{ {
char buf[1000]; char buf[1000];
sprintf (buf, "%s: %lld", prog_name, pid); sprintf (buf, "%s: %lld", prog_name, dwpid ?: pid);
perror (buf); perror (buf);
ret = 1; ret = 1;
} }
argv++;
pid = 0;
} }
return ret; return ret;
} }