diff options
author | pankunull <panku_null@proton.me> | 2025-08-30 14:00:35 +0200 |
---|---|---|
committer | pankunull <panku_null@proton.me> | 2025-08-30 14:00:35 +0200 |
commit | 669fcb0b6be1085064267e817764fbb4f578a675 (patch) | |
tree | 5443ab2b332c1785ad0a6f2cfe3129e5dea58194 |
Added files.
-rw-r--r-- | Makefile | 58 | ||||
-rwxr-xr-x | Makefile.clang | 1 | ||||
-rw-r--r-- | chproc.c | 192 |
3 files changed, 251 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4dcc90a --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +# Compiler and flags +CC = gcc +CFLAGS = -Wall -O2 + +# Source and target names +TARGET = chproc +SRC = $(TARGET).c +PRE = $(TARGET).i +ASM = $(TARGET).s +OBJ = $(TARGET).o + +# Example argument for test +ARG = --list init + +# Default: build executable +all: $(TARGET) + +# Stage 1: Preprocess +$(PRE): $(SRC) + $(CC) -E $(CFLAGS) $< -o $@ + +# Stage 2: Compile to assembly +$(ASM): $(PRE) + $(CC) -S $(CFLAGS) $< -o $@ + +# Stage 3: Assemble to object file +$(OBJ): $(ASM) + $(CC) -c $(CFLAGS) $< -o $@ + +# Stage 4: Link object to executable +$(TARGET): $(OBJ) + $(CC) $(CFLAGS) $< -o $@ + +# Run tests +define run_test + @name="$(1) $(2)"; \ + width=40; \ + printf "%s" "$$name"; \ + dots=$$((width - $${#name})); \ + for i in $$(seq 1 $$dots); do printf "."; done; \ + ./$(TARGET) $(2) >/dev/null 2>&1; \ + ec=$$?; \ + if [ $$ec -eq 0 ] || [ $$ec -eq 2 ]; then \ + echo " OK"; \ + else \ + echo " FAILED (exit $$ec)"; \ + exit 1; \ + fi +endef + +test: $(TARGET) + $(call run_test,$(TARGET) no args,) + $(call run_test,$(TARGET),$(ARG),) + +# Clean all generated files +clean: + rm -v -f $(PRE) $(ASM) $(OBJ) $(TARGET) + diff --git a/Makefile.clang b/Makefile.clang new file mode 100755 index 0000000..e275c31 --- /dev/null +++ b/Makefile.clang @@ -0,0 +1 @@ +clang -Weverything -o chproc_clang chproc.c diff --git a/chproc.c b/chproc.c new file mode 100644 index 0000000..6d407fb --- /dev/null +++ b/chproc.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * chproc.c - simple process checker + * + * Iterate over /proc and print PIDs of processes matching the given name. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <ctype.h> +#include <sys/stat.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <getopt.h> +#include <signal.h> +#include <stdbool.h> + +#define PROGRAM_NAME "chproc" + +struct options { + int list; + int kill; + char *process_name; + char *process_pid; +}; + + +static void options_init(struct options *x) +{ + x->list = false; + x->kill = false; + x->process_pid = NULL; + x->process_name = NULL; +} + + +static void usage(void) +{ + fprintf(stderr, + "Usage: %s <option> [process_name, pid]\n" + " -l, --list <name> list all PID of that process\n" + " -k, --kill <PID> kill a proces give then PID\n" + , PROGRAM_NAME); +} + + + +static int process_list(DIR *dir, + const char *proc_name) +{ + char path[PATH_MAX]; + char buffer[256]; + char *endptr; + FILE *f; + int count; + long pid; + struct dirent *entry; + size_t len; + + count = 0; + + while ((entry = readdir(dir)) != NULL) { + /* skip "." and ".." */ + if (strcmp(entry->d_name, ".") == 0) + continue; + if (strcmp(entry->d_name, "..") == 0) + continue; + + + pid = strtol(entry->d_name, &endptr, 10); + + if (*endptr != '\0') /* not a pure number */ + 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)); + continue; + } + + if (fgets(buffer, sizeof(buffer), f)) { + len = strlen(buffer); + + if (len > 0 && buffer[len-1] == '\n') + buffer[len-1] = '\0'; + + if (strcmp(buffer, proc_name) == 0) { + printf("%s - %s\n", entry->d_name, buffer); + ++count; + } + } + fclose(f); + } + + closedir(dir); + + if (count == 0) + return 1; + else + return 0; +} + + +static int process_kill(const char *process_id) +{ + pid_t pid; + + if (atoi(process_id) < 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"); + return 1; + } + + printf("Process '%d' killed.\n", pid); + return 0; +} + + +int main(int argc, char *argv[]) +{ + int opt; + DIR *dir_proc; + + struct options x; + + struct option long_options[] = { + {"list", required_argument, 0, 'l'}, + {"kill", required_argument, 0, 'k'}, + {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 < 3) { + usage(); + return 2; + } + + while ((opt = getopt_long(argc, argv, "l:k:", + long_options, NULL)) != -1) { + switch (opt) { + case 'l': + x.list = true; + x.process_name = optarg; + break; + case 'k': + x.kill = true; + x.process_pid = optarg; + break; + default: + fprintf(stderr, + "Unknow option.\n"); + usage(); + exit(2); + } + } + + if (x.list) + if (process_list(dir_proc, x.process_name) == 1) + return 1; + + if (x.kill) + if (process_kill(x.process_pid) == 1) + return 1; + + return 0; +} + + + |