Introduce floppy-utils: a CLI for creating, editing, archiving, and restoring floppy disk images on Linux with USB floppy drive support. Includes main floppy command, legacy wrappers, dependency checker, install script, and comprehensive documentation.
226 lines
5.5 KiB
Bash
Executable File
226 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Verify dependencies for floppy-utils on Debian-based systems; optionally install via apt.
|
|
set -euo pipefail
|
|
|
|
INSTALL=0
|
|
QUIET=0
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: check-deps.sh [OPTIONS]
|
|
|
|
Check that base tools required by floppy-utils are available.
|
|
On Debian, Ubuntu, Raspberry Pi OS, and derivatives, missing packages can be
|
|
installed with apt when --install is passed.
|
|
|
|
Options:
|
|
--install, -i Install missing packages (requires apt and root/sudo)
|
|
--quiet, -q Only print errors and the install command
|
|
-h, --help Show this help
|
|
|
|
Examples:
|
|
./check-deps.sh
|
|
./check-deps.sh --install
|
|
sudo ./check-deps.sh -i
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--install|-i) INSTALL=1; shift ;;
|
|
--quiet|-q) QUIET=1; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "check-deps.sh: unknown option: $1" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
log() {
|
|
[[ "$QUIET" -eq 0 ]] && echo "$@"
|
|
}
|
|
|
|
warn() {
|
|
echo "check-deps.sh: $*" >&2
|
|
}
|
|
|
|
die() {
|
|
warn "$*"
|
|
exit 1
|
|
}
|
|
|
|
is_debian_like() {
|
|
if [[ -f /etc/debian_version ]]; then
|
|
return 0
|
|
fi
|
|
if [[ -f /etc/os-release ]]; then
|
|
# shellcheck source=/dev/null
|
|
source /etc/os-release
|
|
case "${ID:-}:${ID_LIKE:-}" in
|
|
debian:*|*debian*|ubuntu:*|*ubuntu*|raspbian:*|linuxmint:*|pop:*|elementary:*|kali:*|devuan:*)
|
|
return 0
|
|
;;
|
|
esac
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
os_description() {
|
|
if [[ -f /etc/os-release ]]; then
|
|
# shellcheck source=/dev/null
|
|
source /etc/os-release
|
|
printf '%s %s\n' "${NAME:-Linux}" "${VERSION_ID:-}"
|
|
elif [[ -f /etc/debian_version ]]; then
|
|
printf 'Debian %s\n' "$(cat /etc/debian_version)"
|
|
else
|
|
echo "Unknown"
|
|
fi
|
|
}
|
|
|
|
# command -> Debian package providing it
|
|
declare -A CMD_PKG=(
|
|
[lsblk]=util-linux
|
|
[blockdev]=util-linux
|
|
[losetup]=util-linux
|
|
[findmnt]=util-linux
|
|
[fdisk]=util-linux
|
|
[blkid]=util-linux
|
|
[mount]=mount
|
|
[umount]=mount
|
|
[dd]=coreutils
|
|
[readlink]=coreutils
|
|
[mkfs.vfat]=dosfstools
|
|
[sudo]=sudo
|
|
[udisksctl]=udisks2
|
|
[udevadm]=udev
|
|
[eject]=eject
|
|
)
|
|
|
|
REQUIRED_CMDS=(
|
|
lsblk blockdev losetup findmnt blkid mount umount dd readlink mkfs.vfat
|
|
)
|
|
|
|
RECOMMENDED_CMDS=(
|
|
sudo udisksctl udevadm eject fdisk
|
|
)
|
|
|
|
have_cmd() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
packages_for_cmds() {
|
|
local -A seen=()
|
|
local cmd pkg
|
|
for cmd in "$@"; do
|
|
pkg="${CMD_PKG[$cmd]:-}"
|
|
[[ -n "$pkg" && -z "${seen[$pkg]:-}" ]] || continue
|
|
seen[$pkg]=1
|
|
printf '%s\n' "$pkg"
|
|
done
|
|
}
|
|
|
|
check_cmds() {
|
|
local label="$1"
|
|
local required="$2"
|
|
shift 2
|
|
local cmd
|
|
local -a missing=()
|
|
|
|
log "$label"
|
|
for cmd in "$@"; do
|
|
if have_cmd "$cmd"; then
|
|
log " OK $cmd"
|
|
else
|
|
if [[ "$required" -eq 1 ]]; then
|
|
log " MISS $cmd (required)"
|
|
else
|
|
log " MISS $cmd (recommended)"
|
|
fi
|
|
missing+=("$cmd")
|
|
fi
|
|
done
|
|
log ""
|
|
|
|
MISSING_RESULT=("${missing[@]}")
|
|
}
|
|
|
|
run_apt_install() {
|
|
local -a packages=("$@")
|
|
[[ ${#packages[@]} -gt 0 ]] || return 0
|
|
|
|
if ! command -v apt-get >/dev/null 2>&1; then
|
|
die "apt-get not found; install manually: ${packages[*]}"
|
|
fi
|
|
|
|
local -a apt_cmd=(apt-get)
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
command -v sudo >/dev/null 2>&1 || die "root or sudo required to install: ${packages[*]}"
|
|
apt_cmd=(sudo apt-get)
|
|
fi
|
|
|
|
log "Installing: ${packages[*]}"
|
|
"${apt_cmd[@]}" update -qq
|
|
DEBIAN_FRONTEND=noninteractive "${apt_cmd[@]}" install -y --no-install-recommends "${packages[@]}"
|
|
}
|
|
|
|
main() {
|
|
local -a missing_required=() missing_recommended=() packages=()
|
|
local debian=0
|
|
|
|
log "floppy-utils dependency check"
|
|
log "OS: $(os_description)"
|
|
|
|
if is_debian_like; then
|
|
debian=1
|
|
log "Debian-based system detected."
|
|
else
|
|
warn "Not a Debian-based system — will check commands only (no apt install)."
|
|
fi
|
|
log ""
|
|
|
|
check_cmds "Required commands:" 1 "${REQUIRED_CMDS[@]}"
|
|
missing_required=("${MISSING_RESULT[@]}")
|
|
check_cmds "Recommended commands:" 0 "${RECOMMENDED_CMDS[@]}"
|
|
missing_recommended=("${MISSING_RESULT[@]}")
|
|
|
|
if [[ ${#missing_required[@]} -eq 0 && ${#missing_recommended[@]} -eq 0 ]]; then
|
|
log "All required and recommended commands are available."
|
|
exit 0
|
|
fi
|
|
|
|
if [[ ${#missing_required[@]} -gt 0 ]]; then
|
|
log "Missing required: ${missing_required[*]}"
|
|
fi
|
|
if [[ ${#missing_recommended[@]} -gt 0 ]]; then
|
|
log "Missing recommended: ${missing_recommended[*]}"
|
|
fi
|
|
|
|
mapfile -t packages < <(packages_for_cmds "${missing_required[@]}" "${missing_recommended[@]}")
|
|
if [[ ${#packages[@]} -gt 0 ]]; then
|
|
log "Debian packages: ${packages[*]}"
|
|
fi
|
|
|
|
if [[ "$INSTALL" -eq 1 ]]; then
|
|
[[ "$debian" -eq 1 ]] || die "refusing --install on non-Debian system"
|
|
run_apt_install "${packages[@]}"
|
|
log ""
|
|
log "Re-checking..."
|
|
INSTALL=0
|
|
main
|
|
return
|
|
fi
|
|
|
|
if [[ "$debian" -eq 1 && ${#packages[@]} -gt 0 ]]; then
|
|
log ""
|
|
log "To install:"
|
|
log " sudo ./check-deps.sh --install"
|
|
log " # or: sudo apt-get install -y ${packages[*]}"
|
|
fi
|
|
|
|
if [[ ${#missing_required[@]} -gt 0 ]]; then
|
|
die "required dependencies missing"
|
|
fi
|
|
|
|
warn "recommended tools missing — floppy-utils works with reduced functionality"
|
|
exit 0
|
|
}
|
|
|
|
main |