#!/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 "$@"