1ca987d46SWarner Losh\ Copyright (c) 2006-2015 Devin Teske <dteske@FreeBSD.org> 2ca987d46SWarner Losh\ All rights reserved. 3ca987d46SWarner Losh\ 4ca987d46SWarner Losh\ Redistribution and use in source and binary forms, with or without 5ca987d46SWarner Losh\ modification, are permitted provided that the following conditions 6ca987d46SWarner Losh\ are met: 7ca987d46SWarner Losh\ 1. Redistributions of source code must retain the above copyright 8ca987d46SWarner Losh\ notice, this list of conditions and the following disclaimer. 9ca987d46SWarner Losh\ 2. Redistributions in binary form must reproduce the above copyright 10ca987d46SWarner Losh\ notice, this list of conditions and the following disclaimer in the 11ca987d46SWarner Losh\ documentation and/or other materials provided with the distribution. 12ca987d46SWarner Losh\ 13ca987d46SWarner Losh\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14ca987d46SWarner Losh\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15ca987d46SWarner Losh\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16ca987d46SWarner Losh\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17ca987d46SWarner Losh\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18ca987d46SWarner Losh\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19ca987d46SWarner Losh\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20ca987d46SWarner Losh\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21ca987d46SWarner Losh\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22ca987d46SWarner Losh\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23ca987d46SWarner Losh\ SUCH DAMAGE. 24ca987d46SWarner Losh\ 25ca987d46SWarner Losh 26ca987d46SWarner Loshmarker task-menu-commands.4th 27ca987d46SWarner Losh 28ca987d46SWarner Loshinclude /boot/menusets.4th 29ca987d46SWarner Losh 30ca987d46SWarner Loshonly forth definitions 31ca987d46SWarner Losh 32ca987d46SWarner Loshvariable kernel_state 33ca987d46SWarner Loshvariable root_state 34ca987d46SWarner Losh0 kernel_state ! 35ca987d46SWarner Losh0 root_state ! 36ca987d46SWarner Losh 37ca987d46SWarner Loshalso menu-namespace also menu-command-helpers 38ca987d46SWarner Losh 39ca987d46SWarner Losh\ 40ca987d46SWarner Losh\ Boot 41ca987d46SWarner Losh\ 42ca987d46SWarner Losh 43ca987d46SWarner Losh: init_boot ( N -- N ) 44ca987d46SWarner Losh dup 45ca987d46SWarner Losh s" boot_single" getenv -1 <> if 46ca987d46SWarner Losh drop ( n n c-addr -- n n ) \ unused 47ca987d46SWarner Losh toggle_menuitem ( n n -- n n ) 48ca987d46SWarner Losh s" set menu_keycode[N]=115" \ base command to execute 49ca987d46SWarner Losh else 50ca987d46SWarner Losh s" set menu_keycode[N]=98" \ base command to execute 51ca987d46SWarner Losh then 52ca987d46SWarner Losh 17 +c! \ replace 'N' with ASCII numeral 53ca987d46SWarner Losh evaluate 54ca987d46SWarner Losh; 55ca987d46SWarner Losh 56ca987d46SWarner Losh\ 57ca987d46SWarner Losh\ Alternate Boot 58ca987d46SWarner Losh\ 59ca987d46SWarner Losh 60ca987d46SWarner Losh: init_altboot ( N -- N ) 61ca987d46SWarner Losh dup 62ca987d46SWarner Losh s" boot_single" getenv -1 <> if 63ca987d46SWarner Losh drop ( n c-addr -- n ) \ unused 64ca987d46SWarner Losh toggle_menuitem ( n -- n ) 65ca987d46SWarner Losh s" set menu_keycode[N]=109" \ base command to execute 66ca987d46SWarner Losh else 67ca987d46SWarner Losh s" set menu_keycode[N]=115" \ base command to execute 68ca987d46SWarner Losh then 69ca987d46SWarner Losh 17 +c! \ replace 'N' with ASCII numeral 70ca987d46SWarner Losh evaluate 71ca987d46SWarner Losh; 72ca987d46SWarner Losh 73ca987d46SWarner Losh: altboot ( N -- NOTREACHED ) 74ca987d46SWarner Losh s" boot_single" 2dup getenv -1 <> if 75ca987d46SWarner Losh drop ( c-addr/u c-addr -- c-addr/u ) \ unused 76ca987d46SWarner Losh unsetenv ( c-addr/u -- ) 77ca987d46SWarner Losh else 78ca987d46SWarner Losh 2drop ( c-addr/u -- ) \ unused 79ca987d46SWarner Losh s" set boot_single=YES" evaluate 80ca987d46SWarner Losh then 81ca987d46SWarner Losh 0 boot ( state -- ) 82ca987d46SWarner Losh; 83ca987d46SWarner Losh 84ca987d46SWarner Losh\ 85ca987d46SWarner Losh\ ACPI 86ca987d46SWarner Losh\ 87ca987d46SWarner Losh 88ca987d46SWarner Losh: acpi_enable ( -- ) 89ca987d46SWarner Losh s" set acpi_load=YES" evaluate \ XXX deprecated but harmless 90ca987d46SWarner Losh s" set hint.acpi.0.disabled=0" evaluate 91ca987d46SWarner Losh s" loader.acpi_disabled_by_user" unsetenv 92ca987d46SWarner Losh; 93ca987d46SWarner Losh 94ca987d46SWarner Losh: acpi_disable ( -- ) 95ca987d46SWarner Losh s" acpi_load" unsetenv \ XXX deprecated but harmless 96ca987d46SWarner Losh s" set hint.acpi.0.disabled=1" evaluate 97ca987d46SWarner Losh s" set loader.acpi_disabled_by_user=1" evaluate 98ca987d46SWarner Losh; 99ca987d46SWarner Losh 100ca987d46SWarner Losh: toggle_acpi ( N -- N TRUE ) 101ca987d46SWarner Losh 102ca987d46SWarner Losh \ Make changes effective _before_ calling menu-redraw 103ca987d46SWarner Losh 104ca987d46SWarner Losh acpienabled? if 105ca987d46SWarner Losh acpi_disable 106ca987d46SWarner Losh else 107ca987d46SWarner Losh acpi_enable 108ca987d46SWarner Losh then 109ca987d46SWarner Losh 110ca987d46SWarner Losh menu-redraw 111ca987d46SWarner Losh 112ca987d46SWarner Losh TRUE \ loop menu again 113ca987d46SWarner Losh; 114ca987d46SWarner Losh 115ca987d46SWarner Losh\ 116ca987d46SWarner Losh\ Safe Mode 117ca987d46SWarner Losh\ 118ca987d46SWarner Losh 119ca987d46SWarner Losh: safemode_enabled? ( -- flag ) 120ca987d46SWarner Losh s" kern.smp.disabled" getenv -1 <> dup if 121ca987d46SWarner Losh swap drop ( c-addr flag -- flag ) 122ca987d46SWarner Losh then 123ca987d46SWarner Losh; 124ca987d46SWarner Losh 125ca987d46SWarner Losh: safemode_enable ( -- ) 126ca987d46SWarner Losh s" set kern.smp.disabled=1" evaluate 127ca987d46SWarner Losh s" set hw.ata.ata_dma=0" evaluate 128ca987d46SWarner Losh s" set hw.ata.atapi_dma=0" evaluate 129ca987d46SWarner Losh s" set kern.eventtimer.periodic=1" evaluate 130ca987d46SWarner Losh s" set kern.geom.part.check_integrity=0" evaluate 131*48b05b8fSKyle Evans s" set boot_safe=YES" evaluate 132ca987d46SWarner Losh; 133ca987d46SWarner Losh 134ca987d46SWarner Losh: safemode_disable ( -- ) 135ca987d46SWarner Losh s" kern.smp.disabled" unsetenv 136ca987d46SWarner Losh s" hw.ata.ata_dma" unsetenv 137ca987d46SWarner Losh s" hw.ata.atapi_dma" unsetenv 138ca987d46SWarner Losh s" kern.eventtimer.periodic" unsetenv 139ca987d46SWarner Losh s" kern.geom.part.check_integrity" unsetenv 140*48b05b8fSKyle Evans s" boot_safe" unsetenv 141ca987d46SWarner Losh; 142ca987d46SWarner Losh 143ca987d46SWarner Losh: init_safemode ( N -- N ) 144ca987d46SWarner Losh safemode_enabled? if 145ca987d46SWarner Losh toggle_menuitem ( n -- n ) 146ca987d46SWarner Losh then 147ca987d46SWarner Losh; 148ca987d46SWarner Losh 149ca987d46SWarner Losh: toggle_safemode ( N -- N TRUE ) 150ca987d46SWarner Losh toggle_menuitem 151ca987d46SWarner Losh 152ca987d46SWarner Losh \ Now we're going to make the change effective 153ca987d46SWarner Losh 154ca987d46SWarner Losh dup toggle_stateN @ 0= if 155ca987d46SWarner Losh safemode_disable 156ca987d46SWarner Losh else 157ca987d46SWarner Losh safemode_enable 158ca987d46SWarner Losh then 159ca987d46SWarner Losh 160ca987d46SWarner Losh menu-redraw 161ca987d46SWarner Losh 162ca987d46SWarner Losh TRUE \ loop menu again 163ca987d46SWarner Losh; 164ca987d46SWarner Losh 165ca987d46SWarner Losh\ 166ca987d46SWarner Losh\ Single User Mode 167ca987d46SWarner Losh\ 168ca987d46SWarner Losh 169ca987d46SWarner Losh: singleuser_enabled? ( -- flag ) 170ca987d46SWarner Losh s" boot_single" getenv -1 <> dup if 171ca987d46SWarner Losh swap drop ( c-addr flag -- flag ) 172ca987d46SWarner Losh then 173ca987d46SWarner Losh; 174ca987d46SWarner Losh 175ca987d46SWarner Losh: singleuser_enable ( -- ) 176ca987d46SWarner Losh s" set boot_single=YES" evaluate 177ca987d46SWarner Losh; 178ca987d46SWarner Losh 179ca987d46SWarner Losh: singleuser_disable ( -- ) 180ca987d46SWarner Losh s" boot_single" unsetenv 181ca987d46SWarner Losh; 182ca987d46SWarner Losh 183ca987d46SWarner Losh: init_singleuser ( N -- N ) 184ca987d46SWarner Losh singleuser_enabled? if 185ca987d46SWarner Losh toggle_menuitem ( n -- n ) 186ca987d46SWarner Losh then 187ca987d46SWarner Losh; 188ca987d46SWarner Losh 189ca987d46SWarner Losh: toggle_singleuser ( N -- N TRUE ) 190ca987d46SWarner Losh toggle_menuitem 191ca987d46SWarner Losh menu-redraw 192ca987d46SWarner Losh 193ca987d46SWarner Losh \ Now we're going to make the change effective 194ca987d46SWarner Losh 195ca987d46SWarner Losh dup toggle_stateN @ 0= if 196ca987d46SWarner Losh singleuser_disable 197ca987d46SWarner Losh else 198ca987d46SWarner Losh singleuser_enable 199ca987d46SWarner Losh then 200ca987d46SWarner Losh 201ca987d46SWarner Losh TRUE \ loop menu again 202ca987d46SWarner Losh; 203ca987d46SWarner Losh 204ca987d46SWarner Losh\ 205ca987d46SWarner Losh\ Verbose Boot 206ca987d46SWarner Losh\ 207ca987d46SWarner Losh 208ca987d46SWarner Losh: verbose_enabled? ( -- flag ) 209ca987d46SWarner Losh s" boot_verbose" getenv -1 <> dup if 210ca987d46SWarner Losh swap drop ( c-addr flag -- flag ) 211ca987d46SWarner Losh then 212ca987d46SWarner Losh; 213ca987d46SWarner Losh 214ca987d46SWarner Losh: verbose_enable ( -- ) 215ca987d46SWarner Losh s" set boot_verbose=YES" evaluate 216ca987d46SWarner Losh; 217ca987d46SWarner Losh 218ca987d46SWarner Losh: verbose_disable ( -- ) 219ca987d46SWarner Losh s" boot_verbose" unsetenv 220ca987d46SWarner Losh; 221ca987d46SWarner Losh 222ca987d46SWarner Losh: init_verbose ( N -- N ) 223ca987d46SWarner Losh verbose_enabled? if 224ca987d46SWarner Losh toggle_menuitem ( n -- n ) 225ca987d46SWarner Losh then 226ca987d46SWarner Losh; 227ca987d46SWarner Losh 228ca987d46SWarner Losh: toggle_verbose ( N -- N TRUE ) 229ca987d46SWarner Losh toggle_menuitem 230ca987d46SWarner Losh menu-redraw 231ca987d46SWarner Losh 232ca987d46SWarner Losh \ Now we're going to make the change effective 233ca987d46SWarner Losh 234ca987d46SWarner Losh dup toggle_stateN @ 0= if 235ca987d46SWarner Losh verbose_disable 236ca987d46SWarner Losh else 237ca987d46SWarner Losh verbose_enable 238ca987d46SWarner Losh then 239ca987d46SWarner Losh 240ca987d46SWarner Losh TRUE \ loop menu again 241ca987d46SWarner Losh; 242ca987d46SWarner Losh 243ca987d46SWarner Losh\ 244ca987d46SWarner Losh\ Escape to Prompt 245ca987d46SWarner Losh\ 246ca987d46SWarner Losh 247ca987d46SWarner Losh: goto_prompt ( N -- N FALSE ) 248ca987d46SWarner Losh 249ca987d46SWarner Losh s" set autoboot_delay=NO" evaluate 250ca987d46SWarner Losh 251ca987d46SWarner Losh cr 252ca987d46SWarner Losh ." To get back to the menu, type `menu' and press ENTER" cr 253ca987d46SWarner Losh ." or type `boot' and press ENTER to start FreeBSD." cr 254ca987d46SWarner Losh cr 255ca987d46SWarner Losh 256ca987d46SWarner Losh FALSE \ exit the menu 257ca987d46SWarner Losh; 258ca987d46SWarner Losh 259ca987d46SWarner Losh\ 260ca987d46SWarner Losh\ Cyclestate (used by kernel/root below) 261ca987d46SWarner Losh\ 262ca987d46SWarner Losh 263ca987d46SWarner Losh: init_cyclestate ( N K -- N ) 264ca987d46SWarner Losh over cycle_stateN ( n k -- n k addr ) 265ca987d46SWarner Losh begin 266ca987d46SWarner Losh tuck @ ( n k addr -- n addr k c ) 267ca987d46SWarner Losh over <> ( n addr k c -- n addr k 0|-1 ) 268ca987d46SWarner Losh while 269ca987d46SWarner Losh rot ( n addr k -- addr k n ) 270ca987d46SWarner Losh cycle_menuitem 271ca987d46SWarner Losh swap rot ( addr k n -- n k addr ) 272ca987d46SWarner Losh repeat 273ca987d46SWarner Losh 2drop ( n k addr -- n ) 274ca987d46SWarner Losh; 275ca987d46SWarner Losh 276ca987d46SWarner Losh\ 277ca987d46SWarner Losh\ Kernel 278ca987d46SWarner Losh\ 279ca987d46SWarner Losh 280ca987d46SWarner Losh: init_kernel ( N -- N ) 281ca987d46SWarner Losh kernel_state @ ( n -- n k ) 282ca987d46SWarner Losh init_cyclestate ( n k -- n ) 283ca987d46SWarner Losh; 284ca987d46SWarner Losh 285ca987d46SWarner Losh: activate_kernel ( N -- N ) 286ca987d46SWarner Losh dup cycle_stateN @ ( n -- n n2 ) 287ca987d46SWarner Losh dup kernel_state ! ( n n2 -- n n2 ) \ copy for re-initialization 288ca987d46SWarner Losh 48 + ( n n2 -- n n2' ) \ kernel_state to ASCII num 289ca987d46SWarner Losh 290ca987d46SWarner Losh s" set kernel=${kernel_prefix}${kernel[N]}${kernel_suffix}" 291ca987d46SWarner Losh 36 +c! ( n n2 c-addr/u -- n c-addr/u ) \ 'N' to ASCII num 292ca987d46SWarner Losh evaluate ( n c-addr/u -- n ) \ sets $kernel to full kernel-path 293ca987d46SWarner Losh; 294ca987d46SWarner Losh 295ca987d46SWarner Losh: cycle_kernel ( N -- N TRUE ) 296ca987d46SWarner Losh cycle_menuitem \ cycle cycle_stateN to next value 297ca987d46SWarner Losh activate_kernel \ apply current cycle_stateN 298ca987d46SWarner Losh menu-redraw \ redraw menu 299ca987d46SWarner Losh TRUE \ loop menu again 300ca987d46SWarner Losh; 301ca987d46SWarner Losh 302ca987d46SWarner Losh\ 303ca987d46SWarner Losh\ Root 304ca987d46SWarner Losh\ 305ca987d46SWarner Losh 306ca987d46SWarner Losh: init_root ( N -- N ) 307ca987d46SWarner Losh root_state @ ( n -- n k ) 308ca987d46SWarner Losh init_cyclestate ( n k -- n ) 309ca987d46SWarner Losh; 310ca987d46SWarner Losh 311ca987d46SWarner Losh: activate_root ( N -- N ) 312ca987d46SWarner Losh dup cycle_stateN @ ( n -- n n2 ) 313ca987d46SWarner Losh dup root_state ! ( n n2 -- n n2 ) \ copy for re-initialization 314ca987d46SWarner Losh 48 + ( n n2 -- n n2' ) \ root_state to ASCII num 315ca987d46SWarner Losh 316ca987d46SWarner Losh s" set root=${root_prefix}${root[N]}${root_suffix}" 317ca987d46SWarner Losh 30 +c! ( n n2 c-addr/u -- n c-addr/u ) \ 'N' to ASCII num 318ca987d46SWarner Losh evaluate ( n c-addr/u -- n ) \ sets $root to full kernel-path 319ca987d46SWarner Losh; 320ca987d46SWarner Losh 321ca987d46SWarner Losh: cycle_root ( N -- N TRUE ) 322ca987d46SWarner Losh cycle_menuitem \ cycle cycle_stateN to next value 323ca987d46SWarner Losh activate_root \ apply current cycle_stateN 324ca987d46SWarner Losh menu-redraw \ redraw menu 325ca987d46SWarner Losh TRUE \ loop menu again 326ca987d46SWarner Losh; 327ca987d46SWarner Losh 328ca987d46SWarner Losh\ 329ca987d46SWarner Losh\ Menusets 330ca987d46SWarner Losh\ 331ca987d46SWarner Losh 332ca987d46SWarner Losh: goto_menu ( N M -- N TRUE ) 333ca987d46SWarner Losh menu-unset 334ca987d46SWarner Losh menuset-loadsetnum ( n m -- n ) 335ca987d46SWarner Losh menu-redraw 336ca987d46SWarner Losh TRUE \ Loop menu again 337ca987d46SWarner Losh; 338ca987d46SWarner Losh 339ca987d46SWarner Losh\ 340ca987d46SWarner Losh\ Defaults 341ca987d46SWarner Losh\ 342ca987d46SWarner Losh 343ca987d46SWarner Losh: set_default_boot_options ( N -- N TRUE ) 344ca987d46SWarner Losh acpi_enable 345ca987d46SWarner Losh safemode_disable 346ca987d46SWarner Losh singleuser_disable 347ca987d46SWarner Losh verbose_disable 348ca987d46SWarner Losh 2 goto_menu 349ca987d46SWarner Losh; 350ca987d46SWarner Losh 351ca987d46SWarner Losh\ 352ca987d46SWarner Losh\ Set boot environment defaults 353ca987d46SWarner Losh\ 354ca987d46SWarner Losh 355ca987d46SWarner Losh: init_bootenv ( -- ) 356ca987d46SWarner Losh s" set menu_caption[1]=${bemenu_current}${vfs.root.mountfrom}" evaluate 357ca987d46SWarner Losh s" set ansi_caption[1]=${beansi_current}${vfs.root.mountfrom}" evaluate 358ca987d46SWarner Losh s" set menu_caption[2]=${bemenu_bootfs}${zfs_be_active}" evaluate 359ca987d46SWarner Losh s" set ansi_caption[2]=${beansi_bootfs}${zfs_be_active}" evaluate 360ca987d46SWarner Losh s" set menu_caption[3]=${bemenu_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate 361ca987d46SWarner Losh s" set ansi_caption[3]=${beansi_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate 362ca987d46SWarner Losh; 363ca987d46SWarner Losh 364ca987d46SWarner Losh\ 365ca987d46SWarner Losh\ Redraw the entire screen. A long BE name can corrupt the menu 366ca987d46SWarner Losh\ 367ca987d46SWarner Losh 368ca987d46SWarner Losh: be_draw_screen 369ca987d46SWarner Losh clear \ Clear the screen (in screen.4th) 370ca987d46SWarner Losh print_version \ print version string (bottom-right; see version.4th) 371ca987d46SWarner Losh draw-beastie \ Draw FreeBSD logo at right (in beastie.4th) 372ca987d46SWarner Losh draw-brand \ Draw brand.4th logo at top (in brand.4th) 373ca987d46SWarner Losh menu-init \ Initialize menu and draw bounding box (in menu.4th) 374ca987d46SWarner Losh; 375ca987d46SWarner Losh 376ca987d46SWarner Losh\ 377ca987d46SWarner Losh\ Select a boot environment 378ca987d46SWarner Losh\ 379ca987d46SWarner Losh 380ca987d46SWarner Losh: set_bootenv ( N -- N TRUE ) 381ca987d46SWarner Losh dup s" set vfs.root.mountfrom=${bootenv_root[E]}" 38 +c! evaluate 382ca987d46SWarner Losh s" set currdev=${vfs.root.mountfrom}:" evaluate 383ca987d46SWarner Losh s" unload" evaluate 384ca987d46SWarner Losh free-module-options 385ca987d46SWarner Losh s" /boot/defaults/loader.conf" read-conf 386ca987d46SWarner Losh s" /boot/loader.conf" read-conf 387ca987d46SWarner Losh s" /boot/loader.conf.local" read-conf 388ca987d46SWarner Losh init_bootenv 389ca987d46SWarner Losh be_draw_screen 390ca987d46SWarner Losh menu-redraw 391ca987d46SWarner Losh TRUE 392ca987d46SWarner Losh; 393ca987d46SWarner Losh 394ca987d46SWarner Losh\ 395ca987d46SWarner Losh\ Switch to the next page of boot environments 396ca987d46SWarner Losh\ 397ca987d46SWarner Losh 398ca987d46SWarner Losh: set_be_page ( N -- N TRUE ) 399ca987d46SWarner Losh s" zfs_be_currpage" getenv dup -1 = if 400ca987d46SWarner Losh drop s" 1" 401ca987d46SWarner Losh else 402ca987d46SWarner Losh 0 s>d 2swap 403ca987d46SWarner Losh >number ( ud caddr/u -- ud' caddr'/u' ) \ convert string to numbers 404ca987d46SWarner Losh 2drop \ drop the string 405ca987d46SWarner Losh 1 um/mod ( ud u1 -- u2 u3 ) \ convert double ud' to single u3' and remainder u2 406ca987d46SWarner Losh swap drop ( ud2 u3 -- u3 ) \ drop the remainder u2 407ca987d46SWarner Losh 1+ \ increment the page number 408ca987d46SWarner Losh s>d <# #s #> \ convert back to a string 409ca987d46SWarner Losh then 410ca987d46SWarner Losh s" zfs_be_currpage" setenv 411ca987d46SWarner Losh s" reloadbe" evaluate 412ca987d46SWarner Losh 3 goto_menu 413ca987d46SWarner Losh; 414ca987d46SWarner Losh 415ca987d46SWarner Loshonly forth definitions 416