1

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?

  • 1
    pidof takes multiple program names, so this looks for any process called systemctl, stop, or Myservice. The obvious fix is to quote those three words as one string. However, that is probably not the process name: the program name is systemctl, and stop and Myservice are its arguments. You may need a specific ps -o pid,args | grep ... to achieve this. – Paul_Pedant Jun 07 '22 at 15:49
  • 1
    What language is that? PHP? Why are you redirecting the output to /dev/null? That's never going to return anything. And why compare it to 0? 0 is a very unlikely output. If that's PHP you probably want to use the second argument to system to get the return value. Otherwise you'll just get empty output in every case, which is never identical to 0. – frabjous Jun 07 '22 at 16:19
  • I was reading it that the system( ) call of whatever-language-that-is was coming back with the exit code of the executed command. If it does work in that manner, the approach seems valid, if not the command being run. If it doesn't work like that, well that is probably a discussion for a different Stack site. – bxm Jun 07 '22 at 16:24

2 Answers2

3

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)
procps-ng-3.3.10-28.el7.x86_64
$ rpm -q --whatprovides $(which ps)
procps-ng-3.3.10-28.el7.x86_64

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.

bxm
  • 4,855
  • pgrep is by default present in os or we need to install some package for it because I need to use ps aux or pidof os commands only. – Gaurav Baghel Jun 07 '22 at 16:24
  • If you are constrained in what commands you can use for some reason, please add those details to the question. It will probably be helpful to include information about the underlying OS as well. – bxm Jun 07 '22 at 16:27
  • in Linux pgrep is present by default ? – Gaurav Baghel Jun 07 '22 at 16:28
  • there are no constrained, just need to verify if this command works in every Linux platform, that's it like ps aux command – Gaurav Baghel Jun 07 '22 at 16:30
  • 1
    pgrep will be on most mainstream (server or desktop) linux distros. It won't be on tiny distros, which typically use busybox to provide very simple implementations of ps and many other programs. – cas Jun 08 '22 at 03:44
  • For an exact match, you'd also want to add the -x option to pgrep. Otherwise, it would match on oldsystemctl start MyServiceNew for instance (as it contains systemctl start MyService). To get the output of pgrep, the OP would also need to use popen() instead of system(). – Stéphane Chazelas Jun 08 '22 at 08:06
  • @GauravBaghel answer updated based on comments elsewhere. – bxm Jun 09 '22 at 05:55
0

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.

  • I am writing a c code if service named My service is stopped , i have to some specific action , that's why writing a c code, any better solution than this code? – Gaurav Baghel Jun 08 '22 at 10:08
  • bxm, I think your comment was intended for @GauravBaghel – Stéphane Chazelas Jun 08 '22 at 13:20
  • @bxm, at the time of stop action I am seeing the status is like this Active: deactivating (stop), how can I use this thing in c code to check this action – Gaurav Baghel Jun 08 '22 at 14:22
  • @StéphaneChazelas yes, apologies, my comment didn’t really belong on your answer, moved into my answer – bxm Jun 09 '22 at 05:56