views:

486

answers:

5

I'd like to know if it's possible to find out the "command" that a PID is set to. When I say command, I mean what you see in the last column when you run the command "top" in a linux shell. I'd like to get this information from Python somehow when I have a specific PID.

Any help would be great. Thanks.

+3  A: 

Read up on the ps command and parse its output.

ps -p [PID] -o cmd

should do it

Ben S
A: 

The proc filesystem exports this (and other) information. Look at the /proc/PID/cmd symlink.

Kristof Provost
+4  A: 

Look in /proc/$PID/cmdline

DigitalRoss
Thank you. This works great.
Evan Fosmark
+2  A: 

PLEASE, do not use /proc filesystem in production code. Instead, use well-defined POSIX interfaces, such as glibc calls and standard shell commands! Make the Linux world more standardized, it really needs to!

What you need is well achieved by invoking a shell command

ps -p <YOUR PID> -o cmd h

No parsing is needed!

Let alone that reading shell command output from python takes no more effort than reading from a file in /proc. And this makes your program more portable, either!

Pavel Shved
All sort of true, but the question was for linux, so we did answer the actual question, and I think most of us made the assumption that he knew about `ps(1)`.
DigitalRoss
@DigitalRoss: then the question would sound like "Where does `ps` take command line info from?"
Pavel Shved
Little too pretentious for me.
Nick Stinemates
ps works by reading the virtual files in /proc. So much for the well-defined POSIX interface (which one was that, anyway?).
Michael Foukarakis
Listen, I would have marked you both as correct answers but I couldn't. Pavel's answer just seemed to be more of what I was looking for but the answer given for DigitalRoss was great too. Upvotes for both.
Evan Fosmark
@Nick Stinemates, @Michael Foukarakis. Hey, I know how ps works (yes, it indeed reads files in `/proc`). But when instead of `/proc` they'll invent `/foobar` system, you'll have to rewrite your program. Anyway, maybe I've been braindamaged by working in LSB workgroup, but you really should stick to standards where it's enough for you--which is the case under consideration.
Pavel Shved
+2  A: 

Look in /proc/$PID/cmdline, and then os.readlink() on /proc/$PID/exe.

/proc/$PID/cmdline is not necessarily going to be correct, as a program can change its argument vector or it may not contain a full path. Three examples of this from my current process list are:

  • avahi-daemon: chroot helper
  • qmgr -l -t fifo -u
  • /usr/sbin/postgrey --pidfile=/var/run/postgrey.pid --daemonize --inet=127.0.0.1:60000 --delay=55

That first one is obvious - it's not a valid path or program name. The second is just an executable with no path name. The third looks ok, but that whole command line is actually in argv[0], with spaces separating the arguments. Normally you should have NUL separated arguments.

All this goes to show that /proc/$PID/cmdline (or the ps(1) output) is not reliable.

However, nor is /proc/$PID/exe. Usually it is a symlink to the executable that is the main text segment of the process. But sometimes it has " (deleted)" after it if the executable is no longer in the filesystem.

Also, the program that is the text segment is not always what you want. For instance, /proc/$PID/exe from that /usr/sbin/postgrey example above is /usr/bin/perl. This will be the case for all interpretted scripts (#!).

I settled on parsing /proc/$PID/cmdline - taking the first element of the vector, and then looking for spaces in that, and taking all before the first space. If that was an executable file - I stopped there. Otherwise I did a readlink(2) on /proc/$PID/exe and removed any " (deleted)" strings on the end. That first part will fail if the executable filename actually has spaces in it. There's not much you can do about that.

BTW. The argument to use ps(1) instead of /proc/$PID/cmdline does not apply in this case, since you are going to fall back to /proc/$PID/exe. You will be dependent on the /proc filesystem, so you may as well read it with read(2) instead of pipe(2), fork(2), execve(2), readdir(3)..., write(2), read(2). While ps and /proc/$PID/cmdline may be the same from the point of view of lines of python code, there's a whole lot more going on behind the scenes with ps.

camh
Great write-up. Thanks for this, camh.
Evan Fosmark