iPXE
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.
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.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ pxe_menu_parse()

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 NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define DHCP_PXE_BOOT_MENU_PROMPT
PXE boot menu prompt.
Definition dhcp.h:140
#define DHCP_PXE_BOOT_MENU
PXE boot menu.
Definition dhcp.h:127
#define ENOSPC
No space left on device.
Definition errno.h:550
#define ENOMEM
Not enough space.
Definition errno.h:535
#define le16_to_cpu(value)
Definition byteswap.h:113
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
int fetch_raw_setting(struct settings *settings, const struct setting *setting, void *data, size_t len)
Fetch value of setting.
Definition settings.c:804
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
PXE boot menu prompt.
Definition dhcp.h:143
uint8_t timeout
Timeout.
Definition dhcp.h:153
char prompt[0]
Prompt to press F8.
Definition dhcp.h:155
PXE boot menu.
Definition dhcp.h:130
A setting.
Definition settings.h:24

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(), dhcp_pxe_boot_menu_prompt::timeout, dhcp_pxe_boot_menu::type, and zalloc().

Referenced by pxe_menu_boot().

◆ pxe_menu_draw_item()

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}
long index
Definition bigint.h:65
#define mvprintw(y, x, fmt,...)
Definition curses.h:649
static int move(int y, int x)
Definition curses.h:594
#define color_set(cpno, opts)
Definition curses.h:241
ring len
Length.
Definition dwmac.h:226
#define CPAIR_DEFAULT
Default colour pair.
Definition ansicol.h:38
#define CPAIR_PXE
PXE selected menu entry.
Definition ansicol.h:59
#define LINES(...)
Define inline lines.
char * desc
Description.
Definition pxemenu.c:54
unsigned int num_items
Number of menu items.
Definition pxemenu.c:72
struct pxe_menu_item items[0]
Menu items.
Definition pxemenu.c:76
#define COLS
Definition vga.h:27
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383

References color_set, COLS, CPAIR_DEFAULT, CPAIR_PXE, pxe_menu_item::desc, index, pxe_menu::items, len, LINES, move(), mvprintw, NULL, pxe_menu::num_items, and snprintf().

Referenced by pxe_menu_select().

◆ pxe_menu_select()

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}
union @162305117151260234136356364136041353210355154177 key
Sense key.
Definition scsi.h:3
#define ESC
Escape character.
Definition ansiesc.h:93
static int toupper(int character)
Convert character to upper case.
Definition ctype.h:121
#define start_color()
Definition curses.h:397
int getkey(unsigned long timeout)
Get single keypress.
Definition getkey.c:72
#define ECANCELED
Operation canceled.
Definition errno.h:344
#define KEY_DOWN
Down arrow.
Definition keys.h:107
#define LF
Definition keys.h:48
#define CTRL_C
Definition keys.h:21
#define CR
Definition keys.h:49
#define KEY_MIN
Minimum value for special keypresses.
Definition keys.h:70
#define KEY_UP
Up arrow.
Definition keys.h:106
static void pxe_menu_draw_item(struct pxe_menu *menu, unsigned int index, int selected)
Draw PXE boot menu item.
Definition pxemenu.c:193
unsigned int selection
Selected menu item.
Definition pxemenu.c:74
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:465
WINDOW * initscr(void)
Initialise console environment.
Definition wininit.c:18
int endwin(void)
Finalise console environment.
Definition wininit.c:32

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

Referenced by pxe_menu_prompt_and_select().

◆ pxe_menu_prompt_and_select()

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 iskey(void)
Check for available input on any console.
Definition console.c:131
uint32_t start
Starting offset.
Definition netvsc.h:1
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16
#define KEY_F8
F8 (for PXE)
Definition keys.h:119
static int pxe_menu_select(struct pxe_menu *menu)
Make selection from PXE boot menu.
Definition pxemenu.c:219
int timeout
Timeout (in seconds)
Definition pxemenu.c:70
const char * prompt
Prompt string (optional)
Definition pxemenu.c:65
unsigned long currticks(void)
Get current system time in ticks.
Definition timer.c:43

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

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}
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
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:130
struct uri * fetch_next_server_and_filename(struct settings *settings)
Fetch next-server and filename settings into a URI.
Definition autoboot.c:242
#define URIBOOT_NO_SAN
Definition autoboot.h:27
int pxebs(struct net_device *netdev, unsigned int pxe_type)
Definition dhcpmgmt.c:42
static struct net_device * netdev
Definition gdbudp.c:53
#define PXEBS_SETTINGS_NAME
Setting block name used for BootServerDHCP responses.
Definition dhcp.h:717
static int pxe_menu_prompt_and_select(struct pxe_menu *menu)
Prompt for (and make selection from) PXE boot menu.
Definition pxemenu.c:281
static int pxe_menu_parse(struct pxe_menu **menu)
Parse and allocate PXE boot menu.
Definition pxemenu.c:88
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
struct settings * find_settings(const char *name)
Find settings block.
Definition settings.c:407
unsigned int type
Boot Server type.
Definition pxemenu.c:52
A PXE boot menu.
Definition pxemenu.c:63
A settings block.
Definition settings.h:133
A Uniform Resource Identifier.
Definition uri.h:65
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition uri.h:206

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