First off, I know that similar questions have been asked, but the answers provided haven't been very helpful so far (they all recommend one of the following options).
I have a user application that needs to determine if a particular process is running. Here's what I know about the process:
root
)launchd
(pid 1)I've tried several ways to get this, but none have worked so far. Here's what I've tried:
Running ps
and parsing the output. This works, but it's slow (fork
/exec
is expensive), and I'd like this to be as fast as possible.
Using the GetBSDProcessList
function listed here. This also works, but the way in which they say to retrieve the process name (accessing kp_proc.p_comm
from each kinfo_proc
structure) is flawed. The resulting char*
only contains the first 16 characters of the process name, which can be seen in the definition of the kp_proc
structure:
#define MAXCOMLEN 16 //defined in param.h struct extern_proc { //defined in proc.h ...snip... char p_comm[MAXCOMLEN+1]; ...snip... };
Using libProc.h to retrieve process information:
pid_t pids[1024]; int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids)); for (int i = 0; i < numberOfProcesses; ++i) { if (pids[i] == 0) { continue; } char name[1024]; proc_name(pids[i], name, sizeof(name)); printf("Found process: %s\n", name); }
This works, except it has the same flaw as GetBSDProcessList
. Only the first portion of the process name is returned.
Using the ProcessManager function in Carbon:
ProcessSerialNumber psn; psn.lowLongOfPSN = kNoProcess; psn.highLongOfPSN = 0; while (GetNextProcess(&psn) == noErr) { CFStringRef procName = NULL; if (CopyProcessName(&psn, &procName) == noErr) { NSLog(@"Found process: %@", (NSString *)procName); } CFRelease(procName); }
This does not work. It only returns process that are registered with the WindowServer (or something like that). In other words, it only returns apps with UIs, and only for the current user.
I can't use -[NSWorkspace launchedApplications]
, since this must be 10.5-compatible. In addition, this only returns information about applications that appear in the Dock for the current user.
I know that it's possible to retrieve the name of running processes (since ps
can do it), but the question is "Can I do it without forking and exec'ing ps
?".
Any suggestions?
EDIT
After doing a lot more research, I've been unable to find a way to do this. I found this SO question, which referred to this C file in a python module. This was really useful in trying to use the KERN_PROCARGS
values in a sysctl
call.
However, Python module code seemed to be derived from the source to ps
, which I found here. ps
can somehow get the executable path of every running process, but my best efforts to extract how its doing this have been unsuccessful. There's a function in print.c
called getproclline
that seems to be doing the magic, but when I run the same code from within my own command line tool, I'm unable to retrieve the process executable for any processes other than my own.
I'll keep experimenting, but without more conclusive evidence, it looks like @drawnonward's answer is the most correct so far.
EDIT (a long time later)
Thanks to the answer pointed to by Quinn Taylor, I've found something that works. It gets the executable path of each process, and then I can just grab the last path component to get the actual process name.
#import <sys/proc_info.h>
#import <libproc.h>
int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
pid_t pids[numberOfProcesses];
bzero(pids, sizeof(pids));
proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
for (int i = 0; i < numberOfProcesses; ++i) {
if (pids[i] == 0) { continue; }
char pathBuffer[PROC_PIDPATHINFO_MAXSIZE];
bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE);
proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer));
if (strlen(pathBuffer) > 0) {
printf("path: %s\n", pathBuffer);
}
}
What about this answer to a related question? https://stackoverflow.com/a/12274588/120292 This purports to get the full path for a process by the pid, and you can grab just the last path component.