Skip to content

Instantly share code, notes, and snippets.

@rversteegen
Created July 19, 2023 00:08
Show Gist options
  • Save rversteegen/32bb0b2786ee1092762627f0f7035427 to your computer and use it in GitHub Desktop.
Save rversteegen/32bb0b2786ee1092762627f0f7035427 to your computer and use it in GitHub Desktop.
My GRUB linux boot entry generation script
#!/usr/bin/env python3
#exec tail -n +3 $0
# Be careful not to change
# the 'exec tail' line above.
# This script lives in /etc/grub.d/
# 2015,2022 Ralph Versteegen
# The menuentry template was orginally generated by /etc/grub.d/10_linux
import os
import glob
import re
import sys
import subprocess
def tell(*args):
print(*args, file = sys.stderr)
def run(cmd):
tell(cmd)
ret = subprocess.check_output(cmd.split()).decode('utf-8').rstrip()
tell(" ->", ret)
return ret
# Don't use initrd; the kernel image has it builtin and this breaks it
# I blame the patch applied in the SlackBuild to GRUB2 which makes it look for /boot/initrd.gz...
#################### bootflags
# Useful kernel params:
# rootdelay= [KNL] Delay (in seconds) to pause before attempting to
# mount the root filesystem
# S [KNL] Run init in single mode
# libata.force=1.00:1.5,norst,udma4 or udma3 pio4 etc
bootflags = "rootflags=subvol=root rootfstype=btrfs ro"
#################### disks
# Find HDD and SSD devices which have mounted partitions
disks = {}
for part in ("/mnt/btrfs_ssd", "/mnt/btrfs_pool", "/mnt/btrfs_hdd"):
if not os.path.isdir(part):
continue
part_dev = run("findmnt -vfn -o SOURCE " + part)
if part not in disks:
# Trim the partition number, to get disk's device
disks[part] = re.match("[^0-9]*", part_dev).group(0)
tell("Found disks:", disks)
#################### Entry for each disk
for disk_path,disk_dev in disks.items():
# PARTUUID of the root's btrfs partition
# PARTUUID shown by "lsblk -f -o +PARTUUID,SIZE", and by gdisk 'i' (information) as "Partition unique GUID"
# It is stored in MBR or GPT
root_partuuid = run("findmnt -vfn -o PARTUUID " + disk_path)
# Check fstab for a /mnt/boot entry
# It's also possible to search HDD for LABEL=boot using blkid
#boot_dev = run("findmnt -vfn -o UUID /mnt/boot")
# Check for a partition labelled "boot"
try:
boot_dev = run("blkid -t LABEL=boot -o device " + " ".join(glob.glob(disk_dev + "*")))
#if boot_dev:
tell("Found boot partition " + boot_dev)
boot_uuid = run("lsblk -n -o UUID " + boot_dev)
#else:
except subprocess.CalledProcessError:
# No boot partition, using /boot
# UUID aka FS UUID is stored in the FS itself
boot_uuid = run("findmnt -vfn -o UUID " + disk_path)
template = """
menuentry 'Slackware GNU/Linux {NAME}' --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-new' {{
load_video
insmod gzio
insmod part_msdos
insmod part_gpt
insmod btrfs
insmod ext2
echo 'Searching for boot partition...'
search.fs_uuid {BOOTUUID} root
echo 'Loading Linux from' $root
linux /root/boot/{IMAGE} {BOOTFLAGS} root=PARTUUID={ROOTPARTUUID}
}}
"""
for image_name in ("vmlinuz", "vmlinuz-backup"):
image_path = disk_path + "/root/boot/" + image_name
if os.path.isfile(image_path):
name = os.readlink(image_path) + " on " + disk_path
print(template.format(ROOTPARTUUID = root_partuuid,
BOOTUUID = boot_uuid,
BOOTFLAGS = bootflags,
IMAGE = image_name,
NAME = name))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment