19
17
# License along with this library; if not, write to the Free Software
20
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
# This script allows to
24
# display processes information with related container name if available.
31
our $PS_HEADERS; # String containing headers of the ps output
32
our $PS_PID_INDEX; # Index of the PID column in the ps headers
33
our @PS_LINES; # Output lines of the ps command
35
our $LXC_DISPLAY = 0; # By default do not display container information
36
our %LXC_NAMES; # Specified container names (if any)
38
sub get_container_names {
39
my $ref_names = shift;
40
my $lxcpath = '@LXCPATH@';
42
open(active, "netstat -xa | grep $lxcpath |") or return;
45
s#.*$lxcpath/(.*)/command.*#$1#;
52
my $ref_cgroup = shift;
55
$mount_string=`mount -t cgroup |grep -E -e '^lxc '`;
57
# use the one 'lxc' cgroup mount if it exists
59
$$ref_cgroup=`echo "$mount_string" |cut -d' ' -f3`;
62
# Otherwise (i.e. cgroup-bin) use the first cgroup mount
63
$mount_string=`grep -m1 -E '^[^ \t]+[ \t]+[^ \t]+[ \t]+cgroup' /proc/self/mounts`;
64
unless ($mount_string) {
65
die "unable to find mounted cgroup" unless $$ref_cgroup;
68
$$ref_cgroup=`echo "$mount_string" |cut -d' ' -f2`;
73
sub get_pids_in_containers {
74
my $ref_names = shift;
75
my $ref_cgroup = shift;
77
my $init_cgroup = shift;
81
my $task_file = "$$ref_cgroup/$init_cgroup/lxc/$_/tasks";
84
open(tasks, "cat $task_file 2>/dev/null |") or next;
91
$$ref_pids = join(',', @pidlist);
94
sub reclaim_pid_index {
95
my @headers = split " ", $PS_HEADERS;
96
for my $i (0 .. $#headers) {
97
if ($headers[$i] eq "PID") {
102
print "Cannot find ps PID column !\n";
107
open(ps, "ps @_ |") or die "Cannot execute ps command: $!\n";
118
sub get_init_cgroup {
119
my $filename = "/proc/1/cgroup";
120
open(LXC, "$filename");
124
foreach ( @cgroup ) {
126
# find the container name after :/
134
my $filename = "/proc/$pid/cgroup";
135
open(LXC, "$filename");
136
# read all lines at once
140
foreach ( @cgroup ) {
142
# find the container name after :/
144
# chop off everything up to 'lxc/'
151
sub display_headers {
152
printf "%-10s %s", "CONTAINER", $PS_HEADERS;
157
Usage: lxc-ps [--help] [--usage] [-n|--name NAME...] [--lxc] [-- ps options]
165
Display processes information with related container name if available.
168
--help Display this help.
169
--usage Display the command usage.
170
--name Display processes related to given containers.
171
Containers are identified by a comma separated list of
173
--lxc Display processes related to all lxc containers.
175
Other available options correspond to the ps ones, see the ps manual
176
or try a 'ps --help' for further details.
180
use Getopt::Long qw(:config pass_through);
186
my $init_cgroup = '/';
188
GetOptions('help' => \$arg_help,
189
'usage' => \$arg_usage,
191
'name=s' => \@arg_name);
193
@arg_name = split(/,/, join(',', @arg_name));
196
if ($arg_help) {display_help; exit 0;}
197
if ($arg_usage) {display_usage; exit 0;}
199
if ($ARGV[0] == '--') {
203
# Should we filter processes related to containers
206
get_container_names \@arg_name;
213
$init_cgroup = get_init_cgroup();
215
get_pids_in_containers(\@arg_name, \$cgroup, \$pid_list, $init_cgroup);
217
@ARGV = ("-p $pid_list",@ARGV);
226
my $container = get_container $a[$PS_PID_INDEX];
227
if ($LXC_DISPLAY == 2 and not $LXC_NAMES{$container}) {next;}
228
if ($LXC_DISPLAY == 1 and $container eq '') {next;}
229
printf "%-10s %s", $container, $_;
22
echo "usage: $(basename $0) [--lxc | --name NAME] [--] [PS_OPTIONS...]" >&2
28
echo "List current processes with container names." >&2
30
echo " --lxc show processes in all containers" >&2
31
echo " --name NAME show processes in the specified container" >&2
32
echo " (multiple containers can be separated by commas)" >&2
33
echo " PS_OPTIONS ps command options (see \`ps --help')" >&2
38
local hierarchies hierarchy fields subsystems init_cgroup mountpoint
42
# Obtain a list of hierarchies that contain one or more subsystems
43
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
45
# Iterate through the list until a suitable hierarchy is found
46
for hierarchy in $hierarchies; do
47
# Obtain information about the init process in the hierarchy
48
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
49
if [ -z "$fields" ]; then continue; fi
52
# Get a comma-separated list of the hierarchy's subsystems
53
subsystems=${fields%:*}
55
# Get the cgroup of the init process in the hierarchy
56
init_cgroup=${fields#*:}
58
# Get the filesystem mountpoint of the hierarchy
59
mountpoint=$(awk -v subsysregex="(^|,)$subsystems(,|\$)" \
60
'$3 == "cgroup" && $4 ~ subsysregex {print $2}' /proc/self/mounts)
61
if [ -z "$mountpoint" ]; then continue; fi
63
# Return the absolute path to the containers' parent cgroup
64
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
65
case ",$subsystems," in
66
*,ns,*) parent_cgroup="${mountpoint}${init_cgroup%/}";;
67
*) parent_cgroup="${mountpoint}${init_cgroup%/}/lxc";;
74
list_container_processes=0
80
containers=$2; list_container_processes=1; shift 2;;
82
list_container_processes=1; shift;;
90
if [ "$list_container_processes" -eq "1" ]; then
95
if [ ! -d "$parent_cgroup" ]; then
96
echo "$(basename $0): no cgroup mount point found" >&2
100
if [ -z "$containers" ]; then
101
containers="$(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')"
104
container_field_width=9
106
for container in ${containers}; do
107
if [ "${#container}" -gt "$container_field_width" ]; then
108
container_field_width=${#container}
111
if [ -f "$parent_cgroup/$container/tasks" ]; then
112
tasks_files="$tasks_files $parent_cgroup/$container/tasks"
116
# first file is stdin, the rest are the container tasks
117
ps "$@" | awk -v container_field_width="$container_field_width" \
118
-v list_container_processes="$list_container_processes" '
119
# first line is PS header
121
# find pid field index
122
for (i = 1; i<=NF; i++)
128
print("No PID field found") > "/dev/stderr"
135
# store lines from ps with pid as index
138
pid_of_line[NR] = $pididx
142
# find container name from filename on first line
145
sub(/\/tasks/, "", container)
146
sub(/.*\//, "", container)
151
container_of_pid[$0] = container
155
printf("%-" container_field_width "s %s\n", "CONTAINER", header)
157
container = container_of_pid[pid_of_line[i]]
158
if (list_container_processes == 0 || container != "")
159
printf("%-" container_field_width "s %s\n", container, ps_line[i])