//! The `Command` has mostly same API as `std::process::Command` except where
//! is absolutely needed.
//!
//! In addition `Command` contains methods to configure linux namespaces,
//! chroots and more linux stuff.
//!
//! We have diverged from ``std::process::Command`` in the following
//! major things:
//!
//! 1. Error handling. Since sometimes we have long chains of system calls
//!    involved, we need to give user some way to find out which call failed
//!    with an error, so `io::Error` is not an option.  We have
//!    ``error::Error`` class which describes the error as precisely as
//!    possible
//!
//! 2. We set ``PDEATHSIG`` to ``SIGKILL`` by default. I.e. child process will
//!    die when parent is dead. This is what you want most of the time. If you
//!    want to allow child process to daemonize explicitly call the
//!    ``allow_daemonize`` method (but look at documentation of
//!    ``Command::set_parent_death_signal`` first).
//!
//! 3. We don't search for `program` in `PATH`. It's hard to do right in all
//!    cases of `chroot`, `pivot_root`, user and mount namespaces. So we expect
//!    its easier to do for your specific container setup.
//!
//! Anyway this is low-level interface. You may want to use some higher level
//! abstraction which mounts filesystems, sets network and monitors processes.
#![warn(missing_docs)]

mod callbacks;
mod child;
mod config;
mod error;
mod ffi_util;
mod idmap;
mod linux;
/// Utilities for Linux namespaces
pub mod namespace;
mod run;
mod seccomp;
mod status;
mod std_api;
mod stdio;
mod wait;
mod zombies;

use std::{ffi::CString, os::unix::io::RawFd};

pub use nix::sys::signal::Signal;
use nix::{errno::Errno, libc::pid_t};

use crate::libseccomp::ScmpFilterContext;
pub use crate::unshare::{
    error::Error,
    idmap::{GidMap, UidMap},
    namespace::Namespace,
    status::ExitStatus,
    stdio::{Fd, Stdio},
    zombies::{child_events, reap_zombies, ChildEvent},
};

/// Main class for running processes. Works in the spirit of builder pattern.
#[allow(clippy::type_complexity)]
pub struct Command {
    exe: Executable,
    config: config::Config,
    before_unfreeze: Option<Box<dyn FnMut(u32) -> Result<(), Errno>>>,
    pre_exec: Option<Box<dyn Fn() -> Result<(), Errno>>>,
    seccomp_filter: Option<ScmpFilterContext>,
    seccomp_pipefd: ((RawFd, RawFd), (RawFd, RawFd)),
}

/// The reference to the running child
#[derive(Debug)]
pub struct Child {
    pid: pid_t,
    status: Option<ExitStatus>,
    /// Child pid file descriptor.
    pub pid_fd: RawFd,
    /// Seccomp file descriptor.
    pub seccomp_fd: RawFd,
}

#[derive(Debug)]
enum Executable {
    Library(libloading::os::unix::Library),
    Program((CString, Vec<CString>)),
}
