|
|
|
@ -7,8 +7,64 @@ case "$SRC_ENABLED" in
|
|
|
|
esac
|
|
|
|
esac
|
|
|
|
# ---------------------------------
|
|
|
|
# ---------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# pstree_compat.sh
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# Meant to be sourced (e.g. from .bashrc). Defines functions only —
|
|
|
|
|
|
|
|
# sourcing this file must never print anything or execute pstree.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# Compatibility target: bash 3.2+ (RHEL 5) and bash 4.1 (Debian Squeeze).
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# CAVEAT: this guard only protects against an old/wrong *bash*. If this
|
|
|
|
|
|
|
|
# file is sourced by a non-bash POSIX shell (e.g. dash as /bin/sh on
|
|
|
|
|
|
|
|
# Debian), the bashisms below (arrays, [[ ]], local -a) will cause a
|
|
|
|
|
|
|
|
# parse error at function-definition time, before any runtime check
|
|
|
|
|
|
|
|
# can run. Only source this from bash (.bashrc, not .profile/.sh).
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# After sourcing, call:
|
|
|
|
|
|
|
|
# pstree_compat # root pid 1
|
|
|
|
|
|
|
|
# pstree_compat 1234 # specific pid
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# Returns 0 if running under bash >= 3.0, else prints an error to
|
|
|
|
|
|
|
|
# stderr and returns 1. Called at the top of every public entry point,
|
|
|
|
|
|
|
|
# never at source time.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
bash_pstree_check_bash()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if [[ -z "$BASH_VERSION" ]]; then
|
|
|
|
|
|
|
|
printf 'pstree_compat: requires bash, current shell is not bash\n' >&2
|
|
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [[ -z "${BASH_VERSINFO[0]}" ]] || (( BASH_VERSINFO[0] < 3 )); then
|
|
|
|
|
|
|
|
printf 'pstree_compat: requires bash >= 3.0 (found %s)\n' "$BASH_VERSION" >&2
|
|
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pstree_compat()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
bash_pstree_check_bash || return 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local root_pid="${1:-1}"
|
|
|
|
|
|
|
|
if command -v pstree >/dev/null 2>&1; then
|
|
|
|
|
|
|
|
pstree -p "$root_pid"
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
bash_pstree "$root_pid"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# Iterative (non-recursive) process tree walker.
|
|
|
|
|
|
|
|
# Avoids deep bash function recursion, which can blow the stack
|
|
|
|
|
|
|
|
# and crash the shell on large/deep process trees.
|
|
|
|
|
|
|
|
#
|
|
|
|
bash_pstree()
|
|
|
|
bash_pstree()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
bash_pstree_check_bash || return 1
|
|
|
|
|
|
|
|
|
|
|
|
local root_pid="${1:-1}"
|
|
|
|
local root_pid="${1:-1}"
|
|
|
|
local procdir pid key value name ppid idx
|
|
|
|
local procdir pid key value name ppid idx
|
|
|
|
|
|
|
|
|
|
|
|
@ -17,9 +73,6 @@ bash_pstree()
|
|
|
|
NAMES=()
|
|
|
|
NAMES=()
|
|
|
|
idx=0
|
|
|
|
idx=0
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# Build process table from /proc/*/status.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
for procdir in /proc/[0-9]*; do
|
|
|
|
for procdir in /proc/[0-9]*; do
|
|
|
|
[[ -d "$procdir" ]] || continue
|
|
|
|
[[ -d "$procdir" ]] || continue
|
|
|
|
[[ -r "$procdir/status" ]] || continue
|
|
|
|
[[ -r "$procdir/status" ]] || continue
|
|
|
|
@ -41,33 +94,28 @@ bash_pstree()
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
bash_pstree_set_chars
|
|
|
|
bash_pstree_set_chars
|
|
|
|
bash_pstree_root "$root_pid"
|
|
|
|
|
|
|
|
|
|
|
|
if ! bash_pstree_find_name "$root_pid" >/dev/null; then
|
|
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bash_pstree_walk "$root_pid"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# Pick UTF-8 box-drawing chars if the locale supports them, else
|
|
|
|
|
|
|
|
# fall back to plain ASCII (works on any RHEL5 console/terminal).
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
bash_pstree_set_chars()
|
|
|
|
bash_pstree_set_chars()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
local charmap
|
|
|
|
local charmap
|
|
|
|
charmap=$(locale charmap 2>/dev/null)
|
|
|
|
charmap=$(locale charmap 2>/dev/null)
|
|
|
|
|
|
|
|
|
|
|
|
if [[ "$charmap" == "UTF-8" ]]; then
|
|
|
|
if [[ "$charmap" == "UTF-8" ]]; then
|
|
|
|
BPT_VERT="│ "
|
|
|
|
BPT_VERT="│ "; BPT_TEE="├── "; BPT_LAST="└── "
|
|
|
|
BPT_TEE="├── "
|
|
|
|
|
|
|
|
BPT_LAST="└── "
|
|
|
|
|
|
|
|
else
|
|
|
|
else
|
|
|
|
BPT_VERT="| "
|
|
|
|
BPT_VERT="| "; BPT_TEE="|-- "; BPT_LAST="\`-- "
|
|
|
|
BPT_TEE="|-- "
|
|
|
|
|
|
|
|
BPT_LAST="\`-- "
|
|
|
|
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bash_pstree_find_name()
|
|
|
|
bash_pstree_find_name()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
local target="$1"
|
|
|
|
local target="$1" i
|
|
|
|
local i
|
|
|
|
|
|
|
|
for ((i = 0; i < ${#PIDS[@]}; i++)); do
|
|
|
|
for ((i = 0; i < ${#PIDS[@]}; i++)); do
|
|
|
|
if [[ "${PIDS[$i]}" == "$target" ]]; then
|
|
|
|
if [[ "${PIDS[$i]}" == "$target" ]]; then
|
|
|
|
printf '%s' "${NAMES[$i]}"
|
|
|
|
printf '%s' "${NAMES[$i]}"
|
|
|
|
@ -78,13 +126,12 @@ bash_pstree_find_name()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# Print numerically-sorted child PIDs of $1, one per line.
|
|
|
|
# Prints numerically-sorted children of $1, one per line.
|
|
|
|
|
|
|
|
# Called once per node during the iterative walk (not recursively).
|
|
|
|
#
|
|
|
|
#
|
|
|
|
bash_pstree_children()
|
|
|
|
bash_pstree_children()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
local parent="$1"
|
|
|
|
local parent="$1" i list=""
|
|
|
|
local i list
|
|
|
|
|
|
|
|
list=""
|
|
|
|
|
|
|
|
for ((i = 0; i < ${#PIDS[@]}; i++)); do
|
|
|
|
for ((i = 0; i < ${#PIDS[@]}; i++)); do
|
|
|
|
if [[ "${PPIDS[$i]}" == "$parent" ]]; then
|
|
|
|
if [[ "${PPIDS[$i]}" == "$parent" ]]; then
|
|
|
|
list="$list${PIDS[$i]}
|
|
|
|
list="$list${PIDS[$i]}
|
|
|
|
@ -94,56 +141,78 @@ bash_pstree_children()
|
|
|
|
[[ -n "$list" ]] && printf '%s' "$list" | sort -n
|
|
|
|
[[ -n "$list" ]] && printf '%s' "$list" | sort -n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bash_pstree_root()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
local pid="$1" name
|
|
|
|
|
|
|
|
name=$(bash_pstree_find_name "$pid") || return
|
|
|
|
|
|
|
|
printf '%s(%s)\n' "$name" "$pid"
|
|
|
|
|
|
|
|
bash_pstree_show_children "$pid" ""
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# $1 = parent pid, $2 = prefix accumulated so far
|
|
|
|
# Iterative preorder walk using an explicit stack (three parallel
|
|
|
|
|
|
|
|
# arrays) instead of function recursion.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
bash_pstree_show_children()
|
|
|
|
bash_pstree_walk()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
local parent="$1" prefix="$2"
|
|
|
|
local root_pid="$1"
|
|
|
|
local child name last_line
|
|
|
|
local -a S_PID S_PRINT_PREFIX S_CHILD_PREFIX
|
|
|
|
|
|
|
|
local top pid print_prefix child_prefix name
|
|
|
|
|
|
|
|
local children child last_child new_prefix branch cont
|
|
|
|
|
|
|
|
local -a rev_children
|
|
|
|
|
|
|
|
local i n visited_guard=0
|
|
|
|
|
|
|
|
local max_iterations=200000 # safety valve against any /proc PPid cycle
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
S_PID=("$root_pid")
|
|
|
|
|
|
|
|
S_PRINT_PREFIX=("")
|
|
|
|
|
|
|
|
S_CHILD_PREFIX=("")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while [[ ${#S_PID[@]} -gt 0 ]]; do
|
|
|
|
|
|
|
|
visited_guard=$((visited_guard + 1))
|
|
|
|
|
|
|
|
if [[ $visited_guard -gt $max_iterations ]]; then
|
|
|
|
|
|
|
|
printf 'bash_pstree: aborting, too many nodes (possible /proc cycle)\n' >&2
|
|
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
top=$((${#S_PID[@]} - 1))
|
|
|
|
|
|
|
|
pid="${S_PID[$top]}"
|
|
|
|
|
|
|
|
print_prefix="${S_PRINT_PREFIX[$top]}"
|
|
|
|
|
|
|
|
child_prefix="${S_CHILD_PREFIX[$top]}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# pop
|
|
|
|
|
|
|
|
unset 'S_PID[top]' 'S_PRINT_PREFIX[top]' 'S_CHILD_PREFIX[top]'
|
|
|
|
|
|
|
|
S_PID=("${S_PID[@]}")
|
|
|
|
|
|
|
|
S_PRINT_PREFIX=("${S_PRINT_PREFIX[@]}")
|
|
|
|
|
|
|
|
S_CHILD_PREFIX=("${S_CHILD_PREFIX[@]}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
name=$(bash_pstree_find_name "$pid") || continue
|
|
|
|
|
|
|
|
printf '%s%s(%s)\n' "$print_prefix" "$name" "$pid"
|
|
|
|
|
|
|
|
|
|
|
|
local children
|
|
|
|
children=$(bash_pstree_children "$pid")
|
|
|
|
children=$(bash_pstree_children "$parent")
|
|
|
|
[[ -n "$children" ]] || continue
|
|
|
|
[[ -n "$children" ]] || return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
last_line=$(printf '%s\n' "$children" | tail -n 1)
|
|
|
|
last_child=$(printf '%s\n' "$children" | tail -n 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rev_children=()
|
|
|
|
|
|
|
|
n=0
|
|
|
|
while IFS= read -r child; do
|
|
|
|
while IFS= read -r child; do
|
|
|
|
[[ -n "$child" ]] || continue
|
|
|
|
[[ -n "$child" ]] || continue
|
|
|
|
name=$(bash_pstree_find_name "$child") || continue
|
|
|
|
rev_children[$n]="$child"
|
|
|
|
if [[ "$child" == "$last_line" ]]; then
|
|
|
|
n=$((n + 1))
|
|
|
|
printf '%s%s%s(%s)\n' "$prefix" "$BPT_LAST" "$name" "$child"
|
|
|
|
|
|
|
|
bash_pstree_show_children "$child" "${prefix} "
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
printf '%s%s%s(%s)\n' "$prefix" "$BPT_TEE" "$name" "$child"
|
|
|
|
|
|
|
|
bash_pstree_show_children "$child" "${prefix}${BPT_VERT}"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
done <<< "$children"
|
|
|
|
done <<< "$children"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
for ((i = n - 1; i >= 0; i--)); do
|
|
|
|
# Wrapper:
|
|
|
|
child="${rev_children[$i]}"
|
|
|
|
#
|
|
|
|
if [[ "$child" == "$last_child" ]]; then
|
|
|
|
# pstree_compat
|
|
|
|
branch="$BPT_LAST"
|
|
|
|
# pstree_compat 1234
|
|
|
|
cont="${child_prefix} "
|
|
|
|
#
|
|
|
|
|
|
|
|
pstree_compat()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
local root_pid="${1:-1}"
|
|
|
|
|
|
|
|
if command -v pstree >/dev/null 2>&1; then
|
|
|
|
|
|
|
|
pstree -p "$root_pid"
|
|
|
|
|
|
|
|
else
|
|
|
|
else
|
|
|
|
bash_pstree "$root_pid"
|
|
|
|
branch="$BPT_TEE"
|
|
|
|
|
|
|
|
cont="${child_prefix}${BPT_VERT}"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
new_prefix="${child_prefix}${branch}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
S_PID+=("$child")
|
|
|
|
|
|
|
|
S_PRINT_PREFIX+=("$new_prefix")
|
|
|
|
|
|
|
|
S_CHILD_PREFIX+=("$cont")
|
|
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
done
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
alias pstree='pstree_compat'
|
|
|
|
# NOTE: intentionally no code runs here. Sourcing this file must be a no-op
|
|
|
|
|
|
|
|
# other than defining the functions above.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
alias pstree="pstree_compat"
|
|
|
|
|
|
|
|
|
|
|
|
|