Last active
July 10, 2016 00:52
-
-
Save philpennock/7302365b4baa4e4060894141ce275c72 to your computer and use it in GitHub Desktop.
sysctl-derived process iteration on Darwin (MacOS) & probably *BSD. Handles pid 0 (kernel_task)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file should be valid C99. | |
// Intended for use on MacOS (tested) and *BSD (untested) systems. | |
#include <err.h> | |
#include <limits.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
// gets us some compiler macros for OS | |
#include <sys/param.h> | |
// include <sys/proc.h> -- sensitive to other headers being pulled in, rely upon sys/sysctl.h | |
#include <sys/sysctl.h> | |
#include <sys/types.h> | |
#if defined(__APPLE__) | |
# define USE_KINFO_DARWIN 1 | |
#elif defined(BSD) | |
# include <sys/user.h> | |
# define USE_KINFO_BSD 1 | |
#else | |
# error "Unknown platform for kinfo" | |
#endif | |
#define NullGuard(P) ((P)?(P):"<null>") | |
#ifdef USE_KINFO_DARWIN | |
int /* errcount */ | |
show_proc(struct kinfo_proc *kp) { | |
printf("pid %d\tcommand \"%s\"\n", kp->kp_proc.p_pid, NullGuard(kp->kp_proc.p_comm)); | |
printf("\tppid %d\tpgid %d\n", kp->kp_eproc.e_ppid, kp->kp_eproc.e_pgid); | |
// `struct ucred` is kernel-internal, so avoid kp->kp_eproc.e_pcred.pc_ucred | |
printf("\truid %d\tsvuid %d\trgid %d\tsv_gid %d\n", | |
kp->kp_eproc.e_pcred.p_ruid, | |
kp->kp_eproc.e_pcred.p_svuid, | |
kp->kp_eproc.e_pcred.p_rgid, | |
kp->kp_eproc.e_pcred.p_svgid); | |
printf("\teuid %d\tgroups (%d):\n", kp->kp_eproc.e_ucred.cr_uid, kp->kp_eproc.e_ucred.cr_ngroups); | |
for (int i=0; i < kp->kp_eproc.e_ucred.cr_ngroups; ++i) { | |
printf("\t\tgroup: %d\n", kp->kp_eproc.e_ucred.cr_groups[i]); | |
} | |
printf("\tsleeping \"%s\"\n", NullGuard(kp->kp_proc.p_wmesg)); | |
printf("\ttext: size %u rss %hu\n", kp->kp_eproc.e_xsize, kp->kp_eproc.e_xrssize); | |
printf("\n"); | |
return 0; | |
} | |
#endif // USE_KINFO_DARWIN | |
#ifdef USE_KINFO_BSD | |
int /* errcount */ | |
show_proc(struct kinfo_proc *kp) { | |
printf("pid %d\tcommand \"%s\"\n", kp->ki_pid, NullGuard(kp->ki_comm)); | |
printf("\tppid %d\tpgid %d\n", kp->ki_ppid, kp->ki_pgid); | |
printf("\truid %d\tsvuid %d\trgid %d\tsv_gid %d\n", | |
kp->ki_ruid, | |
kp->ki_svuid, | |
kp->ki_rgid, | |
kp->ki_svgid); | |
printf("\teuid %d\tgroups (%d):\n", kp->ki_uid, kp->ki_ngroups); | |
for (int i=0; i < kp->ki_ngroups; ++i) { | |
printf("\t\tgroup: %d\n", kp->ki_groups[i]); | |
} | |
printf("\tsleeping \"%s\"\n", NullGuard(kp->ki_wmesg)); | |
printf("\ttext: size %lu rss %lu\n", kp->ki_size, kp->ki_rssize); | |
printf("\n"); | |
return 0; | |
} | |
#endif // USE_KINFO_BSD | |
int /* errcount */ | |
my_pidinfo(int pid) { | |
int lookup_oid[4] = { CTL_KERN, KERN_PROC, 0, 0 }; | |
int lookup_oid_len; | |
if (pid == -1) { | |
lookup_oid[2] = KERN_PROC_ALL; | |
lookup_oid_len = 3; | |
} else { | |
lookup_oid[2] = KERN_PROC_PID; | |
lookup_oid[3] = pid; | |
lookup_oid_len = 4; | |
} | |
size_t need; | |
int rc = sysctl(lookup_oid, lookup_oid_len, NULL, &need, NULL, 0); | |
if (rc != 0) err(1, "sysctl lookup needed storage for results"); | |
if (need < 1) errx(1, "invalid storage specified by system (%zu)", need); | |
void *raw_results = calloc(1, need); | |
if (raw_results == NULL) err(1, "allocating %zu bytes", need); | |
size_t got = need; | |
rc = sysctl(lookup_oid, lookup_oid_len, raw_results, &got, NULL, 0); | |
if (rc != 0) err(1, "sysctl lookup results (into %zu bytes (after: %zu))", need, got); | |
struct kinfo_proc *processes = raw_results; | |
int processes_count = got / sizeof(struct kinfo_proc); | |
if (processes_count == 0) { | |
warnx("no process data returned for pid %d", pid); | |
return 1; | |
} | |
int errcount = 0; | |
for (int i = 0; i < processes_count; ++i) { | |
errcount += show_proc(&processes[i]); | |
} | |
return errcount; | |
} | |
int /* system exit */ | |
main(int argc, char *argv[]) { | |
const char *pname = strrchr(argv[0], '/'); | |
if (pname == NULL) { pname = argv[0]; } else { ++pname; } | |
if (argc < 2) { | |
fprintf(stderr, "Usage: %s <pid> [<pid>...]\n", pname); | |
exit(1); | |
} | |
int errcount = 0; | |
for (int i = 1; i < argc; ++i) { | |
char *end; | |
long pid = strtol(argv[i], &end, 0); | |
if (*end != '\0') { | |
warnx("Invalid number for pid '%s'", argv[i]); | |
++errcount; | |
continue; | |
} | |
/* We treat -1 specially, but only -1 */ | |
if (pid < -1) { | |
warnx("Invalid pid (negative): '%s'", argv[i]); | |
++errcount; | |
continue; | |
} | |
if (pid > INT_MAX) { | |
warnx("Invalid pid (too high): '%s'", argv[i]); | |
++errcount; | |
continue; | |
} | |
errcount += my_pidinfo((int)pid); | |
} | |
if (errcount != 0) { | |
warnx("saw %d errors", errcount); | |
return 1; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment