Compare commits

..

23 Commits

Author SHA1 Message Date
e60b3cf2a7 Overall optimations 2025-03-22 11:42:13 +01:00
94fdcf5758 Implemented wrapper for pkgmgr and more sync for safe image transfer and manjaro gnome 24 2025-03-22 10:28:14 +01:00
b4a0b50e1f Added Funding 2025-03-12 20:52:47 +01:00
d613fbf262 Merge branch 'master' of github.com:kevinveenbirkenbach/linux-image-manager 2025-03-12 11:14:39 +01:00
bf95ba6090 Update README.md 2025-03-12 10:49:37 +01:00
7f82c6fcb9 Update README.md 2025-03-04 19:59:47 +01:00
13454c7e87 Added missing keyy add 2025-02-15 12:46:40 +01:00
72c4d95606 Added overview about LUKS encrypted storage devices 2025-02-15 12:03:51 +01:00
3f272790d6 Update Hints 2025-02-14 15:48:01 +01:00
bac3edc404 Optimized logic 2024-07-22 23:49:25 +02:00
b2881c1319 Added platform 2024-07-22 23:43:02 +02:00
3daed9447b Implemented automatic boot_size and .xz file management 2024-07-22 23:23:40 +02:00
bd05fd4c2d Optimized setup of manjaro for raspberry pi 4 2024-07-22 22:46:02 +02:00
bbb54a4237 Optimized logic for luks and implemented administrator setup 2024-07-22 21:23:03 +02:00
9519b314e9 Added logic for luks memory cost 2024-07-22 17:17:37 +02:00
826aa42565 Removed earlyprint 2024-07-22 02:37:59 +02:00
19f5dc7178 Removed typo 2024-07-21 23:13:36 +02:00
5aa8f65584 Implemented optimations for raspberry pi 4 2024-07-21 22:44:39 +02:00
e37d57d569 Solved bug 2024-07-21 16:03:04 +02:00
c05e804fb5 Added cleanup hints 2024-07-21 15:34:05 +02:00
e40974f56d Refactored code and solved bugs 2024-07-21 15:30:17 +02:00
e8581cb448 Solved replacement bug 2024-07-21 03:32:52 +02:00
38a289083d Implemented search replace validation and solved password bug 2024-07-21 01:11:29 +02:00
10 changed files with 497 additions and 109 deletions

7
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
github: kevinveenbirkenbach
patreon: kevinveenbirkenbach
buy_me_a_coffee: kevinveenbirkenbach
custom: https://s.veen.world/paypaldonate

142
README.md
View File

@@ -1,40 +1,136 @@
# Linux Image Manager # Linux Image Manager 🖥️🛠️
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](./LICENSE.txt)
This repository contains some shell scripts to download and configure linux images and to transfer them to a storage. [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate)
## Virtual Btrfs RAID1 Setup [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](./LICENSE.txt) [![GitHub stars](https://img.shields.io/github/stars/kevinveenbirkenbach/linux-image-manager.svg?style=social)](https://github.com/kevinveenbirkenbach/linux-image-manager/stargazers)
To setup a virtual btrfs encrypted raid 1 execute: Linux Image Manager (lim) is a powerful collection of shell scripts for downloading, configuring, and managing Linux images. Whether you're setting up encrypted storage, configuring a virtual Btrfs RAID1, performing backups, or chrooting into an image, this tool makes Linux image administration simple and efficient. 🚀
> **Note:** In this project, `lim` is an alias for the **main.py** wrapper script which orchestrates the execution of the various shell scripts.
## Features ✨
- **Image Download & Setup:** Automatically download and prepare Linux distributions.
- **Encrypted Storage:** Configure LUKS encryption for secure image management.
- **Virtual RAID1:** Easily set up virtual Btrfs RAID1 for data redundancy.
- **Backup & Restore:** Create image backups from devices using dd.
- **Chroot Environment:** Easily enter a chroot shell to maintain or modify Linux images.
- **Automated Procedures:** Simplify partitioning, formatting, mounting, and more.
## Installation 📦
Install Linux Image Manager quickly using [Kevin's Package Manager](https://github.com/kevinveenbirkenbach/package-manager) under the alias `lim`. Just run:
```bash ```bash
bash scripts/encryption/storage/raid1/setup.sh package-manager install lim
``` ```
## Setup This command makes Linux Image Manager globally available as `lim` in your terminal. The `lim` alias points to the **main.py** wrapper script.
To install a Linux distribution execute: ## Usage ⚙️
```bash The **main.py** wrapper provides a unified interface to run the different shell scripts included in this project. It supports various script types and allows you to pass additional parameters. The built-in `--help` option displays detailed usage information.
sudo bash ./scripts/image/setup.sh
```
## Chroot ### Available Script Types
To chroot into a Linux distribution on a storage execute: - **Image Setup (`--type image`):**
Executes the Linux image setup located at `scripts/image/setup.sh`. This setup:
- Creates partitions and formats them.
- Transfers the Linux image file to the device.
- Configures boot and root partitions.
```bash - **Single Drive Encryption Setup (`--type single`):**
sudo bash ./scripts/image/chroot.sh Executes the single-drive encryption setup from `scripts/encryption/storage/single_drive/setup.sh`. This setup:
``` - Sets up disk encryption using LUKS on one drive.
- Configures a Btrfs file system for secure storage.
## Backup - **RAID1 Encryption Setup (`--type raid1`):**
Executes the RAID1 encryption setup found at `scripts/encryption/storage/raid1/setup.sh`. This setup:
- Configures a virtual RAID1 with two drives.
- Uses LUKS encryption and a Btrfs RAID1 file system for redundancy.
To backup a image execute: - **Backup Image Setup (`--type backup`):**
Executes the backup image setup located at `scripts/image/backup.sh`. This setup:
- Creates an image backup from a memory device to a file.
- Uses `dd` to transfer the image from the specified device to an image file.
```bash - **Chroot Environment Setup (`--type chroot`):**
sudo bash ./scripts/image/backup.sh Executes the chroot setup from `scripts/image/chroot.sh`. This setup:
``` - Mounts partitions and configures the chroot environment for a Linux image.
- Provides a shell within the Linux image for system maintenance.
## License ### Command-Line Options
The ["GNU GENERAL PUBLIC LICENSE Version 3"](./LICENSE.txt) applies to this project. - **`--type`**
**(Required)** Choose the type of script to execute. Options include: `image`, `single`, `raid1`, `backup`, and `chroot`.
- **`--extra`**
**(Optional)** Pass any extra parameters directly to the selected shell script.
- **`--auto-confirm`**
**(Optional)** Automatically bypass the confirmation prompt before executing the selected script.
- **`--help`**
**(Optional)** Displays detailed help information about the command-line options and usage of the wrapper. Simply run:
```bash
lim --help
```
to view the complete help message.
### Example Commands
- **Display Help:**
```bash
lim --help
```
- **Show Information About the Image Setup:**
```bash
lim --type image --info
```
- **Execute the Linux Image Setup (with extra parameters):**
```bash
lim --type image --extra --some-option value
```
- **Run the Single Drive Encryption Setup without a confirmation prompt:**
```bash
lim --type single --auto-confirm
```
- **Execute the RAID1 Encryption Setup:**
```bash
lim --type raid1
```
- **Perform a Backup of an Image:**
```bash
lim --type backup
```
- **Enter a Chroot Environment for a Linux Image:**
```bash
lim --type chroot
```
For additional details on each script and further configuration options, please refer to the `scripts/` and `configuration/` directories.
## Configuration & Customization 🔧
Customize your environment in the `configuration/` folder:
- **General Packages:** Contains common packages for all setup scripts.
- **Server LUKS Packages:** Contains packages needed for setting up LUKS encryption on servers.
## License 📜
This project is licensed under the GNU General Public License Version 3. See the [LICENSE.txt](./LICENSE.txt) file for details.
## Contact & Support 💬
- **Author:** Kevin Veen-Birkenbach
- **Email:** [kevin@veen.world](mailto:kevin@veen.world)
- **Website:** [https://www.veen.world/](https://www.veen.world/)
Feel free to contribute, report issues, or get in touch. Happy Linux managing! 😊
```

118
main.py Executable file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env python3
import subprocess
import os
import argparse
import sys
def run_script(script_path, extra_args):
if not os.path.exists(script_path):
print(f"[ERROR] Script not found at {script_path}")
exit(1)
command = ["sudo", "bash", script_path] + extra_args
print(f"[INFO] Running command: {' '.join(command)}")
# Pass the parent's stdout and stderr so that progress output shows in real time.
result = subprocess.run(command, stdout=sys.stdout, stderr=sys.stderr)
if result.returncode != 0:
print(f"[ERROR] Script exited with code {result.returncode}")
exit(result.returncode)
print("[SUCCESS] Script executed successfully.")
def main():
# Use os.path.realpath to get the actual path of this file regardless of symlinks.
repo_root = os.path.dirname(os.path.realpath(__file__))
# Define available scripts along with their descriptions.
setup_scripts = {
"image": {
"path": os.path.join(repo_root, "scripts", "image", "setup.sh"),
"description": (
"Linux Image Setup:\n"
" - Creates partitions and formats them.\n"
" - Transfers the Linux image file to the device.\n"
" - Configures boot and root partitions."
)
},
"single": {
"path": os.path.join(repo_root, "scripts", "encryption", "storage", "single_drive", "setup.sh"),
"description": (
"Single Drive Encryption Setup:\n"
" - Sets up disk encryption using LUKS on one drive.\n"
" - Configures a Btrfs file system for secure storage."
)
},
"raid1": {
"path": os.path.join(repo_root, "scripts", "encryption", "storage", "raid1", "setup.sh"),
"description": (
"RAID1 Encryption Setup:\n"
" - Configures a virtual RAID1 with two drives.\n"
" - Uses LUKS encryption and a Btrfs RAID1 file system for redundancy."
)
},
"backup": {
"path": os.path.join(repo_root, "scripts", "image", "backup.sh"),
"description": (
"Backup Image Setup:\n"
" - Creates an image backup from a memory device to a file.\n"
" - Uses dd to transfer the image from the specified device to an image file."
)
},
"chroot": {
"path": os.path.join(repo_root, "scripts", "image", "chroot.sh"),
"description": (
"Chroot Environment Setup:\n"
" - Mounts partitions and configures the chroot environment for a Linux image.\n"
" - Provides a shell within the Linux image for system maintenance."
)
}
}
parser = argparse.ArgumentParser(
description="Wrapper for executing various scripts from Linux Image Manager.",
epilog=(
"Available script types:\n"
" image - Linux Image Setup\n"
" single - Single Drive Encryption Setup\n"
" raid1 - RAID1 Encryption Setup\n"
" backup - Backup Image Setup\n"
" chroot - Chroot Environment Setup\n\n"
"Additional Options:\n"
" --extra Pass extra parameters to the selected script.\n"
" --auto-confirm Bypass the confirmation prompt before execution.\n"
" --help Display this help message and exit."
),
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("--type", required=True, choices=list(setup_scripts.keys()),
help="Select the script type to execute. Options: " + ", ".join(setup_scripts.keys()))
parser.add_argument("--extra", nargs=argparse.REMAINDER, default=[],
help="Extra parameters to pass to the selected script.")
parser.add_argument("--auto-confirm", action="store_true",
help="Automatically confirm execution without prompting the user.")
args = parser.parse_args()
script_info = setup_scripts[args.type]
print("[INFO] Selected script type:", args.type)
print("[INFO] Description:")
print(script_info["description"])
print("[INFO] Script path:", script_info["path"])
if args.extra:
print("[INFO] Extra parameters provided:", " ".join(args.extra))
else:
print("[INFO] No extra parameters provided.")
if not args.auto_confirm:
try:
input("Press Enter to execute the script or Ctrl+C to cancel...")
except KeyboardInterrupt:
print("\n[ERROR] Execution aborted by user.")
exit(1)
run_script(script_info["path"], args.extra)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[ERROR] Execution aborted by user.")
exit(1)

2
requirements.yml Normal file
View File

@@ -0,0 +1,2 @@
pacman:
- pv

View File

@@ -95,14 +95,34 @@ set_device_path(){
info "Optimal blocksize set to: $OPTIMAL_BLOCKSIZE" || error info "Optimal blocksize set to: $OPTIMAL_BLOCKSIZE" || error
} }
print_partition_table_info() {
echo "##########################################################################################"
echo "Note on Partition Table Deletion:"
echo "---------------------------------------------"
echo "• MBR (Master Boot Record):"
echo " - Typically occupies the first sector (512 bytes), i.e., 1 block."
echo ""
echo "• GPT (GUID Partition Table):"
echo " - Uses a protective MBR (1 block), a GPT header (1 block),"
echo " and usually a partition entry array that takes up about 32 blocks."
echo " - Total: approximately 34 blocks (assuming a 512-byte block size)."
echo ""
echo "Recommendation: For deleting a GPT partition table, use a block size of 512 bytes"
echo " and overwrite at least 34 blocks to ensure the entire table is cleared."
echo "##########################################################################################"
}
overwrite_device() { overwrite_device() {
# Call the function to display the information.
print_partition_table_info
question "Should $device_path be overwritten with zeros before copying? (y/N/block count)" && read -r copy_zeros_to_device question "Should $device_path be overwritten with zeros before copying? (y/N/block count)" && read -r copy_zeros_to_device
case "$copy_zeros_to_device" in case "$copy_zeros_to_device" in
y) y)
info "Overwriting entire device..." && info "Overwriting entire device..." &&
dd if=/dev/zero of="$device_path" bs="$OPTIMAL_BLOCKSIZE" status=progress || error "Overwriting $device_path failed." dd if=/dev/zero of="$device_path" bs="$OPTIMAL_BLOCKSIZE" status=progress && sync || error "Overwriting $device_path failed."
;; ;;
N) N|'')
info "Skipping Overwriting..." info "Skipping Overwriting..."
;; ;;
''|*[!0-9]*) ''|*[!0-9]*)
@@ -111,7 +131,7 @@ overwrite_device() {
*) *)
if [[ "$copy_zeros_to_device" =~ ^[0-9]+$ ]]; then if [[ "$copy_zeros_to_device" =~ ^[0-9]+$ ]]; then
info "Overwriting $copy_zeros_to_device blocks..." && info "Overwriting $copy_zeros_to_device blocks..." &&
dd if=/dev/zero of="$device_path" bs="$OPTIMAL_BLOCKSIZE" count="$copy_zeros_to_device" status=progress || error "Overwriting $device_path failed." dd if=/dev/zero of="$device_path" bs="$OPTIMAL_BLOCKSIZE" count="$copy_zeros_to_device" status=progress && sync || error "Overwriting $device_path failed."
else else
error "Invalid input. Block count must be a number." error "Invalid input. Block count must be a number."
fi fi

View File

@@ -29,12 +29,13 @@ create_luks_key_and_update_cryptab(){
info "Generate secret key under: $secret_key_path" || error info "Generate secret key under: $secret_key_path" || error
if [ -f "$secret_key_path" ] if [ -f "$secret_key_path" ]
then then
warning "File allready exist. Overwritting!" warning "File already exists. Overwriting!"
fi fi
sudo dd if=/dev/urandom of="$secret_key_path" bs=512 count=8 && sudo dd if=/dev/urandom of="$secret_key_path" bs=512 count=8 && sync &&
sudo cryptsetup -v luksAddKey "$2" "$secret_key_path" &&
info "Opening and closing device to verify that that everything works fine..." || error info "Opening and closing device to verify that everything works fine..." &&
sudo cryptsetup -v luksClose "$1" || info "No need to luksClose $1." sudo cryptsetup -v luksClose "$1" || info "No need to luksClose $1. Device isn't open." &&
sudo cryptsetup luksAddKey $2 $secret_key_path &&
sudo cryptsetup -v luksOpen "$2" "$1" --key-file="$secret_key_path" && sudo cryptsetup -v luksOpen "$2" "$1" --key-file="$secret_key_path" &&
sudo cryptsetup -v luksClose "$1" && sudo cryptsetup -v luksClose "$1" &&
info "Reading UUID..." && info "Reading UUID..." &&
@@ -45,7 +46,7 @@ create_luks_key_and_update_cryptab(){
info "Adding crypttab entry..." || error info "Adding crypttab entry..." || error
if sudo grep -q "$crypttab_entry" "$crypttab_path"; if sudo grep -q "$crypttab_entry" "$crypttab_path";
then then
warning "File $crypttab_path contains allready the following entry:" && warning "File $crypttab_path already contains the following entry:" &&
echo "$crypttab_entry" && echo "$crypttab_entry" &&
info "Skipped." || info "Skipped." ||
error error
@@ -59,6 +60,7 @@ create_luks_key_and_update_cryptab(){
error error
} }
# @var $1 mapper_name # @var $1 mapper_name
# @var $2 mount_path # @var $2 mount_path
# #

View File

@@ -3,7 +3,13 @@
# shellcheck disable=SC2154 # Referenced but not assigned # shellcheck disable=SC2154 # Referenced but not assigned
# shellcheck disable=SC2015 #Deactivate bool hint # shellcheck disable=SC2015 #Deactivate bool hint
source "$(dirname "$(readlink -f "${0}")")/base.sh" || (echo "Loading base.sh failed." && exit 1) source "$(dirname "$(readlink -f "${0}")")/base.sh" || (echo "Loading base.sh failed." && exit 1)
info "Automount raid1 encrypted storages..." && info "Activate Automount raid1 encrypted storages..." &&
echo ""
for dev in $(lsblk -dno NAME); do
if sudo cryptsetup isLuks /dev/$dev 2>/dev/null; then
info "/dev/$dev is a LUKS encrypted storage device."
fi
done
set_raid1_devices_mount_partition_and_mapper_paths && set_raid1_devices_mount_partition_and_mapper_paths &&
create_luks_key_and_update_cryptab "$mapper_name_1" "$device_path_1" && create_luks_key_and_update_cryptab "$mapper_name_1" "$device_path_1" &&
info "Creating mount folder unter \"$mount_path_1\"..." && info "Creating mount folder unter \"$mount_path_1\"..." &&

View File

@@ -25,6 +25,6 @@ question "Please confirm by pushing \"Enter\". To cancel use \"Ctrl + Alt + C\""
read -r bestaetigung && echo "$bestaetigung"; read -r bestaetigung && echo "$bestaetigung";
info "Imagetransfer starts. This can take a while..." && info "Imagetransfer starts. This can take a while..." &&
dd if="$device_path" of="$ofi" bs=1M status=progress || error "\"dd\" failed."; dd if="$device_path" of="$ofi" bs=1M status=progress && sync || error "\"dd\" failed.";
success "Imagetransfer successfull." && exit 0; success "Imagetransfer successfull." && exit 0;

View File

@@ -38,7 +38,7 @@ make_mount_folders(){
} }
make_working_folder(){ make_working_folder(){
working_folder_path="/tmp/raspberry-pi-tools-$(date +%s)/" && working_folder_path="/tmp/linux-image-manager-$(date +%s)/" &&
info "Create temporary working folder in $working_folder_path" && info "Create temporary working folder in $working_folder_path" &&
mkdir -v "$working_folder_path" || mkdir -v "$working_folder_path" ||
error error
@@ -48,7 +48,7 @@ decrypt_root(){
if [ "$(blkid "$root_partition_path" -s TYPE -o value)" == "crypto_LUKS" ] if [ "$(blkid "$root_partition_path" -s TYPE -o value)" == "crypto_LUKS" ]
then then
root_partition_uuid=$(blkid "$root_partition_path" -s UUID -o value) && root_partition_uuid=$(blkid "$root_partition_path" -s UUID -o value) &&
root_mapper_name="arch-root-$root_partition_uuid" && root_mapper_name="linux-image-manager-$root_partition_uuid" &&
root_mapper_path="/dev/mapper/$root_mapper_name" && root_mapper_path="/dev/mapper/$root_mapper_name" &&
info "Decrypting of $root_partition_path is neccessary..." && info "Decrypting of $root_partition_path is neccessary..." &&
sudo cryptsetup -v luksOpen "$root_partition_path" "$root_mapper_name" || error sudo cryptsetup -v luksOpen "$root_partition_path" "$root_mapper_name" || error

View File

@@ -21,6 +21,32 @@ install(){
esac esac
} }
replace_in_file() {
# Assign the first function argument to the local variable search_string
local search_string=$1
# Assign the second function argument to the local variable replace_string
local replace_string=$2
# Assign the third function argument to the local variable file_path
local file_path=$3
# Create a temporary file and store its path in temp_file
temp_file=$(mktemp)
# Use sed to replace the search_string with replace_string in the file at file_path
# Write the output to the temporary file
sed "s/$search_string/$replace_string/g" "$file_path" > "$temp_file"
# Compare the original file with the temporary file
if cmp -s "$file_path" "$temp_file"; then
# If files are identical, remove the temporary file and signal an error
rm -f "$temp_file"
error "Error: Search string '$search_string' not found in $file_path."
else
# If files are different, move the temporary file to overwrite the original file
mv "$temp_file" "$file_path"
fi
}
info "Setupscript for images started..." info "Setupscript for images started..."
info "Checking if root..." info "Checking if root..."
@@ -62,32 +88,44 @@ case "$operation_system" in
base_download_url="https://www.fosshub.com/Android-x86.html?dwl=android-x86_64-9.0-r2.iso"; base_download_url="https://www.fosshub.com/Android-x86.html?dwl=android-x86_64-9.0-r2.iso";
image_name="android-x86_64-9.0-r2.iso" image_name="android-x86_64-9.0-r2.iso"
image_checksum="f7eb8fc56f29ad5432335dc054183acf086c539f3990f0b6e9ff58bd6df4604e" image_checksum="f7eb8fc56f29ad5432335dc054183acf086c539f3990f0b6e9ff58bd6df4604e"
boot_size="+500M"
;; ;;
"torbox") "torbox")
base_download_url="https://www.torbox.ch/data/"; base_download_url="https://www.torbox.ch/data/";
image_name="torbox-20220102-v050.gz" image_name="torbox-20220102-v050.gz"
image_checksum="0E1BA7FFD14AAAE5F0462C8293D95B62C3BF1D9E726E26977BD04772C55680D3" image_checksum="0E1BA7FFD14AAAE5F0462C8293D95B62C3BF1D9E726E26977BD04772C55680D3"
boot_size="+200M"
;; ;;
"arch") "arch")
question "Which Raspberry Pi will be used (e.g.: 1, 2, 3, 4...):" && read -r version question "Which Raspberry Pi will be used (e.g.: 1, 2, 3b, 3b+, 4...):" && read -r raspberry_pi_version
boot_size="+500M"
base_download_url="http://os.archlinuxarm.org/os/"; base_download_url="http://os.archlinuxarm.org/os/";
image_name="ArchLinuxARM-rpi-$version.tar.gz" case "$raspberry_pi_version" in
case "$version" in
"1") "1")
image_name="ArchLinuxARM-rpi-latest.tar.gz"
;;
"2" | "3")
image_name="ArchLinuxARM-rpi-armv7-latest.tar.gz" image_name="ArchLinuxARM-rpi-armv7-latest.tar.gz"
luks_memory_cost="64000"
;; ;;
"2")
"4") image_name="ArchLinuxARM-rpi-armv7-latest.tar.gz"
luks_memory_cost="128000"
;;
"3b" | "3b+")
image_name="ArchLinuxARM-rpi-aarch64-latest.tar.gz" image_name="ArchLinuxARM-rpi-aarch64-latest.tar.gz"
luks_memory_cost="128000"
;;
"4" )
image_name="ArchLinuxARM-rpi-aarch64-latest.tar.gz"
luks_memory_cost="256000"
;;
*)
error "Version $raspberry_pi_version isn't supported."
;; ;;
esac esac
;; ;;
"manjaro") "manjaro")
question "Which version(e.g.:architect,gnome) should be used:" && read -r version question "Which version(e.g.:architect,gnome) should be used:" && read -r gnome_version
case "$version" in boot_size="+500M"
case "$gnome_version" in
"architect") "architect")
image_checksum="6b1c2fce12f244c1e32212767a9d3af2cf8263b2" image_checksum="6b1c2fce12f244c1e32212767a9d3af2cf8263b2"
base_download_url="https://osdn.net/frs/redir.php?m=dotsrc&f=%2Fstorage%2Fg%2Fm%2Fma%2Fmanjaro%2Farchitect%2F20.0%2F"; base_download_url="https://osdn.net/frs/redir.php?m=dotsrc&f=%2Fstorage%2Fg%2Fm%2Fma%2Fmanjaro%2Farchitect%2F20.0%2F";
@@ -109,23 +147,35 @@ case "$operation_system" in
base_download_url="https://download.manjaro.org/gnome/22.1.3/" base_download_url="https://download.manjaro.org/gnome/22.1.3/"
image_name="manjaro-gnome-22.1.3-230529-linux61.iso" image_name="manjaro-gnome-22.1.3-230529-linux61.iso"
;; ;;
"24")
base_download_url="https://download.manjaro.org/gnome/24.2.1/"
image_name="manjaro-gnome-24.2.1-241216-linux612.iso"
;;
"raspberrypi") "raspberrypi")
# at the moment just optimized for raspberry pi 4
base_download_url="https://github.com/manjaro-arm/rpi4-images/releases/download/23.02/" base_download_url="https://github.com/manjaro-arm/rpi4-images/releases/download/23.02/"
image_name="Manjaro-ARM-gnome-rpi4-23.02.img.xz" image_name="Manjaro-ARM-gnome-rpi4-23.02.img.xz"
luks_memory_cost="256000"
raspberry_pi_version="4"
;;
*)
error "Gnome Version $gnome_version isn't supported."
;; ;;
esac esac
;; ;;
esac esac
;; ;;
"moode") "moode")
boot_size="+200M"
image_checksum="185cbc9a4994534bb7a4bc2744c78197" image_checksum="185cbc9a4994534bb7a4bc2744c78197"
base_download_url="https://github.com/moode-player/moode/releases/download/r651prod/" base_download_url="https://github.com/moode-player/moode/releases/download/r651prod/"
image_name="moode-r651-iso.zip"; image_name="moode-r651-iso.zip";
;; ;;
"retropie") "retropie")
question "Which version(e.g.:1,2,3,4) should be used:" && read -r version boot_size="+500M"
question "Which version(e.g.:1,2,3,4) should be used:" && read -r raspberry_pi_version
base_download_url="https://github.com/RetroPie/RetroPie-Setup/releases/download/4.8/"; base_download_url="https://github.com/RetroPie/RetroPie-Setup/releases/download/4.8/";
case "$version" in case "$raspberry_pi_version" in
"1") "1")
image_checksum="95a6f84453df36318830de7e8507170e" image_checksum="95a6f84453df36318830de7e8507170e"
image_name="retropie-buster-4.8-rpi1_zero.img.gz" image_name="retropie-buster-4.8-rpi1_zero.img.gz"
@@ -195,18 +245,28 @@ if [ -z "$image_checksum" ]; then
done done
fi fi
if [[ -v image_checksum ]] if [[ -v image_checksum ]]; then
then info "A checksum is defined for the image."
(info "Checking md5 checksum..." && echo "$image_checksum $image_path"| md5sum -c -) || info "Checksums verify file integrity to ensure that the file was not corrupted during download."
(info "Checking sha1 checksum..." && echo "$image_checksum $image_path"| sha1sum -c -) || info "The script will try verifying the integrity using MD5, then SHA1, and finally SHA256 if needed."
(info "Checking sha256 checksum..." && echo "$image_checksum $image_path"| sha256sum -c -) ||
error "Verification failed. HINT: Force the download of the image." info "Trying MD5 checksum verification..."
else (info "Checking md5 checksum..." && echo "$image_checksum $image_path" | md5sum -c -) ||
warning "Verification is not possible. No checksum is defined." (warning "MD5 verification failed. This may indicate data corruption." &&
info "Trying SHA1 checksum verification for a secondary integrity check..." &&
info "Checking sha1 checksum..." && echo "$image_checksum $image_path" | sha1sum -c -) ||
(warning "SHA1 verification failed. Attempting SHA256 verification for thoroughness." &&
info "SHA256 provides a more robust check and is used as a final integrity measure." &&
info "Checking sha256 checksum..." && echo "$image_checksum $image_path" | sha256sum -c -) ||
error "Verification failed. HINT: Force the download of the image."
else
warning "No checksum is defined. Skipping checksum verification."
fi fi
info "Verifying signature..." info "Note: Checksums verify integrity but do not confirm authenticity."
info "Proceeding to signature verification, which ensures the file comes from a trusted source."
signature_download_url="$download_url.sig" signature_download_url="$download_url.sig"
info "Attempting to download the image signature from: $signature_download_url"
info "Try to download image signature from $signature_download_url." info "Try to download image signature from $signature_download_url."
if wget -q --method=HEAD "$signature_download_url"; then if wget -q --method=HEAD "$signature_download_url"; then
@@ -268,13 +328,8 @@ if [ "$transfer_image" = "y" ]
info "Starting image transfer..." info "Starting image transfer..."
if [ "$distribution" = "arch" ] if [ "$distribution" = "arch" ]
then then
# Set default size of the boot partition
# Default size of the boot partition boot_size=${boot_size:-"+500M"}
default_boot_size="+300M"
# Prompt to adjust the boot partition size
question "What size should the boot partition be? (Default: $default_boot_size):" && read -r boot_size
boot_size=${boot_size:-$default_boot_size}
# Use the provided size or the default size # Use the provided size or the default size
info "The boot partition will be set to $boot_size." info "The boot partition will be set to $boot_size."
@@ -304,8 +359,15 @@ if [ "$transfer_image" = "y" ]
if [ "$encrypt_system" == "y" ] if [ "$encrypt_system" == "y" ]
then then
info "Formating $root_partition_path with LUKS..." && # Check if luks_memory_cost is defined and set the luksAddKey command accordingly
sudo cryptsetup -v luksFormat -c aes-xts-plain64 -s 512 -h sha512 --use-random -i 1000 "$root_partition_path" && # @see https://chatgpt.com/share/008ea5f1-670c-467c-8320-1ca67f25ac9a
if [ -n "$luks_memory_cost" ]; then
info "Formating $root_partition_path with LUKS with --pbkdf-memory set to $luks_memory_cost" &&
sudo cryptsetup -v luksFormat -c aes-xts-plain64 -s 512 -h sha512 --use-random -i 1000 --pbkdf-memory "$luks_memory_cost" "$root_partition_path" || error
else
info "Formating $root_partition_path with LUKS" &&
sudo cryptsetup -v luksFormat -c aes-xts-plain64 -s 512 -h sha512 --use-random -i 1000 "$root_partition_path" || error
fi
decrypt_root || error decrypt_root || error
fi fi
@@ -336,7 +398,13 @@ if [ "$transfer_image" = "y" ]
elif [ "${image_path: -4}" = ".iso" ] elif [ "${image_path: -4}" = ".iso" ]
then then
info "Transfering .iso file..." && info "Transfering .iso file..." &&
sudo dd if="$image_path" of="$device_path" bs="$OPTIMAL_BLOCKSIZE" conv=fsync status=progress && pv "$image_path" | sudo dd of="$device_path" bs="$OPTIMAL_BLOCKSIZE" conv=fsync &&
sync ||
error
elif [ "${image_path: -3}" = ".xz" ]
then
info "Transferring .xz file..." &&
unxz -c "$image_path" | sudo dd of="$device_path" bs="$OPTIMAL_BLOCKSIZE" conv=fsync status=progress &&
sync || sync ||
error error
else else
@@ -346,7 +414,8 @@ if [ "$transfer_image" = "y" ]
info "Skipping image transfer..." info "Skipping image transfer..."
fi fi
if [ "$distribution" != "manjaro" ] # Execute Raspberry Pi specific procedures
if [ -n "$raspberry_pi_version" ]
then then
info "Start regular mounting procedure..." info "Start regular mounting procedure..."
if mount | grep -q "$boot_partition_path" if mount | grep -q "$boot_partition_path"
@@ -370,35 +439,53 @@ if [ "$distribution" != "manjaro" ]
info "Content of $fstab_path:$(cat "$fstab_path")" || error info "Content of $fstab_path:$(cat "$fstab_path")" || error
info "Define target paths..." && info "Define target paths..." &&
administrator_username="administrator"
target_home_path="$root_mount_path""home/" && target_home_path="$root_mount_path""home/" &&
target_username=$(ls "$target_home_path") && default_username=$(ls "$target_home_path") &&
question "Should the $default_username be renamed to $administrator_username? (y/N):" && read -r rename_decision
if [ "$rename_decision" == "y" ];
then
variable_old_username="$default_username" &&
target_username="$administrator_username" &&
info "Rename home directory from $target_home_path$variable_old_username to $target_home_path$target_username..." &&
mv -v "$target_home_path$variable_old_username" "$target_home_path$target_username" || error "Failed to rename home directory"
else
target_username="$default_username"
fi
target_user_home_folder_path="$target_home_path$target_username/" && target_user_home_folder_path="$target_home_path$target_username/" &&
target_user_ssh_folder_path="$target_user_home_folder_path"".ssh/" && target_user_ssh_folder_path="$target_user_home_folder_path"".ssh/" &&
target_authorized_keys="$target_user_ssh_folder_path""authorized_keys" && target_authorized_keys="$target_user_ssh_folder_path""authorized_keys" &&
question "Should the ssh-key be copied to the image?(y/N)" && read -r copy_ssh_key || error
if [ "$copy_ssh_key" == "y" ] # Activate later. Here was a bug
question "Should the $target_username have sudo rights? (y/N):" && read -r sudo_decision
if [ "$sudo_decision" == "y" ]; then
sudo_config_dir="$root_mount_path""etc/sudoers.d/"
sudo_config_file="$sudo_config_dir$target_username"
mkdir -vp $sudo_config_dir
echo "$target_username ALL=(ALL:ALL) ALL" > "$sudo_config_file" || error "Failed to create sudoers file for $target_username"
chmod 440 "$sudo_config_file" || error "Failed to set permissions on sudoers file for $target_username"
fi
question "Enter the path to the SSH key to be added to the image (default: none):" && read -r origin_user_rsa_pub || error
if [ -z "$origin_user_rsa_pub" ]
then then
correct_ssh_key_path=false;
while [ "$correct_ssh_key_path" != true ]
do
question "Whats the absolut path to the ssh key:" && read -r origin_user_rsa_pub || error
if [ -f "$origin_user_rsa_pub" ]
then
correct_ssh_key_path=true;
else
warning "The ssh key \"$origin_user_rsa_pub\" can't be copied to \"$target_authorized_keys\" because it doesn't exist."
fi
done
info "Copy ssh key to target..."
mkdir -v "$target_user_ssh_folder_path" || warning "Folder \"$target_user_ssh_folder_path\" exists. Can't be created."
cat "$origin_user_rsa_pub" > "$target_authorized_keys" &&
target_authorized_keys_content=$(cat "$target_authorized_keys") &&
info "$target_authorized_keys contains the following: $target_authorized_keys_content" &&
chown -vR 1000 "$target_user_ssh_folder_path" &&
chmod -v 700 "$target_user_ssh_folder_path" &&
chmod -v 600 "$target_authorized_keys" || error
else
info "Skipped SSH-key copying.." info "Skipped SSH-key copying.."
else
if [ -f "$origin_user_rsa_pub" ]
then
info "Copy ssh key to target..."
mkdir -v "$target_user_ssh_folder_path" || warning "Folder \"$target_user_ssh_folder_path\" exists. Can't be created."
cat "$origin_user_rsa_pub" > "$target_authorized_keys" &&
target_authorized_keys_content=$(cat "$target_authorized_keys") &&
info "$target_authorized_keys contains the following: $target_authorized_keys_content" &&
info "Set permissions with chmod..." &&
chmod -v 700 "$target_user_ssh_folder_path" &&
chmod -v 600 "$target_authorized_keys" || error "Failed to set ownership and permissions on ssh folder"
else
error "The ssh key \"$origin_user_rsa_pub\" can't be copied to \"$target_authorized_keys\" because it doesn't exist."
fi
fi fi
info "Start chroot procedures..." info "Start chroot procedures..."
@@ -409,16 +496,38 @@ if [ "$distribution" != "manjaro" ]
copy_resolve_conf copy_resolve_conf
question "Type in new password (leave empty to skip): " && read -r password_1 chroot_user_home_path="/home/$target_username/"
chroot_user_ssh_folder_path="$chroot_user_home_path.ssh"
if [ "$rename_decision" == "y" ]; then
info "Delete old user and create new user" &&
(
echo "userdel -r $variable_old_username"
echo "useradd -m -d $chroot_user_home_path -s /bin/bash $target_username"
echo "chown -R $target_username:$target_username $chroot_user_home_path"
) | chroot "$root_mount_path" /bin/bash || error "Failed to delete old user and create new user"
fi
if [ -n "$origin_user_rsa_pub" ]
then
info "Chroot to set ownership..." &&
( echo "chown -vR $target_username:$target_username $chroot_user_ssh_folder_path" ) | chroot "$root_mount_path" /bin/bash || error
fi
question "Type in new password for user root and $target_username (leave empty to skip): " && read -r password_1
if [ -n "$password_1" ]; then if [ -n "$password_1" ]; then
question "Repeat new password for \"$target_username\": " && read -r password_2 question "Repeat new password for \"$target_username\": " && read -r password_2
if [ "$password_1" = "$password_2" ]; then if [ "$password_1" = "$password_2" ]; then
info "Changing passwords on target system..." info "Changing passwords on target system..."
( (
echo "$password_1" | chroot "$root_mount_path" passwd --stdin "$target_username" echo "(
echo "$password_1" | chroot "$root_mount_path" passwd --stdin echo '$password_1'
) || error "Failed to change password." echo '$password_1'
) | passwd $target_username"
echo "(
echo '$password_1'
echo '$password_1'
) | passwd"
) | chroot "$root_mount_path" /bin/bash || error "Failed to change password."
else else
error "Passwords didn't match." error "Passwords didn't match."
fi fi
@@ -480,7 +589,9 @@ if [ "$distribution" != "manjaro" ]
if [ "$encrypt_system" == "y" ] if [ "$encrypt_system" == "y" ]
then then
# Adapted this instruction for setting up encrypted systems @see https://gist.github.com/gea0/4fc2be0cb7a74d0e7cc4322aed710d38 # Adapted this instruction for setting up encrypted systems
# @see https://gist.github.com/gea0/4fc2be0cb7a74d0e7cc4322aed710d38
# @see https://gist.github.com/EnigmaCurry/2f9bed46073da8e38057fe78a61e7994
info "Setup encryption..." && info "Setup encryption..." &&
info "Installing neccessary software..." && info "Installing neccessary software..." &&
@@ -490,19 +601,43 @@ if [ "$distribution" != "manjaro" ]
info "Adding $target_authorized_keys to dropbear..." && info "Adding $target_authorized_keys to dropbear..." &&
cp -v "$target_authorized_keys" "$dropbear_root_key_path" && cp -v "$target_authorized_keys" "$dropbear_root_key_path" &&
#Concerning mkinitcpio warning @see https://gist.github.com/imrvelj/c65cd5ca7f5505a65e59204f5a3f7a6d # Concerning mkinitcpio warning
# @see https://gist.github.com/imrvelj/c65cd5ca7f5505a65e59204f5a3f7a6d
mkinitcpio_path="$root_mount_path""etc/mkinitcpio.conf" && mkinitcpio_path="$root_mount_path""etc/mkinitcpio.conf" &&
info "Configuring $mkinitcpio_path..." && info "Configuring $mkinitcpio_path..." &&
mkinitcpio_search_modules="MODULES=()" && mkinitcpio_search_modules="MODULES=()" || error
mkinitcpio_replace_modules="MODULES=(g_cdc usb_f_acm usb_f_ecm smsc95xx g_ether)" &&
# Concerning which moduls to load
# @see https://raspberrypi.stackexchange.com/questions/67051/raspberry-pi-3-with-archarm-and-encrypted-disk-will-not-boot-how-can-be-identif
case "$raspberry_pi_version" in
"1" | "2")
mkinitcpio_additional_modules=""
;;
"3b")
mkinitcpio_additional_modules="smsc95xx"
;;
"3b+" | "4")
mkinitcpio_additional_modules="lan78xx"
;;
*)
warning "Version $raspberry_pi_version isn't supported."
;;
esac
mkinitcpio_replace_modules="MODULES=(g_cdc usb_f_acm usb_f_ecm $mkinitcpio_additional_modules g_ether)" || error
mkinitcpio_search_binaries="BINARIES=()" && mkinitcpio_search_binaries="BINARIES=()" &&
mkinitcpio_replace_binaries=$(echo "BINARIES=(/usr/lib/libgcc_s.so.1)"| sed -e 's/[\/&]/\\&/g') && mkinitcpio_replace_binaries=$(echo "BINARIES=(/usr/lib/libgcc_s.so.1)"| sed -e 's/[\/&]/\\&/g') &&
mkinitcpio_encrypt_hooks="sleep netconf dropbear encryptssh" && mkinitcpio_encrypt_hooks="sleep netconf dropbear encryptssh" &&
mkinitcpio_search_hooks="HOOKS=(base udev autodetect modconf block filesystems keyboard fsck)" && mkinitcpio_hooks_prefix="base udev autodetect microcode modconf kms keyboard keymap consolefont block"
mkinitcpio_replace_hooks="HOOKS=(base udev autodetect modconf block $mkinitcpio_encrypt_hooks filesystems keyboard fsck)" && mkinitcpio_hooks_suffix="filesystems fsck"
sed -i "s/$mkinitcpio_search_modules/$mkinitcpio_replace_modules/g" "$mkinitcpio_path" && mkinitcpio_search_hooks="HOOKS=($mkinitcpio_hooks_prefix $mkinitcpio_hooks_suffix)" &&
sed -i "s/$mkinitcpio_search_binaries/$mkinitcpio_replace_binaries/g" "$mkinitcpio_path" && mkinitcpio_replace_hooks="HOOKS=($mkinitcpio_hooks_prefix $mkinitcpio_encrypt_hooks $mkinitcpio_hooks_suffix)" &&
sed -i "s/$mkinitcpio_search_hooks/$mkinitcpio_replace_hooks/g" "$mkinitcpio_path" && replace_in_file "$mkinitcpio_search_modules" "$mkinitcpio_replace_modules" "$mkinitcpio_path" &&
replace_in_file "$mkinitcpio_search_binaries" "$mkinitcpio_replace_binaries" "$mkinitcpio_path" &&
replace_in_file "$mkinitcpio_search_hooks" "$mkinitcpio_replace_hooks" "$mkinitcpio_path" &&
info "Content of $mkinitcpio_path:$(cat "$mkinitcpio_path")" && info "Content of $mkinitcpio_path:$(cat "$mkinitcpio_path")" &&
info "Generating mkinitcpio..." && info "Generating mkinitcpio..." &&
echo "mkinitcpio -vP" | chroot "$root_mount_path" /bin/bash && echo "mkinitcpio -vP" | chroot "$root_mount_path" /bin/bash &&
@@ -535,9 +670,11 @@ if [ "$distribution" != "manjaro" ]
info "Configuring $boot_txt_path..." && info "Configuring $boot_txt_path..." &&
boot_txt_delete_line=$(echo "part uuid \${devtype} \${devnum}:2 uuid" | sed -e 's/[]\/$*.^[]/\\&/g') && boot_txt_delete_line=$(echo "part uuid \${devtype} \${devnum}:2 uuid" | sed -e 's/[]\/$*.^[]/\\&/g') &&
boot_txt_setenv_origin=$(echo "setenv bootargs console=ttyS1,115200 console=tty0 root=PARTUUID=\${uuid} rw rootwait smsc95xx.macaddr=\"\${usbethaddr}\"" | sed -e 's/[]\/$*.^[]/\\&/g') && boot_txt_setenv_origin=$(echo "setenv bootargs console=ttyS1,115200 console=tty0 root=PARTUUID=\${uuid} rw rootwait smsc95xx.macaddr=\"\${usbethaddr}\"" | sed -e 's/[]\/$*.^[]/\\&/g') &&
boot_txt_setenv_replace=$(echo "setenv bootargs console=ttyS1,115200 console=tty0 ip=::::$target_hostname:eth0:dhcp $cryptdevice_configuration rw rootwait smsc95xx.macaddr=\"\${usbethaddr}\""| sed -e 's/[\/&]/\\&/g') && # Concerning issues with network adapter names;
sed -i "s/$boot_txt_delete_line//g" "$boot_txt_path" && # @see https://forum.iobroker.net/topic/40542/raspberry-pi4-kein-eth0-mehr/16
sed -i "s/$boot_txt_setenv_origin/$boot_txt_setenv_replace/g" "$boot_txt_path" && boot_txt_setenv_replace=$(echo "setenv bootargs console=ttyS1,115200 console=tty0 ip=::::$target_hostname:eth0:dhcp $cryptdevice_configuration rw rootwait smsc95xx.macaddr=\"\${usbethaddr}\" net.ifnames=0 biosdevname=0"| sed -e 's/[\/&]/\\&/g') &&
replace_in_file "$boot_txt_delete_line" "" "$boot_txt_path" &&
replace_in_file "$boot_txt_setenv_origin" "$boot_txt_setenv_replace" "$boot_txt_path" &&
info "Content of $boot_txt_path:$(cat "$boot_txt_path")" && info "Content of $boot_txt_path:$(cat "$boot_txt_path")" &&
info "Generating..." && info "Generating..." &&
echo "cd /boot/ && ./mkscr || exit 1" | chroot "$root_mount_path" /bin/bash || error echo "cd /boot/ && ./mkscr || exit 1" | chroot "$root_mount_path" /bin/bash || error
@@ -546,7 +683,7 @@ if [ "$distribution" != "manjaro" ]
info "Configuring $cmdline_txt_path..." && info "Configuring $cmdline_txt_path..." &&
cmdline_search_string=$(echo "root=/dev/mmcblk0p2" | sed -e 's/[\/&]/\\&/g') && cmdline_search_string=$(echo "root=/dev/mmcblk0p2" | sed -e 's/[\/&]/\\&/g') &&
cmdline_replace_string=$(echo "$cryptdevice_configuration rootfstype=$root_filesystem"| sed -e 's/[\/&]/\\&/g') && cmdline_replace_string=$(echo "$cryptdevice_configuration rootfstype=$root_filesystem"| sed -e 's/[\/&]/\\&/g') &&
sed -i "s/$cmdline_search_string/$cmdline_replace_string/g" "$cmdline_txt_path" && replace_in_file "$cmdline_search_string" "$cmdline_replace_string" "$cmdline_txt_path" &&
info "Content of $cmdline_txt_path:$(cat "$cmdline_txt_path")" || error info "Content of $cmdline_txt_path:$(cat "$cmdline_txt_path")" || error
fi fi
fi fi
@@ -554,7 +691,7 @@ if [ "$distribution" != "manjaro" ]
info "Running system specific procedures..." info "Running system specific procedures..."
if [ "$distribution" = "retropie" ] if [ "$distribution" = "retropie" ]
then then
if [ "$copy_ssh_key" == "y" ] if [ -n "$origin_user_rsa_pub" ]
then then
ssh_file="$boot_mount_path""ssh" && ssh_file="$boot_mount_path""ssh" &&
echo "" > "$ssh_file" echo "" > "$ssh_file"