How to get pid of process with exact name?

I am trying to get id of process name systemctl stop Myservice but not exact pid through this command

   if(0 == system("pidof -x systemctl stop Myservice  > /dev/null")) {
  //A process is running.

This code is giving pid of systemctl start Myservice also if it is running in system, need to get specific pid for this process name "systemctl stop Myservice" only?

Asked By: Gaurav Baghel


If available on your system pgrep seems like a good fit here

pgrep -xf "systemctl stop Myservice"

pgrep is provided by the same package as ps (at least it is on the CentOS 7 system I referred to)

$ rpm -q --whatprovides $(which pgrep)
$ rpm -q --whatprovides $(which ps)

Even lightweight distros using BusyBox seem to be OK from a narrow test:

$ docker run --rm alpine pgrep --help
BusyBox v1.35.0 (2022-05-09 17:27:12 UTC) multi-call binary.

Usage: pgrep [-flanovx] [-s SID|-P PPID|PATTERN]

So I would think that if you have ps you can rely on pgrep, though things could be a bit less certain if your code ends up running inside a container (though this scenario seems pretty unlikely, given what you’re attempting to do).

Are you trying to catch the systemctl stop ... command in action? This seems like it would be quite prone to race conditions and/or performance issues. What if the C program loops too slowly and misses the command running, or too quickly and consumes excessive CPU?

If your goal is simply to detect when the service leaves active state, this approach might be better:

systemctl status Myservice | grep -qE "^ +Active: active"

This should return a non zero exit code if the service is in anything other than active state.

As per your use case, it might be necessary to only flag when the state changes — rather than every time it sees non-active, via some additional logic.

Answered By: bxm

On Linux, the process name is a sequence of 0 to 15 bytes used to name processes. The name of a process changes any time that command executes a command to the first 15 bytes of the basename of the file being executed or when using pctrl(PR_SET_NAME) for instance.

That systemctl stop Myservice looks more like the concatenation with spaces of 3 arguments passed to /usr/bin/systemctl when it was executed by the process or one of its ancestors.

Assuming you want the pids of processes that are currently executing a /usr/bin/systemctl that was passed the systemctl, stop and Myservice arguments upon execution, on Linux, the approach would be to:

  • do a stat() on /proc/*/exe files and check that the st_dev and st_ino are the same as that returned by stat("/usr/bin/systemctl") (assuming that systemd has not been updated since the process executed systemctl).
  • and then check that the /proc/<pid>/cmdline file for the corresponding process contains systemctl<NUL>stop<NUL>Myservice<NUL> (bearing in mind that processes can — though generally don’t — modify that arbitrarily).

I can’t think why you’d want to do that though, especially in a C / C++ program. That looks like an XY Problem.

Answered By: Stéphane Chazelas
Categories: Answers Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.