Linux – Best way to tag/identify processes for killing them later

linuxstartup-scripts

In my linux startup scripts, when I start a process like (openvpn used for this example, but the question is general to any process);

openvpn --config /etc/myserver.conf

what is the best way to find it and be 100% certain it's the right process and kill it in the stop section? I normally use stuff like:

pid=$(ps -efww | grep -v grep | grep openvpn | grep /etc/myserver.conf | awk '{print $2}')

Sure it works nearly all of the time, but sometimes there are issues with accidentally matching processes with nearly the same name (e.g. myserver.conf-new), so I'm looking for a better approach.

  • Some processes have a way to store the pid somewhere, that's fine, but generally I'm skeptical of killing processes solely based on a pid sitting in a file somewhere.
  • Solaris has projects, it's not all roses in my limited experience because you have to set up /etc/projects first, but it does make it easy to tag and later find processes.
  • Maybe using the environment, like setting an environment variable like (MYID=myserver) and then looking for it with ps e -ef | grep MYID=myserver? Still may suffer the same problem with accidental matching.

I wish there were something easy like:

launch --tag myserver openvpn --config /etc/myserver.conf

and

pgrep --tag myserver

Best Answer

Thank you @Iain, @KyleSmith, and @M_1 for your answers, and for helping me get started on Server Fault. If I had more rep here I'd +1 you guys. (Edit: now I have rep, +1s all around).

I'm going to answer my own question because I've found something that does what I was looking for: a general solution that avoids imprecise pattern matching with ps, and doesn't use pid files. It's completely subjective that this would be the "best" way because there's obviously a long and successful history in unix of using pid files, however this was something I explicitly said I didn't like for various reasons, and those are: they can be tricky to create properly, different for every piece of software, done differently on every distro, can be stale/overwritten, and inherently don't necessarily represent what's actually going on. I'd rather use some kind of process tagging, ask the kernel and get real answers.

Trimmed down example:

#!/bin/sh
_TAG=d726cc7fa57a308afdc057b228a13f6d
case "$1" in
start)
  _TAG=$_TAG ./self-backgrounding-process
  _TAG=$_TAG ./non-self-backgrounding-process &
  ;;
stop)
  pids=$(grep -l "\b_TAG=$_TAG\b" /proc/*/environ | cut -d/ -f3)
  [ -n "$pids" ] && kill $pids
  ;;
esac

The key points are:

  • using an md5sum (something very unlikely to be accidentally matched) for the tag
  • using a different tag in each service's startup script
  • querying /proc/*/environ to get an accurate list of running/relevant/tagged processes
  • using grep with \b to match word boundaries to ensure an exact match

I'm not sure I like polluting the environment, but I don't know of any other way (e.g. Solaris projects) to tag a linux process in an arbitrary way that I can ask the kernel for later. At least, /proc/<pid>/environ appears to reflect the environment at startup, and not be affected by any changes the process might make after, which suggests this should be reliable, however, there's the chance this could change unexpectedly. This may or may not work outside Linux, depending on the OS's /proc and grep implementation.

I think I'll give it a try for a while and see how it goes.

Related Topic