| @@ -0,0 +1,210 @@ | |||||
| #!/bin/bash | |||||
| # This was I input to o1-preview with this prompt: | |||||
| # | |||||
| # BLOCKDEV=nvme0n1 | |||||
| # wipefs -a -f /dev/${BLOCKDEV} | |||||
| # parted -s /dev/${BLOCKDEV} "mklabel gpt mkpart zosboot fat32 1 10M set 1 esp on mkpart zoscache btrfs 10M 100%" | |||||
| # mkfs.vfat -F32 /dev/${BLOCKDEV}p1 | |||||
| # mkfs.btrfs -f /dev/${BLOCKDEV}p2 | |||||
| # mkdir zospxe && mount /dev/${BLOCKDEV}p1 -t vfat zospxe && mkdir -p zospxe/efi/boot | |||||
| # wget -q https://bootstrap.grid.tf/uefi/prod/1234 -O zospxe/efi/boot/BOOTX64.EFI | |||||
| # | |||||
| # find a BLOCKDEV that is at least an nvme, ssd (in that order) | |||||
| # and make this script a bit more log-expressive, and failing gracefully. | |||||
| # Also, can you add the if -d $device is specified, it will use that and | |||||
| # not search for a disk, and also make farmerid a parameter | |||||
| # for https://bootstrap.grid.tf/uefi/prod/$farmerid} | |||||
| # Exit immediately if a command exits with a non-zero status. | |||||
| set -e | |||||
| # Function to log messages with timestamps | |||||
| log() { | |||||
| echo "$(date '+%F %T') - $@" | |||||
| } | |||||
| # Function to display usage information | |||||
| usage() { | |||||
| echo "Usage: $0 [-d DEVICE] [-f FARMERID]" | |||||
| echo " -d, --device DEVICE Specify the block device to use (e.g., sda, nvme0n1)." | |||||
| echo " -f, --farmerid FARMERID Specify the farmer ID for the download URL." | |||||
| echo " -h, --help Display this help message." | |||||
| exit 1 | |||||
| } | |||||
| # Function to find a suitable block device | |||||
| find_blockdev() { | |||||
| # Minimum size in bytes (e.g., 10 GiB) | |||||
| MIN_SIZE=$((10 * 1024 * 1024 * 1024)) | |||||
| # First try NVMe devices | |||||
| log "Searching for NVMe devices..." | |||||
| for DEV in /dev/nvme*n1; do | |||||
| if [ -b "$DEV" ]; then | |||||
| SIZE_BYTES=$(blockdev --getsize64 "$DEV") | |||||
| if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then | |||||
| log "Found NVMe device: $DEV ($(numfmt --to=iec $SIZE_BYTES))" | |||||
| BLOCKDEV="${DEV##*/}" | |||||
| return 0 | |||||
| else | |||||
| log "$DEV is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping." | |||||
| fi | |||||
| fi | |||||
| done | |||||
| log "No suitable NVMe devices found. Searching for SSD devices..." | |||||
| for DEV_PATH in /sys/block/*; do | |||||
| DEV_NAME=$(basename "$DEV_PATH") | |||||
| # Exclude unwanted devices | |||||
| case "$DEV_NAME" in | |||||
| loop* | ram* | sr* | fd* | md* | dm-*) | |||||
| continue | |||||
| ;; | |||||
| esac | |||||
| DEVICE="/dev/$DEV_NAME" | |||||
| if [ -b "$DEVICE" ] && [ "$(cat /sys/block/${DEV_NAME}/queue/rotational)" == "0" ]; then | |||||
| SIZE_BYTES=$(blockdev --getsize64 "$DEVICE") | |||||
| if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then | |||||
| log "Found SSD device: $DEVICE ($(numfmt --to=iec $SIZE_BYTES))" | |||||
| BLOCKDEV="$DEV_NAME" | |||||
| return 0 | |||||
| else | |||||
| log "$DEVICE is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping." | |||||
| fi | |||||
| fi | |||||
| done | |||||
| log "No suitable block devices found." | |||||
| return 1 | |||||
| } | |||||
| # Main script execution | |||||
| main() { | |||||
| # Default values | |||||
| BLOCKDEV_SPECIFIED="" | |||||
| FARMERID="1234" # Default farmer ID | |||||
| # Parse command-line arguments | |||||
| while [[ $# -gt 0 ]]; do | |||||
| case "$1" in | |||||
| -d | --device) | |||||
| shift | |||||
| if [ -z "$1" ]; then | |||||
| log "Error: '--device' requires a non-empty option argument." | |||||
| usage | |||||
| fi | |||||
| BLOCKDEV_SPECIFIED="$1" | |||||
| shift | |||||
| ;; | |||||
| -f | --farmerid) | |||||
| shift | |||||
| if [ -z "$1" ]; then | |||||
| log "Error: '--farmerid' requires a non-empty option argument." | |||||
| usage | |||||
| fi | |||||
| FARMERID="$1" | |||||
| shift | |||||
| ;; | |||||
| -h | --help) | |||||
| usage | |||||
| ;; | |||||
| *) | |||||
| log "Error: Unknown option: $1" | |||||
| usage | |||||
| ;; | |||||
| esac | |||||
| done | |||||
| if [ -n "$BLOCKDEV_SPECIFIED" ]; then | |||||
| # Use the specified block device | |||||
| if [[ "$BLOCKDEV_SPECIFIED" != /dev/* ]]; then | |||||
| BLOCKDEV_SPECIFIED="/dev/$BLOCKDEV_SPECIFIED" | |||||
| fi | |||||
| if [ ! -b "$BLOCKDEV_SPECIFIED" ]; then | |||||
| log "Error: Specified device $BLOCKDEV_SPECIFIED does not exist or is not a block device." | |||||
| exit 1 | |||||
| fi | |||||
| BLOCKDEV="${BLOCKDEV_SPECIFIED##*/}" | |||||
| log "Using specified block device: $BLOCKDEV_SPECIFIED" | |||||
| else | |||||
| # Find a suitable block device | |||||
| if ! find_blockdev; then | |||||
| log "Error: No suitable block device found." | |||||
| exit 1 | |||||
| fi | |||||
| log "Selected block device: /dev/${BLOCKDEV}" | |||||
| fi | |||||
| # Confirm with the user before proceeding | |||||
| read -p "This will erase all data on /dev/${BLOCKDEV}. Are you sure you want to proceed? (yes/[no]): " CONFIRM | |||||
| if [ "$CONFIRM" != "yes" ]; then | |||||
| log "Operation cancelled by user." | |||||
| exit 0 | |||||
| fi | |||||
| # Determine partition naming convention | |||||
| if [[ $BLOCKDEV =~ [0-9]$ ]]; then | |||||
| PARTPREFIX="${BLOCKDEV}p" | |||||
| else | |||||
| PARTPREFIX="${BLOCKDEV}" | |||||
| fi | |||||
| # Wipe filesystem signatures | |||||
| log "Wiping filesystem signatures on /dev/${BLOCKDEV}..." | |||||
| wipefs -a -f /dev/${BLOCKDEV} | |||||
| # Create GPT partition table | |||||
| log "Creating GPT partition table on /dev/${BLOCKDEV}..." | |||||
| parted -s /dev/${BLOCKDEV} mklabel gpt | |||||
| # Create partitions | |||||
| log "Creating partition 1 (zosboot) on /dev/${BLOCKDEV}..." | |||||
| parted -s /dev/${BLOCKDEV} mkpart zosboot fat32 1MiB 10MiB | |||||
| log "Setting partition 1 as ESP..." | |||||
| parted -s /dev/${BLOCKDEV} set 1 esp on | |||||
| log "Creating partition 2 (zos-cache) on /dev/${BLOCKDEV}..." | |||||
| parted -s /dev/${BLOCKDEV} mkpart zos-cache btrfs 10MiB 100% | |||||
| # Format partitions | |||||
| log "Formatting /dev/${PARTPREFIX}1 as FAT32..." | |||||
| mkfs.vfat -F32 /dev/${PARTPREFIX}1 | |||||
| log "Formatting /dev/${PARTPREFIX}2 as BTRFS..." | |||||
| mkfs.btrfs -f /dev/${PARTPREFIX}2 | |||||
| # Mount and prepare directories | |||||
| MOUNT_POINT="zospxe" | |||||
| log "Creating mount point at ./${MOUNT_POINT}..." | |||||
| mkdir -p "${MOUNT_POINT}" | |||||
| log "Mounting /dev/${PARTPREFIX}1 to ./${MOUNT_POINT}..." | |||||
| mount /dev/${PARTPREFIX}1 "${MOUNT_POINT}" | |||||
| log "Creating directory structure in ${MOUNT_POINT}..." | |||||
| mkdir -p "${MOUNT_POINT}/efi/boot" | |||||
| # Download the required BOOTX64.EFI file | |||||
| EFI_FILE_URL="https://bootstrap.grid.tf/uefi/prod/${FARMERID}" | |||||
| log "Downloading BOOTX64.EFI from ${EFI_FILE_URL}..." | |||||
| wget -q "${EFI_FILE_URL}" -O "${MOUNT_POINT}/efi/boot/BOOTX64.EFI" | |||||
| # Create zos-cache subvolume | |||||
| log "Creating mount point at ./${MOUNT_POINT}root..." | |||||
| mkdir -p "${MOUNT_POINT}root" | |||||
| log "Mounting /dev/${PARTPREFIX}2 to ./${MOUNT_POINT}root..." | |||||
| mount /dev/${PARTPREFIX}2 "${MOUNT_POINT}root" | |||||
| log "Creating subvolume \"zos-cache\" on ${MOUNT_POINT}root" | |||||
| btrfs subvolume create ${MOUNT_POINT}root/zos-cache | |||||
| # Umount mountpoints | |||||
| log "Umounting ${MOUNT_POINT}/*" | |||||
| umount -l ${MOUNT_POINT} | |||||
| umount -l ${MOUNT_POINT}root | |||||
| log "Operation completed successfully." | |||||
| } | |||||
| # Execute the main function | |||||
| main "$@" | |||||