Skip to content

Instantly share code, notes, and snippets.

@rcarmo
Forked from rversteegen/grub_linux_manual.py
Created July 19, 2023 07:42
Show Gist options
  • Select an option

  • Save rcarmo/8b873ab7f88fef87eec19d01eccad0d8 to your computer and use it in GitHub Desktop.

Select an option

Save rcarmo/8b873ab7f88fef87eec19d01eccad0d8 to your computer and use it in GitHub Desktop.

Revisions

  1. @rversteegen rversteegen created this gist Jul 19, 2023.
    106 changes: 106 additions & 0 deletions grub_linux_manual.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,106 @@
    #!/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))