|  |  | @@ -0,0 +1,269 @@ | 
		
	
		
			
			|  |  |  | #!/bin/bash | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Enable strict error handling | 
		
	
		
			
			|  |  |  | 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 FARM] [-e ENVIRONMENT]" | 
		
	
		
			
			|  |  |  | echo "  -d, --device DEVICE      Specify the block device to use (e.g., sda, nvme0n1)." | 
		
	
		
			
			|  |  |  | echo "  -f, --farm FARM          Specify the FARM ID." | 
		
	
		
			
			|  |  |  | echo "  -e, --environment ENV    Specify the environment (dev, qa, test, prod)." | 
		
	
		
			
			|  |  |  | 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)) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Search for NVMe devices first | 
		
	
		
			
			|  |  |  | 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 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # If no NVMe device found, search for SSD devices | 
		
	
		
			
			|  |  |  | log "No suitable NVMe device 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" ] && [ -e "/sys/block/$DEV_NAME/queue/rotational" ] && [ "$(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 device found." | 
		
	
		
			
			|  |  |  | return 1 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Function to manage UEFI boot entries | 
		
	
		
			
			|  |  |  | manage_boot_entries() { | 
		
	
		
			
			|  |  |  | log "Managing UEFI boot entries..." | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Check if efibootmgr is available | 
		
	
		
			
			|  |  |  | if ! command -v efibootmgr &> /dev/null; then | 
		
	
		
			
			|  |  |  | log "Error: 'efibootmgr' is not installed. Please install it and rerun the script." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Get the list of current boot entries | 
		
	
		
			
			|  |  |  | CURRENT_BOOT_ENTRIES=$(efibootmgr | grep "BootOrder") | 
		
	
		
			
			|  |  |  | log "Current BootOrder: $CURRENT_BOOT_ENTRIES" | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Delete all existing boot entries except the EFI Shell (if present) | 
		
	
		
			
			|  |  |  | log "Deleting existing boot entries..." | 
		
	
		
			
			|  |  |  | BOOT_ENTRIES=$(efibootmgr | grep -E "^Boot[0-9A-F]{4}" | awk '{print $1}' | sed 's/\*//') | 
		
	
		
			
			|  |  |  | for ENTRY in $BOOT_ENTRIES; do | 
		
	
		
			
			|  |  |  | efibootmgr -b ${ENTRY#Boot} -B | 
		
	
		
			
			|  |  |  | log "Deleted boot entry $ENTRY" | 
		
	
		
			
			|  |  |  | done | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Create a new boot entry pointing to BOOTX64.EFI on the first partition | 
		
	
		
			
			|  |  |  | log "Creating new boot entry for /dev/${PARTPREFIX}1..." | 
		
	
		
			
			|  |  |  | # Adjust the partition number if necessary | 
		
	
		
			
			|  |  |  | ESP_PART_NUM=1 | 
		
	
		
			
			|  |  |  | efibootmgr -c -d /dev/${BLOCKDEV} -p $ESP_PART_NUM -L "Zero-OS" -l "\\EFI\\BOOT\\BOOTX64.EFI" || { | 
		
	
		
			
			|  |  |  | log "Error: Failed to create new boot entry." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Set the boot order to include only the new boot entry | 
		
	
		
			
			|  |  |  | NEW_BOOT_NUM=$(efibootmgr | grep "Zero-OS" | awk '{print $1}' | sed 's/\*//;s/Boot//') | 
		
	
		
			
			|  |  |  | if [ -z "$NEW_BOOT_NUM" ]; then | 
		
	
		
			
			|  |  |  | log "Error: Failed to retrieve new boot entry number." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | log "Setting BootOrder to only include Boot$NEW_BOOT_NUM..." | 
		
	
		
			
			|  |  |  | efibootmgr -o $NEW_BOOT_NUM || { | 
		
	
		
			
			|  |  |  | log "Error: Failed to set new BootOrder." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | log "New BootOrder set successfully." | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Main script execution | 
		
	
		
			
			|  |  |  | main() { | 
		
	
		
			
			|  |  |  | # Default values | 
		
	
		
			
			|  |  |  | BLOCKDEV_SPECIFIED="" | 
		
	
		
			
			|  |  |  | FARM="1234" | 
		
	
		
			
			|  |  |  | ENVIRONMENT="prod" | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # 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|--farm) | 
		
	
		
			
			|  |  |  | shift | 
		
	
		
			
			|  |  |  | if [ -z "$1" ]; then | 
		
	
		
			
			|  |  |  | log "Error: '--farm' requires a non-empty option argument." | 
		
	
		
			
			|  |  |  | usage | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | FARM="$1" | 
		
	
		
			
			|  |  |  | shift | 
		
	
		
			
			|  |  |  | ;; | 
		
	
		
			
			|  |  |  | -e|--environment) | 
		
	
		
			
			|  |  |  | shift | 
		
	
		
			
			|  |  |  | if [ -z "$1" ]; then | 
		
	
		
			
			|  |  |  | log "Error: '--environment' requires a non-empty option argument." | 
		
	
		
			
			|  |  |  | usage | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | ENVIRONMENT="$1" | 
		
	
		
			
			|  |  |  | shift | 
		
	
		
			
			|  |  |  | ;; | 
		
	
		
			
			|  |  |  | -h|--help) | 
		
	
		
			
			|  |  |  | usage | 
		
	
		
			
			|  |  |  | ;; | 
		
	
		
			
			|  |  |  | *) | 
		
	
		
			
			|  |  |  | log "Error: Unknown option: $1" | 
		
	
		
			
			|  |  |  | usage | 
		
	
		
			
			|  |  |  | ;; | 
		
	
		
			
			|  |  |  | esac | 
		
	
		
			
			|  |  |  | done | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Validate environment | 
		
	
		
			
			|  |  |  | case "$ENVIRONMENT" in | 
		
	
		
			
			|  |  |  | dev|qa|test|prod) | 
		
	
		
			
			|  |  |  | log "Using environment: $ENVIRONMENT" | 
		
	
		
			
			|  |  |  | ;; | 
		
	
		
			
			|  |  |  | *) | 
		
	
		
			
			|  |  |  | log "Error: Invalid environment '$ENVIRONMENT'. Valid options are 'dev', 'qa', 'test', 'prod'." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | ;; | 
		
	
		
			
			|  |  |  | esac | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 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} || { log "Failed to wipe filesystem signatures."; exit 1; } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Create GPT partition table | 
		
	
		
			
			|  |  |  | log "Creating GPT partition table on /dev/${BLOCKDEV}..." | 
		
	
		
			
			|  |  |  | parted -s /dev/${BLOCKDEV} mklabel gpt || { log "Failed to create GPT partition table."; exit 1; } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Create partitions | 
		
	
		
			
			|  |  |  | log "Creating partitions on /dev/${BLOCKDEV}..." | 
		
	
		
			
			|  |  |  | if ! parted -s /dev/${BLOCKDEV} "mkpart zosboot fat32 1MiB 300MiB set 1 esp on mkpart zoscache btrfs 300MiB 100%"; then | 
		
	
		
			
			|  |  |  | log "Failed to create partitions." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Format partitions | 
		
	
		
			
			|  |  |  | log "Formatting /dev/${PARTPREFIX}1 as FAT32..." | 
		
	
		
			
			|  |  |  | if ! mkfs.vfat -F32 /dev/${PARTPREFIX}1; then | 
		
	
		
			
			|  |  |  | log "Failed to format /dev/${PARTPREFIX}1 as FAT32." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | log "Formatting /dev/${PARTPREFIX}2 as BTRFS..." | 
		
	
		
			
			|  |  |  | if ! mkfs.btrfs -f /dev/${PARTPREFIX}2; then | 
		
	
		
			
			|  |  |  | log "Failed to format /dev/${PARTPREFIX}2 as BTRFS." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Mount and prepare directories | 
		
	
		
			
			|  |  |  | MOUNT_POINT="zospxe" | 
		
	
		
			
			|  |  |  | log "Creating and mounting directory ./${MOUNT_POINT}..." | 
		
	
		
			
			|  |  |  | mkdir -p "${MOUNT_POINT}" | 
		
	
		
			
			|  |  |  | if ! mount /dev/${PARTPREFIX}1 -t vfat "${MOUNT_POINT}"; then | 
		
	
		
			
			|  |  |  | log "Failed to mount /dev/${PARTPREFIX}1 to ${MOUNT_POINT}." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | log "Creating directory structure in ${MOUNT_POINT}..." | 
		
	
		
			
			|  |  |  | mkdir -p "${MOUNT_POINT}/efi/boot" | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Download the required BOOTX64.EFI file | 
		
	
		
			
			|  |  |  | # NOTE:: EDIT THIS WHEN APPROPRIATE AND IN PROD | 
		
	
		
			
			|  |  |  | EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}/debug/zero-os-development-zos-v4-debug-7d2de62033.efi?version=v4" | 
		
	
		
			
			|  |  |  | # EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}" | 
		
	
		
			
			|  |  |  | log "Downloading BOOTX64.EFI from ${EFI_FILE_URL}..." | 
		
	
		
			
			|  |  |  | if ! wget -q "${EFI_FILE_URL}" -O "${MOUNT_POINT}/efi/boot/BOOTX64.EFI"; then | 
		
	
		
			
			|  |  |  | log "Failed to download BOOTX64.EFI." | 
		
	
		
			
			|  |  |  | exit 1 | 
		
	
		
			
			|  |  |  | fi | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | log "Download successful." | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Unmount the partition | 
		
	
		
			
			|  |  |  | log "Unmounting ${MOUNT_POINT}..." | 
		
	
		
			
			|  |  |  | umount -r "${MOUNT_POINT}" || { log "Failed to unmount ${MOUNT_POINT}."; exit 1; } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Manage UEFI boot entries | 
		
	
		
			
			|  |  |  | manage_boot_entries | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | log "Operation completed successfully." | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Execute the main function | 
		
	
		
			
			|  |  |  | main "$@" |