vkill

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

vkill.c (2432B)


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