41

In C, how can I find out programmatically if a process is already running on Linux/Ubuntu to avoid having it start twice? I'm looking for something similar to pidof.

jww
  • 97,681
  • 90
  • 411
  • 885
Frank Vilea
  • 8,323
  • 20
  • 65
  • 86
  • (You could perhaps create a temporary "lock" file in a known location when starting the program, then just check for existence of the file (and delete it on shutdown - although then you have a problem if the program terminates unexpectedly)) – marnir Aug 01 '11 at 12:24
  • @marnir - that's why you have the program write its own PID to the file, then if the file exists, you can check to see if that PID is still active, and if so, if the process name matches your own. It isn't 100% foolproof, but still, abnormal terminations shouldn't be happening *that* often. – George Aug 01 '11 at 12:27
  • 1
    If the "lock file" contained the PID of the program, you could detect abnormal program termination in nearly all cases (is there a running process with the PID matching the PID file)? This is not a perfect solution (finite number of PIDs, PID recycling). – jmtd Aug 01 '11 at 12:28
  • 2
    @marnir - If you actually lock the lockfile, the lock will be released on process exit. The program just tries for a non-blocking exclusive lock, and if it fails, someone else is running. – unpythonic Aug 01 '11 at 12:29
  • Anyone knows how to do this in Windows? – dm76 May 29 '14 at 16:18
  • 1
    honestly, http://stackoverflow.com/questions/5460702/check-running-processes-in-c looks a clear, easy solution – mtk Oct 10 '15 at 22:57
  • @mtk Link is clean unless you know pid, which is the main issue of this topic. – Louis Go Jan 29 '21 at 02:19

4 Answers4

35

You can walk the pid entries in /proc and check for your process in either the cmdline file or perform a readlink on the exe link (The following uses the first method).

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char* endptr;
    char buf[512];

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        /* if endptr is not a null character, the directory is not
         * entirely numeric, so ignore it */
        long lpid = strtol(ent->d_name, &endptr, 10);
        if (*endptr != '\0') {
            continue;
        }

        /* try to open the cmdline file */
        snprintf(buf, sizeof(buf), "/proc/%ld/cmdline", lpid);
        FILE* fp = fopen(buf, "r");

        if (fp) {
            if (fgets(buf, sizeof(buf), fp) != NULL) {
                /* check the first token in the file, the program name */
                char* first = strtok(buf, " ");
                if (!strcmp(first, name)) {
                    fclose(fp);
                    closedir(dir);
                    return (pid_t)lpid;
                }
            }
            fclose(fp);
        }

    }

    closedir(dir);
    return -1;
}


int main(int argc, char* argv[]) 
{
    if (argc == 1) {
        fprintf("usage: %s name1 name2 ...\n", argv[0]);
        return 1;
    }

    int i;
    for(int i = 1; i < argc; ++i) {
        pid_t pid = proc_find(argv[i]);
        if (pid == -1) {
            printf("%s: not found\n", argv[i]);
        } else {
            printf("%s: %d\n", argv[i], pid);
        }
    }

    return 0;
}
John Ledbetter
  • 13,557
  • 1
  • 61
  • 80
18

This is the same as the code posted by John Ledbetter . It is good to refer to the file named stat in /proc/pid/ directory than cmdline since the former gives process states and process name. The cmdline file gives complete arguments with which the process is started. So that fails in some cases. Any way the idea given by John is good. Here I posted the modified code of John. I was looking for the code in c in Linux to check dhcp is running or not . With this code, I am able to do that. I hope it may be useful for someone like me.

#include <sys/types.h>
#include <dirent.h>
#include<unistd.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char buf[512];

    long  pid;
    char pname[100] = {0,};
    char state;
    FILE *fp=NULL; 

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        long lpid = atol(ent->d_name);
        if(lpid < 0)
            continue;
        snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
        fp = fopen(buf, "r");

        if (fp) {
            if ( (fscanf(fp, "%ld (%[^)]) %c", &pid, pname, &state)) != 3 ){
                printf("fscanf failed \n");
                fclose(fp);
                closedir(dir);
                return -1; 
            }
            if (!strcmp(pname, name)) {
                fclose(fp);
                closedir(dir);
                return (pid_t)lpid;
            }
            fclose(fp);
        }
    }


closedir(dir);
return -1;
}


int main(int argc, char* argv[]) 
{
    int i;
    if (argc == 1) {
        printf("usage: %s name1 name2 ...\n", argv[0]);
        return 1;
    }

    for( i = 1; i < argc; ++i) {
        pid_t pid = proc_find(argv[i]);
        if (pid == -1) {
            printf("%s: not found\n", argv[i]);
        } else {
            printf("%s: %d\n", argv[i], pid);
        }
    }

    return 0;
}
demongolem
  • 9,474
  • 36
  • 90
  • 105
yuvaeasy
  • 823
  • 2
  • 10
  • 18
  • On Android 5.1, the process name field in /proc//stat has a pretty small character limit. Just a heads up that some OSs may experience this similar problem. – Allen Jan 25 '18 at 20:39
17

There are ways to avoid /proc usage (and there might be good reasons to do so, e.g. /proc might not be installed at all, and/or it might have been symlinked to something deceptive, or that pid has been hidden in /proc). Granted, the below method doesn't look that good, I wish there were a proper API for that!

Anyway, section 1.9 of a 1997 Unix programming FAQ says:

Use kill() with 0 for the signal number. There are four possible results from this call:

  • kill() returns 0

    This implies that a process exists with the given PID, and the system would allow you to send signals to it. It is system-dependent whether the process could be a zombie.

  • kill() returns -1, errno == ESRCH

    Either no process exists with the given PID, or security enhancements are causing the system to deny its existence. (On some systems, the process could be a zombie.)

  • kill() returns -1, errno == EPERM

    The system would not allow you to kill the specified process. This means that either the process exists (again, it could be a zombie) or draconian security enhancements are present (e.g. your process is not allowed to send signals to anybody).

  • kill() returns -1, with some other value of errno

    You are in trouble!

The most-used technique is to assume that success or failure with EPERM implies that the process exists, and any other error implies that it doesn't.

Camille Goudeseune
  • 2,934
  • 2
  • 35
  • 56
RCL
  • 426
  • 4
  • 6
  • 2
    After re-reading your question... if all you want is preventing the process from being run twice, you could create a named kernel object (e.g. a semaphore, or shared memory) with an unique name and check for its existence in the beginning. It might be better than a lock file as it will go away automatically if your process crashes. – RCL Nov 06 '13 at 05:49
  • But using proc you will have no disk I/O access. – kayle Nov 22 '17 at 09:56
  • Not all files necessitate disk access either. – RCL Feb 08 '18 at 22:20
3

pidof works by walking over the /proc filesystem. In C, you could do something similar by enumerating /proc; opening /proc/X/cmdline for every X where X is a list of one or more decimal numbers. I don't know if you have any portability requirements but bear that in mind if you are to rely on the availability of /proc.

This problem is more commonly solved on UNIX-like systems by wrapping the start-up of the program and maintaining a PID file. See /etc/init.d/* for classic examples of this approach. You will need to be careful to ensure that the code which reads of writes the PID file does so in a safe manner (atomically). If your target OS has a more capable init (such as systemd), you may be able to out source this work to that.

jmtd
  • 1,223
  • 9
  • 11