/* killall.c  -  kill processes by name. Written by Werner Almesberger */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/sched.h>
#include "signals.h"


#define COMM_LEN  sizeof(dummy.comm)
#define PROC_BASE "/proc"


static struct task_struct dummy;
static int verbose = 0,interactive = 0;


static int ask(char *name,pid_t pid)
{
    int ch,c;

    do {
        printf("Kill %s(%d) ? (y/n) ",name,pid);
        fflush(stdout);
	do if ((ch = getchar()) == EOF) exit(0);
	while (ch == '\n' || ch == '\t' || ch == ' ');
	do if ((c = getchar()) == EOF) exit(0);
	while (c != '\n');
    }
    while (ch != 'y' && ch != 'n' && ch != 'Y' && ch != 'N');
    return ch == 'y' || ch == 'Y';
}


static int kill_all(int signal,int names,char **namelist)
{
    DIR *dir;
    struct dirent *de;
    FILE *file;
    char path[PATH_MAX+1],comm[COMM_LEN+1];
    pid_t pid;
    int dummy,i;
    long found;

    found = 0;
    if (!(dir = opendir(PROC_BASE))) {
	perror(PROC_BASE);
	exit(1);
    }
    while (de = readdir(dir))
	if (pid = atoi(de->d_name)) {
	    sprintf(path,"%s/%d/stat",PROC_BASE,pid);
	    if (file = fopen(path,"r")) {
		if (fscanf(file,"%d (%[^)]",&dummy,comm) == 2)
		    for (i = 0; i < names; i++)
			if (!strcmp(namelist[i],comm) && (!interactive ||
			  ask(comm,pid)))
			    if (kill(pid,signal) >= 0) {
				if (verbose)
				    fprintf(stderr,"Killed %s(%d)\n",comm,pid);
				found |= 1 << i;
			    }
			    else if (errno != ESRCH || interactive)
				    fprintf(stderr,"%s(%d): %s\n",comm,pid,
				      strerror(errno));
		(void) fclose(file);
	    }
	}
    (void) closedir(dir);
    for (i = 0; i < names; i++)
	if (!(found & (1 << i)))
	    fprintf(stderr,"%s: no process killed\n",namelist[i]);
    return found == ((1 << (names-1)) | ((1 << (names-1))-1)) ? 0 : 1;
}


static void usage(void)
{
    fprintf(stderr,"usage: killall [ -iv ] [ -signal ] name ...\n");
    fprintf(stderr,"       killall -l\n");
    exit(1);
}


int main(int argc,char **argv)
{
    int sig_num;

    if (argc == 2 && !strcmp(argv[1],"-l")) {
	list_signals();
	return 0;
    }
    sig_num = SIGTERM;
    while (argc > 1 && *argv[1] == '-') {
	argc--;
	argv++;
	    if (!strcmp(*argv,"-v")) verbose = 1;
	else if (!strcmp(*argv,"-i")) interactive = 1;
	else if (!strcmp(*argv,"-vi") || !strcmp(*argv,"-iv"))
		verbose = interactive = 1;
	else sig_num = get_signal(*argv+1,"killall");
    }
    if (argc < 2) usage();
    if (argc > sizeof(long)*8+1) {
	fprintf(stderr,"Maximum number of names is %d\n",sizeof(long)*8);
	exit(1);
    }
    return kill_all(sig_num,argc-1,argv+1);
}
