]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/kill.cc
Cygwin: utils: kill: revert erroneously removed optind correction
[newlib-cygwin.git] / winsup / utils / kill.cc
1 /* kill.cc
2
3 This file is part of Cygwin.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <signal.h>
12 #include <string.h>
13 #include <time.h>
14 #include <errno.h>
15 #include <windows.h>
16 #include <sys/cygwin.h>
17 #include <cygwin/version.h>
18 #include <getopt.h>
19 #include <limits.h>
20
21 static char *prog_name;
22
23 static struct option longopts[] =
24 {
25 {"help", no_argument, NULL, 'h' },
26 {"list", optional_argument, NULL, 'l'},
27 {"force", no_argument, NULL, 'f'},
28 {"signal", required_argument, NULL, 's'},
29 {"winpid", no_argument, NULL, 'W'},
30 {"version", no_argument, NULL, 'V'},
31 {NULL, 0, NULL, 0}
32 };
33
34 static char opts[] = "hl::fs:WV";
35
36 static void
37 usage (FILE *where = stderr)
38 {
39 fprintf (where , ""
40 "Usage: %1$s [-fW] [-signal] [-s signal] pid1 [pid2 ...]\n"
41 " %1$s -l [signal]\n"
42 "\n"
43 "Send signals to processes\n"
44 "\n"
45 " -f, --force force, using win32 interface if necessary\n"
46 " -l, --list print a list of signal names\n"
47 " -s, --signal send signal (use %1$s --list for a list)\n"
48 " -W, --winpid specified pids are windows PIDs, not Cygwin PIDs\n"
49 " (use with extreme caution!)\n"
50 " -h, --help output usage information and exit\n"
51 " -V, --version output version information and exit\n"
52 "\n", prog_name);
53 exit (where == stderr ? 1 : 0);
54 }
55
56 static void
57 print_version ()
58 {
59 printf ("kill (cygwin) %d.%d.%d\n"
60 "Process Signaller\n"
61 "Copyright (C) 1996 - %s Cygwin Authors\n"
62 "This is free software; see the source for copying conditions. There is NO\n"
63 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
64 CYGWIN_VERSION_DLL_MAJOR / 1000,
65 CYGWIN_VERSION_DLL_MAJOR % 1000,
66 CYGWIN_VERSION_DLL_MINOR,
67 strrchr (__DATE__, ' ') + 1);
68 }
69
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
80 static int
81 getsig (const char *in_sig)
82 {
83 const char *sig;
84 char buf[80];
85 int intsig;
86
87 if (strncmp (in_sig, "SIG", 3) == 0)
88 sig = in_sig;
89 else
90 {
91 sprintf (buf, "SIG%-.20s", in_sig);
92 sig = buf;
93 }
94 intsig = strtosigno (sig) ?: atoi (in_sig);
95 char *p;
96 if (!intsig && (strcmp (sig, "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 {
106 fprintf (stderr, "%1$s: unknown signal: %2$s\n"
107 "Try `%1$s --help' for more information.\n",
108 prog_name, sigstr);
109 exit (1);
110 }
111 }
112
113 static void
114 listsig (const char *in_sig)
115 {
116 int sig;
117 if (!in_sig)
118 for (sig = 1; sig < NSIG - 1; sig++)
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);
124 if (sig && atoi (in_sig) == sig)
125 puts (strsigno (sig) + 3);
126 else
127 printf ("%d\n", sig);
128 }
129 }
130
131 static void
132 get_debug_priv (void)
133 {
134 HANDLE tok;
135 LUID luid;
136 TOKEN_PRIVILEGES tkp;
137
138 if (!OpenProcessToken (GetCurrentProcess (),
139 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tok))
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
157 static void __stdcall
158 forcekill (pid_t pid, DWORD winpid, int sig, int wait)
159 {
160 DWORD dwpid;
161
162 /* try to acquire SeDebugPrivilege */
163 get_debug_priv();
164
165 if (!winpid)
166 {
167 external_pinfo *p = (external_pinfo *)
168 cygwin_internal (CW_GETPINFO_FULL, pid);
169 if (!p)
170 {
171 fprintf (stderr, "%s: %d: No such process\n", prog_name, pid);
172 return;
173 }
174 dwpid = p->dwProcessId;
175 }
176 else
177 /* pid is used for printing only after this point */
178 pid = dwpid = winpid;
179
180 HANDLE h = OpenProcess (PROCESS_TERMINATE, FALSE, dwpid);
181 if (!h)
182 {
183 if (!wait || GetLastError () != ERROR_INVALID_PARAMETER)
184 fprintf (stderr, "%s: couldn't open pid %u\n",
185 prog_name, (unsigned int) dwpid);
186 return;
187 }
188 if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
189 if (sig && !TerminateProcess (h, sig << 8)
190 && WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
191 fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
192 prog_name, (unsigned int) dwpid, (unsigned int) GetLastError ());
193 CloseHandle (h);
194 }
195
196 int
197 main (int argc, char **argv)
198 {
199 int sig = SIGTERM;
200 int force = 0;
201 int winpids = 0;
202 int ret = 0;
203 char *gotasig = NULL;
204
205 prog_name = program_invocation_short_name;
206
207 if (argc == 1)
208 usage ();
209
210 opterr = 0;
211
212 char *p;
213
214 for (;;)
215 {
216 int ch;
217 char **av = argv + optind;
218 if ((ch = getopt_long (argc, argv, opts, longopts, NULL)) == EOF)
219 break;
220 switch (ch)
221 {
222 case 's':
223 gotasig = optarg;
224 sig = getsig (gotasig);
225 break;
226 case 'l':
227 if (!optarg)
228 {
229 optarg = argv[optind];
230 if (optarg)
231 {
232 optind++;
233 optreset = 1;
234 }
235 }
236 if (argv[optind])
237 usage ();
238 listsig (optarg);
239 break;
240 case 'f':
241 force = 1;
242 break;
243 case 'W':
244 winpids = 1;
245 break;
246 case 'h':
247 usage (stdout);
248 break;
249 case 'V':
250 print_version ();
251 break;
252 case '?':
253 if (gotasig) /* this is a negative pid, go ahead */
254 {
255 --optind;
256 goto out;
257 }
258 optreset = 1;
259 optind = 1 + av - argv;
260 gotasig = *av + 1;
261 sig = getsig (gotasig);
262 break;
263 default:
264 usage ();
265 break;
266 }
267 }
268
269 out:
270 test_for_unknown_sig (sig, gotasig);
271
272 argv += optind;
273 if (*argv == 0)
274 {
275 fprintf (stderr, "%s: not enough arguments\n", prog_name);
276 return 1;
277 }
278 for (long long int pid = 0; *argv != NULL; argv++)
279 {
280 DWORD dwpid = 0;
281
282 pid = strtoll (*argv, &p, 10);
283 /* INT_MIN <= pid <= INT_MAX. -f only takes positive pids. */
284 if (*p != '\0' || pid < (force ? 1 : INT_MIN) || pid > INT_MAX)
285 {
286 fprintf (stderr, "%s: illegal pid: %s\n", prog_name, *argv);
287 ret = 1;
288 continue;
289 }
290 if (winpids)
291 {
292 dwpid = pid;
293 pid = (pid_t) cygwin_internal (CW_WINPID_TO_CYGWIN_PID, dwpid);
294 }
295 if (kill ((pid_t) pid, sig) == 0)
296 {
297 if (force)
298 forcekill ((pid_t) pid, dwpid, sig, 1);
299 }
300 else if (force)
301 forcekill ((pid_t) pid, dwpid, sig, 0);
302 else
303 {
304 char buf[1000];
305 sprintf (buf, "%s: %lld", prog_name, dwpid ?: pid);
306 perror (buf);
307 ret = 1;
308 }
309 }
310 return ret;
311 }
312
This page took 0.046256 seconds and 6 git commands to generate.