apksigner 1.0.0

APK signer and verifier CLI — a faithful Rust port of AOSP apksigner
//! `apksigner` command-line tool — Rust port of `com.android.apksigner.ApkSignerTool`.
//!
//! The Java tool has its own option grammar (`--name value`, `--name=value`, `-name value`,
//! and repeated per-signer groups delimited by `--next-signer`), so argument parsing is
//! hand-written in `apk_signer_tool` rather than delegated to a general-purpose parser. That
//! keeps the accepted syntax, the messages and the exit codes aligned with the reference.

#![allow(clippy::too_many_arguments)] // signatures mirror the Java reference one-for-one
#![allow(clippy::type_complexity)] // types mirror the Java generics
#![allow(clippy::should_implement_trait)] // next() mirrors the Java pull parser API
#![allow(clippy::needless_range_loop)] // index loops mirror the Java loops
#![allow(clippy::ptr_arg)] // &mut Vec mirrors the Java List parameters

mod apk_signer_tool;
mod encrypted_private_key_info;
mod hex_encoding;
mod java_trace;
mod keystore;
mod options_parser;
mod parameter_exception;
mod password_retriever;
mod security;
mod signer_params;

use std::process::ExitCode;

fn main() -> ExitCode {
    restore_default_sigpipe_disposition();

    let args: Vec<String> = std::env::args().skip(1).collect();
    ExitCode::from(apk_signer_tool::main_with_args(&args) as u8)
}

/// Restores the default `SIGPIPE` disposition for this process.
///
/// Rust starts every program with `SIGPIPE` ignored, which turns a write to a pipe whose reader
/// has exited into an error rather than a signal. `println!` then panics on that error, so
/// `apksigner verify --verbose app.apk | head -1` used to print
/// `failed printing to stdout: Broken pipe` plus a Rust backtrace note. Java never shows that:
/// its `PrintStream` swallows the `IOException` and the tool finishes normally. Restoring the
/// signal removes the panic and makes the tool die the way other Unix filters do.
///
/// The one remaining difference from Java is the exit status: dying from `SIGPIPE` reports 141
/// to the shell where Java reports its normal status. Neither can be reproduced while also
/// refusing to print a diagnostic, and no diagnostic is the more important half.
#[cfg(unix)]
fn restore_default_sigpipe_disposition() {
    // SAFETY: `signal` is called once, before any other thread exists, with a constant
    // disposition. Restoring the default disposition is the documented Unix idiom for a filter
    // that writes to a pipe.
    unsafe {
        libc::signal(libc::SIGPIPE, libc::SIG_DFL);
    }
}

/// On non-Unix platforms `SIGPIPE` does not exist.
#[cfg(not(unix))]
fn restore_default_sigpipe_disposition() {}