pxemenu.c File Reference

PXE Boot Menus. More...

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <byteswap.h>
#include <curses.h>
#include <console.h>
#include <gpxe/dhcp.h>
#include <gpxe/keys.h>
#include <gpxe/timer.h>
#include <gpxe/process.h>
#include <usr/dhcpmgmt.h>
#include <usr/autoboot.h>

Go to the source code of this file.

Data Structures

struct  pxe_menu_item
 A PXE boot menu item. More...
struct  pxe_menu
 A PXE boot menu. More...

Defines

#define CPAIR_NORMAL   1
#define CPAIR_SELECT   2

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static int pxe_menu_parse (struct pxe_menu **menu)
 Parse and allocate PXE boot menu.
static void pxe_menu_draw_item (struct pxe_menu *menu, unsigned int index, int selected)
 Draw PXE boot menu item.
static int pxe_menu_select (struct pxe_menu *menu)
 Make selection from PXE boot menu.
static int pxe_menu_prompt_and_select (struct pxe_menu *menu)
 Prompt for (and make selection from) PXE boot menu.
int pxe_menu_boot (struct net_device *netdev)
 Boot using PXE boot menu.


Detailed Description

PXE Boot Menus.

Definition in file pxemenu.c.


Define Documentation

#define CPAIR_NORMAL   1

Definition at line 44 of file pxemenu.c.

#define CPAIR_SELECT   2

Definition at line 45 of file pxemenu.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

static int pxe_menu_parse ( struct pxe_menu **  menu  )  [static]

Parse and allocate PXE boot menu.

Parameters:
menu PXE boot menu to fill in
Return values:
rc Return status code
It is the callers responsibility to eventually free the allocated boot menu.

Definition at line 86 of file pxemenu.c.

References DBG, dhcp_pxe_boot_menu::desc, dhcp_pxe_boot_menu::desc_len, DHCP_PXE_BOOT_MENU, DHCP_PXE_BOOT_MENU_PROMPT, ENOMEM, ENOSPC, fetch_setting(), fetch_setting_len(), le16_to_cpu, memcpy, memset(), NULL, dhcp_pxe_boot_menu_prompt::prompt, strerror(), setting::tag, dhcp_pxe_boot_menu_prompt::timeout, dhcp_pxe_boot_menu::type, and zalloc().

Referenced by pxe_menu_boot().

00086                                                      {
00087         struct setting pxe_boot_menu_prompt_setting =
00088                 { .tag = DHCP_PXE_BOOT_MENU_PROMPT };
00089         struct setting pxe_boot_menu_setting =
00090                 { .tag = DHCP_PXE_BOOT_MENU };
00091         uint8_t raw_menu[256];
00092         int raw_prompt_len;
00093         int raw_menu_len;
00094         struct dhcp_pxe_boot_menu *raw_menu_item;
00095         struct dhcp_pxe_boot_menu_prompt *raw_menu_prompt;
00096         void *raw_menu_end;
00097         unsigned int num_menu_items;
00098         unsigned int i;
00099         int rc;
00100 
00101         /* Fetch raw menu */
00102         memset ( raw_menu, 0, sizeof ( raw_menu ) );
00103         if ( ( raw_menu_len = fetch_setting ( NULL, &pxe_boot_menu_setting,
00104                                               raw_menu,
00105                                               sizeof ( raw_menu ) ) ) < 0 ) {
00106                 rc = raw_menu_len;
00107                 DBG ( "Could not retrieve raw PXE boot menu: %s\n",
00108                       strerror ( rc ) );
00109                 return rc;
00110         }
00111         if ( raw_menu_len >= ( int ) sizeof ( raw_menu ) ) {
00112                 DBG ( "Raw PXE boot menu too large for buffer\n" );
00113                 return -ENOSPC;
00114         }
00115         raw_menu_end = ( raw_menu + raw_menu_len );
00116 
00117         /* Fetch raw prompt length */
00118         raw_prompt_len = fetch_setting_len ( NULL,
00119                                              &pxe_boot_menu_prompt_setting );
00120         if ( raw_prompt_len < 0 )
00121                 raw_prompt_len = 0;
00122 
00123         /* Count menu items */
00124         num_menu_items = 0;
00125         raw_menu_item = ( ( void * ) raw_menu );
00126         while ( 1 ) {
00127                 if ( ( ( ( void * ) raw_menu_item ) +
00128                        sizeof ( *raw_menu_item ) ) > raw_menu_end )
00129                         break;
00130                 if ( ( ( ( void * ) raw_menu_item ) +
00131                        sizeof ( *raw_menu_item ) +
00132                        raw_menu_item->desc_len ) > raw_menu_end )
00133                         break;
00134                 num_menu_items++;
00135                 raw_menu_item = ( ( ( void * ) raw_menu_item ) +
00136                                   sizeof ( *raw_menu_item ) +
00137                                   raw_menu_item->desc_len );
00138         }
00139 
00140         /* Allocate space for parsed menu */
00141         *menu = zalloc ( sizeof ( **menu ) +
00142                          ( num_menu_items * sizeof ( (*menu)->items[0] ) ) +
00143                          raw_menu_len + 1 /* NUL */ +
00144                          raw_prompt_len + 1 /* NUL */ );
00145         if ( ! *menu ) {
00146                 DBG ( "Could not allocate PXE boot menu\n" );
00147                 return -ENOMEM;
00148         }
00149 
00150         /* Fill in parsed menu */
00151         (*menu)->num_items = num_menu_items;
00152         raw_menu_item = ( ( ( void * ) (*menu) ) + sizeof ( **menu ) +
00153                           ( num_menu_items * sizeof ( (*menu)->items[0] ) ) );
00154         memcpy ( raw_menu_item, raw_menu, raw_menu_len );
00155         for ( i = 0 ; i < num_menu_items ; i++ ) {
00156                 (*menu)->items[i].type = le16_to_cpu ( raw_menu_item->type );
00157                 (*menu)->items[i].desc = raw_menu_item->desc;
00158                 /* Set type to 0; this ensures that the description
00159                  * for the previous menu item is NUL-terminated.
00160                  * (Final item is NUL-terminated anyway.)
00161                  */
00162                 raw_menu_item->type = 0;
00163                 raw_menu_item = ( ( ( void * ) raw_menu_item ) +
00164                                   sizeof ( *raw_menu_item ) +
00165                                   raw_menu_item->desc_len );
00166         }
00167         if ( raw_prompt_len ) {
00168                 raw_menu_prompt = ( ( ( void * ) raw_menu_item ) +
00169                                     1 /* NUL */ );
00170                 fetch_setting ( NULL, &pxe_boot_menu_prompt_setting,
00171                                 raw_menu_prompt, raw_prompt_len );
00172                 (*menu)->timeout =
00173                         ( ( raw_menu_prompt->timeout == 0xff ) ?
00174                           -1 : raw_menu_prompt->timeout );
00175                 (*menu)->prompt = raw_menu_prompt->prompt;
00176         } else {
00177                 (*menu)->timeout = -1;
00178         }
00179 
00180         return 0;
00181 }

static void pxe_menu_draw_item ( struct pxe_menu menu,
unsigned int  index,
int  selected 
) [static]

Draw PXE boot menu item.

Parameters:
menu PXE boot menu
index Index of item to draw
selected Item is selected

Definition at line 190 of file pxemenu.c.

References color_set, COLS, CPAIR_NORMAL, CPAIR_SELECT, pxe_menu_item::desc, pxe_menu::items, LINES, move(), mvprintw, NULL, pxe_menu::num_items, and snprintf().

Referenced by pxe_menu_select().

00191                                                                     {
00192         char buf[COLS+1];
00193         size_t len;
00194         unsigned int row;
00195 
00196         /* Prepare space-padded row content */
00197         len = snprintf ( buf, sizeof ( buf ), " %c. %s",
00198                          ( 'A' + index ), menu->items[index].desc );
00199         while ( len < ( sizeof ( buf ) - 1 ) )
00200                 buf[len++] = ' ';
00201         buf[ sizeof ( buf ) - 1 ] = '\0';
00202 
00203         /* Draw row */
00204         row = ( LINES - menu->num_items + index );
00205         color_set ( ( selected ? CPAIR_SELECT : CPAIR_NORMAL ), NULL );
00206         mvprintw ( row, 0, "%s", buf );
00207         move ( row, 1 );
00208 }

static int pxe_menu_select ( struct pxe_menu menu  )  [static]

Make selection from PXE boot menu.

Parameters:
menu PXE boot menu
Return values:
rc Return status code

Definition at line 216 of file pxemenu.c.

References COLOR_BLACK, color_set, COLOR_WHITE, CPAIR_NORMAL, CPAIR_SELECT, CR, CTRL_C, ECANCELED, endwin(), ESC, getkey(), init_pair(), initscr(), iskey(), KEY_DOWN, KEY_MIN, KEY_UP, LF, NULL, pxe_menu::num_items, printf(), pxe_menu_draw_item(), pxe_menu::selection, start_color, step(), and toupper().

Referenced by pxe_menu_prompt_and_select().

00216                                                      {
00217         int key;
00218         unsigned int key_selection;
00219         unsigned int i;
00220         int rc = 0;
00221 
00222         /* Initialise UI */
00223         initscr();
00224         start_color();
00225         init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
00226         init_pair ( CPAIR_SELECT, COLOR_BLACK, COLOR_WHITE );
00227         color_set ( CPAIR_NORMAL, NULL );
00228 
00229         /* Draw initial menu */
00230         for ( i = 0 ; i < menu->num_items ; i++ )
00231                 printf ( "\n" );
00232         for ( i = 0 ; i < menu->num_items ; i++ )
00233                 pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ), 0 );
00234 
00235         while ( 1 ) {
00236 
00237                 /* Highlight currently selected item */
00238                 pxe_menu_draw_item ( menu, menu->selection, 1 );
00239 
00240                 /* Wait for keyboard input */
00241                 while ( ! iskey() )
00242                         step();
00243                 key = getkey();
00244 
00245                 /* Unhighlight currently selected item */
00246                 pxe_menu_draw_item ( menu, menu->selection, 0 );
00247 
00248                 /* Act upon key */
00249                 if ( ( key == CR ) || ( key == LF ) ) {
00250                         pxe_menu_draw_item ( menu, menu->selection, 1 );
00251                         break;
00252                 } else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
00253                         rc = -ECANCELED;
00254                         break;
00255                 } else if ( key == KEY_UP ) {
00256                         if ( menu->selection > 0 )
00257                                 menu->selection--;
00258                 } else if ( key == KEY_DOWN ) {
00259                         if ( menu->selection < ( menu->num_items - 1 ) )
00260                                 menu->selection++;
00261                 } else if ( ( key < KEY_MIN ) &&
00262                             ( ( key_selection = ( toupper ( key ) - 'A' ) )
00263                               < menu->num_items ) ) {
00264                         menu->selection = key_selection;
00265                         pxe_menu_draw_item ( menu, menu->selection, 1 );
00266                         break;
00267                 }
00268         }
00269 
00270         /* Shut down UI */
00271         endwin();
00272 
00273         return rc;
00274 }

static int pxe_menu_prompt_and_select ( struct pxe_menu menu  )  [static]

Prompt for (and make selection from) PXE boot menu.

Parameters:
menu PXE boot menu
Return values:
rc Return status code

Definition at line 282 of file pxemenu.c.

References CTRL_C, currticks(), ECANCELED, ESC, getkey(), iskey(), KEY_F8, printf(), pxe_menu::prompt, pxe_menu_select(), TICKS_PER_SEC, and pxe_menu::timeout.

Referenced by pxe_menu_boot().

00282                                                                 {
00283         unsigned long start = currticks();
00284         unsigned long now;
00285         unsigned long elapsed;
00286         size_t len = 0;
00287         int key;
00288         int rc = 0;
00289 
00290         /* Display menu immediately, if specified to do so */
00291         if ( menu->timeout < 0 ) {
00292                 if ( menu->prompt )
00293                         printf ( "%s\n", menu->prompt );
00294                 return pxe_menu_select ( menu );
00295         }
00296 
00297         /* Display prompt, if specified */
00298         if ( menu->prompt )
00299                 printf ( "%s", menu->prompt );
00300 
00301         /* Wait for timeout, if specified */
00302         while ( menu->timeout > 0 ) {
00303                 if ( ! len )
00304                         len = printf ( " (%d)", menu->timeout );
00305                 if ( iskey() ) {
00306                         key = getkey();
00307                         if ( key == KEY_F8 ) {
00308                                 /* Display menu */
00309                                 printf ( "\n" );
00310                                 return pxe_menu_select ( menu );
00311                         } else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
00312                                 /* Abort */
00313                                 rc = -ECANCELED;
00314                                 break;
00315                         } else {
00316                                 /* Stop waiting */
00317                                 break;
00318                         }
00319                 }
00320                 now = currticks();
00321                 elapsed = ( now - start );
00322                 if ( elapsed >= TICKS_PER_SEC ) {
00323                         menu->timeout -= 1;
00324                         do {
00325                                 printf ( "\b \b" );
00326                         } while ( --len );
00327                         start = now;
00328                 }
00329         }
00330 
00331         /* Return with default option selected */
00332         printf ( "\n" );
00333         return rc;
00334 }

int pxe_menu_boot ( struct net_device netdev  ) 

Boot using PXE boot menu.

Return values:
rc Return status code
Note that a success return status indicates that a PXE boot menu item has been selected, and that the DHCP session should perform a boot server request/ack.

Definition at line 345 of file pxemenu.c.

References assert, boot_next_server_and_filename(), fetch_ipv4_setting(), fetch_string_setting(), find_settings(), free(), pxe_menu::items, pxe_menu_parse(), pxe_menu_prompt_and_select(), pxebs(), PXEBS_SETTINGS_NAME, pxe_menu::selection, and pxe_menu_item::type.

Referenced by netboot().

00345                                                 {
00346         struct pxe_menu *menu;
00347         unsigned int pxe_type;
00348         struct settings *pxebs_settings;
00349         struct in_addr next_server;
00350         char filename[256];
00351         int rc;
00352 
00353         /* Parse and allocate boot menu */
00354         if ( ( rc = pxe_menu_parse ( &menu ) ) != 0 )
00355                 return rc;
00356 
00357         /* Make selection from boot menu */
00358         if ( ( rc = pxe_menu_prompt_and_select ( menu ) ) != 0 ) {
00359                 free ( menu );
00360                 return rc;
00361         }
00362         pxe_type = menu->items[menu->selection].type;
00363 
00364         /* Free boot menu */
00365         free ( menu );
00366 
00367         /* Return immediately if local boot selected */
00368         if ( ! pxe_type )
00369                 return 0;
00370 
00371         /* Attempt PXE Boot Server Discovery */
00372         if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 )
00373                 return rc;
00374 
00375         /* Attempt boot */
00376         pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
00377         assert ( pxebs_settings );
00378         fetch_ipv4_setting ( pxebs_settings, &next_server_setting,
00379                              &next_server );
00380         fetch_string_setting ( pxebs_settings, &filename_setting,
00381                                filename, sizeof ( filename ) );
00382         return boot_next_server_and_filename ( next_server, filename );
00383 }


Generated on Tue Apr 6 20:01:57 2010 for gPXE by  doxygen 1.5.7.1