Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: updategrub for openSUSE Legacy Grub (not update-grub!)

  1. #1

    Default updategrub for openSUSE Legacy Grub (not update-grub!)

    updategrub is a script which aims to solve all your boot problems ...

    As I just advised somebody to try it, I think I have to post the code now, so that users and others can have a look at it.

    More seriously, it works similarly to Grub2's update-grub under Ubuntu, using the same helper scripts : os-prober and linux-bootprober. I don't know why os-prober wasn't available for openSUSE. So I packaged it from a Fedora/ArchLinux port (which in turn ported the original Ubuntu/Debian script). os-prober will be installed as dependency when you install updategrub from my repo.

    Like update-grub, updategrub allows to append custom boot entries written in /etc/updategrub/custom (Ubuntu uses /etc/grub.d/40_custom). This file doesn't exist by default. It has a couple options that can be turned on/off in /etc/updategrub/defaults. This file is installed with defaults values. The options are explained in details in /usr/share/doc/packages/updategrub/README.

    As a consequence of installing os-prober, Grub2 users under openSUSE will be able to update Grub2 menu entries as well (assuming they use Grub2 under openSUSE). I added such an option, although updategrub isn't originally intended to work with Grub2.

    If - as I read many times - the advantage of Grub2 over Legacy Grub is that it can update Grub menu boot entries:
    • it wasn't entirely true since it is not the job of Grub2 but the fact of os-prober/linux-bootprober
    • it might not be true anymore since updategrub does it better (I hope so) and with more features.


    updategrub will be installed in /usr/bin and is actually a symlink to /usr/bin/updateLegacyGrub (to avoid future conflicts ?).
    I also added the old good findgrub and cfindgrub scripts to the updategrub package.

    Installation from repo:

    Code:
    su -l
    zypper ar http://download.opensuse.org/reposit...openSUSE_11.4/ PTA
    zypper refresh -r PTA
    zypper in updategrub
    Usage:

    Code:
    updategrub     # updtate /boot/grub/menu.lst
    updategrub -l  # display boot entries which could be added but don't write menu.lst
    updategrub -a  # activate Grub primary partition (same as findgrub -a)
    updategrub -r  # restore previous menu.lst
    updategrub -2  # update Grub2 menu.

    Some of updategrub's options in /etc/updategrub/defaults include:

    CHAINLOADGRUB (default yes)
    add other Grubs chainload entries

    MAKEACTIVE
    (default is no and should remain NO!)
    make Windows partition active

    SETBOOTFLAG (default is no)
    (set bootflag on Grub primary partition if any, same as updategrub -a)

    You may also influence the order in which other Linux boot entries will be added in linux_order and ignore failsafe like boot entries as well as entries containing specific keywords, as in the example:
    linux_ignore="Gutsy Hardy"

    I don't guarantee it is bugfree. First versions rarely are. I hope you'll tell me if you find some.
    To Windows users - and I do not intend to work for them, please! - the entries that updategrub will add are the ones found and identified by os-prober, basically the same ones you would see in Ubuntu while running update-grub. Since openSUSE already adds those entries (sometimes also wrong ones), at least one (probably the right one) will appear twice. I guess I'll have to add a windows_ignore option in the next release to avoid duplicates.

    updategrub does not modify the part of menu.lst written by openSUSE YaST or zypper. It does not add other openSUSE's kernel boot entries, since os-prober doesn't check the /boot partition of the current OS. However it will add other openSUSE kernel boot entries if they are installed in other partitions (other openSUSE versions or several installs of the same version).

    Viel Spass.

  2. #2

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    Code:
    #! /bin/bash
    
    #: Title       : updateLegacyGrub
    #: Date Created: Sat Apr  2 16:20:32 PDT 2011
    #: Last Edit   : Fri Apr 15 07:15:49 PDT 2011
    #: Author      : Agnelo de la Crotche (please_try_again) 
    #: Version     : 1.2.2
    #: Description : add other Linux & Windows boot entries to Legacy Grub boot menu (similarly to Grub2's update-grub)
    #: Requires    : os-prober (available in my repo: http://download.opensuse.org/repositories/home:/please_try_again/openSUSE_11.4/)
    #: Usage       : updategrub
    #: Syntax      : There are a few options. Type updategrub -h for help. 
    #              : Read /usr/share/doc/packages/updategrub/README for details.
    #
    #
    # current version
    version="1.2.2"
    prg=$(basename $0)
    devmap=/boot/grub/device.map
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # TESTS 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # check if we are root
    [ $UID -eq 0 ] || exec echo "You have to run this script as root (or sudo)" 
    
    # check for os-prober and linux-boot-prober 
    osprober=`which os-prober 2>/dev/null` || exec echo "os-prober not found"
    linuxbootprober=`which linux-boot-prober 2>/dev/null` || exec echo "linux-boot-prober not found"
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # DEFINE VARIABLES 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    declare -l CHAINLOADGRUB NOFAILSAFE MAKEACTIVE SETBOOTFLAG WINDOWSFIRST DISPLAYONLY EXCLUDE GRUB2
    declare -a GRUBS HDDEV
    
    # Chainload other Grubs by default.
    CHAINLOADGRUB=yes
    # Ignore failsafe, recovery and single user mode entries.
    NOFAILSAFE=yes
    # Make Windows Partition active.
    MAKEACTIVE=no
    # Windows Chainload entries before other Linux distros kernel entries
    WINDOWSFIRST=no
    # Set bootflag on Grub partition
    SETBOOTFLAG=no
    # Display changes but do not write boot menu. 
    DISPLAYONLY=no
    # if NOFAILSAFE is set, reject entries containing this words keywords  
    EXCLUDE='recovery|rescue|failsafe|fallback|single-user'
    
    # import some defaults from (optional) configuration file
    [ -f /etc/updategrub/defaults ] && source /etc/updategrub/defaults
    
    for OPT in CHAINLOADGRUB NOFAILSAFE MAKEACTIVE WINDOWSFIRST SETBOOTFLAG DISPLAYONLY ; do
    	[ "x${!OPT}" == "xyes" -o "x${!OPT}" ==  "xtrue" -o "x${!OPT}" == "x1" ] && eval $OPT=yes
    	[ "x${!OPT}" == "xno" -o "x${!OPT}" ==  "xfalse" -o "x${!OPT}" == "x0" ] && eval unset $OPT
    done 
    
    osprobedir="/usr/lib/os-probes/mounted" 
    
    [ "$NOFAILSAFE" ] || EXCLUDE="fkflsgjtriogserpfkawerpkfdlpw"
    [ "$linux_ignore" ] && EXCLUDE="${EXCLUDE}$(echo $linux_ignore | tr " " "\n" | sed 's/^/|/' | tr -d "\n")"
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # DISTROS SPECIFIC 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    # YaST comment for openSUSE
    [ -f /sbin/yast ] && CAP="###Don't change this comment - YaST2 identifier: Original name:"
    
    # on Fedora and Centos, Grub menu file is /boot/grub/grub.conf
    grubmenu=/boot/grub/menu.lst
    [ -e /etc/redhat-release -a -f /boot/grub/grub.conf ] && grubmenu=/boot/grub/grub.conf
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # some Bootsector ID at offset 0x80,81
    # from bootinfo script by Ulrich Meierfrankenfeld
    # Boot Info Script | Download Boot Info Script software for free at SourceForge.net
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    BSaa75="Legacy Grub"
    BS5272="Legacy Grub"
    BS48b4="Grub 1,96"
    BS488="Grub2 s core.img"
    BS7c3c="Grub2"
    
    BS8053="Lilo"
    
    BSbd0="MSWIN4.1 Fat 32"
    BS7cc6="MSWIN4.1 Fat 32"
    BS7cc6="Windows 98"
    BS8cd="Windows XP"
    BS8ec0="Windows XP"
    BSfa33="Windows XP"
    BSb6d1="Windows XP Fat32"
    BS745="Vista Fat 32"
    BS55aa="Windows Vista/7"
    BSe9d8="Windows Vista/7"
    
    BSb60="Dell Utility Fat16" 
    BSe00="Dell Utility Fat16"
    BS4445="DEll Restore Fat32" 
    BS8ed0="DEll Recovery: Fat32"
    
    BS3a5e="Recovery:Fat 32"
    BS6974="BootIt: Fat16"
    BS6f65="BootIt: Fat16"
    BSe2f7="Fat32, Non Bootable"
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # DEVICE/BIOS MAPPING 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    HDDEV=($(cat /proc/partitions | awk '!/major/{ gsub(/[0-9]/,"",$4) ; print $4 }' | sort -u ))
    
    i=0
    while [ $i -lt ${#HDDEV[*]} ] ; do eval ${HDDEV[$i]}=hd$i ; let i++ ; done
    
    function invalidHD {
    	str="/grub/device.map contains an orphan link: "$1". Maybe you removed a hard disk since you installed Grub. Either delete /boot/grup/device.map or edit the devices  in this file to achieve a correct drive mapping. updategrub can not work with a corrupted device.map." 
    	printf "\n%s\n\n" "$str" | fmt
    	exit
    }
    
    # map hard disk devices to BIOS drives according to /boot/grub/device.map (if this file exists)  
    if [ -f $devmap ] ; then
    	devlinks=($(sed -n '/(hd/s|(\(.*\))[ 	][ 	]*\(.*\)|\2=\1|p' $devmap))
    	if [ ${#devlinks[*]} -ge 1 ] ; then
    		for dev in ${devlinks[*]} ; do
    			sdx=${dev%=*} ; hdn=${dev#*=}
    			if [ -b $sdx ] ; then
    				[ -h $sdx ] && sdx=$(readlink $sdx)
    			else
    				invalidHD $sdx
    			fi
    			eval $(basename $sdx)=$hdn
    		done
    	fi
    fi
    DEVMAP=$(for d in ${HDDEV[*]} ; do printf "s|\\$\\$%s|%s|;" $d ${!d} ; done)
    
    
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # FUNCTIONS 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    function grubname {
    dev=$(basename $1 | tr -d "0-9")
    part=$(($(basename $1 | tr -d "a-z") - 1))
    if [ "${!dev}" ] ; then
    	drv=${!dev}
    else
    	drv=$(echo $dev | sed 's|..|HD|' | tr "abcdefgh" "01234567" | sed 's|HD|hd|')
    fi
    if [ $part -ge 0 ] ; then
    	echo "($drv,$part)"
    else
    	echo "($drv)"
    fi
    }
    
    function writeEntry {
    M=$1 ; shift
    for lin in $* ; do
    	D=${lin##*:} ; LONG=${D//@/ }
    	D=${lin%:*}  ; SHORT=${D%:*} ; DEV=${D#*:} 
    	COM=${CAP:+$CAP $SHORT###}
    	COM=${COM:-# $LONG on $DEV}
    	HDP=$(grubname $DEV)
    	OPT=${SHORT//[0-9]/}_options ; OPT="${!OPT}"
    	O=$(printf "$OPT" | sed 's| *$|\\n|' | tr -d "\n")
    	case $M in 
    	K) 
    	$linuxbootprober $DEV | grep -E -i -v $EXCLUDE | awk -F ":" 'BEGIN { C="'"$COM"'" ; O="'"$O"'" } ; { P=$2 ; sub(/\/dev\//,"",P) ; MAJ=P ; MIN=P ; gsub(/[0-9]/,"",MAJ) ; gsub(/[a-zA-Z]/,"",MIN) ; MIN-- ; printf "\n%s\ntitle %s\n%s    root ($$%s,%s)\n    kernel %s %s\n", C, $3, O, MAJ, MIN, $4, $6 ; if ( $5 != "" ) printf "    initrd %s\n", $5 }' | sed "$DEVMAP" 
    	file -s $DEV | grep -i -q "Grand Unified Bootloader" && GRUBS=(${GRUBS[*]} "$DEV:$HDP:$SHORT")
    	;;
    	C)
    	printf "\n%s\ntitle %s\n" "$COM" "$LONG" 
    	[ "$OPT" ] && printf "%s\n" "$OPT"
    	HD=$(echo ${HDP%%,*} | tr -d "(")
    	[ "$HD" == "hd0" ] || printf "    map (%s) (hd0)\n    map (hd0) (%s)\n" $HD $HD
    	printf "    rootnoverify %s\n" "$HDP"
    	[ "$MAKEACTIVE" ] && printf "    makeactive\n"
    	printf "    chainloader +1\n" 
    	;;
    	esac
    done
    }
    
    function writeGrubChainloadEntries {
    
    	# add Grubs found in the MBR of all HDs.
    	for dev in ${HDDEV[*]} ; do
    		dd if=/dev/$dev bs=512 count=1 2>/dev/null | grep -q GRUB || continue
    		BS="BS$(hexdump -v -s 128 -n  2 -e '/1 "%x"' /dev/$dev)"
    		BS=${!BS} ; title=${BS:-Grub}
    		COM=${CAP:+$CAP GrubOn${dev}###}
    		COM=${COM:-# Grub on $dev MBR}
    		printf "\n%s\ntitle %s in %s MBR\n    rootnoverify (%s)\n    chainloader +1\n" "$COM" "$title" $dev ${!dev} 
    	done
    
    	# add other Grub found in linux (0x83) or extended (0x0f and 0x05) partitions to the GRUBS array.
    	# Grub present in Linux root partition should already have been added.     
    	SKIPROOT=$(df -hl / /boot | awk '/\/dev/ { printf "s| *%s||;",  $1 }')
    
    	devs=`/sbin/fdisk -l 2>/dev/null | awk '/^\/dev/ { sub(/*/,"",$0) ; if ($5=="83" || $5=="f" || $5=="5") print $1 }' | sed "$(echo ${GRUBS[*]} | tr " " "\n" | sed 's|:.*||;s|/|\\\/|g;s|^|/|;s|$|/d|' | tr "\n" ";")" | sed "$SKIPROOT"` 
    
    	for dev in $devs ; do
    		dd if=$dev bs=512 count=1 2>/dev/null | grep -q GRUB &&	GRUBS=(${GRUBS[*]} "$dev:$(grubname $dev):Grub")
    	done
    
    	for entry in ${GRUBS[*]} ; do
    		eval $(echo $entry | awk -F ":" '{printf "DEV=%s ; HDP=%s ; LBL=%s ;", $1, $2, $3}')
    		BS="BS$(hexdump -v -s 128 -n  2 -e '/1 "%x"' $DEV)" ; BS=${!BS} 
    		[ "$LBL" == "Grub" ] || LBL="${LBL}-Grub"
    		[ "$LBL" == "Grub" ] && LBL="$BS"
    		COM=${CAP:+$CAP $LBL###}
    		COM=${COM:-# $LBL on $DEV}
    		printf "\n%s\ntitle %s on %s \n    root (%s)" "$COM" "$(echo $LBL | tr "-" " ")" $DEV "$HDP"
    		case $BS in
    		"Legacy Grub")		 
    			printf "\n    chainloader +1\n"
    		;; 
    		Grub2)
    			COREPOS=$(hexdump -v -s 92 -n 4 -e '"%u"' $DEV)
    			dd if=${DEV:0:8} bs=512 count=1 skip=$(($COREPOS+1)) 2>/dev/null | hexdump -v  -n 64 -e '"%_u"'| sed 's|.*(,\(.*\)|\1|;s|)||;s|nul||g' | grep -q '/boot/grub' && printf "\n    kernel /boot/grub/core.img\n    boot\n" || printf "\n    chainloader +1\n"
    		;;
     		esac
    	done
    }
    
    function setBootFlag {
    	devs=`LC_ALL=C /sbin/fdisk -l 2>/dev/null | awk '/^Disk/&&/dev/ { sub(/:/,"",$2) ; print $2 }'`
    	declare -a grubPt
    	for DEV in $devs ; do
    		if [ "$(grubname $DEV)" == "(hd0)" ] ; then
    			eval $(dd if=$DEV bs=1 skip=446 count=64 2>/dev/null | od -x | head -4 | cat -n | awk 'BEGIN { PART="'"$DEV"'"; I=-1 } ; { sub(/../,"", $3) ; sub(/../,"",$5) ; if ( $5 == "0f" || $5 == "83" ) { I++ ; if ( $3 == "00" ) P="i" ; else P="a" ;  printf "%spart[%s]=%s ;", P, I, $1 }}')
    			if [ ${#apart[*]} -eq 0 -a ${#ipart[*]} -ge 1 ] ; then
    				for n in ${ipart[*]} ; do
                        dd if=${DEV}$n bs=512 count=1 2>/dev/null | grep -q -i GRUB && grubPt=(${grubPt[*]} $n)
    				done
    				[ ${#grubPt[*]} -eq 1 -a -x /sbin/sfdisk ] && /sbin/sfdisk $DEV -A${grubPt[0]}
    			fi
    		fi 
    	done
    }
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # UPDATE GRUB2 !!! 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    function updategrub2 {
    	grubmkconfig=$(find /usr/sbin/ -name "grub*-mkconfig")
    	[ "$grubmkconfig" ] || exec echo "grub2 not found" 
    
    	if [ "$DISPLAYONLY" ] ; then
    		echo "Scanning..."
    		$grubmkconfig
    	else
    		[ -f /etc/default/grub ] || exec echo "/etc/default/grub not found" 
    		grubmenu=$(sed -n 's|.*\(/boot/grub.*/grub.cfg\).*|\1|p' /etc/default/grub | sort -u)
    		[ "$grubmenu" ] || exec echo "could not find grub2 menu"
    		[ -f $grubmenu ] && cp $grubmenu{,.updg}
    		echo "Scanning..."
    		$grubmkconfig -o $grubmenu
    	fi	
    	exit
    }
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # HELP 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    function syntax {
    cat << EOFSYNTAX
    
    $prg $version
    ______________
    usage:
       $prg [options]
    
    options:
       -l --list     : list found boot entries but do not add them to Grub menu.
       -a --activate : activate Grub primary partition (if any) on 1st BIOS drive.
       -r --restore  : restore previous Grub menu
       -h --help     : display this help.
       -2 --grub2    : update Grub2 menu.
    
    EOFSYNTAX
    [ -d $osprobedir ] && find $osprobedir -name "*linux-distro*" -exec awk -F "=" 'BEGIN { printf "linux distros short names:\n\n" } ; /short=/ { s=tolower($2) ; gsub(/"/,"",s) ; gsub(/ /,"",s) ;  print s }' "{}" ";"
    exit
    }
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # BACK UP AND RESTORE GRUB MENU 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    function backupMenu {
    # save original grub menu once 
    [ -f ${grubmenu}.dist ] || cp $grubmenu{,.dist}
    # save current grub menu
    [ -f ${grubmenu} ] && cp $grubmenu{,.updg}
    }
     
    function restoreMenu {
    if [ -f ${grubmenu}.updg ] ; then
    	declare -l yesno
    	read -p "Do you want to restore previously saved grub menu? [y|n]" -n1 yesno
    	printf "\n"
    	[ "x$yesno" == "xy" ] && cp $grubmenu{.updg,}
    fi
    exit
    }
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # parsing options 
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ARGS=`getopt -q -o lahr2 --long list,activate,help,restore,grub2 -- "$@"`
    
    [ "$?" == "0" ] || syntax
    
    eval set -- "$ARGS"
    
    while true ; do
    	case "$1" in
    		-l|--list) DISPLAYONLY=yes ; shift ;;
    		-a|--activate) SETBOOTFLAG=yes ; shift ;;
    		-h|--help) syntax ; shift ;;
    		-r|--restore) restoreMenu ; shift ;;
    		-2|--grub2) GRUB2=yes ; shift ;;
    		--) shift ; break ;;
        esac
    done
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ### ~~~~~~~~~~~~~~~~ MAIN - BEGIN ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # update Grub2 and exit
    [ "$GRUB2" ] && updategrub2
    
    echo "Scanning..."
    
    # If used WITHOUT the option "-n", save Grub menu first
    if [ "$DISPLAYONLY" ] ; then
    	echo "Following boot entries could be added to Grub menu:"
    else
    	backupMenu
    	sed -i '/Added by updategrub/,$d' $grubmenu
    	printf "# *** Don't change this comment - Added by updategrub %s\n" "$(date)" >> $grubmenu
    fi
    
    eval $($osprober 2>/dev/null | awk -F ":" 'BEGIN { OFS=":" ; i=-1 ; j=-1 }; { if ( $4 == "linux" ) { i++ ; I=i } else { j++ ; I=j } ; S=tolower($3) ; s=tolower($2) ; sub(/ .*/,"",s) ; if ( S == "unknownlsb" ) S=s ;  gsub( / /, "@" , $2 ) ;  printf "%s[%s]=\"%s:%s:%s\" ; ", $4, I, S, $1, $2 }')
    
    if [ "$linux_order" ] ; then
    	eval $(echo $linux_order | awk 'BEGIN { RS=" " ; printf "REPLACE=\"" } ; { printf "s|%s|%s%s|;", $1, NR, $1 } ; END { printf "\"" }')
    	linux=($(echo ${linux[*]} | tr " " "\n" | sed "$REPLACE;s|\([a-zA-Z]\):|\10:|" | sort -n | sed 's|^[0-9]*||;s|0:/|:/|'))
    fi
    
    [ $((${#linux[*]} + ${#chain[*]})) -ge 1 ] || exec "No other operating systems found"
    
    if [ "$WINDOWSFIRST" ] ; then
    	if [ "$DISPLAYONLY" ] ; then
    		writeEntry C ${chain[*]}
    		writeEntry K ${linux[*]}
    	else
    		writeEntry C ${chain[*]} >> $grubmenu
    		writeEntry K ${linux[*]} >> $grubmenu
    	fi
    else
    	if [ "$DISPLAYONLY" ] ; then
    		writeEntry K ${linux[*]}
    		writeEntry C ${chain[*]}
    	else
    		writeEntry K ${linux[*]} >> $grubmenu
    		writeEntry C ${chain[*]} >> $grubmenu
    	fi
    fi 
    
    if [ "$CHAINLOADGRUB" ] ; then
    	if [ "$DISPLAYONLY" ] ; then
    		writeGrubChainloadEntries
    	else
    		writeGrubChainloadEntries >> $grubmenu
    	fi
    fi
    
    # append custom boot entries (like other OS chainload entries) from /etc/updategrub/custom
    if [ -f /etc/updategrub/custom ] ; then
    	if [ "$DISPLAYONLY" ] ; then
    		printf "\n"
    		cat /etc/updategrub/custom 
    	else
    		printf "\n" >> $grubmenu
    		cat /etc/updategrub/custom >> $grubmenu
     	fi 
    fi
    
    # Set bootflag on  Grub partition 
    if [ "$SETBOOTFLAG" ] ; then
    	setBootFlag
    fi
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ### ~~~~~~~~~~~~~~~~ MAIN - END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  3. #3

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    v. 1.4.1
    Code:
    #! /bin/bash
    
    #: Title       : updateLegacyGrub
    #: Date Created: Sat Apr 2 16:20:32 PDT 2011
    #: Last Edit   : Fri Apr 22 23:55:09 PDT 2011
    #: Author      : Agnelo de la Crotche (please_try_again)
    #: Version     : 1.4.1
    #: Description : add other Linux & Windows boot entries to Legacy Grub boot menu
    #: Requires    : os-prober, dialog
    #: Usage       : updategrub
    #: Syntax      : There are a few options. Type updategrub -h for help.
    #              : Read /usr/share/doc/packages/updategrub/README for details
    #
    # current version
    version="1.4.1"
    prg=$(basename $0)
    devmap=/boot/grub/device.map
    defaults=/etc/updategrub/defaults
    custom=/etc/updategrub/custom
    
    # ~~~~~
    # TESTS
    # check if we are root
    [ $UID -eq 0 ] || exec echo "You have to run this script as root or sudo"
    
    # check for os-prober & linux-boot-prober
    osprober=`which os-prober 2>/dev/null` || exec echo "os-prober not found"
    linuxbootprober=`which linux-boot-prober 2>/dev/null` || exec echo "linux-boot-prober not found"
    
    # ~~~~~~~~~~~~~~~~
    # DEFINE VARIABLES
    declare -l CHAINLOADGRUB NOFAILSAFE MAKEACTIVE SETBOOTFLAG WINDOWSFIRST INTERACTIVE DISPLAYONLY EXCLUDE GRUB2
    declare -a GRUBS HDDEV
    
    # Chainload other Grubs by default
    CHAINLOADGRUB=yes
    # Ignore failsafe entries
    NOFAILSAFE=yes
    # Make Windows Partition active
    MAKEACTIVE=no
    # Windows Chainload entries before other Linux distros kernel entries
    WINDOWSFIRST=no
    # Set bootflag on Grub partition
    SETBOOTFLAG=no
    # Display changes but do not write boot menu
    DISPLAYONLY=no
    # Interactive menu
    INTERACTIVE=no
    # if NOFAILSAFE is set, reject entries containing this words keywords
    EXCLUDE='recovery|rescue|failsafe|fallback|single-user'
    
    # import some defaults from (optional) configuration file
    [ -f $defaults ] && source $defaults
    
    for OPT in CHAINLOADGRUB NOFAILSAFE MAKEACTIVE WINDOWSFIRST INTERACTIVE SETBOOTFLAG DISPLAYONLY ; do
    	[ "x${!OPT}" == "xyes" -o "x${!OPT}" == "xtrue" -o "x${!OPT}" == "x1" ] && eval $OPT=yes
    	[ "x${!OPT}" == "xno" -o "x${!OPT}" == "xfalse" -o "x${!OPT}" == "x0" ] && eval unset $OPT
    done
    
    osprobedir="/usr/lib/os-probes/mounted"
    
    [ "$NOFAILSAFE" ] || EXCLUDE="fkflsgjtriogserpfkawerpkfdlpw"
    [ "$linux_ignore" ] && EXCLUDE="${EXCLUDE}$(echo $linux_ignore | tr " " "\n" | sed 's/^/|/' | tr -d "\n")"
    
    # ~~~~~~~~~~~~~~~~
    # DISTROS SPECIFIC
    
    # YaST comment for openSUSE
    [ -f /sbin/yast ] && CAP="###Don't change this comment - YaST2 identifier: Original name:"
    
    # on Fedora and Centos, Grub menu file is /boot/grub/grub.conf
    grubmenu=/boot/grub/menu.lst
    [ -e /etc/redhat-release -a -f /boot/grub/grub.conf ] && grubmenu=/boot/grub/grub.conf
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # some Bootsector ID at offset 0x80,81
    
    BSaa75="Legacy Grub"
    BS5272="Legacy Grub"
    BS48b4="Grub 1,96"
    BS488="Grub2 s core.img"
    BS7c3c="Grub2"
    BS8053="Lilo"
    BSbd0="MSWIN4.1 Fat 32"
    BS7cc6="MSWIN4.1 Fat 32"
    BS7cc6="Windows 98"
    BS8cd="Windows XP"
    BS8ec0="Windows XP"
    BSfa33="Windows XP"
    BSb6d1="Windows XP Fat32"
    BS745="Vista Fat 32"
    BS55aa="Windows Vista/7"
    BSe9d8="Windows Vista/7"
    BSb60="Dell Utility Fat16"
    BSe00="Dell Utility Fat16"
    BS4445="DEll Restore Fat32"
    BS8ed0="DEll Recovery: Fat32"
    BS3a5e="Recovery:Fat 32"
    BS6974="BootIt: Fat16"
    BS6f65="BootIt: Fat16"
    BSe2f7="Fat32, Non Bootable"
    
    # ~~~~~~~~~~~~~~~~~~~
    # DEVICE/BIOS MAPPING
    HDDEV=($(cat /proc/partitions | awk '!/major/{ gsub(/[0-9]/,"",$4) ; print $4 }' | sort -u))
    
    i=0
    while [ $i -lt ${#HDDEV[*]} ] ; do eval ${HDDEV[$i]}=hd$i ; let i++ ; done
    
    function invalidHD {
    	str="/grub/device.map contains an orphan link: "$1". Maybe you removed a hard disk since you installed Grub. Either delete /boot/grup/device.map or edit the devices in this file to achieve a correct drive mapping. updategrub can not work with a corrupted device.map."
    	printf "\n%s\n\n" "$str" | fmt
    	exit
    }
    
    # map hard disk devices to BIOS drives according to /boot/grub/device.map (if this file exists)
    if [ -f $devmap ] ; then
    	devlinks=($(sed -n '/(hd/s|(\(.*\))[ 	][ 	]*\(.*\)|\2=\1|p' $devmap))
    	if [ ${#devlinks[*]} -ge 1 ] ; then
    		for dev in ${devlinks[*]} ; do
    			sdx=${dev%=*} ; hdn=${dev#*=}
    			if [ -b $sdx ] ; then
    				[ -h $sdx ] && sdx=$(readlink $sdx)
    			else
    				invalidHD $sdx
    			fi
    			eval $(basename $sdx)=$hdn
    		done
    	fi
    fi
    DEVMAP=$(for d in ${HDDEV[*]} ; do printf "s|\\$\\$%s|%s|;" $d ${!d} ; done)
    
    # ~~~~~~~~~
    # FUNCTIONS
    
    function grubname {
    dev=$(basename $1 | tr -d "0-9")
    part=$(($(basename $1 | tr -d "a-z") - 1))
    if [ "${!dev}" ] ; then
    	drv=${!dev}
    else
    	drv=$(echo $dev | sed 's|..|HD|' | tr "abcdefgh" "01234567" | sed 's|HD|hd|')
    fi
    if [ $part -ge 0 ] ; then
    	echo "($drv,$part)"
    else
    	echo "($drv)"
    fi
    }
    
    function writeEntry {
    M=$1 ; shift
    for lin in $* ; do
    	D=${lin##*:} ; LONG=${D//@/ }
    	D=${lin%:*} ; SHORT=${D%:*} ; DEV=${D#*:}
    	COM=${CAP:+$CAP $SHORT###}
    	COM=${COM:-# $LONG on $DEV}
    	HDP=$(grubname $DEV)
    	OPT=${SHORT//[0-9]/}_options ; OPT="${!OPT}"
    	O=$(printf "$OPT" | sed 's| *$|\\n|' | tr -d "\n")
    	case $M in
    	K)
    	$linuxbootprober $DEV | grep -E -i -v $EXCLUDE | awk -F ":" 'BEGIN { C="'"$COM"'" ; O="'"$O"'" } ; { P=$2 ; sub(/\/dev\//,"",P) ; MAJ=P ; MIN=P ; gsub(/[0-9]/,"",MAJ) ; gsub(/[a-zA-Z]/,"",MIN) ; MIN-- ; printf "\n%s\ntitle %s\n%s    root ($$%s,%s)\n    kernel %s %s\n", C, $3, O, MAJ, MIN, $4, $6 ; if ($5 != "") printf "    initrd %s\n", $5 }' | sed "$DEVMAP"
    	file -s $DEV | grep -i -q "Grand Unified Bootloader" && GRUBS=(${GRUBS[*]} "$DEV:$HDP:$SHORT") ;;
    	C)
    	printf "\n%s\ntitle %s - added by updategrub\n" "$COM" "$LONG"
    	[ "$OPT" ] && printf "%s\n" "$OPT"
    	HD=$(echo ${HDP%%,*} | tr -d "(")
    	[ "$HD" == "hd0" ] || printf "    map (%s) (hd0)\n    map (hd0) (%s)\n" $HD $HD
    	printf "    rootnoverify %s\n" "$HDP"
    	[ "$MAKEACTIVE" ] && printf "    makeactive\n"
    	printf "    chainloader +1\n" ;;
    	esac
    done
    }
    
    function writeGrubChainloadEntries {
    # add Grubs found in the MBR of all HDs
    for dev in ${HDDEV[*]} ; do
    	dd if=/dev/$dev bs=512 count=1 2>/dev/null | grep -q GRUB || continue
    	BS="BS$(hexdump -v -s 128 -n 2 -e '/1 "%x"' /dev/$dev)"
    	BS=${!BS} ; title=${BS:-Grub}
    	COM=${CAP:+$CAP GrubOn${dev}###}
    	COM=${COM:-# Grub on $dev MBR}
    	printf "\n%s\ntitle %s in %s MBR\n    rootnoverify (%s)\n    chainloader +1\n" "$COM" "$title" $dev ${!dev}
    done
    
    # add other Grub found in linux (0x83) or extended (0x0f and 0x05) partitions to the GRUBS array.
    # Grub present in Linux root partition should already have been added.
    SKIPROOT=$(df -hl / /boot | awk '/\/dev/ { printf "s| *%s||;", $1 }')
    
    devs=`/sbin/fdisk -l 2>/dev/null | awk '/^\/dev/ { sub(/*/,"",$0) ; if ($5=="83" || $5=="f" || $5=="5") print $1 }' | sed "$(echo ${GRUBS[*]} | tr " " "\n" | sed 's|:.*||;s|/|\\\/|g;s|^|/|;s|$|/d|' | tr "\n" ";")" | sed "$SKIPROOT"`
    
    for dev in $devs ; do
    	dd if=$dev bs=512 count=1 2>/dev/null | grep -q GRUB &&	GRUBS=(${GRUBS[*]} "$dev:$(grubname $dev):Grub")
    done
    
    for entry in ${GRUBS[*]} ; do
    	eval $(echo $entry | awk -F ":" '{printf "DEV=%s ; HDP=%s ; LBL=%s ;", $1, $2, $3}')
    	BS="BS$(hexdump -v -s 128 -n 2 -e '/1 "%x"' $DEV)" ; BS=${!BS}
    	[ "$LBL" == "Grub" ] || LBL="${LBL}-Grub"
    	[ "$LBL" == "Grub" ] && LBL="$BS"
    	COM=${CAP:+$CAP $LBL###}
    	COM=${COM:-# $LBL on $DEV}
    	printf "\n%s\ntitle %s on %s \n    root (%s)" "$COM" "$(echo $LBL | tr "-" " ")" $DEV "$HDP"
    	case $BS in
    	"Legacy Grub")	printf "\n    chainloader +1\n" ;;
    	Grub2)
    		COREPOS=$(hexdump -v -s 92 -n 4 -e '"%u"' $DEV)
    		dd if=${DEV:0:8} bs=512 count=1 skip=$(($COREPOS+1)) 2>/dev/null | hexdump -v -n 64 -e '"%_u"'| sed 's|.*(,\(.*\)|\1|;s|)||;s|nul||g' | grep -q '/boot/grub' && printf "\n    kernel /boot/grub/core.img\n    boot\n" || printf "\n    chainloader +1\n"
    	;;
    	esac
    done
    }
    
    function setBootFlag {
    devs=`LC_ALL=C /sbin/fdisk -l 2>/dev/null | awk '/^Disk/&&/dev/ { sub(/:/,"",$2) ; print $2 }'`
    declare -a grubPt
    for DEV in $devs ; do
    	if [ "$(grubname $DEV)" == "(hd0)" ] ; then
    		eval $(dd if=$DEV bs=1 skip=446 count=64 2>/dev/null | od -x | head -4 | cat -n | awk 'BEGIN { PART="'"$DEV"'"; I=-1 } ; { sub(/../,"", $3) ; sub(/../,"",$5) ; if ($5 == "0f" || $5 == "83") { I++ ; if ($3 == "00") P="i" ; else P="a" ; printf "%spart[%s]=%s ;", P, I, $1 }}')
    		if [ ${#apart[*]} -eq 0 -a ${#ipart[*]} -ge 1 ] ; then
    			for n in ${ipart[*]} ; do
    				dd if=${DEV}$n bs=512 count=1 2>/dev/null | grep -q -i GRUB && grubPt=(${grubPt[*]} $n)
    			done
    			[ ${#grubPt[*]} -eq 1 -a -x /sbin/sfdisk ] && /sbin/sfdisk $DEV -A${grubPt[0]}
    		fi
    	fi
    done
    exit
    }
    
    # ~~~~~~~~~~~~
    # UPDATE GRUB2
    function updategrub2 {
    grubmkconfig=$(find /usr/sbin/ -name "grub*-mkconfig")
    [ "$grubmkconfig" ] || exec echo "grub2 not found"
    
    if [ "$DISPLAYONLY" ] ; then
    	echo "Scanning..."
    	$grubmkconfig
    else
    	[ -f /etc/default/grub ] || exec echo "/etc/default/grub not found"
    	grubmenu=$(sed -n 's|.*\(/boot/grub.*/grub.cfg\).*|\1|p' /etc/default/grub | sort -u)
    	[ "$grubmenu" ] || exec echo "could not find grub2 menu"
    	[ -f $grubmenu ] && cp $grubmenu{,.updg}
    	echo "Scanning..."
    	$grubmkconfig -o $grubmenu
    fi	
    exit
    }
    
    # ~~~~
    # HELP
    function syntax {
    cat << EOFSYNTAX
    
    $prg $version
    ______________
    usage:
       $prg [options]
    
    options:
       -l --list        : list found boot entries but do not add them to Grub menu
       -i --interactive : launch interactive menu to enable/disable boot entries
       -m --menu        : enable/disable boot entries in grubmenu (without scanning)
       -a --activate    : activate Grub primary partition (if any) on 1st BIOS drive
       -r --restore     : restore previous Grub menu
       -h --help        : display this help
       -2 --grub2       : update Grub2 menu
    
    EOFSYNTAX
    [ -d $osprobedir ] && find $osprobedir -name "*linux-distro*" -exec awk -F "=" 'BEGIN { printf "linux distros short names:\n\n" } ; /short=/ { s=tolower($2) ; gsub(/"/,"",s) ; gsub(/ /,"",s) ; print s }' "{}" ";"
    exit
    }
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # BACK UP & RESTORE GRUB MENU
    function backupMenu {
    # save original grub menu once
    [ -f ${grubmenu}.dist ] || cp $grubmenu{,.dist}
    # save current grub menu
    [ -f ${grubmenu} ] && cp $grubmenu{,.updg}
    }
    
    function restoreMenu {
    if [ -f ${grubmenu}.updg ] ; then
    	declare -l yesno
    	read -p "Do you want to restore previously saved grub menu? [y|n]" -n1 yesno
    	printf "\n"
    	[ "x$yesno" == "xy" ] && cp $grubmenu{.updg,}
    fi
    exit
    }
    
    # ~~~~~~~~~~~~~~~~
    # interactive menu
    function grubmenu {
    
    [ $(tail -1 $grubmenu | wc -L) -gt 0 ] && echo >> $grubmenu
    
    # get checklist width and height
    W=$(($(sed -n '/^#* *title/s/title *//p' $grubmenu | wc -L)+10))
    h=$(sed -n '/^#* *title/s/title *//p' $grubmenu | wc -l)
    H=$(($h + 7))
    [ $W -eq 10 ] && W=80
    [ $H -eq 6 ] && H=15
    
    eval $(grep -E -n -e '^#* *title' -e '^ *$' $grubmenu | sed 's|:|@|;s|:|;|g;s|@|:|;s|\([0-9][0-9]*\):$|=:\1|' | sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' | sed 's/\([0-9][0-9]*\):\(#*\)title *\([^:]*\) :\([0-9][0-9]*\).*/\1:\4:on\2:\3/;s/on#/off/;/^=/d' | awk -F ":" '{ $2-- ; printf "startpos[%s]=%s;endpos[%s]=%s;enable[%s]=%s;entry[%s]=\"%s\"\n" , NR, $1, NR, $2, NR, $3, NR, $4 }')
    glist=$(sed -n '/^#* *title/s/title *//p' $grubmenu | sed 's/^/on /;s/on ##*/off /;s/^on \(.*\) *$/\"\1\" on/;s/^off \(.*\) *$/\"\1\" off/;s/  *"/"/' | awk '{ printf "%s %s ", NR, $0 }')
    
    cat << EOFGLIST | sh -
    dialog --clear --stdout --title "Grub Menu" --nocancel --output-separator "-" --checklist "Press spacebar to select/unselect boot menu entries" $H $W $h $glist | sed 's/"//g;s/$/-/' > /tmp/grubmenu.tmp
    EOFGLIST
    
    [ -f /tmp/grubmenu.tmp ] && enable=$(cat /tmp/grubmenu.tmp) || exec echo "can not get list of Menu entries"
    
    # exit if user pressed escape
    [ "x$enable" == "x" ] && return
    
    i=1
    while [ $i -le $h ] ; do
    	[ "${enable%%-$i-*}" == "${enable}" ] && enable[$i]=off || enable[$i]=on
    	let i++
    done
    
    i=1
    cat << EOFSED | sed -f - -i $grubmenu
    `while [ $i -le $h ] ; do
    	[ "${enable[$i]}" == "on" ] && echo "${startpos[$i]},${endpos[$i]}s/^##*//" || echo "${startpos[$i]},${endpos[$i]}s/^\\\([^#]\\\)/#\\\1/"
    	let i++
    done`
    EOFSED
    }
    
    # ~~~~~~~~~~~~~~~
    # parsing options
    
    ARGS=`getopt -q -o lamihr2 --long list,activate,menu,interactive,help,restore,grub2 -- "$@"`
    
    [ "$?" == "0" ] || syntax
    
    eval set -- "$ARGS"
    
    while true ; do
    case "$1" in
    	-l|--list) DISPLAYONLY=yes ; shift ;;
    	-a|--activate) setBootFlag ; shift ;;
    	-i|--interactive) INTERACTIVE=yes ; shift ;;
    	-m|--menu) GRUBMENU=yes ; shift ;;
    	-h|--help) syntax ; shift ;;
    	-r|--restore) restoreMenu ; shift ;;
    	-2|--grub2) GRUB2=yes ; shift ;;
    	--) shift ; break ;;
    esac
    done
    
    [ "$prg" == "grubmenu" ] && GRUBMENU=yes
    
    ### ~~~ MAIN - BEGIN ~~~
    # run grubmenu without scanning and exit
    if [ "$GRUBMENU" ] ; then
    	grubmenu
    	exit
    fi
    
    # update Grub2 and exit
    [ "$GRUB2" ] && updategrub2
    
    echo "Scanning..."
    
    # If used WITHOUT the option "-n", save Grub menu first
    if [ "$DISPLAYONLY" ] ; then
    	echo "Following boot entries could be added to Grub menu:"
    else
    	backupMenu
    	sed -i '/Added by updategrub/,$d' $grubmenu
    	printf "# *** Don't change this comment - Added by updategrub %s\n" "$(date)" >> $grubmenu
    fi
    
    eval $($osprober 2>/dev/null | awk -F ":" 'BEGIN { OFS=":" ; i=-1 ; j=-1 }; { if ($4 == "linux") { i++ ; I=i } else { j++ ; I=j } ; S=tolower($3) ; s=tolower($2) ; sub(/ .*/,"",s) ; if (S == "unknownlsb") S=s ; gsub(/ /, "@" , $2) ; printf "%s[%s]=\"%s:%s:%s\" ; ", $4, I, S, $1, $2 }')
    
    if [ "$linux_order" ] ; then
    	eval $(echo $linux_order | awk 'BEGIN { RS=" " ; printf "REPLACE=\"" } ; { printf "s|%s|%s%s|;", $1, NR, $1 } ; END { printf "\"" }')
    	linux=($(echo ${linux[*]} | tr " " "\n" | sed "$REPLACE;s|\([a-zA-Z]\):|\10:|" | sort -n | sed 's|^[0-9]*||;s|0:/|:/|'))
    fi
    
    [ $((${#linux[*]} + ${#chain[*]})) -ge 1 ] || exec "No other operating systems found"
    
    if [ "$WINDOWSFIRST" ] ; then
    	if [ "$DISPLAYONLY" ] ; then
    		writeEntry C ${chain[*]}
    		writeEntry K ${linux[*]}
    	else
    		writeEntry C ${chain[*]} >> $grubmenu
    		writeEntry K ${linux[*]} >> $grubmenu
    	fi
    else
    	if [ "$DISPLAYONLY" ] ; then
    		writeEntry K ${linux[*]}
    		writeEntry C ${chain[*]}
    	else
    		writeEntry K ${linux[*]} >> $grubmenu
    		writeEntry C ${chain[*]} >> $grubmenu
    	fi
    fi
    
    if [ "$CHAINLOADGRUB" ] ; then
    	if [ "$DISPLAYONLY" ] ; then
    		writeGrubChainloadEntries
    	else
    		writeGrubChainloadEntries >> $grubmenu
    	fi
    fi
    
    # append custom boot entries (like other OS chainload entries) from /etc/updategrub/custom
    if [ -f $custom ] ; then
    	if [ "$DISPLAYONLY" ] ; then
    		printf "\n"
    		cat $custom
    	else
    		printf "\n" >> $grubmenu
    		cat $custom >> $grubmenu
     	fi
    fi
    
    [ "$DISPLAYONLY" ] && exit
    
    # enabling/disabling boot entries.
    [ "$INTERACTIVE" ] && grubmenu
    
    # Set bootflag on Grub partition and exit
    [ "$SETBOOTFLAG" ] && setBootFlag
    
    ### ~~~ MAIN - END ~~~

  4. #4
    Join Date
    Nov 2010
    Location
    Ελλάδα(Αθήνα)-Россия (г. Красноярск)
    Posts
    2,919

    Default Απ: Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    Very useful guide please_try_again. Thank you!!!!
    Πάντα Φιλικά, Στάμος.
    Desktop: openSUSE Leap 15||x86_64||Gnome 3.14 & KDE 5||AMD Ryzen 7 8 core||Nvidia GTX 1070 Ti Gaming Edition
    Γλώσσες Προγραμματισμού: C++, Qt developing.
    http://bit.ly/fT8Hfi

  5. #5

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    This is version 1.4.1 of updategrub (post above). The full documentation can be seen here: updategrub for openSUSE Legacy Grub (not update-grub!). To install this script, don't copy/paste this code! It depends on 2 other packages: os-prober and dialog. Install the script from repo as described in the HowTo to install the dependencies. The package also includes a config file, a man page and the scripts fingrub and cfindgrub.

    Code:
    # rpm -ql updategrub
    /etc/updategrub
    /etc/updategrub/defaults
    /usr/bin/cfindgrub
    /usr/bin/findgrub
    /usr/bin/grubmenu
    /usr/bin/updateLegacyGrub
    /usr/bin/updategrub
    /usr/share/doc/packages/updategrub
    /usr/share/doc/packages/updategrub/COPYING
    /usr/share/doc/packages/updategrub/README
    /usr/share/doc/packages/updategrub/defaults
    /usr/share/man/man1/updategrub.1.gz

  6. #6

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    After a kernel update, an entry is added to the Grub menu by /usr/lib/bootloader/bootloader_entry, a bash script which in turn calls the perl script /sbin/update-bootloader.

    While updating to the latest kernel on 11.4, the post.sh script of the kernel package to be installed runs the following command:

    Code:
    /usr/lib/bootloader/bootloader_entry add default 2.6.37.6-0.5-default vmlinuz-2.6.37.6-0.5-default initrd-2.6.37.6-0.5-default
    and so when you reboot, you see that the Grub entry for the kernel has changed.

    To delete the previous kernel entry, the postun.sh script of the kernel package to be removed does that:

    Code:
    /usr/lib/bootloader/bootloader_entry remove default 2.6.37.1-1.2-default vmlinuz-2.6.37.1-1.2-default initrd-2.6.37.1-1.2-default
    which means in fact:
    Code:
    /sbin/update-bootloader --image /boot/vmlinuz-2.6.37.1-1.2-default --initrd /boot/initrd-2.6.37.1-1.2-default --remove --force

    But it doesn't only remove the 2.6.37.1-1.2 kernel entries. It removes all other kernel entries (not the chainloading ones) from Grub menu. What has been reported in numerous posts as a YaST bug is IMHO a bug in /sbin/update-bootloader. You can reproduce it easily by adding an entry for the older kernel as well as some others (openSUSE or others) and executing the command described above in a terminal.

    This command was expected to remove only the text in red in the exemple below (simplified). In fact it removed everything in red, blue and green, including the previous openSUSE kernel (red), the updategrub marker (blue) and all kernel menu entries added by updategrub, but didn't touch any of the chainloading entries (there were a lot more, I didn't paste them all).

    Code:
    ###Don't change this comment - YaST2 identifier: Original name: linux###
    title openSUSE 11.4 (Celadon) - kernel 2.6.37.6-0.5 (default)
        root (hd0,10)
        kernel /boot/vmlinuz-2.6.37.6-0.5-default root=/dev/disk/by-uuid/e15f9b1d-d2e4-404f-aac6-79e46b016eb9 resume=/dev/disk/by-uuid/50089717-8b5e-482a-8686-7d47d88b7402 splash=silent quiet showopts vga=0x31a
        initrd /boot/initrd-2.6.37.6-0.5-default
    
    ###Don't change this comment - YaST2 identifier: Original name: failsafe###
    title openSUSE 11.4 (Celadon) - kernel 2.6.37.6-0.5 (failsafe)
        root (hd0,10)
        kernel /boot/vmlinuz-2.6.37.6-0.5-default root=/dev/disk/by-uuid/e15f9b1d-d2e4-404f-aac6-79e46b016eb9 showopts apm=off noresume nosmp maxcpus=0 edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe vga=0x31a
        initrd /boot/initrd-2.6.37.6-0.5-default
    
    ###Don't change this comment - YaST2 identifier: Original name: linux###
    title openSUSE 11.4 (celadon) - kernel 2.6.37.1-1.2
        root (hd0,10)
        kernel /boot/vmlinuz-2.6.37.1-1.2-default root=/dev/disk/by-uuid/e15f9b1d-d2e4-404f-aac6-79e46b016eb9 resume=/dev/disk/by-uuid/50089717-8b5e-482a-8686-7d47d88b7402 splash=silent quiet showopts vga=0x31a
        initrd /boot/initrd-2.6.37.1-1.2-default
    
    ###Don't change this comment - YaST2 identifier: Original name: failsafe###
    title openSUSE 11.4 (celadon) - kernel 2.6.37.1-1.2 (Failsafe)
        root (hd0,10)
        kernel /boot/vmlinuz-2.6.37.1-1.2-default root=/dev/disk/by-uuid/e15f9b1d-d2e4-404f-aac6-79e46b016eb9 showopts apm=off noresume nosmp maxcpus=0 edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe vga=0x31a
        initrd /boot/initrd-2.6.37.1-1.2-default
    
    # *** Don't change this comment - Added by updategrub Mon May  2 06:48:20 PDT 2011
    
    ###Don't change this comment - YaST2 identifier: Original name: ubuntu###
    title Ubuntu 10.10 (maverick) - kernel 2.6.35-28-generic
        root (hd0,4)
        kernel /boot/vmlinuz-2.6.35-28-generic root=UUID=ccee43d6-331d-47dc-aac9-8174471d378a ro vga=791
        initrd /boot/initrd.img-2.6.35-28-generic
    
    ###Don't change this comment - YaST2 identifier: Original name: ubuntu###
    title Ubuntu 10.10 (maverick) - kernel 2.6.35-27-generic
        root (hd0,4)
        kernel /boot/vmlinuz-2.6.35-27-generic root=UUID=ccee43d6-331d-47dc-aac9-8174471d378a ro vga=791
        initrd /boot/initrd.img-2.6.35-27-generic
    
    ###Don't change this comment - YaST2 identifier: Original name: mandrivalinux###
    title linux Mandriva (Farman) - kernel 2.6.33.7-2
        root (hd1,4)
        kernel /boot/vmlinuz-2.6.33.7-desktop-2mnb BOOT_IMAGE=desktop_2.6.33.7-2 root=UUID=4a9d7d4f-dce0-43c5-b354-fae98fec5f76 resume=UUID=50089717-8b5e-482a-8686-7d47d88b7402 splash=silent vga=788
        initrd /boot/initrd-2.6.33.7-desktop-2mnb.img
    
    ###Don't change this comment - YaST2 identifier: Original name: mandrivalinux###
    title linux Mandriva (Farman) - kernel 2.6.33.7-2 (desktop586)
        root (hd1,4)
        kernel /boot/vmlinuz-2.6.33.7-desktop586-2mnb BOOT_IMAGE=desktop586_2.6.33.7-2 root=UUID=4a9d7d4f-dce0-43c5-b354-fae98fec5f76 resume=UUID=50089717-8b5e-482a-8686-7d47d88b7402 splash=silent vga=788
        initrd /boot/initrd-2.6.33.7-desktop586-2mnb.img
    
    ###Don't change this comment - YaST2 identifier: Original name: mandrivalinux###
    title linux Mandriva (Farman) - kernel 2.6.33.7-1
        root (hd1,4)
        kernel /boot/vmlinuz-2.6.33.7-desktop-1mnb BOOT_IMAGE=linux_Mandriva_(Farman)_-_kerne root=UUID=4a9d7d4f-dce0-43c5-b354-fae98fec5f76 resume=UUID=50089717-8b5e-482a-8686-7d47d88b7402 splash=silent vga=788
        initrd /boot/initrd-2.6.33.7-desktop-1mnb.img
    
    ###Don't change this comment - YaST2 identifier: Original name: windows###
    title Microsoft Windows XP Professional - added by updategrub
        rootnoverify (hd0,0)
        chainloader +1
    
    ###Don't change this comment - YaST2 identifier: Original name: windows1###
    title Microsoft Windows XP Professional - added by updategrub
        map (hd1) (hd0)
        map (hd0) (hd1)
        rootnoverify (hd1,0)
        chainloader +1
    
    ###Don't change this comment - YaST2 identifier: Original name: GrubOnsda###
    title Grub2 in sda MBR
        rootnoverify (hd0)
        chainloader +1
    
    ....
    So, what is the consequence for updategrub? Since the marker has been deleted, it will write a new one and add all kernel and chainloading entries it finds below that point. All chainloading entries will then be duplicated in Grub menu. We could certainly edit the /boot/grub/menu.lst and delete the chainloading entries above the marker line. Other workarounds would be:

    • set/uncomment CHAINLOADGRUB=no in /etc/updategrub/defaults, so that it won't add chainloading entries anymore, in fact a very elegant solution.
    • apply the following patch to /usr/lib/bootloader/bootloader_entry, so that it won't delete any entry (including the older openSUSE kernels that will have to be deleted manually):

      Code:
      --- /usr/lib/bootloader/bootloader_entry.orig   2011-05-05 06:59:52.937004863 -0700
      +++ /usr/lib/bootloader/bootloader_entry        2011-05-05 04:12:30.892338883 -0700
      @@ -260,7 +260,6 @@
                              update_bootloader --image /boot/$image \
                                                --initrd /boot/$initrd \
                                                --remove \
      -                                         --force \
                                                 || exit 1
                      fi
      This is actually the option I prefer. I don't care having to delete one or two boot entries if it prevents upate-bootloader from removing 20 others.
    • Get an average Perl programmer to have a look at /sbin/update-bootloader
    • Wait until they fix this file and write a bug report for me ... cause I'm not good at that.

  7. #7

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    updategrub 1.5

    Version 1.5 of updategrub adds an extra check to work around a bug I have observed in linux-boot-prober since the first os-prober versions installed on Ubuntu. Since updategrub uses os-prober as well, this bug affects both update-grub under Ubuntu and updategrub under openSUSE and other Legacy Grub based distros.

    More precisely it affects all but openSUSE distros because it concerns openSUSE's menu.lst. openSUSE's menu.lst is not parsed while running updategrub under openSUSE, because the host system root partition is ignored. Its purpose is to add boot entries for other systems, not write or modify native boot entries. Thus, when you run updategrub under openSUSE, os-prober will skip the openSUSE root partition, and linux-boot-prober will read the boot entries in the menu.lst files on all other Linux root partitions detected by os-prober. It will read them "as is", meaning that if these partitions contain errors, such as wrong device number, wrong partition UUID or anything else, the boot entries added by update-grub and updategrub will contain the same errors.

    What happens if the different menu.lst files include many boot entries for other Linux distro kernels? This is common in complex multiboot setups where you want each Linux distro to use its own Grub and be able to boot any other (whether you added the entries manually or with updategrub). In most cases, it works pretty well. While scanning Fedora's menu.lst on a given partition, linux-boot-prober retrieves only Fedora boot entries; while scanning Mandriva's menu.lst, it retrieves only Mandriva boot entries; same for ArchLinux, Gentoo, Ubuntu and other Grub2-based systems (where it doesn't seem to parse the boot menu). However, linux-boot-prober has problems with openSUSE's menu.lst - which again doesn't matter under openSUSE itself. If this menu.lst contains Mandriva boot entries, linux-boot-prober will retrieve these entries and pass them to update-grub/updategrub which in turn will add a completely wrong boot entry in the menu. I have lived with this bug and removed these entries manually from both Legacy and Grub2 boot menus until I decided that enough was enough and finally added an extra check in updategrub. The new checkroot function makes sure that the root partition currently read by linux-boot-prober matches the one specified in the kernel root option (by device name, UUID, /dev/disk/by-uuid symlinks or label).

    The feature is enabled by default. If it doesn't work as expected for you (i.e if it skips valid boot entries), you can disable this extra check by adding the following option in /etc/updategrub/defaults:
    Code:
    CHECKROOT=no

    Illustration of the bug

    • snip of Ubuntu's /boot/grub/grub.cfg

      Code:
      ### BEGIN /etc/grub.d/30_os-prober ###
      menuentry "openSUSE 11.4 (Celadon) - kernel 2.6.37.6-0.5 (Desktop) (on /dev/sda11)" {
      	insmod part_msdos
      	insmod ext2
      	set root='(hd0,msdos11)'
      	search --no-floppy --fs-uuid --set 86949758-5b38-4f29-9f03-da0b2c055b8e
      	linux /boot/vmlinuz-2.6.37.6-0.5-desktop root=/dev/disk/by-uuid/86949758-5b38-4f29-9f03-da0b2c055b8e resume=/dev/disk/by-uuid/ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent quiet showopts vga=794
      	initrd /boot/initrd-2.6.37.6-0.5-desktop
      }
      menuentry "Mandriva 2010.2 (Farman) - kernel 2.6.38.8 (desktop) (on /dev/sdb6)" {
      	insmod part_msdos
      	insmod ext2
      	set root='(hd1,msdos6)'
      	search --no-floppy --fs-uuid --set 4ecf3517-c7e9-47a1-8930-13a4e188e730
      	linux /boot/vmlinuz-2.6.38.8-desktop-69mib BOOT_IMAGE=2.6.38.8-desktop-69mib root=UUID=4ecf3517-c7e9-47a1-8930-13a4e188e730 resume=UUID=ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent vga=794
      	initrd /boot/initrd-2.6.38.8-desktop-69mib.img
      }
      menuentry "Mandriva 2010.2 (Farman) - kernel 2.6.38.8 (on /dev/sda11)" {
      	insmod part_msdos
      	insmod ext2
      	set root='(hd0,msdos11)'
      	search --no-floppy --fs-uuid --set 86949758-5b38-4f29-9f03-da0b2c055b8e
      	linux /boot/vmlinuz BOOT_IMAGE=linux root=UUID=4ecf3517-c7e9-47a1-8930-13a4e188e730 resume=UUID=ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent vga=794
      	initrd /boot/initrd.img
      }

      The second Mandriva boot entry added by update-grub is obviously wrong: the root partition reported is the same as for openSUSE (hd0,msdos11) but the kernel root options refer to different partitions - which are by the way correct in both cases (meaning that linux-boot-prober parses Grub2 entries in a different way). Notice that neither openSUSE nor Mandriva use separate /boot partitions!

    • snip of /boot/grub/menu.lst created by updategrub (previous to version 2.4x) under Mandriva, Fedora, Archinux (but NOT openSUSE):


      Code:
      title Mandriva 2010.2 (Farman) - kernel 2.6.38.8
          root (hd1,5)
          kernel /boot/vmlinuz BOOT_IMAGE=linux root=UUID=4ecf3517-c7e9-47a1-8930-13a4e188e730 resume=UUID=ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent vga=794
          initrd /boot/initrd.img
      
      # openSUSE 11.4 (x86_64) on /dev/sda11
      title openSUSE 11.4 (Celadon) - kernel 2.6.37.6-0.5 (Desktop)
          root (hd0,10)
          kernel /boot/vmlinuz-2.6.37.6-0.5-desktop root=/dev/disk/by-uuid/86949758-5b38-4f29-9f03-da0b2c055b8e resume=/dev/disk/by-uuid/ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent quiet showopts vga=0x31a
          initrd /boot/initrd-2.6.37.6-0.5-desktop
      
      # openSUSE 11.4 (x86_64) on /dev/sda11
      title Mandriva 2010.2 (Farman) - kernel 2.6.38.8
          root (hd0,10)
          kernel /boot/vmlinuz BOOT_IMAGE=linux root=UUID=4ecf3517-c7e9-47a1-8930-13a4e188e730 resume=UUID=ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent vga=794
          initrd /boot/initrd.img
      In the example above it becomes even clearer that the third boot entry is wrong: linux-boot-prober retrieved the latest Mandriva boot entry from openSUSE's menu.lst. The device (hd0,10) is wrong (since Mandriva is on (hd1,5) and the partitition's UUID provided in the kernel root option is wrong too (it is openSUSE's root partition and not Mandriva's). The function checkroot in version 1.5 will notice that and reject this boot entry.

    • linux-boot-prober output:

      Code:
      /dev/sda11:/dev/sda11:openSUSE 11.4 (Celadon) - kernel 2.6.37.6-0.5 (Desktop):/boot/vmlinuz-2.6.37.6-0.5-desktop:/boot/initrd-2.6.37.6-0.5-desktop:root=/dev/disk/by-uuid/86949758-5b38-4f29-9f03-da0b2c055b8e resume=/dev/disk/by-uuid/ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent quiet showopts vga=0x31a
      /dev/sda11:/dev/sda11:openSUSE 11.4 (Celadon) - kernel 2.6.37.6-0.5 (Failsafe):/boot/vmlinuz-2.6.37.6-0.5-desktop:/boot/initrd-2.6.37.6-0.5-desktop:root=/dev/disk/by-uuid/86949758-5b38-4f29-9f03-da0b2c055b8e showopts apm=off noresume edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe vga=0x31a
      /dev/sda11:/dev/sda11:Mandriva 2010.2 (Farman) - kernel 2.6.38.8:/boot/vmlinuz:/boot/initrd.img:BOOT_IMAGE=linux root=UUID=4ecf3517-c7e9-47a1-8930-13a4e188e730 resume=UUID=ba9db764-a47e-48d9-b6f9-b627b57c0287 splash=silent vga=794
      It should NOT show the Mandriva boot entry on partition sda11.

  8. #8

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    I added support for chainloading Grub 1.99 in updategrub - half support actually, as I don't have too much time to look in the compressed core now. It concerns only other Grub chainload entries that can be optionally added by updategrub. When updategrub finds Grub2 1.97/1.98 signature, it doesn't chainload the bootsector - as it would do for Legacy Grub - but boots the core image instead with such an entry in menu.lst:
    Code:
    kernel /boot/grub/core.img
    Before writing this entry, it has to make sure that the core.img is present on the root partition - the one specified in root (hdX,N) - by jumping to the sector (+1) , which offset is written in the Grub bootsector and looking for the partition containing /boot/grub at this location. The following example looks for "stage2" (although the term is not used for Grub2) in sda6.

    Code:
    corepos=$(hexdump -v -s 92 -n 4 -e '"%u"' /dev/sda6)
    dd if=/dev/sda count=1 bs=512 skip=$(($corepos + 1)) 2>/dev/null | strings
    and - since it finds it - displays:

    Code:
    (,msdos6)/boot/grub
    And so we know that core.img should be in sda6 and we can use root=(hd0,5) and the following entry in Legacy Grub syntax to chainload Grub2:

    Code:
    # Grub 2 on /dev/sda6
    title Grub2 on /dev/sda6
    root (hd0,5)
    kernel /boot/grub/core.img
    boot
    Although booting the core.img is different from chainloading the bootsector, what you get to see is pretty much the same thing: the Grub2 boot menu.

    As it was too simple, they had to change that.

    Since Grub 1.99 - used in Ubuntu Oneiric and I guess Natty too - the core is compressed and you can not find out the location (meaning the partition) to boot without doing some calculation and uncompressing the core first. I did it in findgrub since version 3.5 by adding the function lzmacore - widely inspired from the bootinfo script. I might implement this function in updategrub at some point, but in the meantime, I decided to chainload the bootsector - not ideal but better than before.


    before after



    The latest updategrub version 1.5.5 is available in my repo. The package includes findgrub 3.5.1.
    The code can be viewed here: http://www.unixversal.com/linux/openSUSE/updategrub

  9. #9

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    Ooops! I forgot to remove this line from the code:

    Code:
    5c5
    < #: Last Edit   : Sun Nov 13 16:46:28 PST 2011
    ---
    > #: Last Edit   : Mon Nov 14 10:32:41 PST 2011
    222d221
    < GRUBS=("/dev/sda11:(hd0,10):suse" "/dev/sdb6:(hd1,5):arch")
    
    I fixed it. The package has been scheduled for rebuilding...

  10. #10

    Default Re: updategrub for openSUSE Legacy Grub (not update-grub!)

    I noticed - while running updategrub on openSUSE 12.1 and Fedora 15 (using Legacy Grub) - that if failed to add Ubuntu when Ubuntu's partition is not mounted. The problem comes from os-prober, not updategrub, not detecting ubuntu Oneiric and probably Natty, but not Maverick - I suspect more generally all Oses using Grub2 1.99 with compressed core. Mounting Ubuntu's partition once solves the issue - even if you unmount it afterwards an run updategrub again.

Page 1 of 2 12 LastLast

Similar Threads

  1. How to update grub (legacy) in opensuse?
    By ojosazul in forum Install/Boot/Login
    Replies: 12
    Last Post: 24-Oct-2015, 00:28
  2. Replies: 20
    Last Post: 02-Mar-2010, 11:07

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •