clinuxpidprocfs

Getting list of PIDs from /proc in Linux


I'm making a program that can see if page faults occur in some processes, and my method to do this is to get all process's PIDs and see rss, maj_flt etc. by seeking in every single /proc/[PID], checking if there's a change in total maj_flt.

But in order to get all running process's PIDs, I need to get those directly from my C program, without using existing shell commands like ps, top etc.

Does anyone know where the running PID data exists in /proc or somewhere else? Or if there's another way to do this, like getting it by system call function in my C program?


Solution

  • There is no syscall that exposes a list of PIDs unfortunately. The way you are supposed to get this information in Linux is through the /proc virtual filesystem.

    If you want a list of PIDs of currently running processes, you can use opendir() and readdir() to open /proc and iterate over the list of files/directories in there. Then you can check for directories having a filename that is a number. After checking, you can then open /proc/<PID>/stat to get the information you want (in particular, you want the 12th field majflt).

    Here's a simple working example (some more error checking and adjustments might be needed):

    #include <sys/types.h>
    #include <dirent.h>
    #include <stdio.h>
    #include <ctype.h>
    
    // Helper function to check if a struct dirent from /proc is a PID directory.
    int is_pid_dir(const struct dirent *entry) {
        const char *p;
    
        for (p = entry->d_name; *p; p++) {
            if (!isdigit(*p))
                return 0;
        }
    
        return 1;
    }
    
    int main(void) {
        DIR *procdir;
        FILE *fp;
        struct dirent *entry;
        char path[256 + 5 + 5]; // d_name + /proc + /stat
        int pid;
        unsigned long maj_faults;
    
        // Open /proc directory.
        procdir = opendir("/proc");
        if (!procdir) {
            perror("opendir failed");
            return 1;
        }
    
        // Iterate through all files and directories of /proc.
        while ((entry = readdir(procdir))) {
            // Skip anything that is not a PID directory.
            if (!is_pid_dir(entry))
                continue;
    
            // Try to open /proc/<PID>/stat.
            snprintf(path, sizeof(path), "/proc/%s/stat", entry->d_name);
            fp = fopen(path, "r");
    
            if (!fp) {
                perror(path);
                continue;
            }
    
            // Get PID, process name and number of faults.
            fscanf(fp, "%d %s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %lu",
                &pid, &path, &maj_faults
            );
    
            // Pretty print.
            printf("%5d %-20s: %lu\n", pid, path, maj_faults);
            fclose(fp);
        }
    
        closedir(procdir);
        return 0;
    }
    

    Sample output:

        1 (systemd)           : 37
       35 (systemd-journal)   : 1
       66 (systemd-udevd)     : 2
       91 (dbus-daemon)       : 4
       95 (systemd-logind)    : 1
      113 (dhclient)          : 2
      143 (unattended-upgr)   : 10
      148 (containerd)        : 11
      151 (agetty)            : 1
      ...