From cd4b0016ade2dd3d5fb877f7eccfe050dbbb1cca Mon Sep 17 00:00:00 2001 From: Ricardo Branco Date: Mon, 5 Feb 2024 21:39:06 +0100 Subject: [PATCH] Add Solaris implementation --- README.md | 4 ++ solaris/Makefile | 10 +++ solaris/restartable.c | 164 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 solaris/Makefile create mode 100644 solaris/restartable.c diff --git a/README.md b/README.md index 6935b23..5681720 100644 --- a/README.md +++ b/README.md @@ -61,3 +61,7 @@ Be careful because depending on the service you may lose connection or get kicke ## FreeBSD / NetBSD version [unix](unix) + +## Solaris version + +[solaris](solaris) diff --git a/solaris/Makefile b/solaris/Makefile new file mode 100644 index 0000000..5c0d9d9 --- /dev/null +++ b/solaris/Makefile @@ -0,0 +1,10 @@ +CC = gcc +BIN = restartable +CFLAGS = -Wall -O2 +LDFLAGS = -lproc + +$(BIN): restartable.c + $(CC) -o $@ $(CFLAGS) restartable.c $(LDFLAGS) + +clean: + @rm -f $(BIN) diff --git a/solaris/restartable.c b/solaris/restartable.c new file mode 100644 index 0000000..dec4387 --- /dev/null +++ b/solaris/restartable.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define _KERNEL +#include + +static int verbose; + +static int +compare_pids(const void *a, const void *b) { + return *(const int *)a - *(const int *)b; +} + +static void +parse_psinfo(int pid, int procFd) { + struct passwd *pwd; + char *user = "-"; + psinfo_t psinfo; + int fd; + + if ((fd = openat(procFd, "psinfo", O_RDONLY)) == -1) { + warn("%d", pid); + return; + } + + if (read(fd, &psinfo, sizeof(psinfo_t)) == sizeof(psinfo_t)) { + if ((pwd = getpwuid(psinfo.pr_uid)) != NULL) + user = pwd->pw_name; + printf("%d\t%d\t%d\t%s\t%s\n", psinfo.pr_pid, psinfo.pr_ppid, psinfo.pr_uid, user, psinfo.pr_fname); + if (verbose) + printf("\t%s\n", psinfo.pr_psargs); + } + + (void) close(fd); +} + +/* + * Solaris mounts an optimized /lib/libc.so.1 at boot time + * so it always shows on /proc//path/ as a brokem symlink + */ +static int +is_libc_so(int pid, uintptr_t addr) { + struct ps_prochandle *Pr; + char path[PATH_MAX]; + char pidstr[256]; + ssize_t len; + int gcode; + + (void) snprintf(pidstr, sizeof(pidstr), "%d", pid); + + if ((Pr = proc_arg_grab(pidstr, PR_ARG_PIDS, PGRAB_RDONLY, &gcode)) == NULL) { + warnx("%s: %s", pidstr, Pgrab_error(gcode)); + return 0; + } + + path[0] = '\0'; + if (Pobjname_resolved(Pr, addr, path, sizeof(path)) != NULL) + if ((len = resolvepath(path, path, sizeof(path))) > 0) + path[len] = '\0'; + + (void)Prelease(Pr, 0); + return (!strcmp(path, "/lib/libc.so.1")); +} + +static void +print_proc(int pid) { + char linkPath[PATH_MAX]; + char link[PATH_MAX]; + char procPid[256]; + int procFd, mapFd; + prmap_t entry; + + (void) snprintf(procPid, sizeof(procPid), "/proc/%d", pid); + if ((procFd = open(procPid, O_RDONLY | O_DIRECTORY)) == -1) + return; + + if ((mapFd = openat(procFd, "map", O_RDONLY)) == -1) { + warn("%d", pid); + close(procFd); + return; + } + + while (read(mapFd, &entry, sizeof(entry)) == sizeof(entry)) { + /* Skip anonymous mappings */ + if (entry.pr_mflags & MA_ANON) + continue; + /* Skip non-executable mappings */ + if (!(entry.pr_mflags & MA_EXEC)) + continue; + /* Solaris doesn't have w^x, so skip writable to avoid duplicate entries */ + if (entry.pr_mflags & MA_WRITE) + continue; + + (void) snprintf(linkPath, sizeof(linkPath), "path/%s", entry.pr_mapname); + if ((readlinkat(procFd, linkPath, link, sizeof(link)) == -1 && + !is_libc_so(pid, entry.pr_vaddr)) || + !strncmp(link, "/proc/", sizeof("/proc"))) { + parse_psinfo(pid, procFd); + break; + } + } + + (void) close(mapFd); + (void) close(procFd); +} + +static void +print_all(void) { + DIR *dir; + struct dirent *entry; + int *pids = NULL; + struct stat st; + int nproc; + + /* Get the number of processes through st_nlink */ + if (stat("/proc", &st) == -1) + err(1, "/proc"); + + pids = (int *) malloc(st.st_nlink * sizeof(int)); + if (pids == NULL) + err(1, "malloc"); + + dir = opendir("/proc"); + if (dir == NULL) + err(1, "/proc"); + + for (nproc = 0; nproc < st.st_nlink; nproc++) { + if ((entry = readdir(dir)) == NULL) + break; + pids[nproc] = atoi(entry->d_name); + } + + (void) closedir(dir); + + qsort(pids, ++nproc, sizeof(int), compare_pids); + + for (int i = 0; i < nproc; i++) + print_proc(pids[i]); + + free(pids); +} + +int +main(int argc, char *argv[]) { + if (argc > 2) + errx(1, "Usage: %s [-v]\n", argv[0]); + if (argc > 1 && !strcmp(argv[1], "-v")) + verbose = 1; + + printf("PID\tPPID\tUID\tUser\tCommand\n"); + print_all(); + + return 0; +}