1

Our system often uses ps -C cmdName to check if a process is running and, if not, restart it.

In moving from Centos 6 to Centos 8 it seems the behavior of ps -C has changed which broke much of our system.

Centos 6 (32-bit)

Yes, process is there:

# ps aux | grep DvBuildSegmentList
root     16223  4.0  0.1  16064 11272 pts/0    S    14:14   0:00 ./DvBuildSegmentList
root     16264  0.0  0.0   4416  1880 pts/0    S+   14:14   0:00 grep DvBuildSegmentList

And ps -C on full command name detects the process:

# ps -C DvBuildSegmentList
  PID TTY          TIME CMD
16223 pts/0    00:00:00 DvBuildSegmentL

(note truncated command line in output)

Centos 8 (64-bit)

Yes, process is there:

# ps aux | grep DvBuildSeg
root     15282  0.9  0.2  99796 42424 pts/1    S    14:18   0:04 ./DvBuildSegmentList
root     16989  0.0  0.0 221900  1104 pts/1    S+   14:26   0:00 grep --color=auto DvBuildSeg

Using full command name has no output:

# /bin/ps -C DvBuildSegmentList
  PID TTY          TIME CMD

But using a shortened command name does detect the process:

# /bin/ps -C DvBuildSegmentL
  PID TTY          TIME CMD
15282 pts/1    00:00:06 DvBuildSegmentL

We need to maintain both the 32-bit Centos 6 and the 64-bit Centos 8, ideally without re-writing a lot of code.

  1. Is there a way to get the same behavior of ps between versions? (might not be able to truncate the command name to the first 15 characters because of name collisions)

  2. Is there another approach to detect the process? (There's a lot of code and the ps -C approach is sprinkled across C++, perl, php, and bash)

EDIT I

For what its worth, the content of /proc/<pid>/stat shows the truncated file name:

cat /proc/4605/stat
4605 (DvBuildSegmentL) S 25769 4605 25769 34817 4605 1077936384 10536 304 0 0 225 119 0 0 20 0 1 0 6717759 103620608 10945 18446744073709551615 4194304 4339868 140734307933616 0 0 0 0 4096 16901 1 0 0 17 4 0 0 0 0 0 6438088 6440229 11730944 140734307937640 140734307937666 140734307937666 140734307938275 0

However, /proc/<pid>/cmdline does have the full command name albeit with the full path prepended to it

cat -v /proc/4605/cmdline
/usr/local/blah/blah/blah/DvBuildSegmentList^@-d^@2^@
  • As you have found, ps varies a lot between implementations. I recommend you to stick with the options listed in the POSIX specification if you want to keep portability. -C is not among them. – Quasímodo Aug 1 at 11:50
  • pgrep is more reliable than ps. Pid files are more reliable than either. Open files are more reliable than either. I don't know why the behavior of ps has changed. The truncation at 15 bytes comes from /proc/$pid/stat, but I don't know why ps -C would check that and not the command line from /proc/$pid/cmdline. – Gilles 'SO- stop being evil' Aug 1 at 23:40
  • pgrep behaves the same. DvBuildSegmentL is detected but anything longer is not found. – Danny Aug 14 at 7:41
0

One way I envision to work around this difference is to rebuild CentOS 6's version of procps package then yum swap from procps-ng to it. Not the safest approach, that will replace quite a handful of system programs with their older version.

So you might want to rebuild procps under a completely different name and having it install only ps, to e.g. /opt/el6-rebuilds/bin/ps. You would then ensure that the containing directory is on the system PATH, via /etc/profile.d facility. The result would be "equivalent to CentOS 6" ps version used in CentOS 8.

But all that saying, are you sure of that difference? Just tried it on my RHEL 8 and ps -C <program name> works just fine, when specified exactly (you actually say the opposite, that it only works when specified via partial string).

| improve this answer | |
  • Did you check with a name truncated to exactly 15 characters? That's the process name recorded in /proc/$pid/stat and some tools check that. A test with a different substring would not be conclusive. – Gilles 'SO- stop being evil' Aug 1 at 23:30
  • Just checked. /proc/<pid>/stat shows the truncated file name. Details added to the question above. – Danny Aug 14 at 7:29
0

These two approaches seem to work across OS versions:

grep for process name

ps aux | grep myLongProcessName | grep -v

returns 0 if the process is running and 1 if the process is not found. The second grep -v is needed because sometimes (but not always) the grep command itself appears in the output of grep myLongProcessName.

Send signal 0 via killall

killall -9 myLongProcessName

returns 0 if the process exists and 1 if the process is not found.

The "double grep" approach fails if 'myLongProcessName' is, in fact, a substring of another process. eg. If we have three processes:

  • longProcessDBAccess (not running)
  • longProcessDBAccessManager (running)
  • longProcessDBAccessClient (running)

Using the double grep approach to check if 'longProcessDBAccess' is running will fail because it also picks up the existence of the other two.

However, for the killall approach to work, the uid of the processing running killall must have permission to do so.

kill:

The kill() function shall send a signal to a process or a group of processes specified by pid. The signal to be sent is specified by sig and is either one from the list given in <signal.h> or 0. If sig is 0 (the null signal), error checking is performed but no signal is actually sent. The null signal can be used to check the validity of pid.

For a process to have permission to send a signal to a process designated by pid, unless the sending process has appropriate privileges, the real or effective user ID of the sending process shall match the real or saved set-user-ID of the receiving process.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.