Categories
SysOps

How to inspect parent processes

Inspect parent processes to determine whether shell script or specific process has been executed locally, remotely, or by any other application.

Shell scripts

Use list_ppids.sh to display patent processes inside a shell script.

#!/bin/bash
# Display parent processes

# set pid
pid=$$
[ -n "$pid" ] || exit 1

# set ppid (parent pid)
ppid=$PPID
[ -n "$ppid" ] || exit 1

# print header
printf "%-5s %-5s %s\n" "PID" "PPID" "CMDLINE"

# iterate from pid to process 1
while [ "$pid" -ge 1 ]; do
  # get cmdline
  cmdline="$(tr  '\0' ' ' </proc/$pid/cmdline)"
  
  # 0 is not a valid ppid
  [ $ppid -eq 0 ] && ppid=""

  # print pid, ppid, cmdline
  printf "%-5s %-5s %s\n" "$pid" "$ppid" "$cmdline"

  # define new pid and ppid or exit
  [ -z $ppid ] && break
  pid=$ppid
  ppid=$(awk -F: '$1 == "PPid" {gsub(/^[ \t]+/, "", $2); print $2}' /proc/$pid/status)
done

Use am_i_child_of.sh shell script to inspect parent processes.

#!/bin/bash
# Check if I am child of specific process and display results

# Check if I am child of specific process
# Example: am_i_child_of "sshd"
# Return values:
#  0              - no
#  1              - yes
#  anything else - specific error
function am_i_child_of() {
  look_for_parent="$1"
  [ -n "$look_for_parent" ] || return 255

  # set ppid (parent pid)
  ppid=$PPID
  [ -n "$ppid" ] || return 253

  # iterate from ppid to process 1
  while [ "$ppid" -ge 1 ]; do
    # check cmdline for parent
    cmdline_check="$(tr  '\0' ' ' </proc/$ppid/cmdline | grep -w $look_for_parent)"

    # return 1 when parent is found
    [ -n "$cmdline_check" ] && return 1

    # define new ppid
    ppid=$(awk -F: '$1 == "PPid" {gsub(/^[ \t]+/, "", $2); print $2}' /proc/$ppid/status)
  done
}

# pretty print am_i_child_of result 
human_result_of_am_i_child_of() {
  case "$1" in
    "0") echo "I am not a child of this process" ;;
    "1") echo "I am a child of this process" ;;
    *)   echo "There was an error" ;;
  esac
}

# Sample usage

echo "Am I child of null?"
am_i_child_of ""
human_result_of_am_i_child_of $?
echo

echo "Am I child of mc?"
am_i_child_of "mc"
human_result_of_am_i_child_of $?
echo

echo "Am I child of sshd?"
am_i_child_of "sshd"
human_result_of_am_i_child_of $?
echo

echo "Am I child of kdeinit5?"
am_i_child_of "kdeinit5"
human_result_of_am_i_child_of $?
echo

echo "Am I child of init?"
am_i_child_of "init"
human_result_of_am_i_child_of $?

Use is_pid_child_of.sh shell script to inspect parent processes for specific PID.

#!/bin/bash
# Check if provided PID is a child of specific process and display results

# Check if provided PID is a child of specific process
# Example: is_pid_child_of "2341" "sshd"
# Return values:
#  0              - no
#  1              - yes
#  anything else - specific error
function is_pid_child_of() {
  pid="$1"
  [ -n "$pid" ] || return 252

  ppid=$(awk -F: '$1 == "PPid" {gsub(/^[ \t]+/, "", $2); print $2}' /proc/$pid/status)
  [ -n "$ppid" ] || return 253

  look_for_parent="$2"
  [ -n "$look_for_parent" ] || return 255

  # iterate from ppid to process 1
  while [ "$ppid" -ge 1 ]; do
    # check cmdline for parent
    cmdline_check="$(tr  '\0' ' ' </proc/$ppid/cmdline | grep -w $look_for_parent)"

    # return 1 when parent is found
    [ -n "$cmdline_check" ] && return 1

    # define new ppid
    ppid=$(awk -F: '$1 == "PPid" {gsub(/^[ \t]+/, "", $2); print $2}' /proc/$ppid/status)
  done
  return 0
}

# Params
pid=$1
process="sshd"

# Sample usage
echo "Is PID ${pid} child of ${process}? "
is_pid_child_of "$pid" "$process"
exit_code="$?"
if [ "$exit_code" -eq "1" ]; then
  echo "PID ${pid} is a child of ${process}"
elif [ "$exit_code" -eq "0" ]; then
  echo "PID ${pid} is not a child of ${process}"
else
  echo "There was an error"
fi

Usage

Use list_ppids.sh locally to display parent processes.

local$ bash list_ppids.sh
PID   PPID  CMDLINE
11536 9918  bash list_ppids.sh 
9918  9916  bash -rcfile .bashrc 
9916  2191  mc 
2191  2183  bash 
2183  2088  bash 
2088  3699  /bin/bash 
3699  3534  /usr/bin/konsole -session 10197196ff12b000155643869600000066580014_1559489111_488515 
3534  1     kdeinit5: Running...                                   
1           /sbin/init splash

Use list_ppids.sh over SSH connection to display parent processes.

remote$ bash list_ppids.sh
PID   PPID  CMDLINE
14328 14139 bash list_ppids.sh
14139 14138 -bash 
14138 14106 sshd: milosz@pts/3   
14106 105   sshd: milosz [priv]  
105   1     /usr/sbin/sshd -D 
1           /sbin/init

Use am_i_child_of.sh locally.

local$ bash am_i_child_of.sh
Am I child of null?
There was an error

Am I child of mc?
I am a child of this process

Am I child of sshd?
I am not a child of this process

Am I child of kdeinit5?
I am a child of this process

Am I child of init?
I am a child of this process

Use am_i_child_of.sh remotely.

remote$ bash am_i_child_of.sh
Am I child of null?
There was an error

Am I child of mc?
I am not a child of this process

Am I child of sshd?
I am a child of this process

Am I child of kdeinit5?
I am not a child of this process

Am I child of init?
I am a child of this process

Use is_pid_child_of.sh to check if a local process is executed over the SSH connection.

local$ bash is_pid_child_of.sh 9918
Is PID 9918 child of sshd? 
PID 9918 is not a child of sshd

Use is_pid_child_of.sh to check if a remote process is executed over the SSH connection.

remote$ bash is_pid_child_of.sh 14139
Is PID 14139 child of sshd? 
PID 14139 is a child of sshd