Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieve names of running processes

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:

  • The name
  • The user (root)
  • It should already be running, since it's a LaunchDaemon, which means
  • Its parent process should be launchd (pid 1)

I've tried several ways to get this, but none have worked so far. Here's what I've tried:

  1. 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.

  2. 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... };
  3. 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.

  4. 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.

  5. 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);     } } 
like image 911
Dave DeLong Avatar asked Jun 10 '10 20:06

Dave DeLong


People also ask

How do I get a list of running processes?

The most common way to list processes currently running on your system is to use the command ps (short for process status). This command has a lot of options that come in handy when troubleshooting your system. The most used options with ps are a, u and x.

How do I list running processes in Windows?

Task Manager can be opened in a number of ways, but the simplest is to select Ctrl+Alt+Delete, and then select Task Manager. In Windows, first click More details to expand the information displayed. From the Processes tab, select Details to see the process ID listed in the PID column. Click on any column name to sort.

How can I list all the running processes on a Linux machine?

To list currently running processes, use the ps , top , htop , and atop Linux commands. You can also combine the ps command with the pgrep command to identify individual processes.

How do I get the process name from PID?

In this quick article, we've explored how to get the name and the command line of a given PID in the Linux command line. The ps -p <PID> command is pretty straightforward to get the process information of a PID. Alternatively, we can also access the special /proc/PID directory to retrieve process information.


2 Answers

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.

like image 180
Quinn Taylor Avatar answered Oct 01 '22 13:10

Quinn Taylor


The only complete list of running processes is provided by 2 above, asking the kernel. Getting the actual name of the process is not straight forward. In a nutshell, you look up the pid in any other source you can find until you get a match.

For some processes, the following will work:

ProcessSerialNumber         psn; CFStringRef             name = NULL; status = GetProcessForPID( inPID , &psn ); if ( noErr == status ) CopyProcessName( &psn , &name ); 

For some processes, you can look up the pid in the results of [[NSWorkspace sharedWorkspace] launchedApplications] by NSApplicationProcessIdentifier. Available with 10.2 and later. Most, but maybe not all, items in this list will be the same as CopyProcessName above.

For some processes, you can look up the process arguments and get the full path from the first argument. Similar to getting the original list, but using KERN_PROCARGS or KERN_PROCARGS2 as the second mib value. This is what ps is doing.

For some processes, you are stuck with the 16 character p_comm.

like image 38
drawnonward Avatar answered Oct 01 '22 13:10

drawnonward