upgrades!

This commit is contained in:
jess 2026-04-24 17:13:50 -07:00
parent 4135c34d3d
commit 8ae11a1e70
3 changed files with 230 additions and 116 deletions

146
README.md
View File

@ -1,127 +1,43 @@
# Manjaro ARM Installer # Manjaro ARM Installer
Scripts for installing Manjaro ARM directly to SD/eMMC cards or USB sticks without the need for images. Fork of [upstream](https://gitlab.manjaro.org/manjaro-arm/applications/manjaro-arm-installer) with `--output-image` mode added — builds to a sparse `.img` file via loop device instead of writing to a real block device. With no flags, behaves identically to upstream.
This script is "interactive". Meaning that it asks you questions when run to customize your install. Like username, password etc. ## Usage
```bash
# build to an image file (12 GB)
sudo ./manjaro-arm-installer --output-image ./manjaro.img --image-size 12G
## Dependencies (Arch package names): # env-var form (drop-in for scripts)
* bash sudo IMG_OUTPUT=manjaro.img IMG_SIZE=12G ./manjaro-arm-installer
* wget
* git
* systemd
* dialog
* parted
* libarchive
* qemu-user-static-binfmt (only needed when script is run from other architectures than `aarch64`)
* openssl
* gawk
* dosfstools
* polkit
* btrfs-progs (for btrfs filesystem support)
* f2fs-tools (for f2fs filesystem support)
* cryptsetup (for encryption support)
* grub-efi-arm64 (only needed when script is run from other arcitectures than `aarch64`) (from AUR) (for `generic-efi` support)
## Installing and using from Manjaro (x64 and ARM) repositories: # compress after build (xz preferred, zstd fallback)
To use this script, please make sure that the following is correct: sudo ./manjaro-arm-installer --output-image ./manjaro.img --compress
* An SD/eMMC card with at least 8 GB storage is plugged in, but not mounted. This Script **will** remove everything on it.
* That your user account has `sudo` rights.
Then install the `manjaro-arm-installer` package with:
```
sudo pacman -Syu manjaro-arm-installer
```
Then reboot or run `sudo systemctl restart systemd-binfmt`. You can now launch the installer with:
```
sudo bash manjaro-arm-installer
``` ```
Default image size is `8G` if `--image-size` isn't passed.
## Installing and using from gitlab: The interactive dialogs (edition, user, password, locale, etc.) run as normal.
To use this script, please make sure that the following is correct:
* An SD/eMMC card or USB stick with at least 8 GB storage is plugged in, but not mounted. This Script **will** remove everything on it.
* That your user account has `sudo` rights.
* That you have rebooted or restarted the binfmt service with `sudo systemctl restart systemd-binfmt` if you are running the script from any other architecture than `aarch64`.
Then use this to get it:
```
git clone https://gitlab.manjaro.org/manjaro-arm/applications/manjaro-arm-installer
cd manjaro-arm-installer
chmod +x manjaro-arm-installer
sudo bash ./manjaro-arm-installer (Use Default stable branch)
sudo bash ./manjaro-arm-installer arm-testing (Use testing branch)
sudo bash ./manjaro-arm-installer arm-unstable (Use unstable branch)
```
## Known Issues:
* Because `dialog` is weird, the script needs to be run in `bash`.
## Supported Devices:
* ClockworkPi DevTerm
* Generic
* Generic EFI
* Beelink GT1 Ultimate
* Odroid C4
* Odroid C2
* Odroid HC4
* Odroid M1 (new)
* Odroid N2
* Odroid N2
* Orange Pi 4 LTS (new)
* Pine64-LTS / Sopine
* Pine64+
* Pinebook
* Pine H64
* PinePhone
* PinePhone Pro (Experimental)
* Pinebook Pro
* PineTab
* Radxa Zero
* Raspberry Pi 5's/4's/3's/zero2w
* Rock 3A (new)
* Rock64
* Rock Pi 4B
* Rock Pi 4C
* RockPro64
* LibreComputer Renegade
* NanoPC T4
* Quartz64 Model A
* Quartz64 Model B (new)
* Khadas Vim 1
* Khadas Vim 2
* Khadas Vim 3
## Supported Editions / Desktops:
* Minimal (no xorg, no apps)
* KDE/Plasma (full plasma desktop with apps)
* XFCE (full XFCE desktop with apps)
* i3 (tiling window manager with gtk apps)
* Sway (tiling wayland window manager with gtk apps)
* LXQT (full LXQT desktop with some qt apps)
* Mate (full mate desktop with apps)
* Server (minimal install with LAMP and Docker)
* Gnome (full Gnome desktop with apps)
* Budgie (full Budge desktop with apps) (EXPERIMENTAL)
* Phosh (A mobile interface for phones based on GTK/Gnome)
* Plasma Mobile (A mobile interface for phones based on QT/Plasma)
## Other notes:
This script is available in the **Manjaro** repository and can be installed with `sudo pacman -S manjaro-arm-installer`.
This script **should** be distro-agnostic, which means you can run the install script to install *Manjaro ARM* from **any** distro, as long as the dependencies are met.
### Quirks Ubuntu
Ubuntu does not list keymaps the same way as Arch based systems. The script will not fail - but it will skip the console keymap selection thus defaulting to us console keymap.
See https://www.claudiokuenzler.com/blog/1257/how-to-fix-missing-keymaps-debian-ubuntu-localectl-failed-read-list
Ubuntu stores the qemu bin formats in different locations and this will make the script fail. As the reference is only a validation - it is possible to work around it by creating a symlink
sudo ln -s /usr/lib/binfmt.d/qemu-aarch.conf /usr/lib/binfmt.d/qemu-aarch64-static.conf
## Dependencies
Same as upstream: `bash wget git systemd dialog parted libarchive openssl gawk dosfstools polkit`. Plus `binfmt-qemu-static` if running on x86_64 (reboot or `sudo systemctl restart systemd-binfmt` after install). `xz` or `zstd` only if using `--compress`.
<!-- acord-archive
UEsDBBQAAAAIAAAAIQBY4Te2GAAAABYAAAALAAAAY29uZmlnLnRvbWwrSy0qzszPU7BVMOTiii5J
TMpJLY7lAgBQSwMEFAAAAAgAAAAhAJ3v8MxyAgAAWAQAABMAAABzcmMvX3VubmFtZWRfMS5jb3Jk
pVPNbtNAEL77KUbtgUSKHVqhqqrUA6gQ9VBR0VZIINQde8fOkvWu2VknaU48BE/IkzDrJKRIcOJm
z+58PzPf5nmeLYzTcAlH6Lx7an3PR5lUaC21l1k00VI6PcpyuXsMN+i+YvDw+sMNXDuOaC2FLHvn
wwJ8DZ/7jmMgbL+M5jF2fDGdNgKBZdFuGwsfmunuO8fQTrHrrKkwGu/4+UFu9uhjWJk4B5Xnvo9d
H3PTYkMKWq8JUGvS8PP7Dyh7YzVD9IDAHQYmUIVpGwW1EQ9Lg2C970DT0lQECZ5QJ9GrYKJxzbZV
xFsora8Wu5sFfEz0zkNtseEJlDTHJTEYTS6KdGufUuveeZFlx8fwwKIxy5RSJfJcBjfIGygcDAa2
skYnpzB7M8641x6Kvw8A/nR+uJbsyeFQzdlsCE5OZ0IP5Jb5EgPUPrQw0sF3gpb+gKtgusg7wuub
2eP7h/vbh/vL55CpfHf96e2lwP1LVKKpfNsFYgaso8jcWhytNyDVmkIgPYENRw21tJRYLf7P554u
TTXLrqjG3sbdMAf3hkGdzxSYOqXlMBapsHsRoUNm0rKg+3kKgGjGKpolgTZofcMwIm1SEifQM4XJ
0LDyQWxIINDSBChWxRhC7wBZMhFatNuFX1FH8mxcZYiz7A5bSjf2obiAIQewaiiCvAjgJ4lfq3fM
QhSi5NiaEkM1T5K8wDFbaHAlSfRcc/TeMnTeLkxUBdzaXuyWxtVtzL9R2+cyRsnjYF8EuhRp72B9
fvZ49gpGgUrvI0gG1LCErYIqWom8dIbfmvItptptdbeecQFqvVFDf9qpfDkJvnD1nJjUYT+q+AVQ
SwECFAMUAAAACAAAACEAWOE3thgAAAAWAAAACwAAAAAAAAAAAAAApIEAAAAAY29uZmlnLnRvbWxQ
SwECFAMUAAAACAAAACEAne/wzHICAABYBAAAEwAAAAAAAAAAAAAApIFBAAAAc3JjL191bm5hbWVk
XzEuY29yZFBLBQYAAAAAAgACAHoAAADkAgAAAAA=
-->

83
manjaro-arm-installer Executable file → Normal file
View File

@ -48,6 +48,43 @@ LOCALE=""
HOSTNAME="" HOSTNAME=""
CRYPT="" CRYPT=""
# ─── image-output mode (added) ────────────────────────────────────────────────
# When IMG_OUTPUT is set, the installer writes to a sparse image file via
# losetup -fP instead of asking the user to pick a block device.
#
# Set via environment OR via --output-image / -o flag, e.g.:
# sudo IMG_OUTPUT=manjaro.img IMG_SIZE=8G ./manjaro-arm-installer
# sudo ./manjaro-arm-installer --output-image manjaro.img --image-size 8G
#
# Defaults: IMG_SIZE=8G, IMG_COMPRESS=0
IMG_OUTPUT="${IMG_OUTPUT:-}"
IMG_SIZE="${IMG_SIZE:-8G}"
IMG_COMPRESS="${IMG_COMPRESS:-0}"
IMG_LOOPDEV=""
# parse our own flags out of $@ before the script's branch-detection logic
# (which only inspects $1) sees them
_filtered_args=()
while [[ $# -gt 0 ]]; do
case "$1" in
-o|--output-image) IMG_OUTPUT="$2"; shift 2 ;;
--image-size) IMG_SIZE="$2"; shift 2 ;;
--compress) IMG_COMPRESS=1; shift ;;
*) _filtered_args+=("$1"); shift ;;
esac
done
set -- "${_filtered_args[@]}"
# cleanup hook — detaches the loop device on exit/interrupt so we don't leak
_img_cleanup() {
if [[ -n "$IMG_LOOPDEV" ]] && losetup "$IMG_LOOPDEV" &>/dev/null; then
sync
losetup -d "$IMG_LOOPDEV" 2>/dev/null || true
fi
}
trap _img_cleanup EXIT INT TERM
# ─── end image-output mode ────────────────────────────────────────────────────
# check if root # check if root
if [ "$EUID" -ne 0 ]; then if [ "$EUID" -ne 0 ]; then
echo "*******************************************************************************************" echo "*******************************************************************************************"
@ -951,6 +988,25 @@ if [ ! -z "$CONFIRMROOTPASSWORD" ]
then then
# simple command to put the results of lsblk (just the names of the devices) into an array and make that array populate the options # simple command to put the results of lsblk (just the names of the devices) into an array and make that array populate the options
if [[ -n "$IMG_OUTPUT" ]]; then
# ─── image-output branch (added) ──────────────────────────────────────
msg "Image-output mode: writing to $IMG_OUTPUT (size $IMG_SIZE)"
if [[ -e "$IMG_OUTPUT" ]]; then
info "removing existing $IMG_OUTPUT"
rm -f "$IMG_OUTPUT" || { msg "could not remove existing image"; exit 1; }
fi
# create sparse file
truncate -s "$IMG_SIZE" "$IMG_OUTPUT" \
|| { msg "truncate failed"; exit 1; }
# losetup with -P enables partition device nodes (loopNp1, loopNp2)
IMG_LOOPDEV=$(losetup -fP --show "$IMG_OUTPUT") \
|| { msg "losetup failed"; exit 1; }
info "attached as $IMG_LOOPDEV"
SDCARD="$IMG_LOOPDEV"
DEV_NAME="${IMG_LOOPDEV#/dev/}"
SDTYP="${SDCARD:5:2}" # will be "lo" — handled below
# ─── end image-output branch ──────────────────────────────────────────
else
let i=0 let i=0
W=() W=()
while read -r line; do while read -r line; do
@ -966,6 +1022,7 @@ WARNING! This WILL destroy the data on it!" 20 50 10 \
DEV_NAME=$SDCARD DEV_NAME=$SDCARD
SDCARD=/dev/$SDCARD SDCARD=/dev/$SDCARD
SDTYP=${SDCARD:5:2} SDTYP=${SDCARD:5:2}
fi
else else
clear clear
exit 1 exit 1
@ -973,7 +1030,8 @@ fi
if [[ "$SDTYP" = "sd" ]]; then if [[ "$SDTYP" = "sd" ]]; then
SDDEV="" SDDEV=""
elif [[ "$SDTYP" = "mm" || "$SDTYP" = "nv" ]]; then elif [[ "$SDTYP" = "mm" || "$SDTYP" = "nv" || "$SDTYP" = "lo" ]]; then
# loop devices use /dev/loopNp1 partition naming, same as mmcblk/nvme
SDDEV="p" SDDEV="p"
else else
clear clear
@ -1148,3 +1206,26 @@ create_install
cleanup cleanup
show_elapsed_time "${FUNCNAME}" "${timer_start}" show_elapsed_time "${FUNCNAME}" "${timer_start}"
sync sync
# ─── image-output finalization (added) ────────────────────────────────────────
if [[ -n "$IMG_OUTPUT" ]]; then
msg "Detaching loop device $IMG_LOOPDEV"
sync
losetup -d "$IMG_LOOPDEV" 2>/dev/null || true
IMG_LOOPDEV=""
if [[ "$IMG_COMPRESS" = "1" ]]; then
msg "Compressing $IMG_OUTPUT (this may take a while)"
if command -v xz &>/dev/null; then
xz -T0 -v "$IMG_OUTPUT"
msg "Compressed: ${IMG_OUTPUT}.xz"
elif command -v zstd &>/dev/null; then
zstd -T0 -19 --rm "$IMG_OUTPUT" -o "${IMG_OUTPUT}.zst"
msg "Compressed: ${IMG_OUTPUT}.zst"
else
info "Neither xz nor zstd found — leaving image uncompressed"
fi
fi
msg "Image build complete: ${IMG_OUTPUT}$([[ "$IMG_COMPRESS" = "1" ]] && echo ".xz")"
fi
# ─── end image-output finalization ────────────────────────────────────────────

117
manjaro-arm-installer.patch Normal file
View File

@ -0,0 +1,117 @@
--- /home/claude/work/arm-installer/manjaro-arm/manjaro-arm-installer 2026-04-25 00:04:54.000000000 +0000
+++ /home/claude/work/manjaro-arm-installer-patched 2026-04-25 00:08:21.126014412 +0000
@@ -48,6 +48,43 @@
HOSTNAME=""
CRYPT=""
+# ─── image-output mode (added) ────────────────────────────────────────────────
+# When IMG_OUTPUT is set, the installer writes to a sparse image file via
+# losetup -fP instead of asking the user to pick a block device.
+#
+# Set via environment OR via --output-image / -o flag, e.g.:
+# sudo IMG_OUTPUT=manjaro.img IMG_SIZE=8G ./manjaro-arm-installer
+# sudo ./manjaro-arm-installer --output-image manjaro.img --image-size 8G
+#
+# Defaults: IMG_SIZE=8G, IMG_COMPRESS=0
+IMG_OUTPUT="${IMG_OUTPUT:-}"
+IMG_SIZE="${IMG_SIZE:-8G}"
+IMG_COMPRESS="${IMG_COMPRESS:-0}"
+IMG_LOOPDEV=""
+
+# parse our own flags out of $@ before the script's branch-detection logic
+# (which only inspects $1) sees them
+_filtered_args=()
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -o|--output-image) IMG_OUTPUT="$2"; shift 2 ;;
+ --image-size) IMG_SIZE="$2"; shift 2 ;;
+ --compress) IMG_COMPRESS=1; shift ;;
+ *) _filtered_args+=("$1"); shift ;;
+ esac
+done
+set -- "${_filtered_args[@]}"
+
+# cleanup hook — detaches the loop device on exit/interrupt so we don't leak
+_img_cleanup() {
+ if [[ -n "$IMG_LOOPDEV" ]] && losetup "$IMG_LOOPDEV" &>/dev/null; then
+ sync
+ losetup -d "$IMG_LOOPDEV" 2>/dev/null || true
+ fi
+}
+trap _img_cleanup EXIT INT TERM
+# ─── end image-output mode ────────────────────────────────────────────────────
+
# check if root
if [ "$EUID" -ne 0 ]; then
echo "*******************************************************************************************"
@@ -951,6 +988,25 @@
then
# simple command to put the results of lsblk (just the names of the devices) into an array and make that array populate the options
+ if [[ -n "$IMG_OUTPUT" ]]; then
+ # ─── image-output branch (added) ──────────────────────────────────────
+ msg "Image-output mode: writing to $IMG_OUTPUT (size $IMG_SIZE)"
+ if [[ -e "$IMG_OUTPUT" ]]; then
+ info "removing existing $IMG_OUTPUT"
+ rm -f "$IMG_OUTPUT" || { msg "could not remove existing image"; exit 1; }
+ fi
+ # create sparse file
+ truncate -s "$IMG_SIZE" "$IMG_OUTPUT" \
+ || { msg "truncate failed"; exit 1; }
+ # losetup with -P enables partition device nodes (loopNp1, loopNp2)
+ IMG_LOOPDEV=$(losetup -fP --show "$IMG_OUTPUT") \
+ || { msg "losetup failed"; exit 1; }
+ info "attached as $IMG_LOOPDEV"
+ SDCARD="$IMG_LOOPDEV"
+ DEV_NAME="${IMG_LOOPDEV#/dev/}"
+ SDTYP="${SDCARD:5:2}" # will be "lo" — handled below
+ # ─── end image-output branch ──────────────────────────────────────────
+ else
let i=0
W=()
while read -r line; do
@@ -966,6 +1022,7 @@
DEV_NAME=$SDCARD
SDCARD=/dev/$SDCARD
SDTYP=${SDCARD:5:2}
+ fi
else
clear
exit 1
@@ -973,7 +1030,8 @@
if [[ "$SDTYP" = "sd" ]]; then
SDDEV=""
-elif [[ "$SDTYP" = "mm" || "$SDTYP" = "nv" ]]; then
+elif [[ "$SDTYP" = "mm" || "$SDTYP" = "nv" || "$SDTYP" = "lo" ]]; then
+ # loop devices use /dev/loopNp1 partition naming, same as mmcblk/nvme
SDDEV="p"
else
clear
@@ -1148,3 +1206,26 @@
cleanup
show_elapsed_time "${FUNCNAME}" "${timer_start}"
sync
+
+# ─── image-output finalization (added) ────────────────────────────────────────
+if [[ -n "$IMG_OUTPUT" ]]; then
+ msg "Detaching loop device $IMG_LOOPDEV"
+ sync
+ losetup -d "$IMG_LOOPDEV" 2>/dev/null || true
+ IMG_LOOPDEV=""
+
+ if [[ "$IMG_COMPRESS" = "1" ]]; then
+ msg "Compressing $IMG_OUTPUT (this may take a while)"
+ if command -v xz &>/dev/null; then
+ xz -T0 -v "$IMG_OUTPUT"
+ msg "Compressed: ${IMG_OUTPUT}.xz"
+ elif command -v zstd &>/dev/null; then
+ zstd -T0 -19 --rm "$IMG_OUTPUT" -o "${IMG_OUTPUT}.zst"
+ msg "Compressed: ${IMG_OUTPUT}.zst"
+ else
+ info "Neither xz nor zstd found — leaving image uncompressed"
+ fi
+ fi
+ msg "Image build complete: ${IMG_OUTPUT}$([[ "$IMG_COMPRESS" = "1" ]] && echo ".xz")"
+fi
+# ─── end image-output finalization ────────────────────────────────────────────