our $LXC_DISPLAY = 0; # By default do not display container information
our %LXC_NAMES; # Specified container names (if any)
+sub get_container_names {
+ my $ref_names = shift;
+ my $lxcpath='@LXCPATH@';
+
+ open(active, "netstat -xa | grep $lxcpath |") or return;
+ while(<active>) {
+ chomp;
+ s#.*$lxcpath/(.*)/command.*#$1#;
+ push @$ref_names, $_;
+ }
+ close active;
+}
+
+sub get_cgroup {
+ my $ref_cgroup = shift;
+ my $mount_string;
+
+ $mount_string=`mount -t cgroup |grep -E -e '^lxc '`;
+ unless ($mount_string) {
+ $mount_string=`mount |grep -m1 'type cgroup'`;
+ }
+ chomp($mount_string);
+ if ($mount_string) {
+ $$ref_cgroup=`echo "$mount_string" |cut -d' ' -f3`;
+ chomp($$ref_cgroup);
+ }
+ die "unable to find mounted cgroup" unless $$ref_cgroup;
+}
-# Reclaim the PID index in the ps output.
-# The $PS_HEADERS must be set to the first line of ps output and must
-# contains the columns headers.
-# This function will set the $PS_PID_INDEX global or exit with an error
-# message if the PID index can't be retrieved.
+sub get_pids_in_containers {
+ my $ref_names = shift;
+ my $ref_cgroup = shift;
+ my $ref_pids = shift;
+ my @pidlist;
+
+ for (@{$ref_names}) {
+ my $task_file = "$$ref_cgroup/$_/tasks";
+
+ $LXC_NAMES{$_} = 1;
+ open(tasks, "cat $task_file 2>/dev/null |") or next;
+ while (<tasks>) {
+ chomp $_;
+ push @pidlist, $_;
+ }
+ close tasks;
+ }
+ $$ref_pids = join(',', @pidlist);
+}
sub reclaim_pid_index {
my @headers = split " ", $PS_HEADERS;
exit 1;
}
-
-# Execute the ps command
-
sub execute_ps {
open(ps, "ps @_ |") or die "Cannot execute ps command: $!\n";
- # Reclaim the PID index in ps output
$PS_HEADERS = <ps>;
reclaim_pid_index;
- # Reclaim lines of ps output
while (<ps>) {
push @PS_LINES, $_;
}
close ps;
}
-
-# Get the container name (if any) associated to a given PID.
-# @param $pid The PID to use.
-# @return The container name as a string or an empty string.
-
sub get_container {
my $pid = shift;
my $filename = "/proc/$pid/cgroup";
return $container;
}
-
-# Display headers line.
-# The $PS_HEADERS global must be set.
-
sub display_headers {
printf "%-10s %s", "CONTAINER", $PS_HEADERS;
}
-
-# Display command usage
-
sub display_usage {
print <<EOF;
Usage: lxc-ps [--help] [--usage] [--name NAME...] [--lxc] [ps options]
EOF
}
-
-# Display command help
-
sub display_help {
display_usage;
print <<EOF;
EOF
}
-
-# Process lxc-ps arguments and build
-
use Getopt::Long qw(:config no_auto_abbrev pass_through);
my $arg_help = '';
# Should we filter processes related to containers
if ($arg_lxc) {
- # Display processes related to all containers
- $LXC_DISPLAY = 1;
- @ARGV = ('-e', @ARGV);
-} elsif (@arg_name > 0) {
- # Display processes related to specified containers
- $LXC_DISPLAY = 2;
- foreach (@arg_name) {
- $LXC_NAMES{$_} = 1;
- }
- @ARGV = ('-e', @ARGV);
+ $LXC_DISPLAY = 1;
+ get_container_names \@arg_name;
+}
+if (@arg_name > 0) {
+ my $cgroup;
+ my $pid_list;
+ $LXC_DISPLAY = 2;
+
+ get_cgroup \$cgroup;
+ get_pids_in_containers(\@arg_name, \$cgroup, \$pid_list);
+ if ($pid_list) {
+ @ARGV = ("-p $pid_list",@ARGV);
+ }
}
-
-
-# Execute the ps command
execute_ps @ARGV;
-
-# Display result with addition of container name
-
display_headers;
for (@PS_LINES) {
my @a = split;
my $container = get_container $a[$PS_PID_INDEX];
- if ($LXC_DISPLAY == 1 and $container eq '') {next;}
if ($LXC_DISPLAY == 2 and not $LXC_NAMES{$container}) {next;}
+ if ($LXC_DISPLAY == 1 and $container eq '') {next;}
printf "%-10s %s", $container, $_;
}
-
-# Done
-
exit 0;