From 25f11804292df41209f43eb7dccbecbafbab272b Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Sun, 28 Sep 2025 22:37:07 +1000 Subject: [PATCH] implement pgetppid pgetppid will aid in detecting which terminal emulator a process is running under --- Makefile | 2 +- src/pgetppid.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/pgetppid.h | 15 +++++++++ src/term.c | 5 ++- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/pgetppid.c create mode 100644 src/pgetppid.h diff --git a/Makefile b/Makefile index 7a0ad5c..7d33c49 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ all: tests .PHONY: tests tests: $(BIN) $(BIN)/ct_test -$(BIN)/ct_test: $(BUILD) $(addprefix $(BUILD)/, ct_test.o term.o termio.o) +$(BIN)/ct_test: $(BUILD) $(addprefix $(BUILD)/, ct_test.o term.o termio.o pgetppid.o) $(LD) $(LDFLAGS) -o $@ $(filter %.o, $^) $(BUILD)/%.o: $(SRC)/%.c diff --git a/src/pgetppid.c b/src/pgetppid.c new file mode 100644 index 0000000..c60b4a7 --- /dev/null +++ b/src/pgetppid.c @@ -0,0 +1,85 @@ +/* XXX: WARNING: TODO + * This file's implementation is Linux dependent! + * XXX: WARNING: TODO + */ +#include +#include + +#include "pgetppid.h" +#include "ct_shared.h" + +int pgetppid(const pid_t pid, pid_t *const ppid, char *const name) { + /* I'm making the assumption that each line in /proc/pid/status + * has a hard length limit of PAGE_SIZE. + */ + static int CT_K_PAGE_SIZE; + CT_K_PAGE_SIZE = getpagesize(); + + FILE *stream; + char line[CT_K_PAGE_SIZE]; + + /* The maximum PID value on a 64-Bit Linux kernel is defined 4194304, + * not INT_MAX even through pid_t is typedef'd to signed int. + * Hence "/proc/4194304/status\0" is the maximum path (length 21). + */ +#define PROCPATH_MAX (21) + char procname[PROCPATH_MAX]; // Holds /proc/4294967296/status\0 + // XXX: NOTE: should this be %d not %u since pid_t is typedef'd to signed int? + snprintf(procname, PROCPATH_MAX, "/proc/%u/status", pid); +#undef PROCPATH_MAX + stream = fopen(procname, "r"); + if (stream == NULL) { + return NERR; + } + + /* /proc/pid/status format: ($ cat /proc/$$/status) + Name: bash + Umask: 0022 + State: S (sleeping) + Tgid: 17248 + Ngid: 0 + Pid: 17248 + PPid: 17200 + */ + + /* Name Line Format: "Name:___$NAME\n\0" where _ are spaces (5+3+len(NAME)+2 = + * 10+len(NAME)) `man proc_pid_status` claims $NAME will be truncated to + * TASK_COMM_LEN (including \0 terminating byte) aka 15+1 bytes long. However, + * They fail to account for work-queue-threads and kernel-threads which + * seem to not have this restriction. + * ie `rcu_exp_par_gp_kthread_worker/0` clearly exceeds this. + * We define NAMELINE_MAX to 9 + TASK_COMM_LEN (yes 9) because TASK_COMMON = + * len(NAME)+1 (for \0). + * NOTE: TASK_COMM_LEN isn't accessible in userspace so we define CT_PROC_NAME_MAX + */ +#define NAMELINE_MAX (9 + CT_PROC_NAME_MAX) + if (fgets(line, NAMELINE_MAX, stream) == NULL) + goto fail; + /* Fail if over max length, ie this is kernel related + * thread and we've recursed too deep. */ + // if (line[NAMELINE_MAX - 2] != '\n') + // goto fail; + else if (sscanf(line, "Name: %s\n", name) == 0) + return 0; +#undef NAMELINE_MAX + + /* Skip over the Umask, State, Tgid, Ngid, Pid lines + * The compiler can unroll this loop for us. */ + for (int i = 0; i < 5; i++) { + if (fgets(line, CT_K_PAGE_SIZE, stream) == NULL) + goto fail; + } + + if (fgets(line, CT_K_PAGE_SIZE, stream) == NULL) + goto fail; + else if (sscanf(line, "PPid: %d\n", ppid) == 0) + goto fail; + + fclose(stream); + return OK; + +fail: + fclose(stream); + return NERR; +} + diff --git a/src/pgetppid.h b/src/pgetppid.h new file mode 100644 index 0000000..ed9cd82 --- /dev/null +++ b/src/pgetppid.h @@ -0,0 +1,15 @@ +#ifndef CURSETREE_PGETPPID_H +#define CURSETREE_PGETPPID_H + +#include + +/* XXX: WARNING: TODO: Linux kernel specific + * TASK_COMM_LEN isn't accessible in userspace so we define CT_PROC_NAME_MAX + * instead, representing the maximum (in most instances) truncated length of + * a process' Name field in /proc/pid/status. + */ +#define CT_PROC_NAME_MAX 16 + +int pgetppid(const pid_t pid, pid_t *const ppid, char *const name); + +#endif diff --git a/src/term.c b/src/term.c index 0c4188f..9611981 100644 --- a/src/term.c +++ b/src/term.c @@ -1,5 +1,4 @@ #include -#include #include #include @@ -51,3 +50,7 @@ void ct_resetterm(struct ct_term *const term) { free(term); } +/* TODO: use pgetppid() and write a terminfo parser, otherwise default to TERM */ +// static inline int ct_detectterm() { +// secure_getenv("TERM"); +// }