Skip to content

Instantly share code, notes, and snippets.

@nguyen-phillip
Last active November 30, 2023 13:01
Show Gist options
  • Save nguyen-phillip/de66b0ea2144e20ddd844c41c9d93eb9 to your computer and use it in GitHub Desktop.
Save nguyen-phillip/de66b0ea2144e20ddd844c41c9d93eb9 to your computer and use it in GitHub Desktop.
Using libproc.h
#include <stdio.h>
#include <stdlib.h>
#include <libproc.h>
// Uses proc_pidinfo from libproc.h to find the parent of given pid.
// Call this repeatedly until ppid(pid) == pid to get ancestors.
int ppid(pid_t pid) {
struct proc_bsdinfo info;
proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, sizeof(info));
return info.pbi_ppid;
}
void print_info(pid_t pid) {
// proc_pidinfo(pid, flavor, arg, buffer, buffersize)
// flavor = PROC_PIDLISTFDS, buffer = &proc_fdinfo
// flavor = PROC_PIDTASKALLINFO, buffer = &proc_taskallinfo
// flavor = PROC_PIDTBSDINFO, buffer = &proc_bsdinfo
// flavor = PROC_PIDTASKINFO, buffer = &proc_taskinfo
// flavor = PROC_PIDTHREADINFO, buffer = &proc_threadinfo
// flavor = PROC_PIDVNODEPATHINFO, buffer = &proc_vnodepathinfo
// flavor = PROC_PIDPATHINFO, buffer = char *
// see more in sys/proc_info.h
struct proc_bsdinfo info;
proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, sizeof(info));
// proc_name(pid, buffer, buffersize)
// Copies the contents of info.pbi_name or info.pbi_comm into buffer.
// Since pbi_comm is limited to first 15 chars, pbi_name is preferred.
char name[2*MAXCOMLEN];
proc_name(pid, name, sizeof(name));
// proc_pidpath(pid, buffer, buffersize)
char path[PROC_PIDPATHINFO_MAXSIZE];
proc_pidpath(pid, path, sizeof(path));
printf("%d\t%d\t%-15s\t%s\tproc_name=%s\tpath=%s\n",
info.pbi_pid, info.pbi_ppid, info.pbi_comm, info.pbi_name,
name, path);
}
int main(void) {
// proc_listpids(type, typeinfo, buffer, buffersize)
// type = PROC_ALL_PIDS, typeinfo = 0 (use proc_listallpids)
// type = PROC_PGRP_ONLY, typeinfo = process group id (use proc_listpgrppids)
// type = PROC_TTY_ONLY, typeinfo = tty
// type = PROC_UID_ONLY, typeinfo = uid
// type = PROC_RUID_ONLY, typeinfo = ruid
// type = PROC_PPID_ONLY, typeinfo = ppid (use proc_listchildpids)
// Call with buffer = NULL to return number of pids.
int n = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
int *buffer = (int *)malloc(sizeof(int)*n);
// Then call again with int *buffer and nonzero buffersize.
// The return value is number of pids placed into buffer (<= buffersize).
int k = proc_listpids(PROC_ALL_PIDS, 0, buffer, n*sizeof(int));
printf("%d processes:\n", k);
for (int i = 0; i < k; i++) {
int pid = buffer[i];
if (pid == 0) continue; // ignore loginwindow spam
print_info(pid);
}
return 0;
}
@mezantrop
Copy link

mezantrop commented Nov 30, 2023

@mrexodia, I believe you are mixing proc_listpids() and proc_listallpids(). The last returns the number of processes, but the first returns a buffer to store an array of the PIDs. That's exactly is what we can see in the kernel sources (https://opensource.apple.com/source/xnu/xnu-7195.141.2/libsyscall/wrappers/libproc/libproc.c.auto.html):

int
proc_listallpids(void * buffer, int buffersize)
{
	int numpids;
	numpids = proc_listpids(PROC_ALL_PIDS, (uint32_t)0, buffer, buffersize);

	if (numpids == -1) {
		return -1;
	} else {
		return numpids / sizeof(int);
	}
}

@mrexodia
Copy link

Ah yes, you are totally correct my bad!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment