vkill

Verbose & interactive pkill alternative
git clone https://git.sinitax.com/sinitax/vkill
Log | Files | Refs | LICENSE | sfeed.txt

vkill.c (2421B)


      1#include <linux/limits.h>
      2#include <strings.h>
      3#include <unistd.h>
      4#include <termios.h>
      5#include <dirent.h>
      6#include <wait.h>
      7#include <ctype.h>
      8#include <signal.h>
      9#include <err.h>
     10#include <string.h>
     11#include <stdlib.h>
     12#include <stdio.h>
     13
     14static const char usage[] = "vkill [-h] [-SIG] CMD";
     15static int signum = SIGTERM;
     16
     17const char *
     18strcasestr(const char *haystack, const char *needle)
     19{
     20	size_t needle_len;
     21
     22	needle_len = strlen(needle);
     23	while (*haystack) {
     24		if (!strncasecmp(haystack, needle, needle_len))
     25			return haystack;
     26		haystack++;
     27	}
     28
     29	return NULL;
     30}
     31
     32char *
     33readcmd(pid_t pid)
     34{
     35	char pathbuf[PATH_MAX];
     36	size_t i, cap, size;
     37	FILE *file;
     38	char *cmd;
     39
     40	snprintf(pathbuf, PATH_MAX, "/proc/%u/cmdline", pid);
     41	file = fopen(pathbuf, "r");
     42	if (!file) return NULL;
     43
     44	cap = 4096;
     45	cmd = malloc(cap + 1);
     46	if (!cmd) err(1, "malloc");
     47
     48	if (!(size = fread(cmd, 1, cap, file))) {
     49		free(cmd);
     50		fclose(file);
     51		return NULL;
     52	}
     53
     54	for (i = 0; i < size; i++)
     55		if (!cmd[i]) cmd[i] = ' ';
     56	cmd[size] = '\0';
     57
     58	fclose(file);
     59
     60	return cmd;
     61}
     62
     63void
     64killprompt(pid_t pid)
     65{
     66	struct termios old, new;
     67	char c;
     68
     69	tcgetattr(0, &old);
     70	tcgetattr(0, &new);
     71	new.c_lflag &= ~ECHO;
     72	new.c_lflag &= ~ICANON;
     73	new.c_lflag &= ~ISIG;
     74	tcsetattr(0, TCSANOW, &new);
     75
     76	c = getchar();
     77	if (c == 'y') {
     78		kill(pid, signum);
     79		waitpid(pid, NULL, 0);
     80	}
     81
     82	tcsetattr(0, TCSANOW, &old);
     83
     84	if (c == 3) exit(0);
     85}
     86
     87int
     88main(int argc, const char **argv)
     89{
     90	pid_t pid, cpid;
     91	struct dirent *ent;
     92	const char **arg;
     93	const char *query;
     94	char *end, *cmd;
     95	DIR *dir;
     96	int i;
     97
     98	query = NULL;
     99	for (arg = &argv[1]; *arg; arg++) {
    100		if (!strcmp(*arg, "-h")) {
    101			printf("Usage: %s\n", usage);
    102			return 0;
    103		} else if (**arg == '-') {
    104			signum = strtoul(*arg+1, &end, 10);
    105			if (end && *end) errx(1, "Invalid signum");
    106		} else if (!query) {
    107			query = *arg;
    108		} else {
    109			fprintf(stderr, "Usage: %s\n", usage);
    110			return 1;
    111		}
    112	}
    113
    114	if (!query) {
    115		fprintf(stderr, "Usage: %s\n", usage);
    116		return 1;
    117	}
    118
    119	cpid = getpid();
    120
    121	dir = opendir("/proc");
    122	if (!dir) err(1, "opendir");
    123
    124	while ((ent = readdir(dir))) {
    125		pid = strtoul(ent->d_name, &end, 10);
    126		if (end && *end) continue;
    127		if (pid == cpid) continue;
    128
    129		cmd = readcmd(pid);
    130		for (i = 1; i < argc; i++) {
    131			if (cmd && strcasestr(cmd, argv[i])) {
    132				printf("%u: %s", pid, cmd ? cmd : "???");
    133				killprompt(pid);
    134				printf("\n");
    135				break;
    136			}
    137		}
    138		free(cmd);
    139	}
    140
    141	closedir(dir);
    142}