How to Parse /Proc/Pid/Cmdline

parsing command-line arguments from proc/pid/cmdline

Something like this, but with more error checking, should be a good start (this is more C than C++, aside from the cout bit):

const int BUFSIZE = 4096; // should really get PAGESIZE or something instead...
unsigned char buffer[BUFSIZE]; // dynamic allocation rather than stack/global would be better

int fd = open("/proc/self/cmdline", O_RDONLY);
int nbytesread = read(fd, buffer, BUFSIZE);
unsigned char *end = buffer + nbytesread;
for (unsigned char *p = buffer; p < end; /**/)
{ cout << p << endl;
while (*p++); // skip until start of next 0-terminated section
}
close(fd);

In particular, open() and read() should be checked for error conditions, but I haven't shown that part... This may also fail in extreme cases where your command line is > 4096 characters long, or if for some other reason, read() doesn't read the file in one call, which shouldn't happen in current /proc implementations, but is not always guaranteed...

parsing proc/pid/cmdline to get function parameters

All of the command line parameters (what would come through as the argv[] array) are actually null-separated strings in /proc/XXX/cmdline.

abatkin@penguin:~> hexdump -C /proc/28460/cmdline
00000000 70 65 72 6c 00 2d 65 00 31 20 77 68 69 6c 65 20 |perl.-e.1 while |
00000010 74 72 75 65 00 |true.|

This explains why when you cat'ed cmdline they were all "stuck" together (cat ignored the invalid NULL characters) and why your cout stopped after the first command line argument (the process name) since it thought that the process name was a null-terminated string and stopped looking for more characters at that point.

Processing Command Line Arguments

To process the command line arguments, you have a couple options. If you just want the entire command line as one giant string, loop from the 0 to (numRead - 2) (where numRead is the number of characters read) and replace any NULL bytes (curByte == 0) with spaces. Then just make sure to set the last character to be a NULL byte too (in case things got truncated due to the fixed-size buffer).

If you instead want an array with all of the arguments, you need to be more creative. One option would be to loop from 0 to (numRead - 1) and could all of the NULL bytes that you find. Then allocate an array of char*'s of that length. Then loop back through the command line, setting the beginning of every string (i.e. the first byte in the array, plus each byte following a NULL byte) to consecutive elements of the array of char*'s.

Just know that since you read to a fixed-size buffer, anything beyond that buffer would be truncated. So remember that whatever you do, you probably need to manually make sure that the end of the last string ends up being NULL terminated, otherwise most string handling functions won't know where the string ends and will keep on going forever.

Reading /proc/ pid /cmdline in C, getting different results each time

processId should be a pid_t; note the original posted code using %s instead of %d; the return values from fopen() and fscanf() were ignored; output from printing temp was probably showing uninitialized stack data.  Example version:

#include <stdio.h>
#include <unistd.h>

int
main(void)
{
FILE *fp;
char buffer[256], temp[256] = { 0 };
pid_t processId;
int ns;

processId = getpid();
sprintf(buffer, "/proc/%d/cmdline", processId);
fp = fopen(buffer, "r");
if (fp == NULL) {
fprintf(stderr, "fopen() NULL, \"%s\"\n", buffer);
return (1);
}

// consider what happens if cmdline content is larger than temp
ns = fscanf(fp, "%[^\n]", temp);
fclose(fp);
printf("fscanf() returned %d\n", ns);
printf("[%s] (%d)\n", temp, processId);

return (0);
}

How is /proc/ pid /cmdline related to the argv variable of a process?

The file /proc/cmdline relates to a kernel command line and info from boot_params.

For user processes there are cmdline files in subdirs named with a process-id /proc/<pid>/cmdline; shell example: cat /proc/$$/cmdline. A series of struct pointers leads to process command line args; for details see proc_pid_cmdline_read()

note: some symbols may differ between releases

Finding the command for a specific PID in Linux from Python

Using a /proc files has a disadvantage of lower portability, which may or may not be a concern. Here's how you can use the standard shell command for that

ps -w -w -p <YOUR PID> -o cmd h

Note the two -w options that instructs ps to not truncate the output (which it does by default)

Reading its output from python is as simple as calling a single function subprocess.check_output() documented here.



Related Topics



Leave a reply



Submit