summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--src/chproc.c322
2 files changed, 255 insertions, 83 deletions
diff --git a/Makefile b/Makefile
index af3c7f7..23a3caa 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,10 @@ CFLAGS = -Wall -O2
SRC_DIR = src
BIN_DIR = bin
+# Installation directory
+PREFIX ?= /usr/local
+BINDIR ?= $(PREFIX)/bin
+
# Source and target names
TARGET = chproc
SRC = $(SRC_DIR)/$(TARGET).c
@@ -57,6 +61,18 @@ define run_test
fi
endef
+# Install
+install: $(BIN)
+ @echo "Installing $(TARGET) to $(BINDIR)"
+ mkdir -p $(BINDIR)
+ cp -v $(BIN) $(BINDIR)/
+
+# Uninstall
+uninstall:
+ @echo "Removing $(TARGET) from $(BINDIR)"
+ rm -v -f $(BINDIR)/$(TARGET)
+
+# Test
test: $(BIN)
$(call run_test,$(TARGET),no args)
$(call run_test,$(TARGET),$(ARG))
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;
}
-
-