about summary refs log tree commit diff
path: root/xtask
diff options
context:
space:
mode:
authorBaitinq <manuelpalenzuelamerino@gmail.com>2024-01-13 21:05:51 +0100
committerBaitinq <manuelpalenzuelamerino@gmail.com>2024-01-13 21:25:48 +0100
commitea9a3f1af5fe7547617821614b8194e4f484a8e1 (patch)
tree5652060b962ba3c839ac1c18e0e000efaf6bd3e2 /xtask
downloadfs-tracer-ea9a3f1af5fe7547617821614b8194e4f484a8e1.tar.gz
fs-tracer-ea9a3f1af5fe7547617821614b8194e4f484a8e1.tar.bz2
fs-tracer-ea9a3f1af5fe7547617821614b8194e4f484a8e1.zip
Initial commit
Diffstat (limited to 'xtask')
-rw-r--r--xtask/Cargo.toml8
-rw-r--r--xtask/src/build_ebpf.rs67
-rw-r--r--xtask/src/main.rs33
-rw-r--r--xtask/src/run.rs70
4 files changed, 178 insertions, 0 deletions
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
new file mode 100644
index 0000000..c4dea5d
--- /dev/null
+++ b/xtask/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "xtask"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+anyhow = "1"
+clap = { version = "4.1", features = ["derive"] }
diff --git a/xtask/src/build_ebpf.rs b/xtask/src/build_ebpf.rs
new file mode 100644
index 0000000..8da1111
--- /dev/null
+++ b/xtask/src/build_ebpf.rs
@@ -0,0 +1,67 @@
+use std::{path::PathBuf, process::Command};
+
+use clap::Parser;
+
+#[derive(Debug, Copy, Clone)]
+pub enum Architecture {
+    BpfEl,
+    BpfEb,
+}
+
+impl std::str::FromStr for Architecture {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(match s {
+            "bpfel-unknown-none" => Architecture::BpfEl,
+            "bpfeb-unknown-none" => Architecture::BpfEb,
+            _ => return Err("invalid target".to_owned()),
+        })
+    }
+}
+
+impl std::fmt::Display for Architecture {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(match self {
+            Architecture::BpfEl => "bpfel-unknown-none",
+            Architecture::BpfEb => "bpfeb-unknown-none",
+        })
+    }
+}
+
+#[derive(Debug, Parser)]
+pub struct Options {
+    /// Set the endianness of the BPF target
+    #[clap(default_value = "bpfel-unknown-none", long)]
+    pub target: Architecture,
+    /// Build the release target
+    #[clap(long)]
+    pub release: bool,
+}
+
+pub fn build_ebpf(opts: Options) -> Result<(), anyhow::Error> {
+    let dir = PathBuf::from("fs-tracer-ebpf");
+    let target = format!("--target={}", opts.target);
+    let mut args = vec![
+        "build",
+        target.as_str(),
+        "-Z",
+        "build-std=core",
+    ];
+    if opts.release {
+        args.push("--release")
+    }
+
+    // Command::new creates a child process which inherits all env variables. This means env
+    // vars set by the cargo xtask command are also inherited. RUSTUP_TOOLCHAIN is removed
+    // so the rust-toolchain.toml file in the -ebpf folder is honored.
+
+    let status = Command::new("cargo")
+        .current_dir(dir)
+        .env_remove("RUSTUP_TOOLCHAIN")
+        .args(&args)
+        .status()
+        .expect("failed to build bpf program");
+    assert!(status.success());
+    Ok(())
+}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
new file mode 100644
index 0000000..c1c594e
--- /dev/null
+++ b/xtask/src/main.rs
@@ -0,0 +1,33 @@
+mod build_ebpf;
+mod run;
+
+use std::process::exit;
+
+use clap::Parser;
+
+#[derive(Debug, Parser)]
+pub struct Options {
+    #[clap(subcommand)]
+    command: Command,
+}
+
+#[derive(Debug, Parser)]
+enum Command {
+    BuildEbpf(build_ebpf::Options),
+    Run(run::Options),
+}
+
+fn main() {
+    let opts = Options::parse();
+
+    use Command::*;
+    let ret = match opts.command {
+        BuildEbpf(opts) => build_ebpf::build_ebpf(opts),
+        Run(opts) => run::run(opts),
+    };
+
+    if let Err(e) = ret {
+        eprintln!("{e:#}");
+        exit(1);
+    }
+}
diff --git a/xtask/src/run.rs b/xtask/src/run.rs
new file mode 100644
index 0000000..f354f8f
--- /dev/null
+++ b/xtask/src/run.rs
@@ -0,0 +1,70 @@
+use std::process::Command;
+
+use anyhow::Context as _;
+use clap::Parser;
+
+use crate::build_ebpf::{build_ebpf, Architecture, Options as BuildOptions};
+
+#[derive(Debug, Parser)]
+pub struct Options {
+    /// Set the endianness of the BPF target
+    #[clap(default_value = "bpfel-unknown-none", long)]
+    pub bpf_target: Architecture,
+    /// Build and run the release target
+    #[clap(long)]
+    pub release: bool,
+    /// The command used to wrap your application
+    #[clap(short, long, default_value = "doas")]
+    pub runner: String,
+    /// Arguments to pass to your application
+    #[clap(name = "args", last = true)]
+    pub run_args: Vec<String>,
+}
+
+/// Build the project
+fn build(opts: &Options) -> Result<(), anyhow::Error> {
+    let mut args = vec!["build"];
+    if opts.release {
+        args.push("--release")
+    }
+    let status = Command::new("cargo")
+        .args(&args)
+        .status()
+        .expect("failed to build userspace");
+    assert!(status.success());
+    Ok(())
+}
+
+/// Build and run the project
+pub fn run(opts: Options) -> Result<(), anyhow::Error> {
+    // build our ebpf program followed by our application
+    build_ebpf(BuildOptions {
+        target: opts.bpf_target,
+        release: opts.release,
+    })
+    .context("Error while building eBPF program")?;
+    build(&opts).context("Error while building userspace application")?;
+
+    // profile we are building (release or debug)
+    let profile = if opts.release { "release" } else { "debug" };
+    let bin_path = format!("target/{profile}/fs-tracer");
+
+    // arguments to pass to the application
+    let mut run_args: Vec<_> = opts.run_args.iter().map(String::as_str).collect();
+
+    // configure args
+    let mut args: Vec<_> = opts.runner.trim().split_terminator(' ').collect();
+    args.push(bin_path.as_str());
+    args.append(&mut run_args);
+
+    // run the command
+    let status = Command::new(args.first().expect("No first argument"))
+        .args(args.iter().skip(1))
+        .status()
+        .expect("failed to run the command");
+
+    if !status.success() {
+        anyhow::bail!("Failed to run `{}`", args.join(" "));
+    }
+    Ok(())
+}