malwaredb 0.3.2

Service for storing malicious, benign, or unknown files and related metadata and relationships.
// SPDX-License-Identifier: Apache-2.0

use super::Installer;

use std::path::PathBuf;
use std::process::{Command, ExitCode};

use anyhow::{ensure, Result};
use clap::Parser;

const LAUNCH_PATH: &str = "/usr/local/etc/rc.d/malwaredb";

/// Install Malware DB as a system service
#[derive(Parser, Debug, Clone, PartialEq)]
pub struct Install {
    /// Use custom configuration file path
    #[arg(value_hint = clap::ValueHint::FilePath)]
    pub config: Option<PathBuf>,
}

impl Install {
    pub(crate) fn gen_config(&self) -> Result<String> {
        let exec = std::env::current_exe().unwrap();
        let exec = exec.to_str().unwrap();

        let exec_opt = if let Some(config) = &self.config {
            let config = config.to_str().unwrap();
            ensure!(
                config.starts_with('/'),
                "Must use an absolute path for the config file"
            );
            format!("run load {config}")
        } else {
            "run".to_string()
        };

        Ok(format!(
            "#!/bin/sh
#
# PROVIDE: malwaredb
# REQUIRE: DAEMON netif
# KEYWORD: shutdown

. /etc/rc.subr

name=malwaredb
rcvar=malwaredb_enable

command=\"{exec}\"
command_args=\"{exec_opt}\"
malwaredb_user=\"nobody\"
pidfile=\"/var/run/${{name}}.pid\"

start_cmd=\"malwaredb_start\"
stop_cmd=\"malwaredb_stop\"
status_cmd=\"malwaredb_status\"

malwaredb_start() {{
    /usr/sbin/daemon -P ${{pidfile}} -r -f -u ${{malwaredb_user}} ${{command}} ${{command_args}}
}}

malwaredb_stop() {{
    if [ -e \"${{pidfile}}\" ]; then
        kill -s TERM `cat ${{pidfile}}`
    else
        echo \"${{name}} is not running\"
    fi
}}

malwaredb_status() {{
    if [ -e \"${{pidfile}}\" ]; then
        echo \"${{name}} is running as pid `cat ${{pidfile}}`\"
    else
        echo \"${{name}} is not running\"
    fi
}}

load_rc_config $name
: ${{malwaredb_enable:=no}}

run_rc_command \"$1\"
"
        ))
    }
}

impl Installer for Install {
    fn do_install(&self) -> Result<ExitCode> {
        let config = self.gen_config()?;
        std::fs::write(LAUNCH_PATH, config)?;
        Command::new("chmod")
            .arg("+x")
            .arg(LAUNCH_PATH)
            .output()
            .expect("failed to make the config file executable");
        Ok(ExitCode::SUCCESS)
    }
}