diff --git a/.gitignore b/.gitignore index 3c33247..6517ed1 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /target -buf-setup.exe +bufusb-setup.exe # fuck NixOS diff --git a/Cargo.lock b/Cargo.lock index 6832cac..b7d7b7d 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] -name = "buf" +name = "bufusb" version = "0.2.3" dependencies = [ "anyhow", diff --git a/Install/PKGBUILD b/Install/PKGBUILD deleted file mode 100644 index 90f1d70..0000000 --- a/Install/PKGBUILD +++ /dev/null @@ -1,41 +0,0 @@ -# Maintainer: Bryson Kelly -pkgname=buf-cli -_binname=buf -pkgver=0.2.3 -pkgrel=1 -_srcdir="buf-$pkgver" -pkgdesc="A fast, safe bootable USB image flasher" -arch=('x86_64' 'aarch64') -url="https://github.com/brysonak/buf" -license=('GPL-3.0-or-later') -depends=() -makedepends=('rust' 'cargo') -optdepends=('ntfs-3g: NTFS fallback for ISOs that disrespect the FAT32 4GB limit for individual files') -source=("buf-$pkgver.tar.gz::https://github.com/brysonak/buf/archive/refs/tags/v$pkgver.tar.gz") -sha256sums=('') # Intentionally left blank here, see https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=buf-cli#n15 for the sha256sum - -prepare() { - cd "$_srcdir" - export RUSTUP_TOOLCHAIN=stable - cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')" -} - -build() { - cd "$_srcdir" - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - cargo build --release --locked --package buf -} - -check() { - cd "$_srcdir" - export RUSTUP_TOOLCHAIN=stable - cargo test --release --locked --package buf -} - -package() { - cd "$_srcdir" - install -Dm755 "target/release/$_binname" "$pkgdir/usr/bin/$_binname" - install -Dm644 "README.md" "$pkgdir/usr/share/doc/$pkgname/README.md" - install -Dm644 "docs/docs.md" "$pkgdir/usr/share/doc/$pkgname/docs.md" -} diff --git a/Install/install.iss b/Install/install.iss index 876d265..5873c9a 100644 --- a/Install/install.iss +++ b/Install/install.iss @@ -2,22 +2,22 @@ [Setup] AppId={{5D0F69A8-6A08-440E-AFC6-E809B1B82C88} -AppName=buf +AppName=bufusb AppVersion={#BufAppVersion} AppPublisher=Bryson Kelly -AppPublisherURL=https://github.com/brysonak/buf -AppSupportURL=https://github.com/brysonak/buf/issues -AppUpdatesURL=https://github.com/brysonak/buf/releases -DefaultDirName={autopf}\buf -DefaultGroupName=buf +AppPublisherURL=https://github.com/brysonak/bufusb +AppSupportURL=https://github.com/brysonak/bufusb/issues +AppUpdatesURL=https://github.com/brysonak/bufusb/releases +DefaultDirName={autopf}\bufusb +DefaultGroupName=bufusb DisableProgramGroupPage=yes LicenseFile=..\LICENSE VersionInfoVersion={#BufAppVersion} VersionInfoCompany=Bryson Kelly -VersionInfoDescription=buf bootable USB flasher installer +VersionInfoDescription=bufusb bootable USB flasher installer VersionInfoCopyright=Bryson Kelly OutputDir=..\install -OutputBaseFilename=buf-setup +OutputBaseFilename=bufusb-setup Compression=lzma2 SolidCompression=yes @@ -37,13 +37,13 @@ Name: "english"; MessagesFile: "compiler:Default.isl" [Files] -Source: "..\target\release\buf.exe"; DestDir: "{app}"; DestName: "buf.exe"; Flags: ignoreversion +Source: "..\target\release\bufusb.exe"; DestDir: "{app}"; DestName: "bufusb.exe"; Flags: ignoreversion Source: "..\buf-cli\logo.ico"; DestDir: "{app}"; Flags: ignoreversion [Icons] -Name: "{group}\buf"; Filename: "{app}\buf.exe"; IconFilename: "{app}\logo.ico" -Name: "{group}\Uninstall buf"; Filename: "{uninstallexe}" +Name: "{group}\bufusb"; Filename: "{app}\bufusb.exe"; IconFilename: "{app}\logo.ico" +Name: "{group}\Uninstall bufusb"; Filename: "{uninstallexe}" [Code] diff --git a/Install/install.sh b/Install/install.sh index 7756148..95265ec 100644 --- a/Install/install.sh +++ b/Install/install.sh @@ -1,7 +1,7 @@ #!/bin/sh set -eu -REPO="https://github.com/brysonak/buf.git" -BIN="buf" +REPO="https://github.com/brysonak/bufusb.git" +BIN="bufusb" PREFIX="${PREFIX:-/usr/local}" INSTALL_DIR="$PREFIX/bin" require() { @@ -20,7 +20,7 @@ case "$(uname -s)" in esac if [ -f /etc/NIXOS ]; then printf 'NixOS detected, use the flake instead:\n' >&2 - printf ' nix profile install github:brysonak/buf\n' >&2 + printf ' nix profile install github:brysonak/bufusb\n' >&2 exit 1 fi require git @@ -31,7 +31,7 @@ trap 'rm -rf "$CLONE_DIR"' EXIT printf 'Cloning %s...\n' "$REPO" git clone --depth 1 "$REPO" "$CLONE_DIR" cd "$CLONE_DIR" -cargo build --release --package buf +cargo build --release --package bufusb if [ ! -f "target/release/$BIN" ]; then printf 'Error: build failed, target/release/%s not found.\n' "$BIN" >&2 exit 1 diff --git a/README.md b/README.md index adc0119..c524740 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# buf +# bufusb ![buf logo](buf.png) **B**ootable **U**SB **F**lasher is a tool made for flashing .iso/.img files onto USB drives, for booting into operating systems of course... Is it bootable USB flasher or Bryson's USB flasher? -buf is fully cross-platform and open source, under [GPL-v3](https://www.gnu.org/licenses/gpl-3.0.html). +bufusb is fully cross-platform and open source, under [GPL-v3](https://www.gnu.org/licenses/gpl-3.0.html). Logo made by [Mia](https://github.com/marshmallow-mia) @@ -18,9 +18,9 @@ Pre-requisites: Run the following commands: ```bash -git clone https://github.com/brysonak/buf.git +git clone https://github.com/brysonak/bufusb.git -cd buf +cd bufusb cargo build --release ``` diff --git a/buf-cli/Cargo.toml b/buf-cli/Cargo.toml index 5907f98..ef16ce7 100755 --- a/buf-cli/Cargo.toml +++ b/buf-cli/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "buf" +name = "bufusb" version = "0.2.3" edition = "2021" description = "A fast, safe bootable USB flasher" [[bin]] -name = "buf" +name = "bufusb" path = "src/main.rs" [dependencies] diff --git a/buf-cli/src/main.rs b/buf-cli/src/main.rs index 25f8bc4..2c5b336 100755 --- a/buf-cli/src/main.rs +++ b/buf-cli/src/main.rs @@ -24,13 +24,13 @@ use log::{debug, error, info, warn}; #[derive(Parser, Debug)] #[command( - name = "buf", + name = "bufusb", version = "0.2.3", - long_version = "0.2.3\n Copyright (C) 2026 Bryson Kelly\n This program comes with ABSOLUTELY NO WARRANTY; for details, visit: https://github.com/brysonak/buf/blob/main/LICENSE\n This is free software, and you are welcome to redistribute it\n under certain conditions.", + long_version = "0.2.3\n Copyright (C) 2026 Bryson Kelly\n This program comes with ABSOLUTELY NO WARRANTY; for details, visit: https://github.com/brysonak/bufusb/blob/main/LICENSE\n This is free software, and you are welcome to redistribute it\n under certain conditions.", author = "Bryson Kelly", about = "A fast, safe bootable USB image flasher", long_about = None, - after_help = "For full documentation, please visit: https://github.com/brysonak/buf/blob/main/docs/docs.md", + after_help = "For full documentation, please visit: https://github.com/brysonak/bufusb/blob/main/docs/docs.md", styles = clap_styles(), )] struct Cli { @@ -166,7 +166,7 @@ fn run(cli: Cli) -> Result<()> { println!("Logging to: {}", path.display()); } - info!("buf started"); + info!("bufusb started"); debug!("Parsed CLI args: {:?}", cli); let source = cli diff --git a/docs/docs.md b/docs/docs.md index a25269e..b8053e0 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -1,11 +1,11 @@ -# buf +# bufusb These docs serve as a guide on how to use the CLI (command-line interface) ## Usage ``` -buf [OPTIONS] --source --target -buf --list +bufusb [OPTIONS] --source --target +bufusb --list ``` `--source` and `--target` are required for all write operations. All other flags @@ -18,8 +18,8 @@ are optional. Path to the source ISO or IMG file to flash. ```sh -buf -s archlinux.iso -t /dev/sdb -buf --source /home/user/ubuntu.iso --target /dev/sdc +bufusb -s archlinux.iso -t /dev/sdb +bufusb --source /home/user/ubuntu.iso --target /dev/sdc ``` Relative paths are resolved to absolute before any privilege elevation occurs, @@ -45,8 +45,8 @@ Use `--list` to see available devices before writing. List all detected storage devices and exit. No write is performed. ```sh -buf --list -buf -l +bufusb --list +bufusb -l ``` Output example: @@ -64,11 +64,11 @@ Devices are sorted with removable drives first. Volume label for the flashed drive. Copy mode only. ```sh -buf -s archlinux.iso -t /dev/sdb --label archlinux-usb +bufusb -s archlinux.iso -t /dev/sdb --label archlinux-usb ``` -If left unset, buf reuses the source ISO's own volume identifier. +If left unset, bufusb reuses the source ISO's own volume identifier. -Accepted characters are ASCII letters, digits, spaces, _ and -, up to 32 characters. FAT32 stores only the first 11, so longer labels are truncated and buf prints a note. +Accepted characters are ASCII letters, digits, spaces, _ and -, up to 32 characters. FAT32 stores only the first 11, so longer labels are truncated and bufusb prints a note. The label is also used as the GPT partition name. @@ -86,9 +86,9 @@ Accepted suffixes (case-insensitive, all powers of 1024): | G, GB, GiB | 1073741824 | ```sh -buf -s image.iso -t /dev/sdb -b 64MiB -buf -s image.iso -t /dev/sdb --block-size 4096 -buf -s image.iso -t /dev/sdb -b 1G +bufusb -s image.iso -t /dev/sdb -b 64MiB +bufusb -s image.iso -t /dev/sdb --block-size 4096 +bufusb -s image.iso -t /dev/sdb -b 1G ``` Larger block sizes generally give better throughput on fast drives. The default @@ -101,11 +101,11 @@ Start writing at this byte offset into the target device instead of the beginning. Takes a plain integer in bytes. Default is `0`. ```sh -buf -s image.iso -t /dev/sdb --offset 1048576 +bufusb -s image.iso -t /dev/sdb --offset 1048576 ``` Useful for writing to a specific partition or past a reserved region. The source -size is checked against the available space after the offset, so buf will error +size is checked against the available space after the offset, so bufusb will error out rather than run off the end of the device. ### `-f, --force` @@ -113,11 +113,11 @@ out rather than run off the end of the device. Skip the confirmation prompt and write immediately. ```sh -buf -s image.iso -t /dev/sdb --force -buf -s image.iso -t /dev/sdb -f +bufusb -s image.iso -t /dev/sdb --force +bufusb -s image.iso -t /dev/sdb -f ``` -By default buf prints the source path, size, and target device and waits for +By default bufusb prints the source path, size, and target device and waits for `y` before writing. This flag bypasses that. Useful for scripting. ### `--dry-run` @@ -125,7 +125,7 @@ By default buf prints the source path, size, and target device and waits for Run all validation checks without writing any data. Exits after validation. ```sh -buf -s image.iso -t /dev/sdb --dry-run +bufusb -s image.iso -t /dev/sdb --dry-run ``` Checks performed: @@ -142,11 +142,11 @@ of the access check and then immediately closed. Disable log file creation. Warnings and errors still print to stderr. ```sh -buf -s image.iso -t /dev/sdb --no-logging -buf -s image.iso -t /dev/sdb -n +bufusb -s image.iso -t /dev/sdb --no-logging +bufusb -s image.iso -t /dev/sdb -n ``` -By default, buf creates a timestamped log file in the user's home directory on +By default, bufusb creates a timestamped log file in the user's home directory on each run. This flag suppresses that. Cannot be combined with `--log-path`. ### `-m, --mode ` @@ -155,8 +155,8 @@ Choose how the image is written: `dd` or `copy`. Default is auto-detected from the image. ```sh -buf -s archlinux.iso -t /dev/sdb -m dd -buf -s ubuntu.iso -t /dev/sdb --mode copy +bufusb -s archlinux.iso -t /dev/sdb -m dd +bufusb -s ubuntu.iso -t /dev/sdb --mode copy ``` `dd` writes the image byte-for-byte. `copy` writes a GPT @@ -181,8 +181,8 @@ Write the log file to the given path instead of the default timestamped file in the home directory. ```sh -buf -s image.iso -t /dev/sdb --log-path /tmp/flash.log -buf -s image.iso -t /dev/sdb --log-path C:\Users\user\Desktop\flash.log +bufusb -s image.iso -t /dev/sdb --log-path /tmp/flash.log +bufusb -s image.iso -t /dev/sdb --log-path C:\Users\user\Desktop\flash.log ``` The parent directory is created if it does not exist. Cannot be combined with @@ -195,8 +195,8 @@ paths, and internal state. Implies log file creation unless `--no-logging` is also set. ```sh -buf -s image.iso -t /dev/sdb --verbose -buf -s image.iso -t /dev/sdb -v +bufusb -s image.iso -t /dev/sdb --verbose +bufusb -s image.iso -t /dev/sdb -v ``` ### `--help` @@ -209,24 +209,24 @@ Print the version and exit. ## Logging -Unless `--no-logging` is passed, buf writes a timestamped log file to the home +Unless `--no-logging` is passed, bufusb writes a timestamped log file to the home directory on each run. The filename format is: ``` -buf-MM-DD-YY-HH:MM:SS.log (Linux, macOS) -buf-MM-DD-YY-HH-MM-SS.log (Windows, colons are not valid in filenames) +bufusb-MM-DD-YY-HH:MM:SS.log (Linux, macOS) +bufusb-MM-DD-YY-HH-MM-SS.log (Windows, colons are not valid in filenames) ``` Use `--log-path` to write the log to a specific file instead: ```sh -buf -s image.iso -t /dev/sdb --log-path /var/log/buf.log +bufusb -s image.iso -t /dev/sdb --log-path /var/log/bufusb.log ``` The log path is printed at startup: ``` - Logging to: /home/user/buf-05-30-26-14:22:01.log + Logging to: /home/user/bufusb-05-30-26-14:22:01.log ``` Log files contain info-level output by default, debug-level with `--verbose`. @@ -235,13 +235,13 @@ Warnings and errors are always mirrored to stderr regardless of the log settings ## Privileges Writing to block devices requires root on Linux/macOS and Administrator on Windows. -If buf is not already running with the required privileges it will attempt to +If bufusb is not already running with the required privileges it will attempt to re-launch itself elevated automatically. On Linux it tries `sudo` first, then `pkexec` as a fallback. On Windows it triggers a UAC prompt via `ShellExecuteW` with the `runas` verb. -If neither elevator is available on Linux, buf exits with an error asking you to +If neither elevator is available on Linux, bufusb exits with an error asking you to re-run as root manually. ## Examples @@ -249,49 +249,49 @@ re-run as root manually. List devices to find your USB drive: ```sh -buf --list +bufusb --list ``` Flash an ISO with confirmation prompt: ```sh -buf -s ubuntu-24.04.iso -t /dev/sdb +bufusb -s ubuntu-24.04.iso -t /dev/sdb ``` Flash silently from a script: ```sh -buf -s ubuntu-24.04.iso -t /dev/sdb --force --no-logging +bufusb -s ubuntu-24.04.iso -t /dev/sdb --force --no-logging ``` Validate that the image fits on the drive without writing: ```sh -buf -s ubuntu-24.04.iso -t /dev/sdb --dry-run +bufusb -s ubuntu-24.04.iso -t /dev/sdb --dry-run ``` Flash with a larger block size for a fast drive: ```sh -buf -s image.iso -t /dev/sdb -b 128MiB +bufusb -s image.iso -t /dev/sdb -b 128MiB ``` Flash to a specific offset (e.g. past a 1 MiB reserved region): ```sh -buf -s image.iso -t /dev/sdb --offset 1048576 +bufusb -s image.iso -t /dev/sdb --offset 1048576 ``` Write the log to a specific file: ```sh -buf -s image.iso -t /dev/sdb --log-path /tmp/flash.log +bufusb -s image.iso -t /dev/sdb --log-path /tmp/flash.log ``` Windows, flashing to the second physical drive: ```sh -buf -s image.iso -t \\.\PhysicalDrive1 --force +bufusb -s image.iso -t \\.\PhysicalDrive1 --force ``` ## Exit Codes diff --git a/docs/downloading.md b/docs/downloading.md index 982b562..fe2ec77 100644 --- a/docs/downloading.md +++ b/docs/downloading.md @@ -6,15 +6,11 @@ PREREQUISITES (non-Windows): ## Linux and macOS -If you're on Arch, or another Arch based distro, install off the AUR with [yay](https://github.com/jguer/yay): -```bash -yay -S buf-cli -``` -Prefer `paru`? Run `paru -S buf-cli` instead. +**THE PACKAGE ON THE AUR IS IN THE MIDDLE OF BEING RENAMED. Please standby** -**If you're on another distribution or macOS**: +**Linux and macOS**: ```bash -curl -fsSL https://raw.githubusercontent.com/brysonak/buf/refs/heads/main/Install/install.sh | sh +curl -fsSL https://raw.githubusercontent.com/brysonak/bufusb/refs/heads/main/Install/install.sh | sh ``` **NOTE**: This script will ask for privileges, and needs a C compiler (`gcc`/`clang`) on PATH to link the rust binary. **If you're on NixOS**, use the flake instead, see below. @@ -22,9 +18,9 @@ curl -fsSL https://raw.githubusercontent.com/brysonak/buf/refs/heads/main/Instal NixOS users can install straight from the flake. ```bash -nix profile install github:brysonak/buf +nix profile install github:brysonak/bufusb ``` ## Windows -Run the `buf-setup.exe` installer from the [releases page](https://github.com/brysonak/buf/releases). +Run the `bufusb-setup.exe` installer from the [releases page](https://github.com/brysonak/bufusb/releases). diff --git a/flake.nix b/flake.nix index bf91dc1..8aa5591 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "buf, bootable USB flasher"; + description = "bufusb, bootable USB flasher"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; @@ -13,20 +13,20 @@ in { packages.default = pkgs.rustPlatform.buildRustPackage { - pname = "buf"; + pname = "bufusb"; version = "0.2.3"; src = self; cargoLock.lockFile = ./Cargo.lock; - cargoBuildFlags = [ "--package" "buf" ]; + cargoBuildFlags = [ "--package" "bufusb" ]; doCheck = false; meta = with pkgs.lib; { description = "A fast, safe bootable USB image flasher"; - homepage = "https://github.com/brysonak/buf"; + homepage = "https://github.com/brysonak/bufusb"; license = licenses.gpl3Plus; - mainProgram = "buf"; + mainProgram = "bufusb"; }; }; diff --git a/libbuf/src/copy/mod.rs b/libbuf/src/copy/mod.rs index e9b83a7..deff4a6 100644 --- a/libbuf/src/copy/mod.rs +++ b/libbuf/src/copy/mod.rs @@ -1262,7 +1262,7 @@ fn unique_mountpoint() -> PathBuf { .duration_since(std::time::UNIX_EPOCH) .map(|d| d.as_nanos()) .unwrap_or(0); - std::env::temp_dir().join(format!("buf-iso-{}-{}", std::process::id(), n)) + std::env::temp_dir().join(format!("bufusb-iso-{}-{}", std::process::id(), n)) } impl Drop for MountGuard { diff --git a/libbuf/src/copy/ntfs.rs b/libbuf/src/copy/ntfs.rs index b0efcd5..db71b76 100644 --- a/libbuf/src/copy/ntfs.rs +++ b/libbuf/src/copy/ntfs.rs @@ -267,7 +267,7 @@ struct NtfsMount { impl NtfsMount { fn mount(node: &Path) -> Result { let mp = std::env::temp_dir().join(format!( - "buf-ntfs-{}-{}", + "bufusb-ntfs-{}-{}", std::process::id(), std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) diff --git a/libbuf/src/logger.rs b/libbuf/src/logger.rs index abab508..d0ca004 100755 --- a/libbuf/src/logger.rs +++ b/libbuf/src/logger.rs @@ -63,9 +63,9 @@ pub fn log_path() -> Option { let now = Local::now(); // Colons are illegal in Windows filenames #[cfg(windows)] - let filename = now.format("buf-%m-%d-%y-%H-%M-%S.log").to_string(); + let filename = now.format("bufusb-%m-%d-%y-%H-%M-%S.log").to_string(); #[cfg(not(windows))] - let filename = now.format("buf-%m-%d-%y-%H:%M:%S.log").to_string(); + let filename = now.format("bufusb-%m-%d-%y-%H:%M:%S.log").to_string(); home_dir().map(|d| d.join(filename)) } @@ -128,7 +128,7 @@ pub fn init(enabled: bool, verbose: bool, custom_path: Option) -> Resul .apply() .context("Failed to initialise logger")?; - log::info!("buf logging started, file: {}", path.display()); + log::info!("bufusb logging started, file: {}", path.display()); log::info!("Log level: {}", level); Ok(Some(path)) diff --git a/libbuf/src/privilege.rs b/libbuf/src/privilege.rs index 33ee903..657d1e8 100755 --- a/libbuf/src/privilege.rs +++ b/libbuf/src/privilege.rs @@ -42,8 +42,8 @@ pub fn is_privileged() -> bool { } pub fn elevate_or_warn(args: &[String]) -> Result<()> { - warn!("buf must be run as root/Administrator to write to block devices"); - eprintln!("\n buf requires elevated privileges to write to block devices.\n"); + warn!("bufusb must be run as root/Administrator to write to block devices"); + eprintln!("\n bufusb requires elevated privileges to write to block devices.\n"); #[cfg(unix)] return unix_elevate(args); @@ -53,14 +53,14 @@ pub fn elevate_or_warn(args: &[String]) -> Result<()> { #[cfg(not(any(unix, windows)))] { - eprintln!(" Please re-run buf with administrator/root privileges."); + eprintln!(" Please re-run bufusb with administrator/root privileges."); std::process::exit(1); } } #[cfg(unix)] fn unix_elevate(args: &[String]) -> Result<()> { - let exe = std::env::current_exe().unwrap_or_else(|_| std::path::PathBuf::from("buf")); + let exe = std::env::current_exe().unwrap_or_else(|_| std::path::PathBuf::from("bufusb")); const CANDIDATES: [&str; 4] = ["doas", "sudo", "run0", "pkexec"]; @@ -77,7 +77,7 @@ fn unix_elevate(args: &[String]) -> Result<()> { Some(c) => c.to_string(), None => { eprintln!( - "No escalation tool found (tried {}). Re-run buf as root, or set \ + "No escalation tool found (tried {}). Re-run bufusb as root, or set \ BUF_SUDO to the one you use.", CANDIDATES.join(", ") ); @@ -153,7 +153,7 @@ fn windows_elevate(args: &[String]) -> Result<()> { use windows::Win32::UI::Shell::ShellExecuteW; use windows::Win32::UI::WindowsAndMessaging::SW_SHOW; - let exe = std::env::current_exe().unwrap_or_else(|_| std::path::PathBuf::from("buf.exe")); + let exe = std::env::current_exe().unwrap_or_else(|_| std::path::PathBuf::from("bufusb.exe")); let cmd_params = format!("/k \"{}\" {}", exe.to_string_lossy(), args.join(" ")); eprintln!(" Requesting UAC elevation...\n");