| @@ -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 "$@" | |||