Преглед на файлове

[pxe] Display the "Press F8" prompt rather than displaying menu with timeout

The PXE spec dictates the rather ugly feature that we have to present
a DHCP-specified prompt string to the user, then wait to see if they
press F8 before displaying the menu.

This seems to me to be a significant retrograde step from the current
situation of displaying the menu with the timeout counting down
against the default selected boot option, but apparently the lack of
the "Press F8" prompt causes some confusion.
tags/v0.9.7
Michael Brown преди 16 години
родител
ревизия
56066a6085
променени са 1 файла, в които са добавени 112 реда и са изтрити 58 реда
  1. 112
    58
      src/usr/pxemenu.c

+ 112
- 58
src/usr/pxemenu.c Целия файл

@@ -26,9 +26,9 @@
26 26
 #include <curses.h>
27 27
 #include <console.h>
28 28
 #include <gpxe/dhcp.h>
29
-#include <gpxe/vsprintf.h>
30 29
 #include <gpxe/keys.h>
31 30
 #include <gpxe/timer.h>
31
+#include <gpxe/process.h>
32 32
 #include <usr/dhcpmgmt.h>
33 33
 #include <usr/autoboot.h>
34 34
 
@@ -57,6 +57,8 @@ struct pxe_menu_item {
57 57
  * options.
58 58
  */
59 59
 struct pxe_menu {
60
+	/** Prompt string (optional) */
61
+	const char *prompt;
60 62
 	/** Timeout (in seconds)
61 63
 	 *
62 64
 	 * Negative indicates no timeout (i.e. wait indefinitely)
@@ -80,22 +82,24 @@ struct pxe_menu {
80 82
  * boot menu.
81 83
  */
82 84
 static int pxe_menu_parse ( struct pxe_menu **menu ) {
83
-	struct setting tmp_setting = { .name = NULL };
84
-	struct dhcp_pxe_boot_menu_prompt prompt = { .timeout = 0 };
85
+	struct setting pxe_boot_menu_prompt_setting =
86
+		{ .tag = DHCP_PXE_BOOT_MENU_PROMPT };
87
+	struct setting pxe_boot_menu_setting =
88
+		{ .tag = DHCP_PXE_BOOT_MENU };
85 89
 	uint8_t raw_menu[256];
90
+	int raw_prompt_len;
86 91
 	int raw_menu_len;
87 92
 	struct dhcp_pxe_boot_menu *raw_menu_item;
93
+	struct dhcp_pxe_boot_menu_prompt *raw_menu_prompt;
88 94
 	void *raw_menu_end;
89 95
 	unsigned int num_menu_items;
90 96
 	unsigned int i;
91 97
 	int rc;
92 98
 
93
-	/* Fetch relevant settings */
94
-	tmp_setting.tag = DHCP_PXE_BOOT_MENU_PROMPT;
95
-	fetch_setting ( NULL, &tmp_setting, &prompt, sizeof ( prompt ) );
96
-	tmp_setting.tag = DHCP_PXE_BOOT_MENU;
99
+	/* Fetch raw menu */
97 100
 	memset ( raw_menu, 0, sizeof ( raw_menu ) );
98
-	if ( ( raw_menu_len = fetch_setting ( NULL, &tmp_setting, raw_menu,
101
+	if ( ( raw_menu_len = fetch_setting ( NULL, &pxe_boot_menu_setting,
102
+					      raw_menu,
99 103
 					      sizeof ( raw_menu ) ) ) < 0 ) {
100 104
 		rc = raw_menu_len;
101 105
 		DBG ( "Could not retrieve raw PXE boot menu: %s\n",
@@ -108,6 +112,12 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) {
108 112
 	}
109 113
 	raw_menu_end = ( raw_menu + raw_menu_len );
110 114
 
115
+	/* Fetch raw prompt length */
116
+	raw_prompt_len = fetch_setting_len ( NULL,
117
+					     &pxe_boot_menu_prompt_setting );
118
+	if ( raw_prompt_len < 0 )
119
+		raw_prompt_len = 0;
120
+
111 121
 	/* Count menu items */
112 122
 	num_menu_items = 0;
113 123
 	raw_menu_item = ( ( void * ) raw_menu );
@@ -128,15 +138,14 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) {
128 138
 	/* Allocate space for parsed menu */
129 139
 	*menu = zalloc ( sizeof ( **menu ) +
130 140
 			 ( num_menu_items * sizeof ( (*menu)->items[0] ) ) +
131
-			 raw_menu_len + 1 /* NUL */ );
141
+			 raw_menu_len + 1 /* NUL */ +
142
+			 raw_prompt_len + 1 /* NUL */ );
132 143
 	if ( ! *menu ) {
133 144
 		DBG ( "Could not allocate PXE boot menu\n" );
134 145
 		return -ENOMEM;
135 146
 	}
136 147
 
137 148
 	/* Fill in parsed menu */
138
-	(*menu)->timeout =
139
-		( ( prompt.timeout == 0xff ) ? -1 : prompt.timeout );
140 149
 	(*menu)->num_items = num_menu_items;
141 150
 	raw_menu_item = ( ( ( void * ) (*menu) ) + sizeof ( **menu ) +
142 151
 			  ( num_menu_items * sizeof ( (*menu)->items[0] ) ) );
@@ -153,6 +162,18 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) {
153 162
 				  sizeof ( *raw_menu_item ) +
154 163
 				  raw_menu_item->desc_len );
155 164
 	}
165
+	if ( raw_prompt_len ) {
166
+		raw_menu_prompt = ( ( ( void * ) raw_menu_item ) +
167
+				    1 /* NUL */ );
168
+		fetch_setting ( NULL, &pxe_boot_menu_prompt_setting,
169
+				raw_menu_prompt, raw_prompt_len );
170
+		(*menu)->timeout =
171
+			( ( raw_menu_prompt->timeout == 0xff ) ?
172
+			  -1 : raw_menu_prompt->timeout );
173
+		(*menu)->prompt = raw_menu_prompt->prompt;
174
+	} else {
175
+		(*menu)->timeout = -1;
176
+	}
156 177
 
157 178
 	return 0;
158 179
 }
@@ -162,29 +183,20 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) {
162 183
  *
163 184
  * @v menu		PXE boot menu
164 185
  * @v index		Index of item to draw
186
+ * @v selected		Item is selected
165 187
  */
166 188
 static void pxe_menu_draw_item ( struct pxe_menu *menu,
167
-				 unsigned int index ) {
168
-	int selected = ( menu->selection == index );
189
+				 unsigned int index, int selected ) {
169 190
 	char buf[COLS+1];
170
-	char *tmp = buf;
171
-	ssize_t remaining = sizeof ( buf );
172 191
 	size_t len;
173 192
 	unsigned int row;
174 193
 
175 194
 	/* Prepare space-padded row content */
176
-	len = ssnprintf ( tmp, remaining, " %c. %s",
177
-			  ( 'A' + index ), menu->items[index].desc );
178
-	tmp += len;
179
-	remaining -= len;
180
-	if ( selected && ( menu->timeout > 0 ) ) {
181
-		len = ssnprintf ( tmp, remaining, " (%d)", menu->timeout );
182
-		tmp += len;
183
-		remaining -= len;
184
-	}
185
-	for ( ; remaining > 1 ; tmp++, remaining-- )
186
-		*tmp = ' ';
187
-	*tmp = '\0';
195
+	len = snprintf ( buf, sizeof ( buf ), " %c. %s",
196
+			 ( 'A' + index ), menu->items[index].desc );
197
+	while ( len < ( sizeof ( buf ) - 1 ) )
198
+		buf[len++] = ' ';
199
+	buf[ sizeof ( buf ) - 1 ] = '\0';
188 200
 
189 201
 	/* Draw row */
190 202
 	row = ( LINES - menu->num_items + index );
@@ -199,11 +211,7 @@ static void pxe_menu_draw_item ( struct pxe_menu *menu,
199 211
  * @v menu		PXE boot menu
200 212
  * @ret rc		Return status code
201 213
  */
202
-int pxe_menu_select ( struct pxe_menu *menu ) {
203
-	unsigned long start = currticks();
204
-	unsigned long now;
205
-	unsigned long elapsed;
206
-	unsigned int old_selection;
214
+static int pxe_menu_select ( struct pxe_menu *menu ) {
207 215
 	int key;
208 216
 	unsigned int key_selection;
209 217
 	unsigned int i;
@@ -220,37 +228,24 @@ int pxe_menu_select ( struct pxe_menu *menu ) {
220 228
 	for ( i = 0 ; i < menu->num_items ; i++ )
221 229
 		printf ( "\n" );
222 230
 	for ( i = 0 ; i < menu->num_items ; i++ )
223
-		pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ) );
231
+		pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ), 0 );
224 232
 
225 233
 	while ( 1 ) {
226 234
 
227
-		/* Decrease timeout if necessary */
228
-		if ( menu->timeout > 0 ) {
229
-			now = currticks();
230
-			elapsed = ( now - start );
231
-			if ( elapsed >= TICKS_PER_SEC ) {
232
-				start = now;
233
-				menu->timeout--;
234
-				pxe_menu_draw_item ( menu, menu->selection );
235
-			}
236
-		}
237
-
238
-		/* Select current item if we have timed out */
239
-		if ( menu->timeout == 0 )
240
-			break;
235
+		/* Highlight currently selected item */
236
+		pxe_menu_draw_item ( menu, menu->selection, 1 );
241 237
 
242
-		/* Check for keyboard input */
243
-		if ( ! iskey() )
244
-			continue;
238
+		/* Wait for keyboard input */
239
+		while ( ! iskey() )
240
+			step();
245 241
 		key = getkey();
246 242
 
247
-		/* Any keyboard input cancels the timeout */
248
-		menu->timeout = -1;
249
-		pxe_menu_draw_item ( menu, menu->selection );
243
+		/* Unhighlight currently selected item */
244
+		pxe_menu_draw_item ( menu, menu->selection, 0 );
250 245
 
251 246
 		/* Act upon key */
252
-		old_selection = menu->selection;
253 247
 		if ( ( key == CR ) || ( key == LF ) ) {
248
+			pxe_menu_draw_item ( menu, menu->selection, 1 );
254 249
 			break;
255 250
 		} else if ( key == CTRL_C ) {
256 251
 			rc = -ECANCELED;
@@ -265,10 +260,9 @@ int pxe_menu_select ( struct pxe_menu *menu ) {
265 260
 			    ( ( key_selection = ( toupper ( key ) - 'A' ) )
266 261
 			      < menu->num_items ) ) {
267 262
 			menu->selection = key_selection;
268
-			menu->timeout = 0;
263
+			pxe_menu_draw_item ( menu, menu->selection, 1 );
264
+			break;
269 265
 		}
270
-		pxe_menu_draw_item ( menu, old_selection );
271
-		pxe_menu_draw_item ( menu, menu->selection );
272 266
 	}
273 267
 
274 268
 	/* Shut down UI */
@@ -277,6 +271,66 @@ int pxe_menu_select ( struct pxe_menu *menu ) {
277 271
 	return rc;
278 272
 }
279 273
 
274
+/**
275
+ * Prompt for (and make selection from) PXE boot menu
276
+ *
277
+ * @v menu		PXE boot menu
278
+ * @ret rc		Return status code
279
+ */
280
+static int pxe_menu_prompt_and_select ( struct pxe_menu *menu ) {
281
+	unsigned long start = currticks();
282
+	unsigned long now;
283
+	unsigned long elapsed;
284
+	size_t len = 0;
285
+	int key;
286
+	int rc = 0;
287
+
288
+	/* Display menu immediately, if specified to do so */
289
+	if ( menu->timeout < 0 ) {
290
+		if ( menu->prompt )
291
+			printf ( "%s\n", menu->prompt );
292
+		return pxe_menu_select ( menu );
293
+	}
294
+
295
+	/* Display prompt, if specified */
296
+	if ( menu->prompt )
297
+		printf ( "%s", menu->prompt );
298
+
299
+	/* Wait for timeout, if specified */
300
+	while ( menu->timeout > 0 ) {
301
+		if ( ! len )
302
+			len = printf ( " (%d)", menu->timeout );
303
+		if ( iskey() ) {
304
+			key = getkey();
305
+			if ( key == KEY_F8 ) {
306
+				/* Display menu */
307
+				printf ( "\n" );
308
+				return pxe_menu_select ( menu );
309
+			} else if ( key == CTRL_C ) {
310
+				/* Abort */
311
+				rc = -ECANCELED;
312
+				break;
313
+			} else {
314
+				/* Stop waiting */
315
+				break;
316
+			}
317
+		}
318
+		now = currticks();
319
+		elapsed = ( now - start );
320
+		if ( elapsed >= TICKS_PER_SEC ) {
321
+			menu->timeout -= 1;
322
+			do {
323
+				printf ( "\b \b" );
324
+			} while ( --len );
325
+			start = now;
326
+		}
327
+	}
328
+
329
+	/* Return with default option selected */
330
+	printf ( "\n" );
331
+	return rc;
332
+}
333
+
280 334
 /**
281 335
  * Boot using PXE boot menu
282 336
  *
@@ -299,7 +353,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
299 353
 		return rc;
300 354
 
301 355
 	/* Make selection from boot menu */
302
-	if ( ( rc = pxe_menu_select ( menu ) ) != 0 ) {
356
+	if ( ( rc = pxe_menu_prompt_and_select ( menu ) ) != 0 ) {
303 357
 		free ( menu );
304 358
 		return rc;
305 359
 	}

Loading…
Отказ
Запис