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 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: [email protected]/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 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 SSH connection.

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