skill.c 18.9 KB
Newer Older
csmall's avatar
csmall committed
1
/*
2 3 4 5 6 7 8 9 10
 * skill.c - send a signal to process
 * Copyright 1998-2002 by Albert Cahalan
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
csmall's avatar
csmall committed
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13 14 15 16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
csmall's avatar
csmall committed
18
 */
19

20
#include <ctype.h>
csmall's avatar
csmall committed
21 22
#include <dirent.h>
#include <errno.h>
23
#include <fcntl.h>
24
#include <getopt.h>
25 26
#include <limits.h>
#include <pwd.h>
csmall's avatar
csmall committed
27 28 29 30 31 32 33 34 35
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
Sami Kerola's avatar
Sami Kerola committed
36 37

#include "c.h"
38
#include "fileutils.h"
39
#include "nsutils.h"
40
#include "strutils.h"
Sami Kerola's avatar
Sami Kerola committed
41
#include "nls.h"
42
#include "xalloc.h"
albert's avatar
albert committed
43
#include "proc/pwcache.h"
44 45
#include "proc/sig.h"
#include "proc/devname.h"
46
#include "proc/procps.h"	/* char *pwcache_get_user(uid_t uid) */
47
#include "proc/readproc.h"
Sami Kerola's avatar
Sami Kerola committed
48
#include "proc/version.h"	/* procps_version */
49
#include "rpmatch.h"
csmall's avatar
csmall committed
50

51 52
#define DEFAULT_NICE 4

53 54 55 56 57 58 59 60
struct run_time_conf_t {
	int fast;
	int interactive;
	int verbose;
	int warnings;
	int noaction;
	int debugging;
};
61
static int tty_count, uid_count, cmd_count, pid_count, namespace_count;
csmall's avatar
csmall committed
62 63
static int *ttys;
static uid_t *uids;
albert's avatar
albert committed
64
static const char **cmds;
csmall's avatar
csmall committed
65
static int *pids;
66 67 68
static char **namespaces;
static int ns_pid;
static proc_t ns_task;
csmall's avatar
csmall committed
69 70

#define ENLIST(thing,addme) do{ \
71 72 73
if(thing##_count < 0 || (size_t)thing##_count >= INT_MAX / sizeof(*thing##s)) \
	xerrx(EXIT_FAILURE, _("integer overflow")); \
thing##s = xrealloc(thing##s, sizeof(*thing##s)*(thing##_count+1)); \
csmall's avatar
csmall committed
74 75 76 77 78 79
thing##s[thing##_count++] = addme; \
}while(0)

static int my_pid;
static int sig_or_pri;

80 81 82 83 84 85 86
enum {
	PROG_UNKNOWN,
	PROG_KILL,
	PROG_SKILL,
	PROG_SNICE
};
static int program = PROG_UNKNOWN;
csmall's avatar
csmall committed
87

Sami Kerola's avatar
Sami Kerola committed
88 89 90 91
static void display_kill_version(void)
{
	fprintf(stdout, PROCPS_NG_VERSION);
}
csmall's avatar
csmall committed
92

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
static int ns_flags = 0x3f;
static int parse_namespaces(char *optarg)
{
	char *ptr = optarg, *tmp;
	int len, id;

	ns_flags = 0;
	while (1) {
		if (strchr(ptr, ',') == NULL) {
			len = -1;
			tmp = strdup(ptr);
		} else {
			len = strchr(ptr, ',') - ptr;
			tmp = strndup(ptr, len);
		}

		id = get_ns_id(tmp);
		if (id == -1) {
			fprintf(stderr, "%s is not a valid namespace\n", tmp);
			free(tmp);
			return 1;
		}
		ns_flags |= (1 << id);
		ENLIST(namespace, tmp);

		if (len == -1)
			break;

		ptr+= len + 1;
	}
	return 0;
}

Sami Kerola's avatar
Sami Kerola committed
126
/* kill or nice a process */
127 128
static void hurt_proc(int tty, int uid, int pid, const char *restrict const cmd,
		      struct run_time_conf_t *run_time)
Sami Kerola's avatar
Sami Kerola committed
129 130 131 132
{
	int failed;
	char dn_buf[1000];
	dev_to_tty(dn_buf, 999, tty, pid, ABBREV_DEV);
133
	if (run_time->interactive) {
134
		char *buf = NULL;
135
		size_t len = 0;
Sami Kerola's avatar
Sami Kerola committed
136
		fprintf(stderr, "%-8s %-8s %5d %-16.16s   ? ",
137
			(char *)dn_buf, pwcache_get_user(uid), pid, cmd);
138
		fflush (stdout);
139 140
		if (getline(&buf, &len, stdin) == -1) {
			free(buf);
141
			return;
142
		}
143 144
		if (rpmatch(buf) < 1) {
			free(buf);
Sami Kerola's avatar
Sami Kerola committed
145
			return;
146 147
		}
		free(buf);
Sami Kerola's avatar
Sami Kerola committed
148 149
	}
	/* do the actual work */
150
	errno = 0;
Sami Kerola's avatar
Sami Kerola committed
151 152 153 154
	if (program == PROG_SKILL)
		failed = kill(pid, sig_or_pri);
	else
		failed = setpriority(PRIO_PROCESS, pid, sig_or_pri);
155
	if ((run_time->warnings && failed) || run_time->debugging || run_time->verbose) {
Sami Kerola's avatar
Sami Kerola committed
156
		fprintf(stderr, "%-8s %-8s %5d %-16.16s   ",
157
			(char *)dn_buf, pwcache_get_user(uid), pid, cmd);
Sami Kerola's avatar
Sami Kerola committed
158 159 160
		perror("");
		return;
	}
161
	if (run_time->interactive)
Sami Kerola's avatar
Sami Kerola committed
162
		return;
163
	if (run_time->noaction) {
Sami Kerola's avatar
Sami Kerola committed
164 165 166
		printf("%d\n", pid);
		return;
	}
167
}
csmall's avatar
csmall committed
168

Sami Kerola's avatar
Sami Kerola committed
169
/* check one process */
170
static void check_proc(int pid, struct run_time_conf_t *run_time)
Sami Kerola's avatar
Sami Kerola committed
171 172 173
{
	char buf[128];
	struct stat statbuf;
174
	proc_t task;
Sami Kerola's avatar
Sami Kerola committed
175 176 177 178
	char *tmp;
	int tty;
	int fd;
	int i;
179
	ssize_t len;
180
	if (pid == my_pid || pid == 0)
Sami Kerola's avatar
Sami Kerola committed
181 182 183 184 185 186
		return;
	/* pid (cmd) state ppid pgrp session tty */
	sprintf(buf, "/proc/%d/stat", pid);
	fd = open(buf, O_RDONLY);
	if (fd == -1) {
		/* process exited maybe */
187
		if (run_time->warnings)
Mike Frysinger's avatar
Mike Frysinger committed
188
			xwarn(_("cannot open file %s"), buf);
Sami Kerola's avatar
Sami Kerola committed
189 190
		return;
	}
191 192
	if (fstat(fd, &statbuf) != 0)
		goto closure;
Sami Kerola's avatar
Sami Kerola committed
193 194 195 196 197 198 199 200 201
	if (uids) {
		/* check the EUID */
		i = uid_count;
		while (i--)
			if (uids[i] == statbuf.st_uid)
				break;
		if (i == -1)
			goto closure;
	}
202 203 204 205
	len = read(fd, buf, sizeof(buf));
	if (len <= 0 || (size_t)len >= sizeof(buf))
		goto closure;
	buf[len] = '\0';
Sami Kerola's avatar
Sami Kerola committed
206
	tmp = strrchr(buf, ')');
207 208
	if (!tmp)
		goto closure;
Sami Kerola's avatar
Sami Kerola committed
209 210 211
	*tmp++ = '\0';
	i = 5;
	while (i--)
212 213 214 215 216
		do {
			if (!*tmp)
				goto closure;
			/* scan to find tty */
		} while (*tmp++ != ' ');
Sami Kerola's avatar
Sami Kerola committed
217 218 219 220 221 222 223 224 225
	tty = atoi(tmp);
	if (ttys) {
		i = tty_count;
		while (i--)
			if (ttys[i] == tty)
				break;
		if (i == -1)
			goto closure;
	}
226 227 228 229
	tmp = strchr(buf, '(');
	if (!tmp)
		goto closure;
	tmp++;
Sami Kerola's avatar
Sami Kerola committed
230 231 232 233 234 235 236 237 238
	if (cmds) {
		i = cmd_count;
		/* fast comparison trick -- useful? */
		while (i--)
			if (cmds[i][0] == *tmp && !strcmp(cmds[i], tmp))
				break;
		if (i == -1)
			goto closure;
	}
239 240 241 242 243 244 245 246 247 248
	if (ns_pid) {
		if (ns_read(pid, &task))
			goto closure;
		for (i = 0; i < NUM_NS; i++) {
			if (ns_flags & (1 << i)) {
				if (task.ns[i] != ns_task.ns[i])
					goto closure;
			}
		}
	}
Sami Kerola's avatar
Sami Kerola committed
249 250 251 252 253
	/* This is where we kill/nice something. */
	/* for debugging purposes?
	fprintf(stderr, "PID %d, UID %d, TTY %d,%d, COMM %s\n",
		pid, statbuf.st_uid, tty >> 8, tty & 0xf, tmp);
	*/
254
	hurt_proc(tty, statbuf.st_uid, pid, tmp, run_time);
Sami Kerola's avatar
Sami Kerola committed
255 256 257
 closure:
	/* kill/nice _first_ to avoid PID reuse */
	close(fd);
csmall's avatar
csmall committed
258 259
}

Sami Kerola's avatar
Sami Kerola committed
260 261 262 263
/* debug function */
static void show_lists(void)
{
	int i;
csmall's avatar
csmall committed
264

265
	fprintf(stderr, "signal: %d\n", sig_or_pri);
266

267
	fprintf(stderr, "%d TTY: ", tty_count);
Sami Kerola's avatar
Sami Kerola committed
268 269 270 271 272 273 274 275
	if (ttys) {
		i = tty_count;
		while (i--) {
			fprintf(stderr, "%d,%d%c", (ttys[i] >> 8) & 0xff,
				ttys[i] & 0xff, i ? ' ' : '\n');
		}
	} else
		fprintf(stderr, "\n");
csmall's avatar
csmall committed
276

277
	fprintf(stderr, "%d UID: ", uid_count);
Sami Kerola's avatar
Sami Kerola committed
278 279 280 281 282 283
	if (uids) {
		i = uid_count;
		while (i--)
			fprintf(stderr, "%d%c", uids[i], i ? ' ' : '\n');
	} else
		fprintf(stderr, "\n");
csmall's avatar
csmall committed
284

285
	fprintf(stderr, "%d PID: ", pid_count);
Sami Kerola's avatar
Sami Kerola committed
286 287 288 289 290 291
	if (pids) {
		i = pid_count;
		while (i--)
			fprintf(stderr, "%d%c", pids[i], i ? ' ' : '\n');
	} else
		fprintf(stderr, "\n");
csmall's avatar
csmall committed
292

293
	fprintf(stderr, "%d CMD: ", cmd_count);
Sami Kerola's avatar
Sami Kerola committed
294 295 296 297 298 299
	if (cmds) {
		i = cmd_count;
		while (i--)
			fprintf(stderr, "%s%c", cmds[i], i ? ' ' : '\n');
	} else
		fprintf(stderr, "\n");
csmall's avatar
csmall committed
300 301
}

Sami Kerola's avatar
Sami Kerola committed
302
/* iterate over all PIDs */
303
static void iterate(struct run_time_conf_t *run_time)
Sami Kerola's avatar
Sami Kerola committed
304 305 306 307 308 309 310
{
	int pid;
	DIR *d;
	struct dirent *de;
	if (pids) {
		pid = pid_count;
		while (pid--)
311
			check_proc(pids[pid], run_time);
Sami Kerola's avatar
Sami Kerola committed
312 313
		return;
	}
csmall's avatar
csmall committed
314
#if 0
Sami Kerola's avatar
Sami Kerola committed
315
	/* could setuid() and kill -1 to have the kernel wipe out a user */
316
	if (!ttys && !cmds && !pids && !run_time->interactive) {
Sami Kerola's avatar
Sami Kerola committed
317
	}
csmall's avatar
csmall committed
318
#endif
Sami Kerola's avatar
Sami Kerola committed
319
	d = opendir("/proc");
320
	if (!d)
321
		xerr(EXIT_FAILURE, "/proc");
Sami Kerola's avatar
Sami Kerola committed
322 323 324 325 326 327 328
	while ((de = readdir(d))) {
		if (de->d_name[0] > '9')
			continue;
		if (de->d_name[0] < '1')
			continue;
		pid = atoi(de->d_name);
		if (pid)
329
			check_proc(pid, run_time);
Sami Kerola's avatar
Sami Kerola committed
330 331
	}
	closedir(d);
csmall's avatar
csmall committed
332 333
}

Sami Kerola's avatar
Sami Kerola committed
334
/* kill help */
335
static void __attribute__ ((__noreturn__)) kill_usage(FILE * out)
Sami Kerola's avatar
Sami Kerola committed
336
{
337 338
	fputs(USAGE_HEADER, out);
	fprintf(out,
339
              _(" %s [options] <pid> [...]\n"), program_invocation_short_name);
340
	fputs(USAGE_OPTIONS, out);
341 342 343 344 345
	fputs(_(" <pid> [...]            send signal to every <pid> listed\n"), out);
	fputs(_(" -<signal>, -s, --signal <signal>\n"
		"                        specify the <signal> to be sent\n"), out);
	fputs(_(" -l, --list=[<signal>]  list all signal names, or convert one to a name\n"), out);
	fputs(_(" -L, --table            list all signal names in a nice table\n"), out);
346
	fputs(USAGE_SEPARATOR, out);
347 348 349
	fputs(USAGE_HELP, out);
	fputs(USAGE_VERSION, out);
	fprintf(out, USAGE_MAN_TAIL("kill(1)"));
350
	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
csmall's avatar
csmall committed
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 362
			program_invocation_short_name);
	} else {
363
		fprintf(out,
364
			_(" %s [new priority] [options] <expression>\n"),
365 366
			program_invocation_short_name);
	}
367
	fputs(USAGE_OPTIONS, out);
368 369 370 371
	fputs(_(" -f, --fast         fast mode (not implemented)\n"), out);
	fputs(_(" -i, --interactive  interactive\n"), out);
	fputs(_(" -l, --list         list all signal names\n"), out);
	fputs(_(" -L, --table        list all signal names in a nice table\n"), out);
Craig Small's avatar
Craig Small committed
372
	fputs(_(" -n, --no-action    do not actually kill processes; just print what would happen\n"), out);
373 374
	fputs(_(" -v, --verbose      explain what is being done\n"), out);
	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 378 379 380 381
		"The options below may be used to ensure correct interpretation.\n"), out);
	fputs(_(" -c, --command <command>  expression is a command name\n"), out);
	fputs(_(" -p, --pid <pid>          expression is a process id number\n"), out);
	fputs(_(" -t, --tty <tty>          expression is a terminal\n"), out);
	fputs(_(" -u, --user <username>    expression is a username\n"), out);
382
	fputs(USAGE_SEPARATOR, out);
383 384 385 386
	fputs(_("Alternatively, expression can be:\n"), out);
	fputs(_(" --ns <pid>               match the processes that belong to the same\n"
		"                          namespace as <pid>\n"), out);
	fputs(_(" --nslist <ns,...>        list which namespaces will be considered for\n"
Craig Small's avatar
Craig Small committed
387 388
		"                          the --ns option; available namespaces are\n:"
	        "                          ipc, mnt, net, pid, user, uts\n"), out);
389 390 391

	fputs(USAGE_SEPARATOR, out);
	fputs(USAGE_SEPARATOR, out);
392 393
	fputs(USAGE_HELP, out);
	fputs(USAGE_VERSION, out);
394
	if (program == PROG_SKILL) {
395
		fprintf(out,
396 397 398 399
			_("\n"
			  "The default signal is TERM. Use -l or -L to list available signals.\n"
			  "Particularly useful signals include HUP, INT, KILL, STOP, CONT, and 0.\n"
			  "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 404 405 406
			_("\n"
			  "The default priority is +4. (snice +4 ...)\n"
			  "Priority numbers range from +20 (slowest) to -20 (fastest).\n"
			  "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 418 419
		if (argv[i][0] == '-') {
			signo = signal_name_to_number(argv[i] + 1);
			if (-1 < signo) {
420 421 422
				memmove(argv + i, argv + i + 1,
					sizeof(char *) * (*argc - i));
				(*argc)--;
423 424 425 426 427 428 429
				return signo;
			}
		}
	}
	return signo;
}

Sami Kerola's avatar
Sami Kerola committed
430
/* kill */
431
static void __attribute__ ((__noreturn__))
432
    kill_main(int argc, char **argv)
Sami Kerola's avatar
Sami Kerola committed
433
{
Sami Kerola's avatar
Sami Kerola committed
434 435 436
	int signo, i;
	long pid;
	int exitvalue = EXIT_SUCCESS;
437
    char *sig_option;
Sami Kerola's avatar
Sami Kerola committed
438 439 440 441 442 443 444 445 446 447

	static const struct option longopts[] = {
		{"list", optional_argument, NULL, 'l'},
		{"table", no_argument, NULL, 'L'},
		{"signal", required_argument, NULL, 's'},
		{"help", no_argument, NULL, 'h'},
		{"version", no_argument, NULL, 'V'},
		{NULL, 0, NULL, 0}
	};

448 449 450
	setlocale (LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	textdomain(PACKAGE);
451
	atexit(close_stdout);
452

Sami Kerola's avatar
Sami Kerola committed
453
	if (argc < 2)
454
		kill_usage(stderr);
csmall's avatar
csmall committed
455

Sami Kerola's avatar
Sami Kerola committed
456 457 458
	signo = skill_sig_option(&argc, argv);
	if (signo < 0)
		signo = SIGTERM;
csmall's avatar
csmall committed
459

Craig Small's avatar
Craig Small committed
460
	opterr=0; /* suppress errors on -123 */
461
	while ((i = getopt_long(argc, argv, "l::Ls:hV", longopts, NULL)) != -1)
Sami Kerola's avatar
Sami Kerola committed
462 463
		switch (i) {
		case 'l':
464 465 466
            sig_option = NULL;
            if (optarg) {
                sig_option = optarg;
467 468
            } else if (argv[optind] != NULL && argv[optind][0] != '-') {
                sig_option = argv[optind];
469 470
            }
			if (sig_option) {
471
				char *s;
472
				s = strtosig(sig_option);
473 474 475
				if (s)
					printf("%s\n", s);
				else
476
					xwarnx(_("unknown signal name %s"),
477
					      sig_option);
478
				free(s);
Sami Kerola's avatar
Sami Kerola committed
479 480 481 482 483
			} else {
				unix_print_signals();
			}
			exit(EXIT_SUCCESS);
		case 'L':
Sami Kerola's avatar
Sami Kerola committed
484
			pretty_print_signals();
Sami Kerola's avatar
Sami Kerola committed
485 486 487 488 489
			exit(EXIT_SUCCESS);
		case 's':
			signo = signal_name_to_number(optarg);
			break;
		case 'h':
490
			kill_usage(stdout);
Sami Kerola's avatar
Sami Kerola committed
491 492 493
		case 'V':
			display_kill_version();
			exit(EXIT_SUCCESS);
Craig Small's avatar
Craig Small committed
494 495 496 497
		case '?':
			if (!isdigit(optopt)) {
				xwarnx(_("invalid argument %c"), optopt);
				kill_usage(stderr);
Craig Small's avatar
Craig Small committed
498 499 500
			} else {
			    /* Special case for signal digit negative
			     * PIDs */
501
			    pid = atoi(argv[optind]);
Craig Small's avatar
Craig Small committed
502 503 504
			    if (kill((pid_t)pid, signo) != 0)
				exitvalue = EXIT_FAILURE;
			    exit(exitvalue);
Craig Small's avatar
Craig Small committed
505
			}
506
			xerrx(EXIT_FAILURE, _("internal error"));
Sami Kerola's avatar
Sami Kerola committed
507
		default:
508
			kill_usage(stderr);
Sami Kerola's avatar
Sami Kerola committed
509
		}
Sami Kerola's avatar
Sami Kerola committed
510

511
	argc -= optind;
Sami Kerola's avatar
Sami Kerola committed
512 513
	argv += optind;

514 515 516
	if (argc < 1)
		kill_usage(stderr);

Sami Kerola's avatar
Sami Kerola committed
517 518 519
	for (i = 0; i < argc; i++) {
		pid = strtol_or_err(argv[i], _("failed to parse argument"));
		if (!kill((pid_t) pid, signo))
Sami Kerola's avatar
Sami Kerola committed
520
			continue;
Craig Small's avatar
Craig Small committed
521
        error(0, errno, "(%ld)", pid);
Sami Kerola's avatar
Sami Kerola committed
522 523
		exitvalue = EXIT_FAILURE;
		continue;
Sami Kerola's avatar
Sami Kerola committed
524
	}
Sami Kerola's avatar
Sami Kerola committed
525

Sami Kerola's avatar
Sami Kerola committed
526
	exit(exitvalue);
csmall's avatar
csmall committed
527
}
Sami Kerola's avatar
Sami Kerola committed
528

csmall's avatar
csmall committed
529
#if 0
Sami Kerola's avatar
Sami Kerola committed
530 531
static void _skillsnice_usage(int line)
{
532
	fprintf(stderr, _("something at line %d\n"), line);
533
	skillsnice_usage(stderr);
csmall's avatar
csmall committed
534
}
Sami Kerola's avatar
Sami Kerola committed
535

csmall's avatar
csmall committed
536 537 538
#define skillsnice_usage() _skillsnice_usage(__LINE__)
#endif

Sami Kerola's avatar
Sami Kerola committed
539
/* common skill/snice argument parsing code */
540

541
static int snice_prio_option(int *argc, char **argv)
542 543 544 545 546 547 548 549 550 551
{
	int i = 1, nargs = *argc;
	long prio = DEFAULT_NICE;

	while (i < nargs) {
		if ((argv[i][0] == '-' || argv[i][0] == '+')
		    && isdigit(argv[i][1])) {
			prio = strtol_or_err(argv[i],
					     _("failed to parse argument"));
			if (prio < INT_MIN || INT_MAX < prio)
552
				xerrx(EXIT_FAILURE,
553
				     _("priority %lu out of range"), prio);
554 555
			memmove(argv + i, argv + i + 1,
				sizeof(char *) * (nargs - i));
556 557 558 559 560 561 562 563
			nargs--;
		} else
			i++;
	}
	*argc = nargs;
	return (int)prio;
}

Sami Kerola's avatar
Sami Kerola committed
564
static void skillsnice_parse(int argc,
565
			     char **argv, struct run_time_conf_t *run_time)
Sami Kerola's avatar
Sami Kerola committed
566 567
{
	int signo = -1;
568 569 570
	int prino = DEFAULT_NICE;
	int ch, i;

571 572 573 574 575
	enum {
		NS_OPTION = CHAR_MAX + 1,
		NSLIST_OPTION,
	};

576 577 578 579 580 581 582 583 584 585 586
	static const struct option longopts[] = {
		{"command", required_argument, NULL, 'c'},
		{"debug", no_argument, NULL, 'd'},
		{"fast", no_argument, NULL, 'f'},
		{"interactive", no_argument, NULL, 'i'},
		{"list", no_argument, NULL, 'l'},
		{"no-action", no_argument, NULL, 'n'},
		{"pid", required_argument, NULL, 'p'},
		{"table", no_argument, NULL, 'L'},
		{"tty", required_argument, NULL, 't'},
		{"user", required_argument, NULL, 'u'},
587 588
		{"ns", required_argument, NULL, NS_OPTION},
		{"nslist", required_argument, NULL, NSLIST_OPTION},
589 590 591 592 593 594 595
		{"verbose", no_argument, NULL, 'v'},
		{"warnings", no_argument, NULL, 'w'},
		{"help", no_argument, NULL, 'h'},
		{"version", no_argument, NULL, 'V'},
		{NULL, 0, NULL, 0}
	};

Sami Kerola's avatar
Sami Kerola committed
596
	if (argc < 2)
597
		skillsnice_usage(stderr);
598

599 600
	sig_or_pri = -1;

601 602
	if (program == PROG_SNICE)
		prino = snice_prio_option(&argc, argv);
603
	else if (program == PROG_SKILL) {
604
		signo = skill_sig_option(&argc, argv);
605
		if (-1 < signo)
606 607
			sig_or_pri = signo;
	}
608

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
	while ((ch =
		getopt_long(argc, argv, "c:dfilnp:Lt:u:vwhV", longopts,
			    NULL)) != -1)
		switch (ch) {
		case 'c':
			ENLIST(cmd, optarg);
			break;
		case 'd':
			run_time->debugging = 1;
			break;
		case 'f':
			run_time->fast = 1;
			break;
		case 'i':
			run_time->interactive = 1;
			break;
		case 'l':
Sami Kerola's avatar
Sami Kerola committed
626
			unix_print_signals();
627 628 629 630 631 632 633 634 635 636 637 638
			exit(EXIT_SUCCESS);
		case 'n':
			run_time->noaction = 1;
			break;
		case 'p':
			ENLIST(pid,
			       strtol_or_err(optarg,
					     _("failed to parse argument")));
			break;
		case 'L':
			pretty_print_signals();
			exit(EXIT_SUCCESS);
Sami Kerola's avatar
Sami Kerola committed
639
		case 't':
640
			{
Sami Kerola's avatar
Sami Kerola committed
641 642
				struct stat sbuf;
				char path[32];
643
				snprintf(path, 32, "/dev/%s", optarg);
Sami Kerola's avatar
Sami Kerola committed
644 645 646 647 648
				if (stat(path, &sbuf) >= 0
				    && S_ISCHR(sbuf.st_mode)) {
					ENLIST(tty, sbuf.st_rdev);
				}
			}
649
			break;
Sami Kerola's avatar
Sami Kerola committed
650
		case 'u':
651
			{
Sami Kerola's avatar
Sami Kerola committed
652
				struct passwd *passwd_data;
653
				passwd_data = getpwnam(optarg);
Sami Kerola's avatar
Sami Kerola committed
654 655 656 657
				if (passwd_data) {
					ENLIST(uid, passwd_data->pw_uid);
				}
			}
658
			break;
659 660 661
		case NS_OPTION:
			ns_pid = atoi(optarg);
			if (ns_pid == 0) {
662
				xwarnx(_("invalid pid number %s"), optarg);
663 664 665 666 667 668
				kill_usage(stderr);
			}
			if (ns_read(ns_pid, &ns_task)) {
				xwarnx(_("error reading reference namespace "
					 "information"));
				kill_usage(stderr);
669
			}
670 671 672 673 674 675 676 677

			break;
		case NSLIST_OPTION:
			if (parse_namespaces(optarg)) {
				xwarnx(_("invalid namespace list"));
				kill_usage(stderr);
			}
			break;
678 679 680 681 682 683 684
		case 'v':
			run_time->verbose = 1;
			break;
		case 'w':
			run_time->warnings = 1;
			break;
		case 'h':
685
			skillsnice_usage(stdout);
686 687 688 689
		case 'V':
			display_kill_version();
			exit(EXIT_SUCCESS);
		default:
690
			skillsnice_usage(stderr);
691 692 693 694 695 696
		}

	argc -= optind;
	argv += optind;

	for (i = 0; i < argc; i++) {
697 698 699 700 701 702 703 704 705
		long num;
		char *end = NULL;
		errno = 0;
		num = strtol(argv[0], &end, 10);
		if (errno == 0 && argv[0] != end && end != NULL && *end == '\0') {
			ENLIST(pid, num);
		} else {
			ENLIST(cmd, argv[0]);
		}
706
		argv++;
Sami Kerola's avatar
Sami Kerola committed
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 713
	if ((run_time->fast | run_time->interactive | run_time->
	     verbose | run_time->warnings | run_time->noaction) & ~1)
714
		xerrx(EXIT_FAILURE, _("general flags may not be repeated"));
715 716
	if (run_time->interactive
	    && (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) {
Sami Kerola's avatar
Sami Kerola committed
721 722
		program = PROG_SKILL;
		/* harmless */
723
		sig_or_pri = 0;
Sami Kerola's avatar
Sami Kerola committed
724
	}
725
	if (program == PROG_SNICE)
Sami Kerola's avatar
Sami Kerola committed
726
		sig_or_pri = prino;
727 728
	else if (sig_or_pri < 0)
		sig_or_pri = SIGTERM;
csmall's avatar
csmall committed
729 730
}

Sami Kerola's avatar
Sami Kerola committed
731
/* main body */
732
int main(int argc, char ** argv)
Sami Kerola's avatar
Sami Kerola committed
733
{
734 735 736
#ifdef HAVE_PROGRAM_INVOCATION_NAME
	program_invocation_name = program_invocation_short_name;
#endif
737 738
	struct run_time_conf_t run_time;
	memset(&run_time, 0, sizeof(struct run_time_conf_t));
Sami Kerola's avatar
Sami Kerola committed
739
	my_pid = getpid();
740 741 742

	if (strcmp(program_invocation_short_name, "kill") == 0 ||
	    strcmp(program_invocation_short_name, "lt-kill") == 0)
Sami Kerola's avatar
Sami Kerola committed
743
		program = PROG_KILL;
744 745
	else if (strcmp(program_invocation_short_name, "skill") == 0 ||
		 strcmp(program_invocation_short_name, "lt-skill") == 0)
Sami Kerola's avatar
Sami Kerola committed
746
		program = PROG_SKILL;
747 748
	else if (strcmp(program_invocation_short_name, "snice") == 0 ||
		 strcmp(program_invocation_short_name, "lt-snice") == 0)
Sami Kerola's avatar
Sami Kerola committed
749
		program = PROG_SNICE;
750 751 752 753 754
#ifdef __CYGWIN__
	else if (strcmp(program_invocation_short_name, "prockill") == 0 ||
		 strcmp(program_invocation_short_name, "lt-prockill") == 0)
		program = PROG_KILL;
#endif
755

Sami Kerola's avatar
Sami Kerola committed
756 757 758 759
	switch (program) {
	case PROG_SNICE:
	case PROG_SKILL:
		setpriority(PRIO_PROCESS, my_pid, -20);
760 761 762 763
		skillsnice_parse(argc, argv, &run_time);
		if (run_time.debugging)
			show_lists();
		iterate(&run_time);
Sami Kerola's avatar
Sami Kerola committed
764 765
		break;
	case PROG_KILL:
766
		kill_main(argc, argv);
Sami Kerola's avatar
Sami Kerola committed
767 768
		break;
	default:
Yuri Chornoivan's avatar
Yuri Chornoivan committed
769
		fprintf(stderr, _("skill: \"%s\" is not supported\n"),
770 771
			program_invocation_short_name);
		fprintf(stderr, USAGE_MAN_TAIL("skill(1)"));
772
		return EXIT_FAILURE;
Sami Kerola's avatar
Sami Kerola committed
773
	}
774
	return EXIT_SUCCESS;
csmall's avatar
csmall committed
775
}