diff options
Diffstat (limited to 'src/chproc.c')
-rw-r--r-- | src/chproc.c | 322 |
1 files changed, 239 insertions, 83 deletions
diff --git a/src/chproc.c b/src/chproc.c index 46876a5..b4ebee9 100644 --- a/src/chproc.c +++ b/src/chproc.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * chproc.c - simple process checker + * chproc.c - simple process manager * - * Iterate over /proc and print PIDs of processes matching the given name. + * Features: list and kill. */ #include <stdio.h> @@ -20,52 +20,96 @@ #include <stdbool.h> #define PROGRAM_NAME "chproc" +#define PROGRAM_VERSION "0.1" -struct options { - int list; +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define DIR_PROC "/proc" + + +struct flag_options { + int name; int all; int kill; + int help; + int version; +}; + + +struct data_options { char *process_name; char *process_pid; }; -static void options_init(struct options *x) -{ - x->list = false; - x->all = false; - x->kill = false; - x->process_pid = NULL; - x->process_name = NULL; -} +struct options { + struct flag_options flags; + struct data_options data; +}; + + +struct flag_handler { + int *flag; + int id; +}; -static void usage(void) +enum flag_index { + F_NAME, + F_ALL, + F_KILL, + F_HELP, + F_VERSION +}; + + +static int usage(void) { fprintf(stderr, "Usage: %s <option> [process_name, pid]\n" - " -l, --list <name> list all pid for that process\n" + " -n, --name <name> list all pid for that process\n" " -a, --all list all processes\n" - " -k, --kill <PID> kill a proces give then PID\n" + " -k, --kill <PID> kill a process give then PID\n" + " -h, --help show this help\n" + " -v, --version show version\n" , PROGRAM_NAME); + + return 2; } +struct process_info { + pid_t pid; + char name[256]; +}; -static int process_list(DIR *dir, - const char *proc_name, - struct options *x) + +struct process_info *get_process_list(size_t *count) { + DIR *dir; + struct dirent *entry; + struct process_info *list; + size_t capacity; + size_t n; + long pid; char path[PATH_MAX]; + FILE *f; char buffer[256]; char *endptr; - FILE *f; - int count; - long pid; - struct dirent *entry; size_t len; + struct process_info *tmp; + + dir = opendir(DIR_PROC); + + capacity = 128; + n = 0; + list = malloc(capacity * (sizeof(*list))); + + if (!list) { + closedir(dir); + return NULL; + } - count = 0; while ((entry = readdir(dir)) != NULL) { /* skip "." and ".." */ @@ -74,21 +118,17 @@ static int process_list(DIR *dir, if (strcmp(entry->d_name, "..") == 0) continue; - pid = strtol(entry->d_name, &endptr, 10); - if (*endptr != '\0') /* not a pure number */ + /* not a pure number */ + if (*endptr != '\0') continue; snprintf(path, sizeof(path), "/proc/%ld/comm", pid); - f = fopen(path, "r"); - if (!f) { - fprintf(stderr, "Failed to open %s: %s\n", - path, strerror(errno)); + if (!f) continue; - } if (!(fgets(buffer, sizeof(buffer), f))) continue; @@ -98,39 +138,83 @@ static int process_list(DIR *dir, if (len > 0 && buffer[len-1] == '\n') buffer[len-1] = '\0'; - /* flag instead of re-writing a function */ - if (x->list) { - if (strcmp(buffer, proc_name) == 0) { - printf("%s - %s\n", entry->d_name, buffer); - ++count; + list[n].pid = (pid_t)pid; + strncpy(list[n].name, buffer, sizeof(list[n].name)); + list[n].name[sizeof(list[n].name) - 1] = '\0'; + n++; + + /* Resize array if needed */ + if (n >= capacity) { + capacity *= 2; + tmp = realloc(list, capacity * sizeof(*list)); + + if (!tmp) { + free(list); + fclose(f); + closedir(dir); + return NULL; } - } else { - printf("%s - %s\n", entry->d_name, buffer); - ++count; + list = tmp; } + + fclose(f); } closedir(dir); - if (count == 0) - return 1; - else - return 0; + *count = n; + return list; } -static int process_kill(const char *process_id) +static int process_get_all(struct process_info *list, + size_t count) +{ + size_t i; + + for (i = 0; i < count; i++) { + printf("%d - %s\n", + list[i].pid, list[i].name); + } + + return 0; +} + + +static int process_get_name(char *pname, + struct options *x, + struct process_info *list, + size_t count) +{ + char *proc_name; + size_t i; + + proc_name = pname; + + + for (i = 0; i < count; i++) { + if (x->flags.name && strcmp(list[i].name, proc_name) == 0) { + printf("%d - %s\n", list[i].pid, list[i].name); + ++count; + } + } + return 0; +} + + +static int process_get_kill(const char *process_id) { pid_t pid; - if (atoi(process_id) < 1) { + pid = (pid_t) atoi(process_id); + + if (pid < 1) { fprintf(stderr, "'%s': not a pid or valid job\n", process_id); usage(); return 1; } - pid = (pid_t) atoi(process_id); if (kill(pid, SIGTERM) == -1) { perror("kill failed"); @@ -142,66 +226,138 @@ static int process_kill(const char *process_id) } -int main(int argc, char *argv[]) +int proc_check(void) +{ + DIR *dir; + + /* /proc/ must exist */ + dir = opendir(DIR_PROC); + + if (dir == NULL) { + fprintf(stderr, "/proc/ not found.\n"); + return 1; + } + + return 0; +} + + +int parse_args(int argc, char *argv[], + struct options *x) { int opt; - DIR *dir_proc; - struct options x; + memset(x, 0, sizeof(*x)); struct option long_options[] = { - {"list", required_argument, 0, 'l'}, - {"all", no_argument, 0, 'a'}, - {"kill", required_argument, 0, 'k'}, + {"name", required_argument, 0, 'n'}, + {"all", no_argument, 0, 'a'}, + {"kill", required_argument, 0, 'k'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; - options_init(&x); - /* /proc/ must to exist */ - dir_proc = opendir("/proc"); - if (dir_proc == NULL) { - fprintf(stderr, "/proc/ not found.\n"); - return EXIT_FAILURE; + if (argc < 2) + return 2; + + while ((opt = getopt_long(argc, + argv, "n:ak:", + long_options, NULL)) != -1) { + switch (opt) { + case 'n': + x->flags.name = true; + x->data.process_name = optarg; + break; + case 'a': + x->flags.all = true; + break; + case 'k': + x->flags.kill = true; + x->data.process_pid = optarg; + break; + case 'h': + x->flags.help = true; + break; + case 'v': + x->flags.version = true; + break; + default: + return 2; + } } - if (argc < 2) { + return 0; +} + + +int main(int argc, char *argv[]) +{ + struct options x = {0}; + int ret; + size_t count; + struct process_info *procs; + struct flag_handler handlers[] = { + { &x.flags.name, F_NAME }, + { &x.flags.all, F_ALL }, + { &x.flags.kill, F_KILL }, + { &x.flags.help, F_HELP }, + { &x.flags.version, F_VERSION }, + }; + size_t i; + size_t n_flags; + + ret = parse_args(argc, argv, &x); + + if (proc_check() != 0) + return 1; + + if (ret != 0) { usage(); - return 2; + return ret; } - while ((opt = getopt_long(argc, argv, "l:k:a", - long_options, NULL)) != -1) { - switch (opt) { - case 'l': - x.list = true; - x.process_name = optarg; + procs = get_process_list(&count); + + if (!procs) { + fprintf(stderr, "Failed to read process list\n"); + return 1; + } + + + n_flags = ARRAY_SIZE(handlers); + + for (i = 0; i < n_flags; i++) { + if (*(handlers[i].flag)) { + switch (handlers[i].id) { + case F_NAME: + if (process_get_name(x.data.process_name, + &x, procs, count) == 1) + return 1; break; - case 'a': - x.all = true; + case F_ALL: + if (process_get_all(procs, count) == 1) + return 1; break; - case 'k': - x.kill = true; - x.process_pid = optarg; + case F_KILL: + if (process_get_kill(x.data.process_pid) == 1) + return 1; break; - default: - fprintf(stderr, - "Unknow option.\n"); - usage(); - exit(2); + case F_HELP: + usage(); + return 2; + case F_VERSION: + printf("%s: %s\n", PROGRAM_NAME, + PROGRAM_VERSION); + return 0; + } } } - if (x.list || x.all) - if (process_list(dir_proc, x.process_name, &x) == 1) - return 1; - if (x.kill) - if (process_kill(x.process_pid) == 1) - return 1; + free(procs); return 0; } - - |