insmod part_gpt insmod part_msdos insmod fat insmod iso9660 insmod udf # wildcard expansion requires this insmod regexp insmod chain # set color_normal=cyan/black # set menu_color_normal=cyan/black # set menu_color_highlight=black/cyan set pager=1 #set debug=all set timeout=-1 # hold shift to disable gfxterm if ! keystatus --shift; then if loadfont unicode; then if [ "${grub_platform}" == 'efi' ]; then insmod efi_gop insmod efi_uga else insmod vbe fi insmod gfxterm set gfxmode=auto # required for debian installer GTK set gfxpayload=keep terminal_output gfxterm #if test -f ${prefix}/themes/starfield/theme.txt; then # insmod png # set theme=${prefix}/themes/starfield/theme.txt #fi fi fi function enum_iso{ # quotes are very tricky in shell scripts, here we want the * to be expanded, thus should not be quoted for p in "$1"/*; do # single quotes prevent escape and variable/wildcard expansion, perfect for regular expression regexp -s n '([^/]+)\.[Ii][Ss][Oo]$' "$p" if ! test -z "$n"; then loopback loop "$p" echo "loopback $p ..." # for old grub, wait for loopback # sleep $2 check_loop "$n" "$p" loopback -d loop unset n fi done } function check_loop{ probe -s iso_label -l (loop) echo -e "\tlabel is $iso_label" if test -f (loop)/boot/grub/loopback.cfg; then loopback_entry "$1" "$2" /boot/grub/loopback.cfg elif test -f (loop)/boot/loopback.cfg; then loopback_entry "$1" "$2" /boot/loopback.cfg elif debian_live_entry "$1" "$2"; then true elif arch_entry "$1" "$2"; then true elif manjaro_entry "$1" "$2"; then true elif casper_entry "$1" "$2"; then true elif redhat_entry "$1" "$2"; then true elif redhat8_entry "$1" "$2"; then true elif opensuse_entry "$1" "$2"; then true elif pclinuxos_entry "$1" "$2"; then true elif tinycore_seagate_entry "$1" "$2"; then true elif debian_installer_entry "$1" "$2"; then true elif mageia_entry "$1" "$2"; then true elif pve_entry "$1" "$2"; then true else echo -e "\toops, unrecognized iso, press enter to continue ..." read fi } # these two doesn't work, just tinkering function debian_installer_entry{ # as of buster 10.4, there is no loop module in the initrd, so no chance if ! test -d (loop)/install.amd; then return 1; fi if ! test -f (loop)/install.amd/vmlinuz; then return 1; fi if ! test -f (loop)/install.amd/initrd.gz; then return 1; fi echo -e "\tDebian Installer detected" menuentry "$1 (Debian Installer)(not working)" "$2" { loopback loop "$2" linux (loop)/install.amd/vmlinuz initrd (loop)/install.amd/initrd.gz } } function mageia_entry{ # as of mageia 5, there is no loop module in the initrd, so no chance if ! test -d (loop)/boot/cdrom; then return 1; fi if ! test -f (loop)/boot/vmlinuz; then return 1; fi if ! test -f (loop)/boot/cdrom/initrd.gz; then return 1; fi echo -e "\tMageia Live detected" menuentry "$1 (Mageia Live)(not working)" "$2" { loopback loop "$2" linux (loop)/boot/vmlinuz vga=788 noiswmd rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 initrd (loop)/boot/cdrom/initrd.gz } } function pve_entry{ # as of 6.2, the initrd does have loop module but sadly there is no mechanism to mount an image file if ! test -d (loop)/proxmox; then return 1; fi if ! test -f (loop)/boot/linux26; then return 1; fi if ! test -f (loop)/boot/initrd.img; then return 1; fi echo -e "\tProxmox VE detected" menuentry "$1 (Proxmox VE)(not working)" "$2" { probe -s root_uuid -u $root loopback loop "$2" linux (loop)/boot/linux26 ro ramdisk_size=16777216 rw splash=silent initrd (loop)/boot/initrd.img } } function loopback_entry{ echo -e "\t$3 detected" menuentry "$1 (loopback.cfg)" "$2" "$3"{ set iso_path="$2" export iso_path # after change root, these might not be available due to incompatible grub version # insmod png # insmod play insmod linux set old_root=$root loopback loop "$2" set root=(loop) if ! test -f /dists/stretch/Release; then configfile "$3" else echo -e "Debian 9 live workaround" read # workaround for Debian 9 Live # see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=866183 # which is fixed as of Debian 10.4 set loopback="findiso=$iso_path" export loopback configfile /boot/grub/grub.cfg fi # in case the user quit loopback.cfg by esc set root=$old_root loopback -d loop } } function casper_entry{ # strangely not all ubuntu based distribution supports loopback.cfg, like the kubuntu-plasma-5 live if ! test -d (loop)/casper; then return 1; fi if ! test -f (loop)/casper/vmlinuz; then return 1; fi if ! test -f (loop)/casper/initrd.lz; then return 1;fi echo -e "\tCasper Live detected" menuentry "$1 (Casper Live)" "$2"{ loopback loop "$2" linux (loop)/casper/vmlinuz iso-scan/filename="$2" file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash -- initrd (loop)/casper/initrd.lz } } # Debian 9 uses loopback.cfg instead function debian_live_entry{ # there was a bug around test -a for -d/-f testings if ! test -d (loop)/live; then return 1; fi if ! test -f (loop)/live/vmlinuz; then return 1; fi if ! test -f (loop)/live/initrd.img; then return 1; fi if ! test -f (loop)/live/filesystem.squashfs; then return 1; fi if ! test -f (loop)/GParted-Live-Version -o -f (loop)/Clonezilla-Live-Version; then echo -e "\tDebian Live detected" debian_live_entry_0 "$1 (Debian Live)" "$2" "" debian_live_entry_0 "$1 (Debian Live toram)" "$2" "toram=filesystem.squashfs" else echo -e "\tGParted/Clonezilla Live detected" debian_live_entry_0 "$1 (GParted Live)" "$2" "union=overlay username=user config components noswap ip= net.ifnames=0 nosplash" debian_live_entry_0 "$1 (GParted Live toram)" "$2" "union=overlay username=user config components noswap ip= net.ifnames=0 nosplash toram=filesystem.squashfs" fi } function debian_live_entry_0{ # name, iso path, additional boot parameter menuentry "$1" "$2" "$3"{ probe -s root_uuid -u $root loopback loop "$2" linux (loop)/live/vmlinuz fromiso=/dev/disk/by-uuid/$root_uuid$2 boot=live components noswap $3 initrd (loop)/live/initrd.img } } function redhat_entry{ if ! test -f (loop)/LiveOS/squashfs.img; then return 1; fi if ! test -d (loop)/isolinux; then return 1; fi for k in (loop)/isolinux/vmlinuz*; do break; done if test -z "$k"; then return 1; fi for r in (loop)/isolinux/initrd*.img; do break; done if test -z "$r"; then return 1; fi if test -f (loop)/.treeinfo; then echo -e "\tRedHat/CentOS Installer detected" menuentry "$1 (RedHat/CentOS Installer)" "$2" "$k" "$r" { loopback loop "$2" probe -s root_uuid -u $root # https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/chap-anaconda-boot-options linux "$3" inst.stage2=hd:UUID="$root_uuid":$2 initrd "$4" } else echo -e "\tRedhat/Fedora/CentOS Live detected" menuentry "$1 (Redhat/Fedora/CentOS Live)" "$2" "$k" "$r" { loopback loop "$2" probe -s iso_label -l (loop) linux "$3" iso-scan/filename="$2" root=live:CDLABEL="$iso_label" rootfstype=auto ro rd.live.image rhgb rd.luks=0 rd.md=0 rd.dm=0 initrd "$4" } fi } function redhat8_entry{ # centos 8 uses a new layout, and no live images available AFAIK # `test -f fa -o -f fb` doesn't seem to be working correctly if ! test -f (loop)/images/install.img; then return 1; fi if ! test -d (loop)/isolinux; then return 1; fi for k in (loop)/isolinux/vmlinuz*; do break; done if test -z "$k"; then return 1; fi for r in (loop)/isolinux/initrd*.img; do break; done if test -z "$r"; then return 1; fi echo -e "\tRedHat/CentOS Installer detected" menuentry "$1 (RedHat/CentOS Installer)" "$2" "$k" "$r" { loopback loop "$2" probe -s root_uuid -u $root linux "$3" inst.stage2=hd:UUID="$root_uuid":$2 initrd "$4" } } function opensuse_entry{ if ! test -d (loop)/boot; then return 1; fi for d in (loop)/boot/*; do if ! test -d "$d"; then continue; fi if ! test -d "$d"/loader; then continue; fi if ! test -f "$d"/loader/linux; then continue; fi if ! test -f "$d"/loader/initrd; then continue; fi regexp -s arch '([^/]+)$' "$d" echo -e "\topenSUSE $arch Live detected" menuentry "$1 (openSUSE Live $3)" "$2" "$arch" { probe -s root_uuid -u $root loopback loop "$2" linux (loop)/boot/"$3"/loader/linux isofrom=/dev/disk/by-uuid/$root_uuid:"$2" isofrom_device=/dev/disk/by-uuid/$root_uuid isofrom_system="$2" ramdisk_size=512000 ramdisk_blocksize=4096 loader=grub splash=silent showopts initrd (loop)/boot/"$3"/loader/initrd } done if test -z $arch; then return 1; else unset arch; return 0; fi } function arch_entry{ if ! test -d (loop)/arch/boot; then return 1; fi # arch single layout, like antergos if test -f (loop)/arch/boot/vmlinuz -a -f (loop)/arch/boot/archiso.img; then echo -e "\tArch detected" arch_entry_0 "$1 (Arch)" "$2" "(loop)/arch/boot" "" arch_entry_0 "$1 (Arch copytoram)" "$2" "(loop)/arch/boot" "copytoram" return 0 fi # official arch dual layout for d in (loop)/arch/boot/*; do if ! test -d "$d"; then continue; fi if ! test -f "$d"/vmlinuz; then continue; fi if ! test -f "$d"/archiso.img; then continue; fi regexp -s arch '([^/]+)$' "$d" echo -e "\tArch $arch detected" arch_entry_0 "$1 (Arch $arch)" "$2" "$d" "" arch_entry_0 "$1 (Arch $arch copytoram)" "$2" "$d" "copytoram" done if test -z "$arch"; then return 1; else unset arch; return 0; fi } function arch_entry_0{ # name, iso path, boot dir, additional boot parameters menuentry "$1" "$2" "$3" "$4"{ probe -s root_uuid -u $root loopback loop "$2" probe -s iso_label -l (loop) linux "$3"/vmlinuz archisolabel="$iso_label" img_dev=/dev/disk/by-uuid/$root_uuid img_loop="$2" earlymodules=loop $4 if test -f "$3"/intel_ucode.img; then initrd "$3"/intel_ucode.img fi initrd "$3"/archiso.img } } function manjaro_entry{ # despite been Arch based, manjaro live iso has lots of different names and parameters if ! test -d (loop)/manjaro/boot; then return 1; fi for d in (loop)/manjaro/boot/*; do if ! test -d "$d"; then continue; fi if ! test -f "$d"/manjaro; then continue; fi if ! test -f "$d"/manjaro.img; then continue; fi regexp -s arch '([^/]+)$' "$d" echo -e "\tManjaro $arch detected" menuentry "$1 (Manjaro $arch)" "$2" "$d"{ probe -s root_uuid -u $root loopback loop "$2" probe -s iso_label -l (loop) linux "$3"/manjaro misobasedir=manjaro misolabel="$iso_label" img_dev=/dev/disk/by-uuid/$root_uuid img_loop="$2" earlymodules=loop nouveau.modeset=0 i915.modeset=1 radeon.modeset=0 nonfree=yes logo.nologo overlay=nonfree quiet splash showopts if test -f (loop)/manjaro/boot/intel_ucode.img; then initrd (loop)/manjaro/boot/intel_ucode.img fi initrd "$3"/manjaro.img } done if test -z "$arch"; then return 1; else unset arch; return 0; fi } function pclinuxos_entry{ if ! test -d (loop)/isolinux; then return 1; fi if ! test -f (loop)/isolinux/vmlinuz; then return 1; fi if ! test -f (loop)/isolinux/initrd.gz; then return 1;fi if ! test -f (loop)/livecd.sqfs; then return 1;fi echo -e "\tPCLinuxOS Live detected" pclinuxos_entry_0 "$1 (PCLinuxOS Live)" "$2" "" pclinuxos_entry_0 "$1 (PCLinuxOS Live copytoram)" "$2" "copytoram" } function pclinuxos_entry_0{ menuentry "$1" "$2" "$3"{ loopback loop "$2" linux (loop)/isolinux/vmlinuz livecd=livecd root=/dev/rd/3 quiet keyb=us splash=silent bootfromiso="$2" "$3" initrd (loop)/isolinux/initrd.gz } } function tinycore_seagate_entry{ if ! test -d (loop)/isolinux; then return 1; fi if ! test -f (loop)/isolinux/STXbzImage; then return 1; fi if ! test -f (loop)/isolinux/tinycore_Seagate.gz; then return 1;fi echo -e "\ttinycore Seagate detected" menuentry "$1 (tinycore Seagate)" "$2"{ loopback loop "$2" linux (loop)/isolinux/STXbzImage superuser loglevel=2 base noacpi noswap waitusb3 video=vesafb:mtrr:3,ywrap vga=792 initrd (loop)/isolinux/tinycore_Seagate.gz } } function enum_puppy{ for p in "$1"/*; do if ! test -d "$p"; then continue; fi if ! test -f "$p"/vmlinuz; then continue; fi if ! test -f "$p"/initrd.gz; then continue; fi regexp -s n '([^/]+)$' "$p" echo -e "\tpuppy $n detected" menuentry "puppy $n" "$p" { linux "$2"/vmlinuz psubdir="$2" pkeys=us initrd "$2"/initrd.gz } done } function enum_linux{ for p in "$1"/*; do if ! test -d "$p"; then continue; fi if ! test -f "$p/$3"; then continue; fi if ! test -f "$p/$4"; then continue; fi regexp -s n '([^/]+)$' "$p" menuentry "$2 $n" "$p" "$3" "$4" { linux "$2/$3" initrd "$2/$4" } done } function enum_linux16{ for p in "$1"/*; do if ! test -f "$p"; then continue; fi regexp -s n '([^/]+)$' "$p" menuentry "$n" "$p" { linux16 "$2" } done } function enum_floppy{ for p in "$1"/*; do if ! test -f "$p"; then continue; fi regexp -s n '([^/]+)$' "$p" menuentry "$n (floppy image memdisk)" "$2" "$p" { linux16 "$2" floppy initrd16 "$3" } done } function enum_efi{ # x86 efi is such a minority I'm gonna ignore that for p in "$1"/*;do if ! test -d "$p"; then continue; fi if ! test -f "$p"/BOOTX64.efi; then continue; fi regexp -s n '([^/]+)$' "$p" if test "$n" == boot; then continue; fi menuentry "$n(EFI chain)" "$p" { chainloader "$2"/BOOTX64.efi } done } if test -d /boot/iso; then enum_iso /boot/iso; fi if test -d /boot/debian-installer; then enum_linux /boot/debian-installer "Debian Installer" vmlinuz initrd.gz enum_linux /boot/debian-installer "Debian Installer" linux initrd.gz fi if test -d /boot/puppy; then enum_puppy /boot/puppy; fi if [ "${grub_platform}" == 'pc']; then if test -d /boot/linux16; then enum_linux16 /boot/linux16; fi if test -f /boot/syslinux/memdisk; then enum_floppy /boot/floppy /boot/syslinux/memdisk; fi if test -f /bootmgr; then menuentry bootmgr {ntldr /bootmgr}; fi if test -f /kernel.sys; then menuentry FreeDOS {freedos /kernel.sys}; fi menuentry "chainloader volume boot record" {chainloader (hd0,msdos1)+1} elif [ "${grub_platform}" == 'efi' ]; then if test -d /efi; then enum_efi /efi; fi fi if test -f "$prefix"/test_grub.cfg; then menuentry "load test_grub.cfg" {configfile "$prefix"/test_grub.cfg} fi echo scan complete, press enter to continue ... read menuentry halt {halt} menuentry reboot {reboot}