Created
November 29, 2018 02:11
-
-
Save leiless/6e19c99448a417c8a95e9e22e1b9e036 to your computer and use it in GitHub Desktop.
(macOS) Fetch all BSD procs into a proc list
This file contains hidden or 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
| /* | |
| * Created 181128 lynnl | |
| */ | |
| #include <stdio.h> | |
| #include <assert.h> | |
| #include <errno.h> | |
| #include <stdlib.h> | |
| #include <sys/sysctl.h> | |
| #ifndef __nullable | |
| #define __nullable /* fake nullable annotation */ | |
| #endif | |
| #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) | |
| /** | |
| * Fetch all BSD procs into a proc list | |
| * @proclist array list to store all bsd procs | |
| * you must free(3) it if success | |
| * pass NULL if you only care count of procs | |
| * @cnt proc count of above list | |
| * @return 0 if success errno o.w. | |
| * | |
| * NOTE: | |
| * first sysctl(3) tends to return a larger buffer length | |
| * as i investigated in such case it's 5 | |
| * the gap is likely used to fix the size-TOCTTOU bug | |
| * | |
| * see: | |
| * https://developer.apple.com/library/archive/qa/qa2001/qa1123.html | |
| * https://stackoverflow.com/q/32134935 | |
| */ | |
| static int fetch_all_bsd_proc( | |
| struct kinfo_proc ** __nullable proclist, | |
| size_t *cnt) | |
| { | |
| int e; | |
| static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; | |
| struct kinfo_proc *list = NULL; | |
| size_t len; | |
| if (proclist != NULL) assert(*proclist == NULL); | |
| assert(cnt != NULL); | |
| while (1) { | |
| assert(list == NULL); | |
| e = sysctl((int *) name, ARRAY_SIZE(name), NULL, &len, NULL, 0); | |
| if (e == -1) { | |
| e = errno; | |
| break; | |
| } else if (proclist == NULL) { | |
| #ifdef DEBUG | |
| printf("length #0: %zu\n", len / sizeof(struct kinfo_proc)); | |
| #endif | |
| /* Only care proc count */ | |
| break; | |
| } | |
| #ifdef DEBUG | |
| printf("length #1: %zu\n", len / sizeof(struct kinfo_proc)); | |
| #endif | |
| list = malloc(len); | |
| if (list == NULL) { | |
| e = ENOMEM; | |
| break; | |
| } | |
| /* | |
| * Call sysctl again with the new buffer | |
| * If we get an ENOMEM error toss away the buffer and start again | |
| */ | |
| e = sysctl((int *) name, ARRAY_SIZE(name), list, &len, NULL, 0); | |
| if (e == -1) e = errno; | |
| if (e == 0) { | |
| #ifdef DEBUG | |
| printf("length #2: %zu\n", len / sizeof(struct kinfo_proc)); | |
| #endif | |
| break; | |
| } else { | |
| assert(list != NULL); | |
| free(list); | |
| list = NULL; | |
| /* | |
| * Abort if met unexpected errno | |
| * Retry if count of proc. larger than last snapshot(got ENOMEM) | |
| */ | |
| if (e != ENOMEM) break; | |
| } | |
| } | |
| if (e == 0) { | |
| if (proclist != NULL) *proclist = list; | |
| *cnt = len / sizeof(struct kinfo_proc); | |
| } else { | |
| assert(list == NULL); | |
| } | |
| return e; | |
| } | |
| int main(void) | |
| { | |
| int e; | |
| size_t cnt; | |
| struct kinfo_proc *list = NULL; | |
| struct kinfo_proc *p; | |
| e = fetch_all_bsd_proc(NULL, &cnt); | |
| if (e == 0) { | |
| printf("#proc: %zu\n", cnt); | |
| } else { | |
| printf("fetch_all_bsd_proc() fail errno: %d\n", e); | |
| } | |
| e = fetch_all_bsd_proc(&list, &cnt); | |
| if (e == 0) { | |
| printf("#proc: %zu\n", cnt); | |
| for (p = list; p - list < cnt; p++) { | |
| printf("pid: %5d %16s uid: %3u prio: %2u\n", | |
| p->kp_proc.p_pid, p->kp_proc.p_comm, | |
| p->kp_eproc.e_ucred.cr_uid, | |
| p->kp_proc.p_priority); | |
| } | |
| free(list); | |
| } else { | |
| printf("fetch_all_bsd_proc() fail errno: %d\n", e); | |
| } | |
| return 0; | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample output: http://ix.io/1uN8