lxc-ps: use posix shell and awk instead of bash

Use awk to parse the output pf 'ps' and the tasks files for the
containers.

Use awk fields to find PID column rather than assume that the PID field
is exactly 5 chars wide and has a leading space ' PID'. This works as
long as the PID field is before the command or other field that include
spaces. This also makes it work with busybox 'ps'.

Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
This commit is contained in:
Natanael Copa 2012-12-26 22:31:56 +01:00 committed by Stéphane Graber
parent 600faead38
commit b5dec5f30b

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
# lxc: linux Container library
@ -56,16 +56,16 @@ get_parent_cgroup()
init_cgroup=${fields#*:}
# Get the filesystem mountpoint of the hierarchy
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
mountpoint=$(awk -v subsysregex="(^|,)$subsystems(,|\$)" \
'$3 == "cgroup" && $4 ~ subsysregex {print $2}' /proc/self/mounts)
if [ -z "$mountpoint" ]; then continue; fi
# Return the absolute path to the containers' parent cgroup
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
if [[ ",$subsystems," == *,ns,* ]]; then
parent_cgroup="${mountpoint}${init_cgroup%/}"
else
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
fi
case ",$subsystems," in
*,ns,*) parent_cgroup="${mountpoint}${init_cgroup%/}";;
*) parent_cgroup="${mountpoint}${init_cgroup%/}/lxc";;
esac
break
done
}
@ -97,46 +97,62 @@ if [ ! -d "$parent_cgroup" ]; then
exit 1
fi
declare -a container_of_pid
container_field_width=9
IFS=","
if [ -z "$containers" ]; then
containers=( $(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d -printf "%f," 2>/dev/null) )
else
containers=( $containers )
containers="$(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')"
fi
declare -i pid
IFS=$'\n'
for container in ${containers[@]}; do
container_field_width=9
tasks_files=
for container in ${containers}; do
if [ "${#container}" -gt "$container_field_width" ]; then
container_field_width=${#container}
fi
if [ -f "$parent_cgroup/$container/tasks" ]; then
while read pid; do
container_of_pid[$pid]=$container
done < "$parent_cgroup/$container/tasks"
tasks_files="$tasks_files $parent_cgroup/$container/tasks"
fi
done
declare -i line_pid_end_position
while read line; do
if [ -z "$line_pid_end_position" ]; then
if [[ "$line" != *" PID"* ]]; then
echo "$(basename $0): no PID column found in \`ps' output" >&2
exit 1
fi
# first file is stdin, the rest are the container tasks
ps "$@" | awk -v container_field_width="$container_field_width" '
# first line is PS header
NR == 1 {
# find pid field index
for (i = 1; i<=NF; i++)
if ($i == "PID") {
pididx = i
break
}
if (pididx == "") {
print("No PID field found") > "/dev/stderr"
exit 1
}
header = $0
next
}
buffer=${line%" PID"*}
let line_pid_end_position=${#buffer}+4
printf "%-${container_field_width}s %s\n" "CONTAINER" "$line"
continue
fi
# store lines from ps with pid as index
NR == FNR {
ps[$pididx] = $0
next
}
buffer=${line:0:$line_pid_end_position}
pid=${buffer##* }
if [ "$list_container_processes" -eq "0" -o ! -z "${container_of_pid[pid]}" ]; then
printf "%-${container_field_width}s %s\n" "${container_of_pid[pid]}" "$line"
fi
done < <(ps "$@")
# find container name from filename on first line
FNR == 1 {
container = FILENAME
sub(/\/tasks/, "", container)
sub(/.*\//, "", container)
}
# container tasks
{
container_of_pid[$0] = container
}
END {
printf("%-" container_field_width "s %s\n", "CONTAINER", header)
for (pid in container_of_pid)
printf("%-" container_field_width "s %s\n", container_of_pid[pid], ps[pid])
}
' - $tasks_files