iPXE
Data Structures | Functions
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 <ipxe/console.h>
#include <ipxe/dhcp.h>
#include <ipxe/keys.h>
#include <ipxe/timer.h>
#include <ipxe/uri.h>
#include <ipxe/ansicol.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...
 

Functions

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

Detailed Description

PXE Boot Menus.

Definition in file pxemenu.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ pxe_menu_parse()

static int pxe_menu_parse ( struct pxe_menu **  menu)
static

Parse and allocate PXE boot menu.

Parameters
menuPXE boot menu to fill in
Return values
rcReturn status code

It is the callers responsibility to eventually free the allocated boot menu.

Definition at line 88 of file pxemenu.c.

88  {
89  struct setting pxe_boot_menu_prompt_setting =
91  struct setting pxe_boot_menu_setting =
92  { .tag = DHCP_PXE_BOOT_MENU };
93  uint8_t raw_menu[256];
94  int raw_prompt_len;
95  int raw_menu_len;
96  struct dhcp_pxe_boot_menu *raw_menu_item;
97  struct dhcp_pxe_boot_menu_prompt *raw_menu_prompt;
98  void *raw_menu_end;
99  unsigned int num_menu_items;
100  unsigned int i;
101  int rc;
102 
103  /* Fetch raw menu */
104  memset ( raw_menu, 0, sizeof ( raw_menu ) );
105  if ( ( raw_menu_len = fetch_raw_setting ( NULL, &pxe_boot_menu_setting,
106  raw_menu,
107  sizeof ( raw_menu ) ) ) < 0 ){
108  rc = raw_menu_len;
109  DBG ( "Could not retrieve raw PXE boot menu: %s\n",
110  strerror ( rc ) );
111  return rc;
112  }
113  if ( raw_menu_len >= ( int ) sizeof ( raw_menu ) ) {
114  DBG ( "Raw PXE boot menu too large for buffer\n" );
115  return -ENOSPC;
116  }
117  raw_menu_end = ( raw_menu + raw_menu_len );
118 
119  /* Fetch raw prompt length */
120  raw_prompt_len =
121  fetch_raw_setting ( NULL, &pxe_boot_menu_prompt_setting,
122  NULL, 0 );
123  if ( raw_prompt_len < 0 )
124  raw_prompt_len = 0;
125 
126  /* Count menu items */
127  num_menu_items = 0;
128  raw_menu_item = ( ( void * ) raw_menu );
129  while ( 1 ) {
130  if ( ( ( ( void * ) raw_menu_item ) +
131  sizeof ( *raw_menu_item ) ) > raw_menu_end )
132  break;
133  if ( ( ( ( void * ) raw_menu_item ) +
134  sizeof ( *raw_menu_item ) +
135  raw_menu_item->desc_len ) > raw_menu_end )
136  break;
137  num_menu_items++;
138  raw_menu_item = ( ( ( void * ) raw_menu_item ) +
139  sizeof ( *raw_menu_item ) +
140  raw_menu_item->desc_len );
141  }
142 
143  /* Allocate space for parsed menu */
144  *menu = zalloc ( sizeof ( **menu ) +
145  ( num_menu_items * sizeof ( (*menu)->items[0] ) ) +
146  raw_menu_len + 1 /* NUL */ +
147  raw_prompt_len + 1 /* NUL */ );
148  if ( ! *menu ) {
149  DBG ( "Could not allocate PXE boot menu\n" );
150  return -ENOMEM;
151  }
152 
153  /* Fill in parsed menu */
154  (*menu)->num_items = num_menu_items;
155  raw_menu_item = ( ( ( void * ) (*menu) ) + sizeof ( **menu ) +
156  ( num_menu_items * sizeof ( (*menu)->items[0] ) ) );
157  memcpy ( raw_menu_item, raw_menu, raw_menu_len );
158  for ( i = 0 ; i < num_menu_items ; i++ ) {
159  (*menu)->items[i].type = le16_to_cpu ( raw_menu_item->type );
160  (*menu)->items[i].desc = raw_menu_item->desc;
161  /* Set type to 0; this ensures that the description
162  * for the previous menu item is NUL-terminated.
163  * (Final item is NUL-terminated anyway.)
164  */
165  raw_menu_item->type = 0;
166  raw_menu_item = ( ( ( void * ) raw_menu_item ) +
167  sizeof ( *raw_menu_item ) +
168  raw_menu_item->desc_len );
169  }
170  if ( raw_prompt_len ) {
171  raw_menu_prompt = ( ( ( void * ) raw_menu_item ) +
172  1 /* NUL */ );
173  fetch_raw_setting ( NULL, &pxe_boot_menu_prompt_setting,
174  raw_menu_prompt, raw_prompt_len );
175  (*menu)->timeout =
176  ( ( raw_menu_prompt->timeout == 0xff ) ?
177  -1 : raw_menu_prompt->timeout );
178  (*menu)->prompt = raw_menu_prompt->prompt;
179  } else {
180  (*menu)->timeout = -1;
181  }
182 
183  return 0;
184 }
#define DHCP_PXE_BOOT_MENU_PROMPT
PXE boot menu prompt.
Definition: dhcp.h:140
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
uint8_t timeout
Timeout.
Definition: dhcp.h:153
PXE boot menu prompt.
Definition: dhcp.h:143
int fetch_raw_setting(struct settings *settings, const struct setting *setting, void *data, size_t len)
Fetch value of setting.
Definition: settings.c:803
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:43
#define ENOMEM
Not enough space.
Definition: errno.h:534
void * memcpy(void *dest, const void *src, size_t len) __nonnull
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
char prompt[0]
Prompt to press F8.
Definition: dhcp.h:155
unsigned char uint8_t
Definition: stdint.h:10
#define DHCP_PXE_BOOT_MENU
PXE boot menu.
Definition: dhcp.h:127
#define le16_to_cpu(value)
Definition: byteswap.h:112
A setting.
Definition: settings.h:23
#define ENOSPC
No space left on device.
Definition: errno.h:549
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
A menu.
Definition: menu.h:15
PXE boot menu.
Definition: dhcp.h:130
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
void * memset(void *dest, int character, size_t len) __nonnull

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_raw_setting(), le16_to_cpu, memcpy(), memset(), NULL, dhcp_pxe_boot_menu_prompt::prompt, rc, strerror(), setting::tag, dhcp_pxe_boot_menu_prompt::timeout, dhcp_pxe_boot_menu::type, and zalloc().

Referenced by pxe_menu_boot().

◆ pxe_menu_draw_item()

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

Draw PXE boot menu item.

Parameters
menuPXE boot menu
indexIndex of item to draw
selectedItem is selected

Definition at line 193 of file pxemenu.c.

194  {
195  char buf[COLS+1];
196  size_t len;
197  unsigned int row;
198 
199  /* Prepare space-padded row content */
200  len = snprintf ( buf, sizeof ( buf ), " %c. %s",
201  ( 'A' + index ), menu->items[index].desc );
202  while ( len < ( sizeof ( buf ) - 1 ) )
203  buf[len++] = ' ';
204  buf[ sizeof ( buf ) - 1 ] = '\0';
205 
206  /* Draw row */
207  row = ( LINES - menu->num_items + index - 1 );
208  color_set ( ( selected ? CPAIR_PXE : CPAIR_DEFAULT ), NULL );
209  mvprintw ( row, 0, "%s", buf );
210  move ( row, 1 );
211 }
#define mvprintw(y, x, fmt,...)
Definition: curses.h:648
struct list_head items
Menu items.
Definition: menu.h:23
#define LINES(...)
Define inline lines.
Definition: linebuf_test.c:44
#define CPAIR_PXE
PXE selected menu entry.
Definition: ansicol.h:58
#define COLS
Definition: curses.h:111
#define CPAIR_DEFAULT
Default colour pair.
Definition: ansicol.h:37
uint32_t len
Length.
Definition: ena.h:14
static int move(int y, int x)
Definition: curses.h:593
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:382
#define color_set(cpno, opts)
Definition: curses.h:240
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
A menu.
Definition: menu.h:15
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321

References color_set, COLS, CPAIR_DEFAULT, CPAIR_PXE, index, menu::items, len, LINES, move(), mvprintw, NULL, and snprintf().

Referenced by pxe_menu_select().

◆ pxe_menu_select()

static int pxe_menu_select ( struct pxe_menu menu)
static

Make selection from PXE boot menu.

Parameters
menuPXE boot menu
Return values
rcReturn status code

Definition at line 219 of file pxemenu.c.

219  {
220  int key;
221  unsigned int key_selection;
222  unsigned int i;
223  int rc = 0;
224 
225  /* Initialise UI */
226  initscr();
227  start_color();
229 
230  /* Draw initial menu */
231  for ( i = 0 ; i < menu->num_items ; i++ )
232  printf ( "\n" );
233  for ( i = 0 ; i < menu->num_items ; i++ )
234  pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ), 0 );
235 
236  while ( 1 ) {
237 
238  /* Highlight currently selected item */
239  pxe_menu_draw_item ( menu, menu->selection, 1 );
240 
241  /* Wait for keyboard input */
242  key = getkey ( 0 );
243 
244  /* Unhighlight currently selected item */
245  pxe_menu_draw_item ( menu, menu->selection, 0 );
246 
247  /* Act upon key */
248  if ( ( key == CR ) || ( key == LF ) ) {
249  pxe_menu_draw_item ( menu, menu->selection, 1 );
250  break;
251  } else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
252  rc = -ECANCELED;
253  break;
254  } else if ( key == KEY_UP ) {
255  if ( menu->selection > 0 )
256  menu->selection--;
257  } else if ( key == KEY_DOWN ) {
258  if ( menu->selection < ( menu->num_items - 1 ) )
259  menu->selection++;
260  } else if ( ( key < KEY_MIN ) &&
261  ( ( key_selection = ( toupper ( key ) - 'A' ) )
262  < menu->num_items ) ) {
263  menu->selection = key_selection;
264  pxe_menu_draw_item ( menu, menu->selection, 1 );
265  break;
266  }
267  }
268 
269  /* Shut down UI */
270  endwin();
271 
272  return rc;
273 }
int getkey(unsigned long timeout)
Get single keypress.
Definition: getkey.c:71
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
#define start_color()
Definition: curses.h:396
int endwin(void)
Finalise console environment.
Definition: wininit.c:31
#define ECANCELED
Operation canceled.
Definition: errno.h:343
static int toupper(int character)
Convert character to upper case.
Definition: ctype.h:120
#define KEY_DOWN
Down arrow.
Definition: keys.h:105
#define KEY_MIN
Minimum value for special keypresses.
Definition: keys.h:68
#define KEY_UP
Up arrow.
Definition: keys.h:104
WINDOW * initscr(void)
Initialise console environment.
Definition: wininit.c:17
static void pxe_menu_draw_item(struct pxe_menu *menu, unsigned int index, int selected)
Draw PXE boot menu item.
Definition: pxemenu.c:193
#define CTRL_C
Definition: keys.h:20
#define ESC
Escape character.
Definition: ansiesc.h:92
#define LF
Definition: keys.h:47
#define CPAIR_DEFAULT
Default colour pair.
Definition: ansicol.h:37
#define CR
Definition: keys.h:48
#define color_set(cpno, opts)
Definition: curses.h:240
A menu.
Definition: menu.h:15
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
union @382 key
Sense key.
Definition: crypto.h:284

References color_set, CPAIR_DEFAULT, CR, CTRL_C, ECANCELED, endwin(), ESC, getkey(), initscr(), key, KEY_DOWN, KEY_MIN, KEY_UP, LF, NULL, printf(), pxe_menu_draw_item(), rc, start_color, and toupper().

Referenced by pxe_menu_prompt_and_select().

◆ pxe_menu_prompt_and_select()

static int pxe_menu_prompt_and_select ( struct pxe_menu menu)
static

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

Parameters
menuPXE boot menu
Return values
rcReturn status code

Definition at line 281 of file pxemenu.c.

281  {
282  unsigned long start = currticks();
283  unsigned long now;
284  unsigned long elapsed;
285  size_t len = 0;
286  int key;
287  int rc = 0;
288 
289  /* Display menu immediately, if specified to do so */
290  if ( menu->timeout < 0 ) {
291  if ( menu->prompt )
292  printf ( "%s\n", menu->prompt );
293  return pxe_menu_select ( menu );
294  }
295 
296  /* Display prompt, if specified */
297  if ( menu->prompt )
298  printf ( "%s", menu->prompt );
299 
300  /* Wait for timeout, if specified */
301  while ( menu->timeout > 0 ) {
302  if ( ! len )
303  len = printf ( " (%d)", menu->timeout );
304  if ( iskey() ) {
305  key = getkey ( 0 );
306  if ( key == KEY_F8 ) {
307  /* Display menu */
308  printf ( "\n" );
309  return pxe_menu_select ( menu );
310  } else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
311  /* Abort */
312  rc = -ECANCELED;
313  break;
314  } else {
315  /* Stop waiting */
316  break;
317  }
318  }
319  now = currticks();
320  elapsed = ( now - start );
321  if ( elapsed >= TICKS_PER_SEC ) {
322  menu->timeout -= 1;
323  do {
324  printf ( "\b \b" );
325  } while ( --len );
326  start = now;
327  }
328  }
329 
330  /* Return with default option selected */
331  printf ( "\n" );
332  return rc;
333 }
int getkey(unsigned long timeout)
Get single keypress.
Definition: getkey.c:71
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define TICKS_PER_SEC
Number of ticks per second.
Definition: timer.h:15
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
#define KEY_F8
F8 (for PXE)
Definition: keys.h:117
#define ECANCELED
Operation canceled.
Definition: errno.h:343
uint32_t start
Starting offset.
Definition: netvsc.h:12
#define CTRL_C
Definition: keys.h:20
#define ESC
Escape character.
Definition: ansiesc.h:92
static int pxe_menu_select(struct pxe_menu *menu)
Make selection from PXE boot menu.
Definition: pxemenu.c:219
uint32_t len
Length.
Definition: ena.h:14
unsigned long currticks(void)
Get current system time in ticks.
Definition: timer.c:42
A menu.
Definition: menu.h:15
int iskey(void)
Check for available input on any console.
Definition: console.c:130
union @382 key
Sense key.
Definition: crypto.h:284

References CTRL_C, currticks(), ECANCELED, ESC, getkey(), iskey(), key, KEY_F8, len, printf(), pxe_menu_select(), rc, start, and TICKS_PER_SEC.

Referenced by pxe_menu_boot().

◆ pxe_menu_boot()

int pxe_menu_boot ( struct net_device netdev)

Boot using PXE boot menu.

Return values
rcReturn 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 344 of file pxemenu.c.

344  {
345  struct pxe_menu *menu;
346  unsigned int pxe_type;
347  struct settings *pxebs_settings;
348  struct uri *uri;
349  int rc;
350 
351  /* Parse and allocate boot menu */
352  if ( ( rc = pxe_menu_parse ( &menu ) ) != 0 )
353  return rc;
354 
355  /* Make selection from boot menu */
356  if ( ( rc = pxe_menu_prompt_and_select ( menu ) ) != 0 ) {
357  free ( menu );
358  return rc;
359  }
360  pxe_type = menu->items[menu->selection].type;
361 
362  /* Free boot menu */
363  free ( menu );
364 
365  /* Return immediately if local boot selected */
366  if ( ! pxe_type )
367  return 0;
368 
369  /* Attempt PXE Boot Server Discovery */
370  if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 )
371  return rc;
372 
373  /* Fetch next server and filename */
374  pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
375  assert ( pxebs_settings );
376  uri = fetch_next_server_and_filename ( pxebs_settings );
377  if ( ! uri )
378  return -ENOMEM;
379 
380  /* Attempt boot */
381  rc = uriboot ( uri, NULL, 0, 0, NULL, URIBOOT_NO_SAN );
382  uri_put ( uri );
383  return rc;
384 }
int uriboot(struct uri *filename, struct uri **root_paths, unsigned int root_path_count, int drive, struct san_boot_config *san_config, unsigned int flags)
Boot from filename and root-path URIs.
Definition: autoboot.c:129
#define URIBOOT_NO_SAN
Definition: autoboot.h:26
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
A PXE boot menu.
Definition: pxemenu.c:63
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition: uri.h:205
static int pxe_menu_prompt_and_select(struct pxe_menu *menu)
Prompt for (and make selection from) PXE boot menu.
Definition: pxemenu.c:281
struct list_head items
Menu items.
Definition: menu.h:23
#define ENOMEM
Not enough space.
Definition: errno.h:534
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
struct uri * fetch_next_server_and_filename(struct settings *settings)
Fetch next-server and filename settings into a URI.
Definition: autoboot.c:241
static struct net_device * netdev
Definition: gdbudp.c:52
#define PXEBS_SETTINGS_NAME
Setting block name used for BootServerDHCP responses.
Definition: dhcp.h:714
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
A settings block.
Definition: settings.h:132
static int pxe_menu_parse(struct pxe_menu **menu)
Parse and allocate PXE boot menu.
Definition: pxemenu.c:88
struct settings * find_settings(const char *name)
Find settings block.
Definition: settings.c:406
A Uniform Resource Identifier.
Definition: uri.h:64
A menu.
Definition: menu.h:15
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
int pxebs(struct net_device *netdev, unsigned int pxe_type)
Definition: dhcpmgmt.c:41

References assert(), ENOMEM, fetch_next_server_and_filename(), find_settings(), free, menu::items, netdev, NULL, pxe_menu_parse(), pxe_menu_prompt_and_select(), pxebs(), PXEBS_SETTINGS_NAME, rc, uri_put(), uriboot(), and URIBOOT_NO_SAN.