OSDN Git Service

* setfacl.c (strchrnul): New function.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / utils / kill.cc
1 /* kill.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <time.h>
16 #include <errno.h>
17 #include <windows.h>
18 #include <sys/cygwin.h>
19 #include <getopt.h>
20 #include <limits.h>
21
22 static const char version[] = "$Revision$";
23 static char *prog_name;
24
25 static struct option longopts[] =
26 {
27   {"help", no_argument, NULL, 'h' },
28   {"list", optional_argument, NULL, 'l'},
29   {"force", no_argument, NULL, 'f'},
30   {"signal", required_argument, NULL, 's'},
31   {"version", no_argument, NULL, 'v'},
32   {NULL, 0, NULL, 0}
33 };
34
35 static char opts[] = "hl::fs:v";
36
37 static void
38 usage (FILE *where = stderr)
39 {
40   fprintf (where , ""
41         "Usage: %s [-f] [-signal] [-s signal] pid1 [pid2 ...]\n"
42         "       %s -l [signal]\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 %s --list for a list)\n"
48         " -h, --help      output usage information and exit\n"
49         " -v, --version   output version information and exit\n"
50         "", prog_name, prog_name, prog_name);
51   exit (where == stderr ? 1 : 0);
52 }
53
54 static void
55 print_version ()
56 {
57   const char *v = strchr (version, ':');
58   int len;
59   if (!v)
60     {
61       v = "?";
62       len = 1;
63     }
64   else
65     {
66       v += 2;
67       len = strchr (v, ' ') - v;
68     }
69   printf ("\
70 %s (cygwin) %.*s\n\
71 Process Signaller\n\
72 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.\n\
73 Compiled on %s\n\
74 ", prog_name, len, v, __DATE__);
75 }
76
77 static const char *
78 strsigno (int signo)
79 {
80   if (signo >= 0 && signo < NSIG)
81     return sys_sigabbrev[signo];
82   static char buf[sizeof ("Unknown signal") + 32];
83   sprintf (buf, "Unknown signal %d", signo);
84   return buf;
85 }
86
87 static int
88 getsig (const char *in_sig)
89 {
90   const char *sig;
91   char buf[80];
92   int intsig;
93
94   if (strncmp (in_sig, "SIG", 3) == 0)
95     sig = in_sig;
96   else
97     {
98       sprintf (buf, "SIG%-.20s", in_sig);
99       sig = buf;
100     }
101   intsig = strtosigno (sig) ?: atoi (in_sig);
102   char *p;
103   if (!intsig && (strcmp (buf, "SIG0") != 0 && (strtol (in_sig, &p, 10) != 0 || *p)))
104     intsig = -1;
105   return intsig;
106 }
107
108 static void
109 test_for_unknown_sig (int sig, const char *sigstr)
110 {
111   if (sig < 0 || sig > NSIG)
112     {
113       fprintf (stderr, "%s: unknown signal: %s\n", prog_name, sigstr);
114       usage ();
115       exit (1);
116     }
117 }
118
119 static void
120 listsig (const char *in_sig)
121 {
122   int sig;
123   if (!in_sig)
124     for (sig = 1; sig < NSIG - 1; sig++)
125       printf ("%s%c", strsigno (sig) + 3, (sig < NSIG - 1) ? ' ' : '\n');
126   else
127     {
128       sig = getsig (in_sig);
129       test_for_unknown_sig (sig, in_sig);
130       if (atoi (in_sig) == sig)
131         puts (strsigno (sig) + 3);
132       else
133         printf ("%d\n", sig);
134     }
135 }
136
137 static void
138 get_debug_priv (void)
139 {
140   HANDLE tok;
141   LUID luid;
142   TOKEN_PRIVILEGES tkp;
143
144   if (!OpenProcessToken (GetCurrentProcess (),
145                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tok))
146     return;
147
148   if (!LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid))
149     {
150       CloseHandle (tok);
151       return;
152     }
153
154   tkp.PrivilegeCount = 1;
155   tkp.Privileges[0].Luid = luid;
156   tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
157
158   AdjustTokenPrivileges (tok, FALSE, &tkp, sizeof tkp, NULL, NULL);
159
160   CloseHandle (tok);
161 }
162
163 static void __stdcall
164 forcekill (int pid, int sig, int wait)
165 {
166   // try to acquire SeDebugPrivilege
167   get_debug_priv();
168
169   external_pinfo *p = NULL;
170   /* cygwin_internal misinterprets negative pids (Win9x pids) */
171   if (pid > 0)
172     p = (external_pinfo *) cygwin_internal (CW_GETPINFO_FULL, pid);
173   DWORD dwpid = p ? p->dwProcessId : (DWORD) pid;
174   HANDLE h = OpenProcess (PROCESS_TERMINATE, FALSE, (DWORD) dwpid);
175   if (!h)
176     {
177       if (!wait || GetLastError () != ERROR_INVALID_PARAMETER) 
178         fprintf (stderr, "%s: couldn't open pid %u\n", 
179                  prog_name, (unsigned) dwpid);
180       return;
181     }
182   if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
183     if (sig && !TerminateProcess (h, sig << 8)
184         && WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
185       fprintf (stderr, "%s: couldn't kill pid %u, %lu\n", 
186                prog_name, (unsigned) dwpid, GetLastError ());
187   CloseHandle (h);
188 }
189
190 int
191 main (int argc, char **argv)
192 {
193   int sig = SIGTERM;
194   int force = 0;
195   int ret = 0;
196   char *gotasig = NULL;
197
198   prog_name = strrchr (argv[0], '/');
199   if (prog_name == NULL)
200     prog_name = strrchr (argv[0], '\\');
201   if (prog_name == NULL)
202     prog_name = argv[0];
203   else
204     prog_name++;
205
206   if (argc == 1)
207     usage ();
208
209   opterr = 0;
210
211   char *p;
212   long long int pid = 0;
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 'h':
244           usage (stdout);
245           break;
246         case 'v':
247           print_version ();
248           break;
249         case '?':
250           if (gotasig)
251             {
252               --optind;
253               goto out;
254             }
255           optreset = 1;
256           optind = 1 + av - argv;
257           gotasig = *av + 1;
258           sig = getsig (gotasig);
259           break;
260         default:
261           usage ();
262           break;
263         }
264     }
265
266 out:
267   test_for_unknown_sig (sig, gotasig);
268
269   argv += optind;
270   while (*argv != NULL)
271     {
272       if (!pid)
273         pid = strtoll (*argv, &p, 10);
274       if (*p != '\0'
275           || (!force && (pid < LONG_MIN || pid > LONG_MAX))
276           || (force && (pid <= 0 || pid > ULONG_MAX))) 
277         {
278           fprintf (stderr, "%s: illegal pid: %s\n", prog_name, *argv);
279           ret = 1;
280         }
281       else if (pid <= LONG_MAX && kill ((pid_t) pid, sig) == 0)
282         {
283           if (force)
284             forcekill ((pid_t) pid, sig, 1);
285         }
286       else if (force)
287         forcekill ((pid_t) pid, sig, 0);
288       else
289         {
290           char buf[1000];
291           sprintf (buf, "%s: %lld", prog_name, pid);
292           perror (buf);
293           ret = 1;
294         }
295       argv++;
296       pid = 0;
297     }
298   return ret;
299 }
300