]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* kill.cc |
2 | ||
df0f949c CF |
3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, |
4 | 2009, 2011 Red Hat, Inc. | |
1fd5e000 CF |
5 | |
6 | This file is part of Cygwin. | |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <signal.h> | |
15 | #include <string.h> | |
16 | #include <time.h> | |
cc631726 CF |
17 | #include <errno.h> |
18 | #include <windows.h> | |
6b70b463 | 19 | #include <sys/cygwin.h> |
92b499ac | 20 | #include <cygwin/version.h> |
c49fa762 | 21 | #include <getopt.h> |
87b83839 | 22 | #include <limits.h> |
c49fa762 | 23 | |
ef48a2ca CF |
24 | static char *prog_name; |
25 | ||
c49fa762 CF |
26 | static struct option longopts[] = |
27 | { | |
28 | {"help", no_argument, NULL, 'h' }, | |
29 | {"list", optional_argument, NULL, 'l'}, | |
30 | {"force", no_argument, NULL, 'f'}, | |
31 | {"signal", required_argument, NULL, 's'}, | |
92b499ac | 32 | {"version", no_argument, NULL, 'V'}, |
c49fa762 CF |
33 | {NULL, 0, NULL, 0} |
34 | }; | |
35 | ||
92b499ac | 36 | static char opts[] = "hl::fs:V"; |
c49fa762 | 37 | |
af53a09c | 38 | static void |
30feaa22 | 39 | usage (FILE *where = stderr) |
af53a09c | 40 | { |
ef48a2ca | 41 | fprintf (where , "" |
92b499ac CV |
42 | "Usage: %1$s [-f] [-signal] [-s signal] pid1 [pid2 ...]\n" |
43 | " %1$s -l [signal]\n" | |
44 | "\n" | |
aa275fe0 JDF |
45 | "Send signals to processes\n" |
46 | "\n" | |
ef48a2ca CF |
47 | " -f, --force force, using win32 interface if necessary\n" |
48 | " -l, --list print a list of signal names\n" | |
92b499ac | 49 | " -s, --signal send signal (use %1$s --list for a list)\n" |
ef48a2ca | 50 | " -h, --help output usage information and exit\n" |
92b499ac CV |
51 | " -V, --version output version information and exit\n" |
52 | "\n", prog_name); | |
30feaa22 | 53 | exit (where == stderr ? 1 : 0); |
af53a09c CF |
54 | } |
55 | ||
ef48a2ca CF |
56 | static void |
57 | print_version () | |
58 | { | |
92b499ac | 59 | printf ("kill (cygwin) %d.%d.%d\n" |
1b23b30b CF |
60 | "Process Signaller\n" |
61 | "Copyright (C) 1996 - %s Red Hat, Inc.\n" | |
62 | "This is free software; see the source for copying conditions. There is NO\n" | |
92b499ac | 63 | "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", |
1b23b30b CF |
64 | CYGWIN_VERSION_DLL_MAJOR / 1000, |
65 | CYGWIN_VERSION_DLL_MAJOR % 1000, | |
66 | CYGWIN_VERSION_DLL_MINOR, | |
67 | strrchr (__DATE__, ' ') + 1); | |
ef48a2ca CF |
68 | } |
69 | ||
5c8891e9 CF |
70 | static const char * |
71 | strsigno (int signo) | |
72 | { | |
73 | if (signo >= 0 && signo < NSIG) | |
74 | return sys_sigabbrev[signo]; | |
75 | static char buf[sizeof ("Unknown signal") + 32]; | |
76 | sprintf (buf, "Unknown signal %d", signo); | |
77 | return buf; | |
78 | } | |
79 | ||
af53a09c | 80 | static int |
c49fa762 | 81 | getsig (const char *in_sig) |
af53a09c | 82 | { |
c49fa762 | 83 | const char *sig; |
af53a09c | 84 | char buf[80]; |
c49fa762 | 85 | int intsig; |
af53a09c CF |
86 | |
87 | if (strncmp (in_sig, "SIG", 3) == 0) | |
88 | sig = in_sig; | |
89 | else | |
90 | { | |
45345618 | 91 | sprintf (buf, "SIG%-.20s", in_sig); |
af53a09c CF |
92 | sig = buf; |
93 | } | |
c49fa762 CF |
94 | intsig = strtosigno (sig) ?: atoi (in_sig); |
95 | char *p; | |
96 | if (!intsig && (strcmp (buf, "SIG0") != 0 && (strtol (in_sig, &p, 10) != 0 || *p))) | |
97 | intsig = -1; | |
98 | return intsig; | |
99 | } | |
100 | ||
101 | static void | |
102 | test_for_unknown_sig (int sig, const char *sigstr) | |
103 | { | |
104 | if (sig < 0 || sig > NSIG) | |
105 | { | |
92b499ac CV |
106 | fprintf (stderr, "%1$s: unknown signal: %2$s\n" |
107 | "Try `%1$s --help' for more information.\n", | |
108 | prog_name, sigstr); | |
c49fa762 CF |
109 | exit (1); |
110 | } | |
111 | } | |
112 | ||
113 | static void | |
114 | listsig (const char *in_sig) | |
115 | { | |
116 | int sig; | |
117 | if (!in_sig) | |
0512945e | 118 | for (sig = 1; sig < NSIG - 1; sig++) |
c49fa762 CF |
119 | printf ("%s%c", strsigno (sig) + 3, (sig < NSIG - 1) ? ' ' : '\n'); |
120 | else | |
121 | { | |
122 | sig = getsig (in_sig); | |
123 | test_for_unknown_sig (sig, in_sig); | |
6eabab55 CF |
124 | if (atoi (in_sig) == sig) |
125 | puts (strsigno (sig) + 3); | |
126 | else | |
127 | printf ("%d\n", sig); | |
c49fa762 | 128 | } |
af53a09c CF |
129 | } |
130 | ||
5817840a CV |
131 | static void |
132 | get_debug_priv (void) | |
133 | { | |
134 | HANDLE tok; | |
135 | LUID luid; | |
136 | TOKEN_PRIVILEGES tkp; | |
137 | ||
138 | if (!OpenProcessToken (GetCurrentProcess (), | |
1b23b30b | 139 | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tok)) |
5817840a CV |
140 | return; |
141 | ||
142 | if (!LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid)) | |
143 | { | |
144 | CloseHandle (tok); | |
145 | return; | |
146 | } | |
147 | ||
148 | tkp.PrivilegeCount = 1; | |
149 | tkp.Privileges[0].Luid = luid; | |
150 | tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | |
151 | ||
152 | AdjustTokenPrivileges (tok, FALSE, &tkp, sizeof tkp, NULL, NULL); | |
153 | ||
154 | CloseHandle (tok); | |
155 | } | |
156 | ||
af53a09c CF |
157 | static void __stdcall |
158 | forcekill (int pid, int sig, int wait) | |
159 | { | |
5817840a CV |
160 | // try to acquire SeDebugPrivilege |
161 | get_debug_priv(); | |
162 | ||
87b83839 PH |
163 | external_pinfo *p = NULL; |
164 | /* cygwin_internal misinterprets negative pids (Win9x pids) */ | |
165 | if (pid > 0) | |
166 | p = (external_pinfo *) cygwin_internal (CW_GETPINFO_FULL, pid); | |
40d885eb CF |
167 | DWORD dwpid = p ? p->dwProcessId : (DWORD) pid; |
168 | HANDLE h = OpenProcess (PROCESS_TERMINATE, FALSE, (DWORD) dwpid); | |
af53a09c | 169 | if (!h) |
40d885eb | 170 | { |
1b23b30b CF |
171 | if (!wait || GetLastError () != ERROR_INVALID_PARAMETER) |
172 | fprintf (stderr, "%s: couldn't open pid %u\n", | |
173 | prog_name, (unsigned) dwpid); | |
a98a0011 | 174 | return; |
40d885eb | 175 | } |
af53a09c | 176 | if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0) |
87b83839 | 177 | if (sig && !TerminateProcess (h, sig << 8) |
a98a0011 | 178 | && WaitForSingleObject (h, 200) != WAIT_OBJECT_0) |
61522196 CV |
179 | fprintf (stderr, "%s: couldn't kill pid %u, %u\n", |
180 | prog_name, (unsigned) dwpid, (unsigned int) GetLastError ()); | |
af53a09c CF |
181 | CloseHandle (h); |
182 | } | |
1fd5e000 CF |
183 | |
184 | int | |
cc631726 | 185 | main (int argc, char **argv) |
1fd5e000 CF |
186 | { |
187 | int sig = SIGTERM; | |
cc631726 | 188 | int force = 0; |
69f9407f | 189 | int ret = 0; |
b1e00863 | 190 | char *gotasig = NULL; |
1fd5e000 | 191 | |
92b499ac | 192 | prog_name = program_invocation_short_name; |
ef48a2ca | 193 | |
cc631726 | 194 | if (argc == 1) |
1fd5e000 CF |
195 | usage (); |
196 | ||
c49fa762 | 197 | opterr = 0; |
7ed1b504 CF |
198 | |
199 | char *p; | |
87b83839 | 200 | long long int pid = 0; |
7ed1b504 | 201 | |
c49fa762 | 202 | for (;;) |
1fd5e000 | 203 | { |
c49fa762 CF |
204 | int ch; |
205 | char **av = argv + optind; | |
206 | if ((ch = getopt_long (argc, argv, opts, longopts, NULL)) == EOF) | |
207 | break; | |
208 | switch (ch) | |
209 | { | |
210 | case 's': | |
b1e00863 CF |
211 | gotasig = optarg; |
212 | sig = getsig (gotasig); | |
c49fa762 CF |
213 | break; |
214 | case 'l': | |
215 | if (!optarg) | |
216 | { | |
217 | optarg = argv[optind]; | |
218 | if (optarg) | |
219 | { | |
220 | optind++; | |
221 | optreset = 1; | |
222 | } | |
223 | } | |
224 | if (argv[optind]) | |
225 | usage (); | |
226 | listsig (optarg); | |
227 | break; | |
228 | case 'f': | |
229 | force = 1; | |
230 | break; | |
30feaa22 CF |
231 | case 'h': |
232 | usage (stdout); | |
233 | break; | |
92b499ac | 234 | case 'V': |
ef48a2ca CF |
235 | print_version (); |
236 | break; | |
c49fa762 | 237 | case '?': |
b1e00863 | 238 | if (gotasig) |
7ed1b504 | 239 | { |
9e278ffd CV |
240 | --optind; |
241 | goto out; | |
7ed1b504 | 242 | } |
c49fa762 CF |
243 | optreset = 1; |
244 | optind = 1 + av - argv; | |
b1e00863 CF |
245 | gotasig = *av + 1; |
246 | sig = getsig (gotasig); | |
c49fa762 CF |
247 | break; |
248 | default: | |
249 | usage (); | |
250 | break; | |
251 | } | |
1fd5e000 CF |
252 | } |
253 | ||
7ed1b504 | 254 | out: |
b1e00863 | 255 | test_for_unknown_sig (sig, gotasig); |
c49fa762 CF |
256 | |
257 | argv += optind; | |
cc631726 | 258 | while (*argv != NULL) |
1fd5e000 | 259 | { |
7ed1b504 | 260 | if (!pid) |
87b83839 PH |
261 | pid = strtoll (*argv, &p, 10); |
262 | if (*p != '\0' | |
61522196 CV |
263 | || (!force && (pid < INT_MIN || pid > INT_MAX)) |
264 | || (force && (pid <= 0 || pid > UINT_MAX))) | |
12f6d7bc | 265 | { |
ef48a2ca | 266 | fprintf (stderr, "%s: illegal pid: %s\n", prog_name, *argv); |
12f6d7bc CF |
267 | ret = 1; |
268 | } | |
61522196 | 269 | else if (pid <= INT_MAX && kill ((pid_t) pid, sig) == 0) |
12f6d7bc CF |
270 | { |
271 | if (force) | |
87b83839 | 272 | forcekill ((pid_t) pid, sig, 1); |
12f6d7bc | 273 | } |
87b83839 PH |
274 | else if (force) |
275 | forcekill ((pid_t) pid, sig, 0); | |
1fd5e000 CF |
276 | else |
277 | { | |
12f6d7bc | 278 | char buf[1000]; |
87b83839 | 279 | sprintf (buf, "%s: %lld", prog_name, pid); |
12f6d7bc CF |
280 | perror (buf); |
281 | ret = 1; | |
1fd5e000 | 282 | } |
cc631726 | 283 | argv++; |
7ed1b504 | 284 | pid = 0; |
1fd5e000 | 285 | } |
69f9407f | 286 | return ret; |
1fd5e000 | 287 | } |
5817840a | 288 |