use crate::{container::Container, utils}; use anyhow::{bail, Context, Result}; use cgroups; use clap::{self, Clap}; use std::{path::PathBuf, process::Command}; /// display the processes inside a container #[derive(Clap, Debug)] pub struct Ps { /// format to display processes: table or json (default: "table") #[clap(short, long, default_value = "table")] format: String, pub container_id: String, /// options will be passed to the ps utility #[clap(setting = clap::ArgSettings::Last)] ps_options: Vec, } impl Ps { pub fn exec(&self, root_path: PathBuf) -> Result<()> { let container_root = root_path.join(&self.container_id); if !container_root.exists() { bail!("{} doesn't exist.", self.container_id) } let container = Container::load(container_root)?.refresh_status()?; if container.root.exists() { let config_absolute_path = container.root.join("config.json"); log::debug!("load spec from {:?}", config_absolute_path); let spec = oci_spec::Spec::load(config_absolute_path)?; log::debug!("spec: {:?}", spec); let cgroups_path = utils::get_cgroup_path( &spec.linux.context("no linux in spec")?.cgroups_path, container.id(), ); let systemd_cgroup = container .systemd() .context("could not determine cgroup manager")?; let cmanager = cgroups::common::create_cgroup_manager(cgroups_path, systemd_cgroup)?; let pids: Vec = cmanager .get_all_pids()? .iter() .map(|pid| pid.as_raw()) .collect(); if self.format == "json" { println!("{}", serde_json::to_string(&pids)?); } else if self.format == "table" { let default_ps_options = vec![String::from("-ef")]; let ps_options = if self.ps_options.is_empty() { &default_ps_options } else { &self.ps_options }; let output = Command::new("ps").args(ps_options).output()?; if !output.status.success() { println!("{}", std::str::from_utf8(&output.stderr)?); } else { let lines = std::str::from_utf8(&output.stdout)?; let lines: Vec<&str> = lines.split('\n').collect(); let pid_index = get_pid_index(lines[0])?; println!("{}", &lines[0]); for line in &lines[1..] { if line.is_empty() { continue; } let fields: Vec<&str> = line.split_whitespace().collect(); let pid: i32 = fields[pid_index].parse()?; if pids.contains(&pid) { println!("{}", line); } } } } } Ok(()) } } fn get_pid_index(title: &str) -> Result { let titles = title.split_whitespace(); for (index, name) in titles.enumerate() { if name == "PID" { return Ok(index); } } bail!("could't find PID field in ps output"); }