#! /bin/sh # # This script is used to configure the linux kernel. # # It was inspired by a desire to not have to hit <enter> 9 million times # or startup the X server just to change a single kernel parameter. # # This script attempts to parse the configuration files, which are # scattered throughout the kernel source tree, and creates a temporary # set of mini scripts which are in turn used to create nested menus and # radiolists. # # It uses a very modified/mutilated version of the "dialog" utility # written by Savio Lam (lam836@cs.cuhk.hk). Savio is not responsible # for this script or the version of dialog used by this script. # Please do not contact him with questions. The official version of # dialog is available at sunsite.unc.edu or a sunsite mirror. # # Portions of this script were borrowed from the original Configure # script used in linux-1.3.55. # # Please send comments / questions / bug fixes to roadcapw@cfw.com # #---------------------------------------------------------------------------- # # Change this to TRUE if you prefer all kernel options listed # in a single menu rather than the standard menu hierarchy. # # Don't forget to remove linux/.menuconfig.in # single_menu_mode= # # Make sure we're really running bash. # [ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; } # # Cache function definitions # set -h # # Extract available help for an option from Configure.help # and send it to standard output. # # Most of this function was borrowed from the original kernel # Configure script. # function extract_help () { if [ -f Documentation/Configure.help ] then #first escape regexp special characters in the argument: var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g') #now pick out the right help text: text=$(sed -n "/^$var[ ]*\$/,\${ /^$var[ ]*\$/b /^#.*/b;/^[ ]*\$/q p }" Documentation/Configure.help) if [ -z "$text" ] then echo "There is no help available for this setting." else echo "$text" fi else echo "There is no help available for this setting." fi } # # Activate a help dialog. # function help () { extract_help $2 >help.out $DIALOG --backtitle "$backtitle" --title "$1" --textbox help.out 20 75 rm help.out } # # Init temporary scripts for the current menu. # function menu_name () { echo -ne "$DIALOG --title '$1'\ --backtitle '$backtitle' \ --menu '$menu_instructions' \ 21 75 11 '$default' " >submenu >radiolists } # # Additional comments are currently semi-supported # function comment () { comment_ctr=$[ comment_ctr + 1 ] echo -ne "': $comment_ctr' '--- $1' " >>submenu } # # Don't need this yet, but we don't want to puke either. # function define_bool () { : } # # Add a submenu option to the menu currently under construction. # function submenu () { echo -ne "'activate_menu $2' '$1 --->' " >>submenu } # # This is to handle the Sound configuration. # function yuck1 () { echo -ne "'clear ; $MAKE $2' '$1' " >>submenu } # # Create a boolean (Yes/No) function for our current menu # which calls our local bool function. # function bool () { eval $2=\${$2:-'n'} x=\$$2 case $x in y|m) yes='ON' no='OFF' flag="*" ;; n) yes='OFF' no='ON' flag=" " ;; esac echo -ne "'$2' '($flag) $1' " >>submenu echo -e "function $2 () { l_bool '$1' '$yes' '$no' '$2' }\n" \ >>radiolists } # # Handle a boolean (Yes/No) option. # function l_bool () { while true do if $DIALOG --title "$1" \ --backtitle "$backtitle" \ --radiolist "$radiolist_instructions" 12 70 2 \ 'y' 'Yes' $2 'n' 'No' $3 2>dialog.out then eval $4=`cat dialog.out` break fi help "$1" "$4" done } # # Same as bool() except options are (Module/No) # function mod_bool () { eval $2=\${$2:-'n'} x=\$$2 case $x in m) module='ON' no='OFF' flag='M' ;; *) module='OFF' no='ON' flag=' ' ;; esac echo -ne "'$2' '($flag) $1' " >>submenu echo -e "function $2 () { l_mod_bool '$1' '$module' '$no' '$2' }\n" \ >>radiolists } # # Same as l_bool() except options are (Module/No) # function l_mod_bool() { while true do if $DIALOG --title "$1" \ --backtitle "$backtitle" \ --radiolist "$radiolist_instructions" 12 70 2 \ 'm' 'Module' $2 'n' 'No' $3 2>dialog.out then eval $4=`cat dialog.out` break fi help "$1" "$4" done } # # Create a tristate (Yes/No/Module) radiolist function # which calls our local tristate function. # # Collapses to a boolean (Yes/No) if module support is disabled. # function tristate () { if [ "$CONFIG_MODULES" != "y" ] then bool "$1" "$2" else eval $2=\${$2:-'n'} x=\$$2 case $x in y) yes='ON' no='OFF' module='OFF' flag="*" ;; m) yes='OFF' no='OFF' module='ON' flag="M" ;; *) yes='OFF' no='ON' module='OFF' flag=" " ;; esac echo -ne "'$2' '($flag) $1' " >>submenu echo -e " function $2 () { \ l_tristate '$1' '$yes' '$no' '$module' '$2' }" >>radiolists fi } # # Handle a tristate (Yes/No/Module) option. # function l_tristate () { while true do if $DIALOG --title "$1" \ --backtitle "$backtitle" \ --radiolist "$radiolist_instructions" 13 70 3 \ 'y' 'Yes' $2 'n' 'No' $3 'm' 'Module' $4 \ 2>dialog.out then eval $5=`cat dialog.out` break fi help "$1" "$5" done } # # Create a tristate radiolist function which is dependent on # another kernel configuration option. # # Quote from the original configure script: # # If the option we depend upon is a module, # then the only allowable options are M or N. If Y, then # this is a normal tristate. This is used in cases where modules # are nested, and one module requires the presence of something # else in the kernel. # function dep_tristate () { if [ "$CONFIG_MODULES" != "y" ] then bool "$1" "$2" else if eval [ "_$3" != "_m" ] then tristate "$1" "$2" $3 else mod_bool "$1" "$2" fi fi } # # Create a function which will call our local int function. # function int () { eval $2=\${$2:-"$3"} x=\$$2 echo -ne "'$2' '($x) $1' " >>submenu echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }\n" >>radiolists } # # Create a dialog for entering an integer into a kernel option. # function l_int () { while true do if $DIALOG --title "$1" \ --backtitle "$backtitle" \ --inputbox "$inputbox_instructions_int" \ 15 55 "$4" 2>dialog.out then answer="`cat dialog.out`" answer="${answer:-$3}" if expr $answer : '0$\|-?[1-9][0-9]*$' >/dev/null then eval $2="$answer" else eval $2="$3" echo -en "\007" ${DIALOG} --backtitle "$backtitle" \ --infobox "You have made an invalid entry." 3 43 sleep 2 fi break fi help "$1" "$2" done } # # Create a function which will call our local int function. # function hex () { eval $2=\${$2:-"$3"} x=\${$2##*[x,X]} echo -ne "'$2' '($x) $1' " >>submenu echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }\n" >>radiolists } # # Create a dialog for entering a hexidecimal into a kernel option. # function l_hex () { while true do if $DIALOG --title "$1" \ --backtitle "$backtitle" \ --inputbox "$inputbox_instructions_hex" \ 15 55 "$4" 2>dialog.out then answer="`cat dialog.out`" answer="${answer:-$3}" answer="${answer##*[x,X]}" if expr $answer : '[0-9a-fA-F]+$' >/dev/null then eval $2="$answer" else eval $2="$3" echo -en "\007" ${DIALOG} --backtitle "$backtitle" \ --infobox "You have made an invalid entry." 3 43 sleep 2 fi break fi help "$1" "$2" done } # # Create a function which will call our local One-of-Many choice list. # function choice () { # # Need to remember params cause the're gonna get reset. # title=$1 choices=$2 default=$3 current= # # Find out if one of the choices is already set. # If it's not then make it the default. # set -- $choices firstchoice=$2 while [ -n "$2" ] do if eval [ "_\$$2" = "_y" ] then current=$1 break fi shift ; shift done : ${current:=$default} echo -ne "'$firstchoice' '($current) $title' " >>submenu echo -e " function $firstchoice () { l_choice '$title' \"$choices\" $current }\n" >>radiolists } function l_choice () { # # Need to remember params cause the're gonna get reset. # title="$1" choices="$2" current="$3" # # Scan current value of choices and set radiolist switches. # list= set -- $choices firstchoice=$2 while [ -n "$2" ] do case "$1" in "$current") list="$list $2 $1 ON " ;; *) list="$list $2 $1 OFF " ;; esac shift ; shift done while true do if $DIALOG --title "$title" \ --backtitle "$backtitle" \ --radiolist "$radiolist_instructions" \ 22 70 11 $list 2>dialog.out then choice=`cat dialog.out` break fi help "$title" "$firstchoice" done # # Now set the boolean value of each option base on # the selection made from the radiolist. # set -- $choices while [ -n "$2" ] do if [ "$2" = "$choice" ] then eval $2="y" else eval $2="n" fi shift ; shift done } # # Now parse the configuration files and create our mini scripts. # Each script represents a separate menu which when taken together # form a linked menu tree. Since one configuration file # may source another elsewhere in the kernel source tree, this # function is recursive. # function parse_config_files () { if [ "_$single_menu_mode" = "_TRUE" ] then parse_single_menu $1 return fi while read command args do case $command in # # Will it ever happen that mainmenu_option will be followed # by anything other then "next_comment"? This assumes not.. # mainmenu_option) comment_is_option=TRUE ;; comment) if [ "$comment_is_option" ] then comment_is_option= stack="$submenu$stack" menu_no=$[menu_no + 1] x="submenu$menu_no" echo "submenu $args $x" >> $submenu submenu=$x echo menu_name $args >$submenu else echo comment $args >> $submenu fi ;; endmenu) submenu="${stack%%*}" stack="${stack#*}" ;; mainmenu_name) echo menu_name "'Main Menu'" > submenu0 ;; \$MAKE) echo "yuck1 'Configure (You must do this!)' '$args'"\ >>$submenu ;; source) parse_config_files "$args" ;; '#'|'') : ;; *) echo $command $args >> $submenu ;; esac done < $1 } # # Parses configuration files into a single menu structure. # function parse_single_menu () { while read command args do case $command in mainmenu_option | \ endmenu) : ;; mainmenu_name) echo menu_name "'Main Menu'" > submenu0 ;; \$MAKE) echo "yuck1 'Configure (You must do this!)' '$args'"\ >>$submenu ;; source) parse_single_menu "$args" ;; '#'|'') : ;; *) echo $command $args >> $submenu ;; esac done < $1 } # # This is the menu tree's bootstrap. # # Executes a mini script to create a set of functions, one per configuration # option. These functions will in turn execute dialog commands or recursively # call other mini scripts. # function activate_menu () { while true do comment_ctr=0 $1 "$default" #Create the radiolists and dialog cmd . radiolists #Read in the dialog functions. . submenu 2>dialog.out #Activate this menu case "$?" in 0) defaults="`cat dialog.out`$defaults" #pseudo stack source dialog.out default="${defaults%%*}" defaults="${defaults#*}" ;; 2) read selection <dialog.out default="${selection##* }" case "$selection" in *"-->"*) : ;; *) eval help $selection ;; esac ;; 255|1) break ;; esac done } # # Just what it says. # save_configuration () { ${DIALOG} --backtitle "$backtitle" \ --infobox "Saving your new kernel configuration..." 3 43 # # Now, let's redefine the configuration functions for final # output to the config files. # function bool () { eval define_bool "$2" "\${$2:-n}" } function tristate () { eval define_bool "$2" "\${$2:-n}" } function dep_tristate () { eval x=\${$2:-n} if eval [ "_$3" != "_m" ] then tristate "$1" "$2" else if [ "$x" = "y" ] then x="m" fi define_bool "$2" "$x" fi } function int () { eval x=\${$2:-"$3"} echo "$2=$x" >>$CONFIG echo "#define $2 ($x)" >>$CONFIG_H } function hex () { eval x=\${$2:-"$3"} echo "$2=$x" >>$CONFIG echo "#define $2 0x${x##*[x,X]}" >>$CONFIG_H } function define_bool () { case "$2" in y) echo "$1=y" >>$CONFIG echo "#define $1 1" >>$CONFIG_H ;; m) if [ "$CONFIG_MODULES" = "y" ] then echo "$1=m" >>$CONFIG echo "#undef $1" >>$CONFIG_H else echo "$1=y" >>$CONFIG echo "#define $1 1" >>$CONFIG_H fi ;; n) echo "# $1 is not set" >>$CONFIG echo "#undef $1" >>$CONFIG_H ;; esac } function choice () { # # Find the first choice that's already set to 'y' # choices="$2" default="$3" current= set -- $choices while [ -n "$2" ] do if eval [ "_\$$2" = "_y" ] then current=$1 break fi shift ; shift done # # Use the default if none were set. # : ${current:=$default} # # Then extract the actual option from the list of choices. # current=${choices#*$current} ; set $current define_bool "$1" "y" } function mainmenu_name () { : } function mainmenu_option () { comment_is_option=TRUE } function endmenu () { : } function comment () { if [ "$comment_is_option" ] then comment_is_option= echo >>$CONFIG echo "#" >>$CONFIG echo "# $1" >>$CONFIG echo "#" >>$CONFIG echo >>$CONFIG_H echo "/*" >>$CONFIG_H echo " * $1" >>$CONFIG_H echo " */" >>$CONFIG_H fi } # # This will hopfully prevent the sound configuration from # running again. (blagh!) # MAKE=: CONFIG=.tmpconfig CONFIG_H=.tmpconfig.h echo "#" >$CONFIG echo "# Automatically generated by make menuconfig: don't edit" >>$CONFIG echo "#" >>$CONFIG echo "/*" >$CONFIG_H echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H echo " */" >>$CONFIG_H . $CONFIG_IN if [ -f .config ] then rm -f .config.old mv .config .config.old fi mv .tmpconfig .config mv .tmpconfig.h include/linux/autoconf.h } # # Remove temporary files # cleanup () { cleanup1 cleanup2 } cleanup1 () { rm -f submenu* radiolists dialog.out help.out } cleanup2 () { rm -f .tmpconfig .tmpconfig.h } menu_instructions="\ Arrow keys navigate the menu. \ Highlighted letters are shortcuts. \ Select an item with <Space Bar> or <Enter>. \ When finished press <E> or <X> or <Esc>. \ (*) indicates an option will be compiled into the kernel. \ (M) indicates an option will be compiled as a module." radiolist_instructions="\ Use the arrow keys to navigate this radiolist or \ press the first letter of the item you wish to select \ followed by the <SPACE BAR>. Press <H> for additional information about this option." inputbox_instructions_int="\ Please enter a decimal value between 1 and 9999. \ Fractions will not be accepted. \ Use the <TAB> key to move from the input field to buttons below it." inputbox_instructions_hex="\ Please enter a hexidecimal value. \ Use the <TAB> key to move from the input field to buttons below it." backtitle="Linux Kernel Configuration" DIALOG="./scripts/lxdialog/lxdialog" comment_is_option= menu_no=0 submenu=submenu0 kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}" trap "cleanup ; rm -f .menuconfig.in ; exit 1" 1 2 15 # # Locate default files. # DEFAULT="" if [ "$1" = "-d" ] ; then DEFAULT="-d" shift fi CONFIG_IN=./config.in if [ "$1" != "" ] ; then CONFIG_IN=$1 fi DEFAULTS=arch/$ARCH/defconfig if [ -f .config ]; then DEFAULTS=.config fi if [ -f $DEFAULTS ]; then echo "#" echo "# Using defaults found in" $DEFAULTS echo "#" . $DEFAULTS else echo "#" echo "# No defaults found" echo "#" fi # # Convert the configuration files into our mini scripts. # Then put all the mini scripts into a single file which should # stick around and act as a cache until the kernel release changes # or "make mrproper". # if [ -e .menuconfig.in ] then read x <.menuconfig.in if [ "$x" != "# $kernel_version" ] then rm -f .menuconfig.in fi fi if [ ! -e .menuconfig.in ] then $DIALOG --backtitle "$backtitle" \ --infobox "Compiling configuration script..." 3 40 rm -f submenu* parse_config_files $CONFIG_IN # # For handling Sound configuration. (Yuk!) # echo '$MAKE $*' >submenu999 echo "# $kernel_version" >.menuconfig.in for i in submenu* do echo "function $i () {" echo 'default=$1' cat $i echo -e "}\n\n" done >> .menuconfig.in rm -f submenu* fi source .menuconfig.in # # Start the ball rolling from the top. # activate_menu submenu0 # # We're done with the menu scripts. Get rid of them. # cleanup1 # # Confirm and Save # if $DIALOG --backtitle "$backtitle" \ --yesno "Do you wish to save your new kernel configuration?" 5 60 then save_configuration $DIALOG --backtitle "$backtitle" --infobox "\ The linux kernel is now hopefully configured for your setup. \ Check the top-level Makefile for additional configuration, \ and do a 'make dep ; make clean' if you want to be sure all \ the files are correctly re-made." 7 60 else $DIALOG --backtitle "$backtitle" \ --infobox "Your new configuration was not saved." 3 42 fi exit 0