C extracting info from file in /proc

Bill Source

I am trying to get the path which contains the executable of a PID from /proc/pid/cmdline in C. The man page states:

"The command-line arguments appear in this file as a set of strings separated by null bytes ('\0'), with a further null byte after the last string."

My idea (pseudocode):

int main(int argc, char** argv){
    // Assume file_path has been initialized
    char executable_path[1000];
    FILE* file = fopen(file_path, "r");
    if(f != NULL){

        fscanf("%s", executable_path);
    }
    return 0;
}

Since I only want the first string from this file(since that is the path containing the executable) and I know for sure that there is a '\0' after the first string, would fscanf be the correct function to use? Will it detect the first '\0' and then store the whole string up to the first '\0' in the executable_path array? (Note: I don't need to extract any of the other strings).

Thanks!

cfilescanfpid

Answers

answered 3 months ago Pablo #1

Don't use fscanf for this, if the command name has a space in it, you won't get the whole name.

You can use fgets, it will stop reading at the '\0'. I have right now a process running with pid 10979:

FILE *fp = fopen("/proc/10979/cmdline", "r");

char line[1024];
fgets(line, sizeof line, fp);

puts(line);

fclose(fp);

This prints:

/usr/bin/gvim

answered 3 months ago Nominal Animal #2

  1. /proc/PID/cmdline contains the command line used to execute the program (unless modified by the program itself). It does not contain the path to the executable; it only contains the path used to execute it.

    For example, if you execute foo bar baz, its /proc/PID/cmdline will contain foo\0bar\0baz\0.

    You can use e.g. getdelim() with '\0' as the delimiter to read the path to the executable.
     

  2. To get the actual path of the executable, examine the /proc/PID/exe symlink. It will always point to the executable.

    To read the symlink, you can use the POSIX.1 readlink() function provided by the C library.

    I have an example implementation in this answer.

    In Linux, there is a kernel "bug": if an executable is very deep in the filesystem hierarchy, the readlink() call on the /proc/PID/exe pseudo-symlink fails with ENAMETOOLONG error.
     

  3. The path to the executable can also be extracted from /proc/PID/stat.

    The name of the executable is between the first ( and last ) in that pseudo-file.

    You can use getline() to read the entire line (entire pseudofile, actually, because it only contains a newline at end), strchr() to locate the first ( in it, and strrchr() to locate the last ).
     

If you want to experiment with funny/nasty executable names, just run e.g.

ln -s /bin/cat $'foo)\nbar\n('
$'./foo)\nbar\n(' /proc/self/stat
rm $'foo)\nbar\n('

in Bash, and examine the contents of /proc/self/stat.

comments powered by Disqus