#! /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. # # 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. # single_menu_mode= # # Make sure we're really running bash. # [ -z "$BASH" ] && { echo "Menuconfig 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[ ]*\$/d /^#.*/d /^[ ]*\$/q p }" Documentation/Configure.help) if [ -z "$text" ] then echo "There is no help available for this kernel option." else echo "$text" fi else echo "There is no help available for this kernel option." fi } # # Activate a help dialog. # function help () { if extract_help $1 >help.out then $DIALOG --backtitle "$backtitle" --title "$2"\ --textbox help.out 20 75 else $DIALOG --backtitle "$backtitle" \ --textbox help.out 20 75 fi rm help.out } # # Show the README file. # function show_readme() { $DIALOG --backtitle "$backtitle" \ --textbox scripts/README.Menuconfig 21 75 } # # Begin building the dialog menu command and Initialize the # Radiolist function file. # function menu_name () { echo -ne "$DIALOG --title '$1'\ --backtitle '$backtitle' \ --menu '$menu_instructions' \ 21 75 11 '$default' " >MCmenu >MCradiolists } # # Additional comments # function comment () { comment_ctr=$[ comment_ctr + 1 ] echo -ne "': $comment_ctr' '--- $1' " >>MCmenu } # # 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 --->' " >>MCmenu } # # Create a menu entry to handle the traditional sound configuration. # function soundcfg () { echo -ne "'l_soundcfg' "\ "'Old configuration script "\ "(For: SM Wave, PSS & AudioTrix Pro) -->' " >>MCmenu } # # Startup the traditional sound configuration program. # function l_soundcfg () { clear $MAKE -C drivers/sound config } # # 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' " >>MCmenu echo -e "function $2 () { l_bool '$1' '$yes' '$no' '$2' }\n" \ >>MCradiolists } # # Handle a boolean (Yes/No) option. # function l_bool () { while true do $DIALOG --title "$1" \ --backtitle "$backtitle" \ --radiolist "$radiolist_instructions" 12 70 2 \ 'y' 'Yes' $2 'n' 'No' $3 2>MCdialog.out case "$?" in 0) eval $4=`cat MCdialog.out` break ;; 1) help "$4" "$1" ;; *) break ;; esac 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' " >>MCmenu echo -e "function $2 () { l_mod_bool '$1' '$module' '$no' '$2' }\n" \ >>MCradiolists } # # Same as l_bool() except options are (Module/No) # function l_mod_bool() { while true do $DIALOG --title "$1" \ --backtitle "$backtitle" \ --radiolist "$radiolist_instructions" 12 70 2 \ 'm' 'Module' $2 'n' 'No' $3 2>MCdialog.out case "$?" in 0) eval $4=`cat MCdialog.out` break ;; 1) help "$4" "$1" ;; *) break ;; esac 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' " >>MCmenu echo -e " function $2 () { \ l_tristate '$1' '$yes' '$no' '$module' '$2' }" >>MCradiolists fi } # # Handle a tristate (Yes/No/Module) option. # function l_tristate () { while true do $DIALOG --title "$1" \ --backtitle "$backtitle" \ --radiolist "$radiolist_instructions" 13 70 3 \ 'y' 'Yes' $2 'n' 'No' $3 'm' 'Module' $4 \ 2>MCdialog.out case "$?" in 0) eval $5=`cat MCdialog.out` break ;; 1) help "$5" "$1" ;; *) break ;; esac 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 } # # Add a menu item which will call our local int function. # function int () { eval $2=\${$2:-"$3"} x=\$$2 echo -ne "'$2' '($x) $1' " >>MCmenu echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }\n" >>MCradiolists } # # 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>MCdialog.out then answer="`cat MCdialog.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 "$2" "$1" done } # # Add a menu item which will call our local int function. # function hex () { eval $2=\${$2:-"$3"} x=\${$2##*[x,X]} echo -ne "'$2' '($x) $1' " >>MCmenu echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }\n" >>MCradiolists } # # 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>MCdialog.out then answer="`cat MCdialog.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 "$2" "$1" done } # # Add a menu item 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' " >>MCmenu echo -e " function $firstchoice () { l_choice '$title' \"$choices\" $current }\n" >>MCradiolists } 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>MCdialog.out then choice=`cat MCdialog.out` break fi help "$firstchoice" "$title" 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 } # # A faster awk based recursive parser. (I hope) # function parser1 () { awk ' BEGIN { menu_no = 0 comment_is_option = 0 parser("'$CONFIG_IN'","MCmenu0") } function parser(ifile,menu) { while (getline <ifile) { if ($1 == "mainmenu_option") { comment_is_option = "1" } else if ($1 == "comment" && comment_is_option == "1") { comment_is_option= "0" sub($1,"",$0) ++menu_no printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu printf( "function MCmenu%s () {\n"\ "default=$1\n"\ "menu_name %s\n",\ menu_no, $0) >"MCmenu"menu_no parser(ifile, "MCmenu"menu_no) } else if ($1 ~ "endmenu") { printf("}\n") >>menu return } else if ($0 ~ /^#|$MAKE|mainmenu_name/) { printf("") >>menu } else if ($1 == "source") { # Yuk! Blah! Phooey! if ($2 ~ "drivers/sound") { printf("soundcfg\n") >>menu } parser($2,menu) } else { print >>menu } } }' } # # Secondary parser for single menu mode. # function parser2 () { awk ' BEGIN { parser("'$CONFIG_IN'","MCmenu0") } function parser(ifile,menu) { while (getline <ifile) { if ($1 ~ /mainmenu_option|endmenu/) { printf("") >>menu } else if ($0 ~ /^#|$MAKE|mainmenu_name/) { printf("") >>menu } else if ($1 == "source") { if ($2 ~ "drivers/sound") { printf("soundcfg\n") >>menu } parser($2,menu) } else { print >>menu } } }' } # # Parse all the config.in files into mini scripts. # function parse_config_files () { rm -f MCmenu* echo "function MCmenu0 () {" >MCmenu0 echo 'default=$1' >>MCmenu0 echo "menu_name 'Main Menu'" >>MCmenu0 if [ "_$single_menu_mode" = "_TRUE" ] then parser2 else parser1 fi echo "}" >>MCmenu0 # # These mini scripts must be sourced into the current # environment in order for all of this to work. Leaving # them on the disk as executables screws up the recursion # in activate_menu(), among other things. Once they are # sourced we can disgard them. # for i in MCmenu* do source $i done rm -f MCmenu* } # # This is the menu tree's bootstrap. # # Executes the parsed menus on demand and creates a set of functions, # one per configuration option. These functions will in turn execute # dialog commands or recursively call other menus. # function activate_menu () { while true do comment_ctr=0 $1 "$default" #Create the radiolists and dialog cmd . MCradiolists #Read in the dialog functions. . MCmenu 2>MCdialog.out #Activate this menu case "$?" in 0) defaults="`cat MCdialog.out`$defaults" #psuedo stack . MCdialog.out default="${defaults%%*}" defaults="${defaults#*}" ;; 2) echo >>MCdialog.out read selection <MCdialog.out default="${selection%% *}" case "$selection" in *"-->"*) show_readme ;; *) 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 if [ "$x" = "y" ] then x="m" fi fi define_bool "$2" "$x" } 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 () { eval $1="$2" 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 } 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 MAKE=: #To prevent sound Makefile from running. if . $CONFIG_IN >>.menuconfig.log 2>&1 then # # Create the sound driver's config files for cards # Which are compatible with the new config method. # if [ "_$CONFIG_TRIX" != "_y" -a\ "_$CONFIG_PSS" != "_y" -a\ "_$CONFIG_SMWAVE" != "_y" ] then make -C drivers/sound kernelconfig >>.menuconfig.log 2>&1 fi if [ -f .config ] then rm -f .config.old mv .config .config.old fi mv .tmpconfig .config mv .tmpconfig.h include/linux/autoconf.h return 0 else return 1 fi } # # Remove temporary files # cleanup () { cleanup1 cleanup2 } cleanup1 () { rm -f MCmenu* MCradiolists MCdialog.out help.out } cleanup2 () { rm -f .tmpconfig .tmpconfig.h } menu_instructions="\ Arrow keys navigate the menu. \ Highlighted letters are hotkeys. \ Select an item with <Space Bar> or <Enter>. \ When finished press <Esc><Esc> or <X>. \ A (*) marks an option to be compiled into the kernel. \ An (M) marks an option to be compiled as a module." radiolist_instructions="\ Use the arrow keys to navigate this window or \ press the hotkey 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" kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}" trap "cleanup ; rm -f .menuconfig ; 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 # Fresh new log. >.menuconfig.log $DIALOG --backtitle "$backtitle" \ --infobox "Preparing configuration scripts..." 3 40 # # Check kernel version of previous menuconfig build. # If it's different then we should tell the sound driver # to rebuild it's Config.in file. # rebuildsound=TRUE if [ -e .menuconfig ] then read x <.menuconfig if [ "$x" = "# $kernel_version" ] then rebuildsound= fi fi if [ "$rebuildsound" ] then # Activate the Linux compatible sound configuration. # This may not work for all sound cards. (See sound docs) # make -C drivers/sound mkscript >>.menuconfig.log 2>&1 echo "# $kernel_version" >.menuconfig fi # # Read config.in files and parse them into one shell function per menu. # parse_config_files $CONFIG_IN # # Start the ball rolling from the top. # activate_menu MCmenu0 # # All done! # cleanup1 # # Confirm and Save # if $DIALOG --backtitle "$backtitle" \ --yesno "Do you wish to save your new kernel configuration?" 5 60 then save_configuration clear cat <<EOM 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. EOM else clear echo -e "Your kernel configuration changes were NOT saved.\n" fi exit 0