Monday, February 20, 2012

Get process id by name in Linux using C++

Although it seems like a pretty common activity, locating a running process by name is a little harder in Linux than you'd expect. Various solutions are available on the web, ranging from code relying on sysctl calls to samples that use the results from running certain bash scripts. The following implementation takes advantage of the functionality offered by the /proc filesystem. It enumerates all numeric (pid) entries and accesses the cmdline file to retrieve the program that was used to start the process and matches it against the requested process name.

Function getProcIdByName shown below accepts the name of the requested process and returns the pid if the process is found or -1 otherwise.

#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

int getProcIdByName(string procName)

{
    int pid = -1;

    // Open the /proc directory

    DIR *dp = opendir("/proc");
    if (dp != NULL)
    {
        // Enumerate all entries in directory until process found
        struct dirent *dirp;
        while (pid < 0 && (dirp = readdir(dp)))
        {
            // Skip non-numeric entries
            int id = atoi(dirp->d_name);
            if (id > 0)
            {
                // Read contents of virtual /proc/{pid}/cmdline file
                string cmdPath = string("/proc/") + dirp->d_name + "/cmdline";
                ifstream cmdFile(cmdPath.c_str());
                string cmdLine;
                getline(cmdFile, cmdLine);
                if (!cmdLine.empty())
                {
                    // Keep first cmdline item which contains the program path
                    size_t pos = cmdLine.find('\0');
                    if (pos != string::npos)
                        cmdLine = cmdLine.substr(0, pos);
                    // Keep program name only, removing the path
                    pos = cmdLine.rfind('/');
                    if (pos != string::npos)
                        cmdLine = cmdLine.substr(pos + 1);
                    // Compare against requested process name
                    if (procName == cmdLine)
                        pid = id;
                }
            }
        }
    }

    closedir(dp);

    return pid;

}

int main(int argc, char* argv[])

{
    // Fancy command line processing skipped for brevity
    int pid = getProcIdByName(argv[1]);
    cout << "pid: " << pid << endl;
    return 0;
}

7 comments:

  1. Thank you for sharing your code.
    A minor hint:
    There might be several pids for a given procName - maybe getFirstProcIdByName is more precise.


    Kind regards

    ReplyDelete
  2. could you please post the same program in C? Thanks!

    ReplyDelete
  3. very good example to get the process information. It helps me a lot.
    "/proc/[pid]/stat" can also be used to get the same information...
    because if any process is forked by any other process , in that case the
    /proc/{pid}/cmdline file will show the parent process name not the actual process name.
    but in "/proc/[pid]/stat" file the actual process information can be extracted.
    please see the man page (man proc )to scan the stat file...

    ReplyDelete
  4. Your code is extremely helpful, thank you!

    ReplyDelete
  5. Thanks a lot for this code! Very useful for solving a problem I've been pondering for a while: sending SIGINT to a process when I couldn't access the terminal from which it was called due to a plot refreshing every 1/50sec.

    ReplyDelete
  6. Really helpful. Thanks for sharing.

    ReplyDelete
  7. Wow! this is Amazing! Do you know your hidden name meaning ? Click here to find your hidden name meaning

    ReplyDelete