Skip to content

Instantly share code, notes, and snippets.

@philpennock
Last active July 10, 2016 00:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save philpennock/7302365b4baa4e4060894141ce275c72 to your computer and use it in GitHub Desktop.
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 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