Script to create a boot CD, DVD or USB stick for your system
No matter what systems are installed on your machine, they all depend on the master boot loader performing correctly.
If for example, a new install destroys your bootloader, then it's really handy to have an alternative way to boot any of your installations.
This will produce just that, a custom boot CD, DVD or USB stick to boot your systems.
It uses grub2 to create a boot iso and then offers to write it to the required media.
Various options are available during the creation, including erasure of CD/DVD-RW media, making it very easy to use.
The script installs any extra packages that it requires, and also offers to uninstall them on completion. If you do not remove them a list of the packages is created in a text file.
Please contact me if you find a bug.
Follow the instructions in the "Use:" section in the script below.
#!/bin/bash # mk-grub2-boot ########################################################### # Author - Barry Jackson (barjac) ########################################################### # NOTE: !!!!!! NOT FOR UEFI SYSTEMS !!!!! # Description: # This script creates a Mageia GRUB2 boot CD/DVD or USB stick. # An option to erase RW media is available before burning. # All systems on the machine should be bootable and will be # included in the menu. # It does not matter whether grub, lilo, grub2 or whatever is # the current bootloader. # Grub2 and other packages are temporarily installed to create # the files, but this makes no permanent changes to your current # bootloader. The script offers to remove all extra packages it # installs and restore any changed theme. (It may leave one orphan) # os-prober is used to probe for all systems, however if you are # using grub2 and have it disabled in /etc/default/grub then it # will not be used. # A graphical theme may be used for the boot menu. # Note that a theme may cause the menu to be too slow on old # hardware, so in this case you can opt to not use one. ########################################################### # Use: # Save this script as mk-grub2-boot # Make it executable: chmod +x mk-grub2-boot # Run it as root from the same directory. # su # ./mk-grub2-boot ########################################################### ver=2.8 # Changelog: # 2.8 17/12/2014 Don't try to remove orphan lib(64)lvm2app2.2 # 2.7 12/09/2013 Minor update to CD/DVD-RW media detection # 2.6 10/09/2013 Don't use auto-orphans # 2.5 28/07/2013 Add ESC to abort usb detection loop and fix # stray characters on ESC in CD and usb detection # 2.4 24/07/2013 Really fix USB detection ;) Fix typo # Added DVD-RW erase option. # 2.3 21/07/2013 Fix USB detection bug. # 2.2 18/07/2013 Really fix cleanup messages, thanks Bogdan ;) # 2.1 17/07/2013 Added option to erase a CD-RW before burn # 2.0 16/07/2013 Fix CD Write problem caused by earlier code changes # Fix removal of grub2 when not prev installed # Fix incorrect cleanup messages in txt files # 1.9 15/07/2013 Fix minor code duplication # 1.8 14/07/2013 Fixed uninitialised var # Validate answer to theme to be used # Fix typos in created txt file # Don't mention current theme if there isn't one # 1.7 12/07/2013 Add date to txt filename and fix bad entries # 1.6 12/07/2013 Add * to indicate current theme in list. # Corrected some imperfect bash syntax. # 1.5 11/07/2013 Added option to use any available theme from # currently enabled repos # Added mk-grub2-boot.txt in current dir to # record packages not removed or restored. # 1.4 11/07/2013 Code clean up - removed redundant vars # 1.3 10/07/2013 Corrected some typos, fixed usb detection issue # 1.2 04/07/2013 Clarify opening question and only ask if iso exists # 1.1 14/06/2013 Catch user error plugging usb drive # 1.0 13/06/2013 Faster transactioned deps install/uninstall # 0.9 13/06/2013 Better script structure, better dd safety, # ESC to abort CD detect, don't needlessly # install theme # 0.8 13/06/2013 Fix udisks uninstalled too early # 0.7 10/06/2013 Force umount of CDROM before write # 0.6 10/06/2013 Option to use theme or not # 0.5 10/06/2013 Use array in devlst() not tmp file # 0.4 09/06/2013 Fix bug in udiskinfo(), improved listusbdrives() # 0.3 09/06/2013 Don't add theme. Better usb detection # 0.2 07/06/2013 Add options to burn CD or write USB. # 0.1 06/06/2013 First release ########################################################### # Configuration: # None required :) ########################################################### # License: # Totally free with no warranty whatsoever. ########################################################### # Thanks go to: # Bogdan Gruescu for much testing and many bug reports :) ########################################################### # Functions------------------------------------------------ # Talk to user confirm() { params=( "$@" ) rval=3 while [ $rval -gt 2 ];do echo -ne ${params[0]}" "${params[1]}" " ans= rval= read ans if [[ -z "$ans" ]] || (( ${#ans} > 1 )); then rval=3 else case "$ans" in [${params[2]}]*) rval=0 ;; [${params[3]}]*) rval=1 ;; [${params[4]}]*) rval=2 ;; *) rval=3 ;; esac fi done return $rval } # Install requires getreqs() { [[ -e /boot/grub2/grub.cfg ]] || { urpmi grub2 --no-suggests; grub2=1; } instlist=() rpm -q os-prober > /dev/null || instlist+=("os-prober") rpm -q memtest86+ > /dev/null || instlist+=("memtest86+") rpm -q udisks > /dev/null || instlist+=("udisks") rpm -q xorriso > /dev/null || instlist+=("xorriso") if confirm "\nDo you wish to use a theme for the boot menu?" "[Y/N]" "Yy" "Nn"; then gettheme rpm -q $theme2use > /dev/null || instlist+=($theme2use) usetheme=1 else usetheme=0 fi if (( ${#instlist[@]} > 0 )); then urpmi --auto ${instlist[@]} || { echo "Install of package failed"; exit 0; } fi [[ $grub2 = 1 ]] && instlist+=("grub2") } # Clean up cleanup() { now=$(dte) if [[ $grub2 != 1 ]] && (( ${#theme2use} > 0 )); then instlist=($(echo ${instlist[@]} | sed "s/$theme2use//")) fi if (( ${#instlist[@]} > 0 )); then if confirm "\nDo you wish to remove all packages that were not originally installed on your machine?" "[Y/N]" "Yy" "Nn"; then urpme ${instlist[@]} else echo "The following packages were installed by mk-grub2-boot and you opted not to remove them: ${instlist[@]}" > mk-grub2-boot-$now.txt fi fi if [[ $grub2 != 1 ]] && [[ $burnwrite_only != 1 ]]; then if [[ ${#theme2use} > 0 ]] && [[ ${#themeinstalled} = 0 ]]; then if rpm -q $theme2use > /dev/null && confirm "\nA boot menu theme ($theme2use) was installed, do you wish to remove it?" "[Y/N]" "Yy" "Nn"; then urpme $theme2use else echo "A boot menu theme ($theme2use) was installed and you opted not to remove it." >> mk-grub2-boot-$now.txt fi else if [[ ${#theme2use} > 0 ]] && [[ ${#themeinstalled} > 0 ]] && [[ $themeinstalled != $theme2use ]]; then if confirm "\nYour boot menu theme was changed, do you wish to restore the original ($themeinstalled)?" "[Y/N]" "Yy" "Nn"; then urpmi $themeinstalled else echo "Your original theme ($themeinstalled) was changed (to $theme2use) and you opted not to restore it." >> mk-grub2-boot-$now.txt fi fi fi fi rm -rf grub2-boot } isnumeric(){ echo "$@" | grep -q -v "[^0-9]" } # Get theme gettheme() { themes=($(urpmq grub2 -y | grep theme)) i=0 echo while true; do mark= if (( ${#themes[$i]} > 0 )); then rpm -q --qf %{NAME} ${themes[$i]} > /dev/null 2>&1 && { themeinstalled=${themes[$i]}; mark="*"; } echo "#$i ${themes[$i]} $mark" i=$((i+1)) else (( ${#themeinstalled} > 0 )) && echo -e "\nYour current theme is marked with *" echo -e "\nEnter the # of the theme you wish to use" read ans isnumeric $ans && (( $ans >= 0 )) && (( $ans <= (( ${#themes[@]}-1 )) )) || \ { echo -e "\nInvalid selection!\n"; i=0; continue; } break fi done theme2use=${themes[$ans]} } # Create iso createiso() { getreqs # Start with clean iso dir [[ -d grub2-boot ]] && rm -rf grub2-boot # Create iso tree mkdir -p grub2-boot/boot/grub # Add memtest to tree cp /boot/memtest.bin grub2-boot/boot/ # Copy grub2 files to tree cp -r /boot/grub2/* grub2-boot/boot/grub/ configedit # Create iso grub2-mkrescue -o grub2-boot.iso grub2-boot/ && \ echo -e "\ngrub2-boot.iso was written sucessfully :)\n" burnwrite } # Function to output numeric date string dte() { echo -n $(date +%Y%m%d%H%M) } # Get udisks info udiskinfo() { if [[ $2 = "media" ]];then output=$(udisks --show-info $1|grep $2:|tail -1|cut -d: -f2) else output=$(udisks --show-info $1|grep -m1 $2:|cut -d: -f2) fi echo $output } # List all usb drives listusbdrives () { drives=() for dev in $(udisks --enumerate |rev|cut -d/ -f1|rev|tr -d [:digit:]|sort -u ); do int=$(udiskinfo /dev/$dev "interface") [[ $int = "usb" ]] && drives+=($dev) done } # Detect USB detectusb() { escape=$'\x1b' while true; do unset d if confirm "\nMake sure the USB stick is UNPLUGGED now. Ready?" "[Y/N]" "Yy" "Nn";then listusbdrives a=("${drives[@]}") echo -n -e "\nPLUG IN the usb stick now. (ESC to abort)\nDetecting." while true; do listusbdrives b=("${drives[@]}") read -s -n1 -t1 key if [[ $key = $escape ]]; then esc=1 break else key="" fi (( ${#a[@]} != ${#b[@]} )) && break echo -n "." done ( (( ${#a[@]} > ${#b[@]} )) || [[ esc = 1 ]] ) && { echo; continue; } echo echo fi for item1 in "${b[@]}"; do for item2 in "${a[@]}"; do found=0 if [[ $item1 = $item2 ]]; then found=1; break fi done [[ $found = 1 ]] && continue d=$item1; break done break done } # Blank CD rw= blankcd() { if confirm "\nWould you like to erase a CD/DVD-RW first?" "[Y/N]" "Yy" "Nn"; then escape=$'\x1b' echo -n -e "\nInsert a disk to erase now. (ESC to abort)\nLooking for RW media ..." cdlst=($(udisks --enumerate | grep "devices/sr"|rev|cut -d/ -f1|rev)) [[ "${#cdlst}" -eq 0 ]] && { echo "No CD/DVD ROM found"; cdr=''; return 0; } found= while (( ${#found} == 0 )); do read -s -n1 -t1 key if [[ $key = $escape ]]; then esc=1 break else key="" fi echo -n "." for cdr in ${cdlst[@]}; do found=$(udiskinfo /dev/$cdr "media") ( [[ $found = optical_cd_rw ]] || \ [[ $found = optical_dvd_rw ]] || \ [[ $found = optical_dvd_plus_rw ]] ) && \ { rw=1; echo; break; } done done fi if [[ $rw = 1 ]] && confirm "\nErase disk in /dev/$cdr now?" "[Y/N]" "Yy" "Nn"; then wodim speed=16 -eject dev=/dev/$cdr -blank fast && echo -e "\nDisk erased successfully" fi } # Detect CDROM detectcd() { escape=$'\x1b' echo -n -e "\nInsert a blank disk now. (ESC to abort)\nDetecting..." cdlst=($(udisks --enumerate | grep "devices/sr"|rev|cut -d/ -f1|rev)) [[ ${#cdlst} -eq 0 ]] && { echo "No media found"; cdr=''; return 0; } while [[ $blank != 1 ]]; do read -s -n1 -t1 key if [[ $key = $escape ]]; then esc=1 break else key="" fi echo -n "." for cdr in ${cdlst[@]}; do blank=$(udiskinfo /dev/$cdr "blank") [[ $blank = 1 ]] && { echo; break; } done done } # Write USB writeusb() { detectusb if (( ${#d} != 0 )); then if confirm "Found /dev/$d ( $(udiskinfo /dev/$d "model") ) All data on /dev/$d will be lost - OK?" "[Y/N]" "Yy" "Nn"; then echo -e "\nPlease wait - writing to USB..." dd if=grub2-boot.iso of=/dev/$d bs=1M && \ echo -e "\nUSB write complete - wait for USB light to stop flashing before removing device." fi fi } # Burn CD burncd() { detectcd if (( ${#cdr} > 0 )) && [[ $esc != 1 ]]; then # Unmount CDROM in case a disk was swapped umount $(df | grep /dev/$cdr | cut -d% -f2) > /dev/null 2>&1 if confirm "\nBurn iso to /dev/$cdr - OK?" "[Y/N]" "Yy" "Nn"; then wodim speed=16 -eject dev=/dev/$cdr grub2-boot.iso && echo "Disk write complete" fi fi } # Offer to burn CD or Write USB burnwrite() { rpm -q udisks > /dev/null || { instlist+=("udisks"); urpmi --auto udisks; } while true; do if confirm "\nWould you like to (B)urn a CD/DVD, (W)rite a USB stick or (Q)uit?" "[B/W/Q]" "Bb" "Ww" "Qq"; then blankcd burncd elif (( $? == 1 )); then writeusb else break fi done } # Get numeric position of letter in alphabet (a=0, b=1) alphapos() { y=0 for x in {a..z}; do [[ $1 = $x ]] && { echo $y; break; } y=$((y+1)) done } # Get array of root devices for all systems devlst() { devs=($(df -h /boot |(read; awk '{print $1;exit}'))" "$(os-prober|cut -d: -f1)) } # Create 'hdx,msdosy' from /dev/sdxy mkhdpart() { hdalpha=$(echo $1 |tr -d [:digit:] | cut -dd -f3) hdn=$(alphapos $hdalpha) part=$(echo $1 | grep -P -o "[0-9]+") hdstr="'"hd$hdn",msdos"$part"'" } # Get uuid from /dev/sdxy getuuid() { uuidstr=$(udiskinfo $1 "uuid") } # Modify grub.cfg and theme for boot iso configedit() { if (( $usetheme == 1 )); then sed -i 's/"Mageia Grub 2 Menu"/"Mageia Grub 2 Rescue"/' $(find . -name theme.txt) else rm grub2-boot/boot/grub/themes -rf sed -i "s/^set theme=.*//" grub2-boot/boot/grub/grub.cfg sed -i "s/^export theme//" grub2-boot/boot/grub/grub.cfg fi # Add colours to text menu cat>>grub2-boot/boot/grub/grub.cfg<<EOF set menu_color_normal=cyan/blue set menu_color_highlight=yellow/blue EOF # Remove root assignment as disk id will change if using usb sed -i "s/^set root=.*//" grub2-boot/boot/grub/grub.cfg # Change refs to 'grub2' as upstream uses 'grub' sed -i 's/grub2/grub/g' grub2-boot/boot/grub/grub.cfg # Remove more indirect references to original root sed -i '/x$feature_platform_search_hint/,+4d' grub2-boot/boot/grub/grub.cfg # Remove and replace memtest entry to remove root and add better title sed -i '/93_memtest/,+8d' grub2-boot/boot/grub/grub.cfg cat >> grub2-boot/boot/grub/grub.cfg <<EOF menuentry 'Memtest' { insmod part_msdos insmod ext2 echo 'Loading Memtest ...Loading memtest.bin ...' linux16 /boot/memtest.bin } EOF # Change all device references to cater for usb and replace with uuid search instead. devlst for dv in ${devs[@]}; do getuuid $dv mkhdpart $dv sed -i "s/set root=$hdstr/search --no-floppy --fs-uuid --set=root $uuidstr/g" grub2-boot/boot/grub/grub.cfg done } # Main script---------------------------------------------- # Check we are root (((UID))) && { echo "Must be root to run $0"; exit 0; } # Say hello clear echo -e "Welcome to mk-grub2-boot - version $ver\n" # Check for existing iso if [[ -e grub2-boot.iso ]] && \ confirm "You already have a previously generated iso.\n(U)se it or (C)reate a new one?" "[U/C]" "Uu" "Cc"; then burnwrite_only=1 burnwrite else createiso fi cleanup echo -e "\nBye :)" # End of mk-grub2-boot