Bump to procps-ng 3.3.16
[platform/upstream/procps-ng.git] / skill.c
1 /*
2  * skill.c - send a signal to process
3  * Copyright 1998-2002 by Albert Cahalan
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include <ctype.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <getopt.h>
25 #include <limits.h>
26 #include <pwd.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/resource.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36
37 #include "c.h"
38 #include "fileutils.h"
39 #include "nsutils.h"
40 #include "strutils.h"
41 #include "nls.h"
42 #include "xalloc.h"
43 #include "proc/pwcache.h"
44 #include "proc/sig.h"
45 #include "proc/devname.h"
46 #include "proc/procps.h"        /* char *pwcache_get_user(uid_t uid) */
47 #include "proc/readproc.h"
48 #include "proc/version.h"       /* procps_version */
49 #include "rpmatch.h"
50
51 #define DEFAULT_NICE 4
52
53 struct run_time_conf_t {
54         int fast;
55         int interactive;
56         int verbose;
57         int warnings;
58         int noaction;
59         int debugging;
60 };
61 static int tty_count, uid_count, cmd_count, pid_count, namespace_count;
62 static int *ttys;
63 static uid_t *uids;
64 static const char **cmds;
65 static int *pids;
66 static char **namespaces;
67 static int ns_pid;
68 static proc_t ns_task;
69
70 #define ENLIST(thing,addme) do{ \
71 if(thing##_count < 0 || (size_t)thing##_count >= INT_MAX / sizeof(*thing##s)) \
72         xerrx(EXIT_FAILURE, _("integer overflow")); \
73 thing##s = xrealloc(thing##s, sizeof(*thing##s)*(thing##_count+1)); \
74 thing##s[thing##_count++] = addme; \
75 }while(0)
76
77 static int my_pid;
78 static int sig_or_pri;
79
80 enum {
81         PROG_UNKNOWN,
82         PROG_KILL,
83         PROG_SKILL,
84         PROG_SNICE
85 };
86 static int program = PROG_UNKNOWN;
87
88 static void display_kill_version(void)
89 {
90         fprintf(stdout, PROCPS_NG_VERSION);
91 }
92
93 static int ns_flags = 0x3f;
94 static int parse_namespaces(char *optarg)
95 {
96         char *ptr = optarg, *tmp;
97         int len, id;
98
99         ns_flags = 0;
100         while (1) {
101                 if (strchr(ptr, ',') == NULL) {
102                         len = -1;
103                         tmp = strdup(ptr);
104                 } else {
105                         len = strchr(ptr, ',') - ptr;
106                         tmp = strndup(ptr, len);
107                 }
108
109                 id = get_ns_id(tmp);
110                 if (id == -1) {
111                         fprintf(stderr, "%s is not a valid namespace\n", tmp);
112                         free(tmp);
113                         return 1;
114                 }
115                 ns_flags |= (1 << id);
116                 ENLIST(namespace, tmp);
117
118                 if (len == -1)
119                         break;
120
121                 ptr+= len + 1;
122         }
123         return 0;
124 }
125
126 /* kill or nice a process */
127 static void hurt_proc(int tty, int uid, int pid, const char *restrict const cmd,
128                       struct run_time_conf_t *run_time)
129 {
130         int failed;
131         char dn_buf[1000];
132         dev_to_tty(dn_buf, 999, tty, pid, ABBREV_DEV);
133         if (run_time->interactive) {
134                 char *buf = NULL;
135                 size_t len = 0;
136                 fprintf(stderr, "%-8s %-8s %5d %-16.16s   ? ",
137                         (char *)dn_buf, pwcache_get_user(uid), pid, cmd);
138                 fflush (stdout);
139                 if (getline(&buf, &len, stdin) == -1) {
140                         free(buf);
141                         return;
142                 }
143                 if (rpmatch(buf) < 1) {
144                         free(buf);
145                         return;
146                 }
147                 free(buf);
148         }
149         /* do the actual work */
150         errno = 0;
151         if (program == PROG_SKILL)
152                 failed = kill(pid, sig_or_pri);
153         else
154                 failed = setpriority(PRIO_PROCESS, pid, sig_or_pri);
155         if ((run_time->warnings && failed) || run_time->debugging || run_time->verbose) {
156                 fprintf(stderr, "%-8s %-8s %5d %-16.16s   ",
157                         (char *)dn_buf, pwcache_get_user(uid), pid, cmd);
158                 perror("");
159                 return;
160         }
161         if (run_time->interactive)
162                 return;
163         if (run_time->noaction) {
164                 printf("%d\n", pid);
165                 return;
166         }
167 }
168
169 /* check one process */
170 static void check_proc(int pid, struct run_time_conf_t *run_time)
171 {
172         char buf[128];
173         struct stat statbuf;
174         proc_t task;
175         char *tmp;
176         int tty;
177         int fd;
178         int i;
179         ssize_t len;
180         if (pid == my_pid || pid == 0)
181                 return;
182         /* pid (cmd) state ppid pgrp session tty */
183         sprintf(buf, "/proc/%d/stat", pid);
184         fd = open(buf, O_RDONLY);
185         if (fd == -1) {
186                 /* process exited maybe */
187                 if (run_time->warnings)
188                         xwarn(_("cannot open file %s"), buf);
189                 return;
190         }
191         if (fstat(fd, &statbuf) != 0)
192                 goto closure;
193         if (uids) {
194                 /* check the EUID */
195                 i = uid_count;
196                 while (i--)
197                         if (uids[i] == statbuf.st_uid)
198                                 break;
199                 if (i == -1)
200                         goto closure;
201         }
202         len = read(fd, buf, sizeof(buf));
203         if (len <= 0)
204                 goto closure;
205         buf[sizeof(buf) -1] = '\0';
206         tmp = strrchr(buf, ')');
207         if (!tmp)
208                 goto closure;
209         *tmp++ = '\0';
210         i = 5;
211         while (i--)
212                 do {
213                         if (!*tmp)
214                                 goto closure;
215                         /* scan to find tty */
216                 } while (*tmp++ != ' ');
217         tty = atoi(tmp);
218         if (ttys) {
219                 i = tty_count;
220                 while (i--)
221                         if (ttys[i] == tty)
222                                 break;
223                 if (i == -1)
224                         goto closure;
225         }
226         tmp = strchr(buf, '(');
227         if (!tmp)
228                 goto closure;
229         tmp++;
230         if (cmds) {
231                 i = cmd_count;
232                 /* fast comparison trick -- useful? */
233                 while (i--)
234                         if (cmds[i][0] == *tmp && !strcmp(cmds[i], tmp))
235                                 break;
236                 if (i == -1)
237                         goto closure;
238         }
239         if (ns_pid) {
240                 if (ns_read(pid, &task))
241                         goto closure;
242                 for (i = 0; i < NUM_NS; i++) {
243                         if (ns_flags & (1 << i)) {
244                                 if (task.ns[i] != ns_task.ns[i])
245                                         goto closure;
246                         }
247                 }
248         }
249         /* This is where we kill/nice something. */
250         /* for debugging purposes?
251         fprintf(stderr, "PID %d, UID %d, TTY %d,%d, COMM %s\n",
252                 pid, statbuf.st_uid, tty >> 8, tty & 0xf, tmp);
253         */
254         hurt_proc(tty, statbuf.st_uid, pid, tmp, run_time);
255  closure:
256         /* kill/nice _first_ to avoid PID reuse */
257         close(fd);
258 }
259
260 /* debug function */
261 static void show_lists(void)
262 {
263         int i;
264
265         fprintf(stderr, "signal: %d\n", sig_or_pri);
266
267         fprintf(stderr, "%d TTY: ", tty_count);
268         if (ttys) {
269                 i = tty_count;
270                 while (i--) {
271                         fprintf(stderr, "%d,%d%c", (ttys[i] >> 8) & 0xff,
272                                 ttys[i] & 0xff, i ? ' ' : '\n');
273                 }
274         } else
275                 fprintf(stderr, "\n");
276
277         fprintf(stderr, "%d UID: ", uid_count);
278         if (uids) {
279                 i = uid_count;
280                 while (i--)
281                         fprintf(stderr, "%d%c", uids[i], i ? ' ' : '\n');
282         } else
283                 fprintf(stderr, "\n");
284
285         fprintf(stderr, "%d PID: ", pid_count);
286         if (pids) {
287                 i = pid_count;
288                 while (i--)
289                         fprintf(stderr, "%d%c", pids[i], i ? ' ' : '\n');
290         } else
291                 fprintf(stderr, "\n");
292
293         fprintf(stderr, "%d CMD: ", cmd_count);
294         if (cmds) {
295                 i = cmd_count;
296                 while (i--)
297                         fprintf(stderr, "%s%c", cmds[i], i ? ' ' : '\n');
298         } else
299                 fprintf(stderr, "\n");
300 }
301
302 /* iterate over all PIDs */
303 static void iterate(struct run_time_conf_t *run_time)
304 {
305         int pid;
306         DIR *d;
307         struct dirent *de;
308         if (pids) {
309                 pid = pid_count;
310                 while (pid--)
311                         check_proc(pids[pid], run_time);
312                 return;
313         }
314 #if 0
315         /* could setuid() and kill -1 to have the kernel wipe out a user */
316         if (!ttys && !cmds && !pids && !run_time->interactive) {
317         }
318 #endif
319         d = opendir("/proc");
320         if (!d)
321                 xerr(EXIT_FAILURE, "/proc");
322         while ((de = readdir(d))) {
323                 if (de->d_name[0] > '9')
324                         continue;
325                 if (de->d_name[0] < '1')
326                         continue;
327                 pid = atoi(de->d_name);
328                 if (pid)
329                         check_proc(pid, run_time);
330         }
331         closedir(d);
332 }
333
334 /* kill help */
335 static void __attribute__ ((__noreturn__)) kill_usage(FILE * out)
336 {
337         fputs(USAGE_HEADER, out);
338         fprintf(out,
339               _(" %s [options] <pid> [...]\n"), program_invocation_short_name);
340         fputs(USAGE_OPTIONS, out);
341         fputs(_(" <pid> [...]            send signal to every <pid> listed\n"), out);
342         fputs(_(" -<signal>, -s, --signal <signal>\n"
343                 "                        specify the <signal> to be sent\n"), out);
344         fputs(_(" -l, --list=[<signal>]  list all signal names, or convert one to a name\n"), out);
345         fputs(_(" -L, --table            list all signal names in a nice table\n"), out);
346         fputs(USAGE_SEPARATOR, out);
347         fputs(USAGE_HELP, out);
348         fputs(USAGE_VERSION, out);
349         fprintf(out, USAGE_MAN_TAIL("kill(1)"));
350         exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
351 }
352
353 /* skill and snice help */
354 static void __attribute__ ((__noreturn__)) skillsnice_usage(FILE * out)
355 {
356         fputs(USAGE_HEADER, out);
357
358         if (program == PROG_SKILL) {
359                 fprintf(out,
360                         _(" %s [signal] [options] <expression>\n"),
361                         program_invocation_short_name);
362         } else {
363                 fprintf(out,
364                         _(" %s [new priority] [options] <expression>\n"),
365                         program_invocation_short_name);
366         }
367         fputs(USAGE_OPTIONS, out);
368         fputs(_(" -f, --fast         fast mode (not implemented)\n"), out);
369         fputs(_(" -i, --interactive  interactive\n"), out);
370         fputs(_(" -l, --list         list all signal names\n"), out);
371         fputs(_(" -L, --table        list all signal names in a nice table\n"), out);
372         fputs(_(" -n, --no-action    do not actually kill processes; just print what would happen\n"), out);
373         fputs(_(" -v, --verbose      explain what is being done\n"), out);
374         fputs(_(" -w, --warnings     enable warnings (not implemented)\n"), out);
375         fputs(USAGE_SEPARATOR, out);
376         fputs(_("Expression can be: terminal, user, pid, command.\n"
377                 "The options below may be used to ensure correct interpretation.\n"), out);
378         fputs(_(" -c, --command <command>  expression is a command name\n"), out);
379         fputs(_(" -p, --pid <pid>          expression is a process id number\n"), out);
380         fputs(_(" -t, --tty <tty>          expression is a terminal\n"), out);
381         fputs(_(" -u, --user <username>    expression is a username\n"), out);
382         fputs(USAGE_SEPARATOR, out);
383         fputs(_("Alternatively, expression can be:\n"), out);
384         fputs(_(" --ns <pid>               match the processes that belong to the same\n"
385                 "                          namespace as <pid>\n"), out);
386         fputs(_(" --nslist <ns,...>        list which namespaces will be considered for\n"
387                 "                          the --ns option; available namespaces are\n:"
388                 "                          ipc, mnt, net, pid, user, uts\n"), out);
389
390         fputs(USAGE_SEPARATOR, out);
391         fputs(USAGE_SEPARATOR, out);
392         fputs(USAGE_HELP, out);
393         fputs(USAGE_VERSION, out);
394         if (program == PROG_SKILL) {
395                 fprintf(out,
396                         _("\n"
397                           "The default signal is TERM. Use -l or -L to list available signals.\n"
398                           "Particularly useful signals include HUP, INT, KILL, STOP, CONT, and 0.\n"
399                           "Alternate signals may be specified in three ways: -SIGKILL -KILL -9\n"));
400                 fprintf(out, USAGE_MAN_TAIL("skill(1)"));
401         } else {
402                 fprintf(out,
403                         _("\n"
404                           "The default priority is +4. (snice +4 ...)\n"
405                           "Priority numbers range from +20 (slowest) to -20 (fastest).\n"
406                           "Negative priority numbers are restricted to administrative users.\n"));
407                 fprintf(out, USAGE_MAN_TAIL("snice(1)"));
408         }
409         exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
410 }
411
412 static int skill_sig_option(int *argc, char **argv)
413 {
414         int i;
415         int signo = -1;
416         for (i = 1; i < *argc; i++) {
417                 if (argv[i][0] == '-') {
418                         signo = signal_name_to_number(argv[i] + 1);
419                         if (-1 < signo) {
420                                 memmove(argv + i, argv + i + 1,
421                                         sizeof(char *) * (*argc - i));
422                                 (*argc)--;
423                                 return signo;
424                         }
425                 }
426         }
427         return signo;
428 }
429
430 /* kill */
431 static void __attribute__ ((__noreturn__))
432     kill_main(int argc, char **argv)
433 {
434         int signo, i;
435         long pid;
436         int exitvalue = EXIT_SUCCESS;
437     char *sig_option;
438
439         static const struct option longopts[] = {
440                 {"list", optional_argument, NULL, 'l'},
441                 {"table", no_argument, NULL, 'L'},
442                 {"signal", required_argument, NULL, 's'},
443                 {"help", no_argument, NULL, 'h'},
444                 {"version", no_argument, NULL, 'V'},
445                 {NULL, 0, NULL, 0}
446         };
447
448         setlocale (LC_ALL, "");
449         bindtextdomain(PACKAGE, LOCALEDIR);
450         textdomain(PACKAGE);
451         atexit(close_stdout);
452
453         if (argc < 2)
454                 kill_usage(stderr);
455
456         signo = skill_sig_option(&argc, argv);
457         if (signo < 0)
458                 signo = SIGTERM;
459
460         opterr=0; /* suppress errors on -123 */
461         while ((i = getopt_long(argc, argv, "l::Ls:hV", longopts, NULL)) != -1)
462                 switch (i) {
463                 case 'l':
464             sig_option = NULL;
465             if (optarg) {
466                 sig_option = optarg;
467             } else if (argv[optind] != NULL && argv[optind][0] != '-') {
468                 sig_option = argv[optind];
469             }
470                         if (sig_option) {
471                                 char *s;
472                                 s = strtosig(sig_option);
473                                 if (s)
474                                         printf("%s\n", s);
475                                 else
476                                         xwarnx(_("unknown signal name %s"),
477                                               sig_option);
478                                 free(s);
479                         } else {
480                                 unix_print_signals();
481                         }
482                         exit(EXIT_SUCCESS);
483                 case 'L':
484                         pretty_print_signals();
485                         exit(EXIT_SUCCESS);
486                 case 's':
487                         signo = signal_name_to_number(optarg);
488                         break;
489                 case 'h':
490                         kill_usage(stdout);
491                 case 'V':
492                         display_kill_version();
493                         exit(EXIT_SUCCESS);
494                 case '?':
495                         if (!isdigit(optopt)) {
496                                 xwarnx(_("invalid argument %c"), optopt);
497                                 kill_usage(stderr);
498                         } else {
499                             /* Special case for signal digit negative
500                              * PIDs */
501                             pid = atoi(argv[optind]);
502                             if (kill((pid_t)pid, signo) != 0)
503                                 exitvalue = EXIT_FAILURE;
504                             exit(exitvalue);
505                         }
506                         xerrx(EXIT_FAILURE, _("internal error"));
507                 default:
508                         kill_usage(stderr);
509                 }
510
511         argc -= optind;
512         argv += optind;
513
514         if (argc < 1)
515                 kill_usage(stderr);
516
517         for (i = 0; i < argc; i++) {
518                 pid = strtol_or_err(argv[i], _("failed to parse argument"));
519                 if (!kill((pid_t) pid, signo))
520                         continue;
521         error(0, errno, "(%ld)", pid);
522                 exitvalue = EXIT_FAILURE;
523                 continue;
524         }
525
526         exit(exitvalue);
527 }
528
529 #if 0
530 static void _skillsnice_usage(int line)
531 {
532         fprintf(stderr, _("something at line %d\n"), line);
533         skillsnice_usage(stderr);
534 }
535
536 #define skillsnice_usage() _skillsnice_usage(__LINE__)
537 #endif
538
539 /* common skill/snice argument parsing code */
540
541 static int snice_prio_option(int *argc, char **argv)
542 {
543         int i = 1, nargs = *argc;
544         long prio = DEFAULT_NICE;
545
546         while (i < nargs) {
547                 if ((argv[i][0] == '-' || argv[i][0] == '+')
548                     && isdigit(argv[i][1])) {
549                         prio = strtol_or_err(argv[i],
550                                              _("failed to parse argument"));
551                         if (prio < INT_MIN || INT_MAX < prio)
552                                 xerrx(EXIT_FAILURE,
553                                      _("priority %lu out of range"), prio);
554                         memmove(argv + i, argv + i + 1,
555                                 sizeof(char *) * (nargs - i));
556                         nargs--;
557                 } else
558                         i++;
559         }
560         *argc = nargs;
561         return (int)prio;
562 }
563
564 static void skillsnice_parse(int argc,
565                              char **argv, struct run_time_conf_t *run_time)
566 {
567         int signo = -1;
568         int prino = DEFAULT_NICE;
569         int ch, i;
570
571         enum {
572                 NS_OPTION = CHAR_MAX + 1,
573                 NSLIST_OPTION,
574         };
575
576         static const struct option longopts[] = {
577                 {"command", required_argument, NULL, 'c'},
578                 {"debug", no_argument, NULL, 'd'},
579                 {"fast", no_argument, NULL, 'f'},
580                 {"interactive", no_argument, NULL, 'i'},
581                 {"list", no_argument, NULL, 'l'},
582                 {"no-action", no_argument, NULL, 'n'},
583                 {"pid", required_argument, NULL, 'p'},
584                 {"table", no_argument, NULL, 'L'},
585                 {"tty", required_argument, NULL, 't'},
586                 {"user", required_argument, NULL, 'u'},
587                 {"ns", required_argument, NULL, NS_OPTION},
588                 {"nslist", required_argument, NULL, NSLIST_OPTION},
589                 {"verbose", no_argument, NULL, 'v'},
590                 {"warnings", no_argument, NULL, 'w'},
591                 {"help", no_argument, NULL, 'h'},
592                 {"version", no_argument, NULL, 'V'},
593                 {NULL, 0, NULL, 0}
594         };
595
596         if (argc < 2)
597                 skillsnice_usage(stderr);
598
599         sig_or_pri = -1;
600
601         if (program == PROG_SNICE)
602                 prino = snice_prio_option(&argc, argv);
603         else if (program == PROG_SKILL) {
604                 signo = skill_sig_option(&argc, argv);
605                 if (-1 < signo)
606                         sig_or_pri = signo;
607         }
608
609         while ((ch =
610                 getopt_long(argc, argv, "c:dfilnp:Lt:u:vwhV", longopts,
611                             NULL)) != -1)
612                 switch (ch) {
613                 case 'c':
614                         ENLIST(cmd, optarg);
615                         break;
616                 case 'd':
617                         run_time->debugging = 1;
618                         break;
619                 case 'f':
620                         run_time->fast = 1;
621                         break;
622                 case 'i':
623                         run_time->interactive = 1;
624                         break;
625                 case 'l':
626                         unix_print_signals();
627                         exit(EXIT_SUCCESS);
628                 case 'n':
629                         run_time->noaction = 1;
630                         break;
631                 case 'p':
632                         ENLIST(pid,
633                                strtol_or_err(optarg,
634                                              _("failed to parse argument")));
635                         break;
636                 case 'L':
637                         pretty_print_signals();
638                         exit(EXIT_SUCCESS);
639                 case 't':
640                         {
641                                 struct stat sbuf;
642                                 char path[32];
643                                 snprintf(path, 32, "/dev/%s", optarg);
644                                 if (stat(path, &sbuf) >= 0
645                                     && S_ISCHR(sbuf.st_mode)) {
646                                         ENLIST(tty, sbuf.st_rdev);
647                                 }
648                         }
649                         break;
650                 case 'u':
651                         {
652                                 struct passwd *passwd_data;
653                                 passwd_data = getpwnam(optarg);
654                                 if (passwd_data) {
655                                         ENLIST(uid, passwd_data->pw_uid);
656                                 }
657                         }
658                         break;
659                 case NS_OPTION:
660                         ns_pid = atoi(optarg);
661                         if (ns_pid == 0) {
662                                 xwarnx(_("invalid pid number %s"), optarg);
663                                 kill_usage(stderr);
664                         }
665                         if (ns_read(ns_pid, &ns_task)) {
666                                 xwarnx(_("error reading reference namespace "
667                                          "information"));
668                                 kill_usage(stderr);
669                         }
670
671                         break;
672                 case NSLIST_OPTION:
673                         if (parse_namespaces(optarg)) {
674                                 xwarnx(_("invalid namespace list"));
675                                 kill_usage(stderr);
676                         }
677                         break;
678                 case 'v':
679                         run_time->verbose = 1;
680                         break;
681                 case 'w':
682                         run_time->warnings = 1;
683                         break;
684                 case 'h':
685                         skillsnice_usage(stdout);
686                 case 'V':
687                         display_kill_version();
688                         exit(EXIT_SUCCESS);
689                 default:
690                         skillsnice_usage(stderr);
691                 }
692
693         argc -= optind;
694         argv += optind;
695
696         for (i = 0; i < argc; i++) {
697                 long num;
698                 char *end = NULL;
699                 errno = 0;
700                 num = strtol(argv[0], &end, 10);
701                 if (errno == 0 && argv[0] != end && end != NULL && *end == '\0') {
702                         ENLIST(pid, num);
703                 } else {
704                         ENLIST(cmd, argv[0]);
705                 }
706                 argv++;
707         }
708
709         /* No more arguments to process. Must sanity check. */
710         if (!tty_count && !uid_count && !cmd_count && !pid_count && !ns_pid)
711                 xerrx(EXIT_FAILURE, _("no process selection criteria"));
712         if ((run_time->fast | run_time->interactive | run_time->
713              verbose | run_time->warnings | run_time->noaction) & ~1)
714                 xerrx(EXIT_FAILURE, _("general flags may not be repeated"));
715         if (run_time->interactive
716             && (run_time->verbose | run_time->fast | run_time->noaction))
717                 xerrx(EXIT_FAILURE, _("-i makes no sense with -v, -f, and -n"));
718         if (run_time->verbose && (run_time->interactive | run_time->fast))
719                 xerrx(EXIT_FAILURE, _("-v makes no sense with -i and -f"));
720         if (run_time->noaction) {
721                 program = PROG_SKILL;
722                 /* harmless */
723                 sig_or_pri = 0;
724         }
725         if (program == PROG_SNICE)
726                 sig_or_pri = prino;
727         else if (sig_or_pri < 0)
728                 sig_or_pri = SIGTERM;
729 }
730
731 /* main body */
732 int main(int argc, char ** argv)
733 {
734 #ifdef HAVE_PROGRAM_INVOCATION_NAME
735         program_invocation_name = program_invocation_short_name;
736 #endif
737         struct run_time_conf_t run_time;
738         memset(&run_time, 0, sizeof(struct run_time_conf_t));
739         my_pid = getpid();
740
741         if (strcmp(program_invocation_short_name, "kill") == 0 ||
742             strcmp(program_invocation_short_name, "lt-kill") == 0)
743                 program = PROG_KILL;
744         else if (strcmp(program_invocation_short_name, "skill") == 0 ||
745                  strcmp(program_invocation_short_name, "lt-skill") == 0)
746                 program = PROG_SKILL;
747         else if (strcmp(program_invocation_short_name, "snice") == 0 ||
748                  strcmp(program_invocation_short_name, "lt-snice") == 0)
749                 program = PROG_SNICE;
750 #ifdef __CYGWIN__
751         else if (strcmp(program_invocation_short_name, "prockill") == 0 ||
752                  strcmp(program_invocation_short_name, "lt-prockill") == 0)
753                 program = PROG_KILL;
754 #endif
755
756         switch (program) {
757         case PROG_SNICE:
758         case PROG_SKILL:
759                 setpriority(PRIO_PROCESS, my_pid, -20);
760                 skillsnice_parse(argc, argv, &run_time);
761                 if (run_time.debugging)
762                         show_lists();
763                 iterate(&run_time);
764                 break;
765         case PROG_KILL:
766                 kill_main(argc, argv);
767                 break;
768         default:
769                 fprintf(stderr, _("skill: \"%s\" is not supported\n"),
770                         program_invocation_short_name);
771                 fprintf(stderr, USAGE_MAN_TAIL("skill(1)"));
772                 return EXIT_FAILURE;
773         }
774         return EXIT_SUCCESS;
775 }