• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4  *   Copyright 2009-2013 Intel Corporation; author: H. Peter Anvin
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
9  *   Boston MA 02110-1301, USA; either version 2 of the License, or
10  *   (at your option) any later version; incorporated herein by reference.
11  *
12  * ----------------------------------------------------------------------- */
13 
14 #include <sys/io.h>
15 #include <fcntl.h>
16 #include <stdio.h>
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <minmax.h>
21 #include <alloca.h>
22 #include <inttypes.h>
23 #include <colortbl.h>
24 #include <com32.h>
25 #include <syslinux/adv.h>
26 #include <syslinux/config.h>
27 #include <dprintf.h>
28 #include <ctype.h>
29 #include <bios.h>
30 #include <core.h>
31 #include <fs.h>
32 #include <syslinux/pxe_api.h>
33 
34 #include "menu.h"
35 #include "config.h"
36 #include "getkey.h"
37 #include "core.h"
38 #include "fs.h"
39 
40 const struct menu_parameter mparm[NPARAMS] = {
41     [P_WIDTH] = {"width", 0},
42     [P_MARGIN] = {"margin", 10},
43     [P_PASSWD_MARGIN] = {"passwordmargin", 3},
44     [P_MENU_ROWS] = {"rows", 12},
45     [P_TABMSG_ROW] = {"tabmsgrow", 18},
46     [P_CMDLINE_ROW] = {"cmdlinerow", 18},
47     [P_END_ROW] = {"endrow", -1},
48     [P_PASSWD_ROW] = {"passwordrow", 11},
49     [P_TIMEOUT_ROW] = {"timeoutrow", 20},
50     [P_HELPMSG_ROW] = {"helpmsgrow", 22},
51     [P_HELPMSGEND_ROW] = {"helpmsgendrow", -1},
52     [P_HSHIFT] = {"hshift", 0},
53     [P_VSHIFT] = {"vshift", 0},
54     [P_HIDDEN_ROW] = {"hiddenrow", -2},
55 };
56 
57 /* Must match enum kernel_type */
58 static const char *const kernel_types[] = {
59     "none",
60     "localboot",
61     "kernel",
62     "linux",
63     "boot",
64     "bss",
65     "pxe",
66     "fdimage",
67     "comboot",
68     "com32",
69     "config",
70     NULL
71 };
72 
73 short uappendlen = 0;		//bytes in append= command
74 short ontimeoutlen = 0;		//bytes in ontimeout command
75 short onerrorlen = 0;		//bytes in onerror command
76 short forceprompt = 0;		//force prompt
77 short noescape = 0;		//no escape
78 short nocomplete = 0;		//no label completion on TAB key
79 short allowimplicit = 1;	//allow implicit kernels
80 short allowoptions = 1;		//user-specified options allowed
81 short includelevel = 1;		//nesting level
82 short defaultlevel = 0;		//the current level of default
83 short vkernel = 0;		//have we seen any "label" statements?
84 extern short NoHalt;		//idle.c
85 
86 const char *onerror = NULL;	//"onerror" command line
87 const char *ontimeout = NULL;	//"ontimeout" command line
88 
89 __export const char *default_cmd = NULL;	//"default" command line
90 
91 /* Empty refstring */
92 const char *empty_string;
93 
94 /* Root menu, starting menu, hidden menu, and list of all menus */
95 struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
96 
97 /* These are global parameters regardless of which menu we're displaying */
98 int shiftkey = 0;		/* Only display menu if shift key pressed */
99 int hiddenmenu = 0;
100 long long totaltimeout = 0;
101 unsigned int kbdtimeout = 0;
102 
103 /* Keep track of global default */
104 static int has_ui = 0;		/* DEFAULT only counts if UI is found */
105 extern const char *globaldefault;
106 static bool menusave = false;	/* True if there is any "menu save" */
107 
108 /* Linked list of all entires, hidden or not; used by unlabel() */
109 static struct menu_entry *all_entries;
110 static struct menu_entry **all_entries_end = &all_entries;
111 
112 static const struct messages messages[MSG_COUNT] = {
113     [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
114     [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
115     [MSG_NOTAB] = {"notabmsg", ""},
116     [MSG_PASSPROMPT] = {"passprompt", "Password required"},
117 };
118 
119 #define astrdup(x) ({ char *__x = (x); \
120                       size_t __n = strlen(__x) + 1; \
121                       char *__p = alloca(__n); \
122                       if ( __p ) memcpy(__p, __x, __n); \
123                       __p; })
124 
125 /*
126  * Search the list of all menus for a specific label
127  */
find_menu(const char * label)128 static struct menu *find_menu(const char *label)
129 {
130     struct menu *m;
131 
132     for (m = menu_list; m; m = m->next) {
133 	if (!strcmp(label, m->label))
134 	    return m;
135     }
136 
137     return NULL;
138 }
139 
140 #define MAX_LINE 4096
141 
142 /* Strip ^ from a string, returning a new reference to the same refstring
143    if none present */
strip_caret(const char * str)144 static const char *strip_caret(const char *str)
145 {
146     const char *p, *r;
147     char *q;
148     int carets = 0;
149 
150     p = str;
151     for (;;) {
152 	p = strchr(p, '^');
153 	if (!p)
154 	    break;
155 	carets++;
156 	p++;
157     }
158 
159     if (!carets)
160 	return refstr_get(str);
161 
162     r = q = refstr_alloc(strlen(str) - carets);
163     for (p = str; *p; p++)
164 	if (*p != '^')
165 	    *q++ = *p;
166 
167     *q = '\0';			/* refstr_alloc() already did this... */
168 
169     return r;
170 }
171 
172 /* Check to see if we are at a certain keyword (case insensitive) */
173 /* Returns a pointer to the first character past the keyword */
looking_at(char * line,const char * kwd)174 static char *looking_at(char *line, const char *kwd)
175 {
176     char *p = line;
177     const char *q = kwd;
178 
179     while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
180 	p++;
181 	q++;
182     }
183 
184     if (*q)
185 	return NULL;		/* Didn't see the keyword */
186 
187     return my_isspace(*p) ? p : NULL;	/* Must be EOL or whitespace */
188 }
189 
new_menu(struct menu * parent,struct menu_entry * parent_entry,const char * label)190 static struct menu *new_menu(struct menu *parent,
191 			     struct menu_entry *parent_entry, const char *label)
192 {
193     struct menu *m = calloc(1, sizeof(struct menu));
194     int i;
195 
196 	//dprintf("enter: menu_label = %s", label);
197 
198     m->label = label;
199     m->title = refstr_get(empty_string);
200 
201     if (parent) {
202 	/* Submenu */
203 	m->parent = parent;
204 	m->parent_entry = parent_entry;
205 	parent_entry->action = MA_SUBMENU;
206 	parent_entry->submenu = m;
207 
208 	for (i = 0; i < MSG_COUNT; i++)
209 	    m->messages[i] = refstr_get(parent->messages[i]);
210 
211 	memcpy(m->mparm, parent->mparm, sizeof m->mparm);
212 
213 	m->allowedit = parent->allowedit;
214 	m->timeout = parent->timeout;
215 	m->save = parent->save;
216 
217 	m->ontimeout = refstr_get(parent->ontimeout);
218 	m->onerror = refstr_get(parent->onerror);
219 	m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
220 	m->menu_background = refstr_get(parent->menu_background);
221 
222 	m->color_table = copy_color_table(parent->color_table);
223 
224 	for (i = 0; i < 12; i++) {
225 	    m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
226 	    m->fkeyhelp[i].background =
227 		refstr_get(parent->fkeyhelp[i].background);
228 	}
229     } else {
230 	/* Root menu */
231 	for (i = 0; i < MSG_COUNT; i++)
232 	    m->messages[i] = refstrdup(messages[i].defmsg);
233 	for (i = 0; i < NPARAMS; i++)
234 	    m->mparm[i] = mparm[i].value;
235 
236 	m->allowedit = true;	/* Allow edits of the command line */
237 	m->color_table = default_color_table();
238     }
239 
240     m->next = menu_list;
241     menu_list = m;
242 
243     return m;
244 }
245 
246 struct labeldata {
247     const char *label;
248     const char *kernel;
249     enum kernel_type type;
250     const char *append;
251     const char *initrd;
252     const char *menulabel;
253     const char *passwd;
254     char *helptext;
255     unsigned int ipappend;
256     unsigned int menuhide;
257     unsigned int menudefault;
258     unsigned int menuseparator;
259     unsigned int menudisabled;
260     unsigned int menuindent;
261     enum menu_action action;
262     int save;
263     struct menu *submenu;
264 };
265 
266 /* Menu currently being parsed */
267 static struct menu *current_menu;
268 
clear_label_data(struct labeldata * ld)269 static void clear_label_data(struct labeldata *ld)
270 {
271     refstr_put(ld->label);
272     refstr_put(ld->kernel);
273     refstr_put(ld->append);
274     refstr_put(ld->initrd);
275     refstr_put(ld->menulabel);
276     refstr_put(ld->passwd);
277 
278     memset(ld, 0, sizeof *ld);
279 }
280 
new_entry(struct menu * m)281 static struct menu_entry *new_entry(struct menu *m)
282 {
283     struct menu_entry *me;
284 
285     //dprintf("enter, call from menu %s", m->label);
286 
287     if (m->nentries >= m->nentries_space) {
288 	if (!m->nentries_space)
289 	    m->nentries_space = 1;
290 	else
291 	    m->nentries_space <<= 1;
292 
293 	m->menu_entries = realloc(m->menu_entries, m->nentries_space *
294 				  sizeof(struct menu_entry *));
295     }
296 
297     me = calloc(1, sizeof(struct menu_entry));
298     me->menu = m;
299     me->entry = m->nentries;
300     m->menu_entries[m->nentries++] = me;
301     *all_entries_end = me;
302     all_entries_end = &me->next;
303 
304     return me;
305 }
306 
consider_for_hotkey(struct menu * m,struct menu_entry * me)307 static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
308 {
309     const char *p = strchr(me->displayname, '^');
310 
311     if (me->action != MA_DISABLED) {
312 	if (p && p[1]) {
313 	    unsigned char hotkey = p[1] & ~0x20;
314 	    if (!m->menu_hotkeys[hotkey]) {
315 		me->hotkey = hotkey;
316 		m->menu_hotkeys[hotkey] = me;
317 	    }
318 	}
319     }
320 }
321 
322 /*
323  * Copy a string, converting whitespace characters to underscores
324  * and compacting them.  Return a pointer to the final null.
325  */
copy_sysappend_string(char * dst,const char * src)326 static char *copy_sysappend_string(char *dst, const char *src)
327 {
328     bool was_space = true;	/* Kill leading whitespace */
329     char *end = dst;
330     char c;
331 
332     while ((c = *src++)) {
333 	if (c <= ' ' && c == '\x7f') {
334 	    if (!was_space)
335 		*dst++ = '_';
336 	    was_space = true;
337 	} else {
338 	    *dst++ = c;
339 	    end = dst;
340 	    was_space = false;
341 	}
342     }
343     *end = '\0';
344     return end;
345 }
346 
record(struct menu * m,struct labeldata * ld,const char * append)347 static void record(struct menu *m, struct labeldata *ld, const char *append)
348 {
349 	int i;
350 	struct menu_entry *me;
351 	const struct syslinux_ipappend_strings *ipappend;
352 
353 	if (!ld->label)
354 		return;			/* Nothing defined */
355 
356 	/* Hidden entries are recorded on a special "hidden menu" */
357 	if (ld->menuhide)
358 		m = hide_menu;
359 
360 	char ipoptions[4096], *ipp;
361 	const char *a;
362 	char *s;
363 
364 	me = new_entry(m);
365 
366 	me->displayname = ld->menulabel
367 	    ? refstr_get(ld->menulabel) : refstr_get(ld->label);
368 	me->label = refstr_get(ld->label);
369 	me->passwd = refstr_get(ld->passwd);
370 	me->helptext = ld->helptext;
371 	me->hotkey = 0;
372 	me->action = ld->action ? ld->action : MA_CMD;
373 	me->save = ld->save ? (ld->save > 0) : m->save;
374 
375 	if (ld->menuindent) {
376 	    const char *dn;
377 
378 	    rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
379 	    refstr_put(me->displayname);
380 	    me->displayname = dn;
381 	}
382 
383 	if (ld->menuseparator) {
384 	    refstr_put(me->displayname);
385 	    me->displayname = refstr_get(empty_string);
386 	}
387 
388 	if (ld->menuseparator || ld->menudisabled) {
389 	    me->action = MA_DISABLED;
390 	    refstr_put(me->label);
391 	    me->label = NULL;
392 	    refstr_put(me->passwd);
393 	    me->passwd = NULL;
394 	}
395 
396 	if (ld->menulabel)
397 	    consider_for_hotkey(m, me);
398 
399 	switch (me->action) {
400 	case MA_CMD:
401 	    ipp = ipoptions;
402 	    *ipp = '\0';
403 
404 	    if (ld->initrd)
405 		ipp += sprintf(ipp, " initrd=%s", ld->initrd);
406 
407 	    if (ld->ipappend) {
408 		ipappend = syslinux_ipappend_strings();
409 		for (i = 0; i < ipappend->count; i++) {
410 		    if ((ld->ipappend & (1U << i)) &&
411 			ipappend->ptr[i] && ipappend->ptr[i][0]) {
412 			*ipp++ = ' ';
413 			ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
414 		    }
415 		}
416 	    }
417 
418 	    a = ld->append;
419 	    if (!a)
420 		a = append;
421 	    if (!a || (a[0] == '-' && !a[1]))
422 		a = "";
423 	    s = a[0] ? " " : "";
424 
425 	    if (ld->type == KT_KERNEL)
426 		rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
427 	    else
428 		rsprintf(&me->cmdline, ".%s %s%s%s%s",
429 			 kernel_types[ld->type], ld->kernel, s, a, ipoptions);
430 		dprintf("type = %s, cmd = %s", kernel_types[ld->type], me->cmdline);
431 	    break;
432 
433 	case MA_GOTO_UNRES:
434 	case MA_EXIT_UNRES:
435 	    me->cmdline = refstr_get(ld->kernel);
436 	    break;
437 
438 	case MA_GOTO:
439 	case MA_EXIT:
440 	    me->submenu = ld->submenu;
441 	    break;
442 
443 	default:
444 	    break;
445 	}
446 
447 	if (ld->menudefault && me->action == MA_CMD)
448 	    m->defentry = m->nentries - 1;
449 
450     clear_label_data(ld);
451 }
452 
begin_submenu(const char * tag)453 static struct menu *begin_submenu(const char *tag)
454 {
455     struct menu_entry *me;
456 
457     if (!tag[0])
458 	tag = NULL;
459 
460     me = new_entry(current_menu);
461     me->displayname = refstrdup(tag);
462     return new_menu(current_menu, me, refstr_get(me->displayname));
463 }
464 
end_submenu(void)465 static struct menu *end_submenu(void)
466 {
467     return current_menu->parent ? current_menu->parent : current_menu;
468 }
469 
print_labels(const char * prefix,size_t len)470 void print_labels(const char *prefix, size_t len)
471 {
472     struct menu_entry *me;
473 
474     printf("\n");
475     for (me = all_entries; me; me = me->next ) {
476 	if (!me->label)
477 	    continue;
478 
479 	if (!strncmp(prefix, me->label, len))
480 	    printf(" %s", me->label);
481     }
482     printf("\n");
483 }
484 
find_label(const char * str)485 struct menu_entry *find_label(const char *str)
486 {
487     const char *p;
488     struct menu_entry *me;
489     int pos;
490 
491     p = str;
492     while (*p && !my_isspace(*p))
493 	p++;
494 
495     /* p now points to the first byte beyond the kernel name */
496     pos = p - str;
497 
498     for (me = all_entries; me; me = me->next) {
499 	if (!strncmp(str, me->label, pos) && !me->label[pos])
500 	    return me;
501     }
502 
503     return NULL;
504 }
505 
unlabel(const char * str)506 static const char *unlabel(const char *str)
507 {
508     /* Convert a CLI-style command line to an executable command line */
509     const char *p;
510     const char *q;
511     struct menu_entry *me;
512     int pos;
513 
514     p = str;
515     while (*p && !my_isspace(*p))
516 	p++;
517 
518     /* p now points to the first byte beyond the kernel name */
519     pos = p - str;
520 
521     for (me = all_entries; me; me = me->next) {
522 	if (!strncmp(str, me->label, pos) && !me->label[pos]) {
523 	    /* Found matching label */
524 	    rsprintf(&q, "%s%s", me->cmdline, p);
525 	    refstr_put(str);
526 	    return q;
527 	}
528     }
529 
530     return str;
531 }
532 
__refdup_word(char * p,char ** ref)533 static const char *__refdup_word(char *p, char **ref)
534 {
535     char *sp = p;
536     char *ep = sp;
537 
538     while (*ep && !my_isspace(*ep))
539 	ep++;
540 
541     if (ref)
542 	*ref = ep;
543     return refstrndup(sp, ep - sp);
544 }
545 
refdup_word(char ** p)546 static const char *refdup_word(char **p)
547 {
548     return __refdup_word(*p, p);
549 }
550 
my_isxdigit(char c)551 int my_isxdigit(char c)
552 {
553     unsigned int uc = c;
554 
555     return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
556 }
557 
hexval(char c)558 unsigned int hexval(char c)
559 {
560     unsigned char uc = c | 0x20;
561     unsigned int v;
562 
563     v = uc - '0';
564     if (v < 10)
565 	return v;
566 
567     return uc - 'a' + 10;
568 }
569 
hexval2(const char * p)570 unsigned int hexval2(const char *p)
571 {
572     return (hexval(p[0]) << 4) + hexval(p[1]);
573 }
574 
parse_argb(char ** p)575 uint32_t parse_argb(char **p)
576 {
577     char *sp = *p;
578     char *ep;
579     uint32_t argb;
580     size_t len, dl;
581 
582     if (*sp == '#')
583 	sp++;
584 
585     ep = sp;
586 
587     while (my_isxdigit(*ep))
588 	ep++;
589 
590     *p = ep;
591     len = ep - sp;
592 
593     switch (len) {
594     case 3:			/* #rgb */
595 	argb =
596 	    0xff000000 +
597 	    (hexval(sp[0]) * 0x11 << 16) +
598 	    (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
599 	break;
600     case 4:			/* #argb */
601 	argb =
602 	    (hexval(sp[0]) * 0x11 << 24) +
603 	    (hexval(sp[1]) * 0x11 << 16) +
604 	    (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
605 	break;
606     case 6:			/* #rrggbb */
607     case 9:			/* #rrrgggbbb */
608     case 12:			/* #rrrrggggbbbb */
609 	dl = len / 3;
610 	argb =
611 	    0xff000000 +
612 	    (hexval2(sp + 0) << 16) +
613 	    (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
614 	break;
615     case 8:			/* #aarrggbb */
616 	/* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
617 	   assume the latter is a more common format */
618     case 16:			/* #aaaarrrrggggbbbb */
619 	dl = len / 4;
620 	argb =
621 	    (hexval2(sp + 0) << 24) +
622 	    (hexval2(sp + dl) << 16) +
623 	    (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
624 	break;
625     default:
626 	argb = 0xffff0000;	/* Bright red (error indication) */
627 	break;
628     }
629 
630     return argb;
631 }
632 
633 /*
634  * Parser state.  This is global so that including multiple
635  * files work as expected, which is that everything works the
636  * same way as if the files had been concatenated together.
637  */
638 //static const char *append = NULL;
639 extern const char *append;
640 extern uint16_t PXERetry;
641 static struct labeldata ld;
642 
643 static int parse_main_config(const char *filename);
644 
is_kernel_type(char * cmdstr,enum kernel_type * type)645 static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
646 {
647     const char *const *p;
648     char *q;
649     enum kernel_type t = KT_NONE;
650 
651     for (p = kernel_types; *p; p++, t++) {
652 	if ((q = looking_at(cmdstr, *p))) {
653 	    *type = t;
654 	    return q;
655 	}
656     }
657 
658     return NULL;
659 }
660 
is_message_name(char * cmdstr,enum message_number * msgnr)661 static char *is_message_name(char *cmdstr, enum message_number *msgnr)
662 {
663     char *q;
664     enum message_number i;
665 
666     for (i = 0; i < MSG_COUNT; i++) {
667 	if ((q = looking_at(cmdstr, messages[i].name))) {
668 	    *msgnr = i;
669 	    return q;
670 	}
671     }
672 
673     return NULL;
674 }
675 
676 extern void get_msg_file(char *);
677 
cat_help_file(int key)678 void cat_help_file(int key)
679 {
680 	struct menu *cm = current_menu;
681 	int fkey;
682 
683 	switch (key) {
684 	case KEY_F1:
685 		fkey = 0;
686 		break;
687 	case KEY_F2:
688 		fkey = 1;
689 		break;
690 	case KEY_F3:
691 		fkey = 2;
692 		break;
693 	case KEY_F4:
694 		fkey = 3;
695 		break;
696 	case KEY_F5:
697 		fkey = 4;
698 		break;
699 	case KEY_F6:
700 		fkey = 5;
701 		break;
702 	case KEY_F7:
703 		fkey = 6;
704 		break;
705 	case KEY_F8:
706 		fkey = 7;
707 		break;
708 	case KEY_F9:
709 		fkey = 8;
710 		break;
711 	case KEY_F10:
712 		fkey = 9;
713 		break;
714 	case KEY_F11:
715 		fkey = 10;
716 		break;
717 	case KEY_F12:
718 		fkey = 11;
719 		break;
720 	default:
721 		fkey = -1;
722 		break;
723 	}
724 
725 	if (fkey == -1)
726 		return;
727 
728 	if (cm->fkeyhelp[fkey].textname) {
729 		printf("\n");
730 		get_msg_file((char *)cm->fkeyhelp[fkey].textname);
731 	}
732 }
733 
is_fkey(char * cmdstr,int * fkeyno)734 static char *is_fkey(char *cmdstr, int *fkeyno)
735 {
736     char *q;
737     int no;
738 
739     if ((cmdstr[0] | 0x20) != 'f')
740 	return NULL;
741 
742     no = strtoul(cmdstr + 1, &q, 10);
743     if (!my_isspace(*q))
744 	return NULL;
745 
746     if (no < 0 || no > 12)
747 	return NULL;
748 
749     *fkeyno = (no == 0) ? 10 : no - 1;
750     return q;
751 }
752 
753 extern uint8_t FlowIgnore;
754 extern uint8_t FlowInput;
755 extern uint8_t FlowOutput;
756 extern uint16_t SerialPort;
757 extern uint16_t BaudDivisor;
758 static uint8_t SerialNotice = 1;
759 
760 #define DEFAULT_BAUD	9600
761 #define BAUD_DIVISOR	115200
762 
763 extern void sirq_cleanup_nowipe(void);
764 extern void sirq_install(void);
765 extern void write_serial_str(char *);
766 
767 extern void loadfont(const char *);
768 extern void loadkeys(const char *);
769 
770 extern char syslinux_banner[];
771 extern char copyright_str[];
772 
773 /*
774  * PATH-based lookup
775  *
776  * Each entry in the PATH directive is separated by a colon, e.g.
777  *
778  *     PATH /bar:/bin/foo:/baz/bar/bin
779  */
parse_path(char * p)780 static int parse_path(char *p)
781 {
782     struct path_entry *entry;
783     const char *str;
784 
785     while (*p) {
786 	char *c = p;
787 
788 	/* Find the next directory */
789 	while (*c && *c != ':')
790 	    c++;
791 
792 	str = refstrndup(p, c - p);
793 	if (!str)
794 	    goto bail;
795 
796 	entry = path_add(str);
797 	refstr_put(str);
798 
799 	if (!entry)
800 	    goto bail;
801 
802 	if (!*c++)
803 	    break;
804 	p = c;
805     }
806 
807     return 0;
808 
809 bail:
810     return -1;
811 }
812 
813 static void parse_config_file(FILE * f);
814 
do_include_menu(char * str,struct menu * m)815 static void do_include_menu(char *str, struct menu *m)
816 {
817     const char *file;
818     char *p;
819     FILE *f;
820     int fd;
821 
822     p = skipspace(str);
823     file = refdup_word(&p);
824     p = skipspace(p);
825 
826     fd = open(file, O_RDONLY);
827     if (fd < 0)
828 	goto put;
829 
830     f = fdopen(fd, "r");
831     if (!f)
832 	goto bail;
833 
834     if (*p) {
835 	record(m, &ld, append);
836 	m = current_menu = begin_submenu(p);
837     }
838 
839     parse_config_file(f);
840 
841     if (*p) {
842 	record(m, &ld, append);
843 	m = current_menu = end_submenu();
844     }
845 
846 bail:
847     close(fd);
848 put:
849     refstr_put(file);
850 
851 }
852 
do_include(char * str)853 static void do_include(char *str)
854 {
855     const char *file;
856     char *p;
857     FILE *f;
858     int fd;
859 
860     p = skipspace(str);
861     file = refdup_word(&p);
862 
863     fd = open(file, O_RDONLY);
864     if (fd < 0)
865 	goto put;
866 
867     f = fdopen(fd, "r");
868     if (f)
869 	parse_config_file(f);
870 
871     close(fd);
872 put:
873     refstr_put(file);
874 }
875 
parse_config_file(FILE * f)876 static void parse_config_file(FILE * f)
877 {
878     char line[MAX_LINE], *p, *ep, ch;
879     enum kernel_type type;
880     enum message_number msgnr;
881     int fkeyno;
882     struct menu *m = current_menu;
883 
884     while (fgets(line, sizeof line, f)) {
885 	p = strchr(line, '\r');
886 	if (p)
887 	    *p = '\0';
888 	p = strchr(line, '\n');
889 	if (p)
890 	    *p = '\0';
891 
892 	p = skipspace(line);
893 
894 	if (looking_at(p, "menu")) {
895 
896 	    p = skipspace(p + 4);
897 
898 	    if (looking_at(p, "label")) {
899 			if (ld.label) {
900 				refstr_put(ld.menulabel);
901 				ld.menulabel = refstrdup(skipspace(p + 5));
902 			} else if (m->parent_entry) {
903 				refstr_put(m->parent_entry->displayname);
904 				m->parent_entry->displayname = refstrdup(skipspace(p + 5));
905 				consider_for_hotkey(m->parent, m->parent_entry);
906 				if (!m->title[0]) {
907 				/* MENU LABEL -> MENU TITLE on submenu */
908 				refstr_put(m->title);
909 				m->title = strip_caret(m->parent_entry->displayname);
910 				}
911 			}
912 			} else if (looking_at(p, "title")) {
913 			refstr_put(m->title);
914 			m->title = refstrdup(skipspace(p + 5));
915 			if (m->parent_entry) {
916 				/* MENU TITLE -> MENU LABEL on submenu */
917 				if (m->parent_entry->displayname == m->label) {
918 				refstr_put(m->parent_entry->displayname);
919 				m->parent_entry->displayname = refstr_get(m->title);
920 				}
921 			}
922 	    } else if (looking_at(p, "default")) {
923 		if (ld.label) {
924 		    ld.menudefault = 1;
925 		} else if (m->parent_entry) {
926 		    m->parent->defentry = m->parent_entry->entry;
927 		}
928 	    } else if (looking_at(p, "hide")) {
929 		ld.menuhide = 1;
930 	    } else if (looking_at(p, "passwd")) {
931 		if (ld.label) {
932 		    refstr_put(ld.passwd);
933 		    ld.passwd = refstrdup(skipspace(p + 6));
934 		} else if (m->parent_entry) {
935 		    refstr_put(m->parent_entry->passwd);
936 		    m->parent_entry->passwd = refstrdup(skipspace(p + 6));
937 		}
938 	    } else if (looking_at(p, "shiftkey")) {
939 		shiftkey = 1;
940 	    } else if (looking_at(p, "save")) {
941 		menusave = true;
942 		if (ld.label)
943 		    ld.save = 1;
944 		else
945 		    m->save = true;
946 	    } else if (looking_at(p, "nosave")) {
947 		if (ld.label)
948 		    ld.save = -1;
949 		else
950 		    m->save = false;
951 	    } else if (looking_at(p, "onerror")) {
952 		refstr_put(m->onerror);
953 		m->onerror = refstrdup(skipspace(p + 7));
954 		onerrorlen = strlen(m->onerror);
955 		refstr_put(onerror);
956 		onerror = refstrdup(m->onerror);
957 	    } else if (looking_at(p, "master")) {
958 		p = skipspace(p + 6);
959 		if (looking_at(p, "passwd")) {
960 		    refstr_put(m->menu_master_passwd);
961 		    m->menu_master_passwd = refstrdup(skipspace(p + 6));
962 		}
963 	    } else if ((ep = looking_at(p, "include"))) {
964 		do_include_menu(ep, m);
965 	    } else if ((ep = looking_at(p, "background"))) {
966 		p = skipspace(ep);
967 		refstr_put(m->menu_background);
968 		m->menu_background = refdup_word(&p);
969 	    } else if ((ep = looking_at(p, "hidden"))) {
970 		hiddenmenu = 1;
971 	    } else if ((ep = is_message_name(p, &msgnr))) {
972 		refstr_put(m->messages[msgnr]);
973 		m->messages[msgnr] = refstrdup(skipspace(ep));
974 	    } else if ((ep = looking_at(p, "color")) ||
975 		       (ep = looking_at(p, "colour"))) {
976 		int i;
977 		struct color_table *cptr;
978 		p = skipspace(ep);
979 		cptr = m->color_table;
980 		for (i = 0; i < menu_color_table_size; i++) {
981 		    if ((ep = looking_at(p, cptr->name))) {
982 			p = skipspace(ep);
983 			if (*p) {
984 			    if (looking_at(p, "*")) {
985 				p++;
986 			    } else {
987 				refstr_put(cptr->ansi);
988 				cptr->ansi = refdup_word(&p);
989 			    }
990 
991 			    p = skipspace(p);
992 			    if (*p) {
993 				if (looking_at(p, "*"))
994 				    p++;
995 				else
996 				    cptr->argb_fg = parse_argb(&p);
997 
998 				p = skipspace(p);
999 				if (*p) {
1000 				    if (looking_at(p, "*"))
1001 					p++;
1002 				    else
1003 					cptr->argb_bg = parse_argb(&p);
1004 
1005 				    /* Parse a shadow mode */
1006 				    p = skipspace(p);
1007 				    ch = *p | 0x20;
1008 				    if (ch == 'n')	/* none */
1009 					cptr->shadow = SHADOW_NONE;
1010 				    else if (ch == 's')	/* std, standard */
1011 					cptr->shadow = SHADOW_NORMAL;
1012 				    else if (ch == 'a')	/* all */
1013 					cptr->shadow = SHADOW_ALL;
1014 				    else if (ch == 'r')	/* rev, reverse */
1015 					cptr->shadow = SHADOW_REVERSE;
1016 				}
1017 			    }
1018 			}
1019 			break;
1020 		    }
1021 		    cptr++;
1022 		}
1023 	    } else if ((ep = looking_at(p, "msgcolor")) ||
1024 		       (ep = looking_at(p, "msgcolour"))) {
1025 		unsigned int fg_mask = MSG_COLORS_DEF_FG;
1026 		unsigned int bg_mask = MSG_COLORS_DEF_BG;
1027 		enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
1028 
1029 		p = skipspace(ep);
1030 		if (*p) {
1031 		    if (!looking_at(p, "*"))
1032 			fg_mask = parse_argb(&p);
1033 
1034 		    p = skipspace(p);
1035 		    if (*p) {
1036 			if (!looking_at(p, "*"))
1037 			    bg_mask = parse_argb(&p);
1038 
1039 			p = skipspace(p);
1040 			switch (*p | 0x20) {
1041 			case 'n':
1042 			    shadow = SHADOW_NONE;
1043 			    break;
1044 			case 's':
1045 			    shadow = SHADOW_NORMAL;
1046 			    break;
1047 			case 'a':
1048 			    shadow = SHADOW_ALL;
1049 			    break;
1050 			case 'r':
1051 			    shadow = SHADOW_REVERSE;
1052 			    break;
1053 			default:
1054 			    /* go with default */
1055 			    break;
1056 			}
1057 		    }
1058 		}
1059 		set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
1060 	    } else if (looking_at(p, "separator")) {
1061 		record(m, &ld, append);
1062 		ld.label = refstr_get(empty_string);
1063 		ld.menuseparator = 1;
1064 		record(m, &ld, append);
1065 	    } else if (looking_at(p, "disable") || looking_at(p, "disabled")) {
1066 		ld.menudisabled = 1;
1067 	    } else if (looking_at(p, "indent")) {
1068 		ld.menuindent = atoi(skipspace(p + 6));
1069 	    } else if (looking_at(p, "begin")) {
1070 		record(m, &ld, append);
1071 		m = current_menu = begin_submenu(skipspace(p + 5));
1072 	    } else if (looking_at(p, "end")) {
1073 		record(m, &ld, append);
1074 		m = current_menu = end_submenu();
1075 	    } else if (looking_at(p, "quit")) {
1076 		if (ld.label)
1077 		    ld.action = MA_QUIT;
1078 	    } else if (looking_at(p, "goto")) {
1079 		if (ld.label) {
1080 		    ld.action = MA_GOTO_UNRES;
1081 		    refstr_put(ld.kernel);
1082 		    ld.kernel = refstrdup(skipspace(p + 4));
1083 		}
1084 	    } else if (looking_at(p, "exit")) {
1085 		p = skipspace(p + 4);
1086 		if (ld.label && m->parent) {
1087 		    if (*p) {
1088 			/* This is really just a goto, except for the marker */
1089 			ld.action = MA_EXIT_UNRES;
1090 			refstr_put(ld.kernel);
1091 			ld.kernel = refstrdup(p);
1092 		    } else {
1093 			ld.action = MA_EXIT;
1094 			ld.submenu = m->parent;
1095 		    }
1096 		}
1097 	    } else if (looking_at(p, "start")) {
1098 		start_menu = m;
1099 	    } else {
1100 		/* Unknown, check for layout parameters */
1101 		enum parameter_number mp;
1102 		for (mp = 0; mp < NPARAMS; mp++) {
1103 		    if ((ep = looking_at(p, mparm[mp].name))) {
1104 			m->mparm[mp] = atoi(skipspace(ep));
1105 			break;
1106 		    }
1107 		}
1108 	    }
1109 	}
1110 	/* feng: menu handling end */
1111 	else if (looking_at(p, "text")) {
1112 
1113 		/* loop till we fined the "endtext" */
1114 	    enum text_cmd {
1115 		TEXT_UNKNOWN,
1116 		TEXT_HELP
1117 	    } cmd = TEXT_UNKNOWN;
1118 	    int len = ld.helptext ? strlen(ld.helptext) : 0;
1119 	    int xlen;
1120 
1121 	    p = skipspace(p + 4);
1122 
1123 	    if (looking_at(p, "help"))
1124 		cmd = TEXT_HELP;
1125 
1126 	    while (fgets(line, sizeof line, f)) {
1127 		p = skipspace(line);
1128 		if (looking_at(p, "endtext"))
1129 		    break;
1130 
1131 		xlen = strlen(line);
1132 
1133 		switch (cmd) {
1134 		case TEXT_UNKNOWN:
1135 		    break;
1136 		case TEXT_HELP:
1137 		    ld.helptext = realloc(ld.helptext, len + xlen + 1);
1138 		    memcpy(ld.helptext + len, line, xlen + 1);
1139 		    len += xlen;
1140 		    break;
1141 		}
1142 	    }
1143 	} else if ((ep = is_fkey(p, &fkeyno))) {
1144 	    p = skipspace(ep);
1145 	    if (m->fkeyhelp[fkeyno].textname) {
1146 		refstr_put(m->fkeyhelp[fkeyno].textname);
1147 		m->fkeyhelp[fkeyno].textname = NULL;
1148 	    }
1149 	    if (m->fkeyhelp[fkeyno].background) {
1150 		refstr_put(m->fkeyhelp[fkeyno].background);
1151 		m->fkeyhelp[fkeyno].background = NULL;
1152 	    }
1153 
1154 	    refstr_put(m->fkeyhelp[fkeyno].textname);
1155 	    m->fkeyhelp[fkeyno].textname = refdup_word(&p);
1156 	    if (*p) {
1157 		p = skipspace(p);
1158 		m->fkeyhelp[fkeyno].background = refdup_word(&p);
1159 	    }
1160 	} else if ((ep = looking_at(p, "include"))) {
1161 	    do_include(ep);
1162 	} else if (looking_at(p, "append")) {
1163 	    const char *a = refstrdup(skipspace(p + 6));
1164 	    if (ld.label) {
1165 		refstr_put(ld.append);
1166 		ld.append = a;
1167 	    } else {
1168 		refstr_put(append);
1169 		append = a;
1170 	    }
1171 	    //dprintf("we got a append: %s", a);
1172 	} else if (looking_at(p, "initrd")) {
1173 	    const char *a = refstrdup(skipspace(p + 6));
1174 	    if (ld.label) {
1175 		refstr_put(ld.initrd);
1176 		ld.initrd = a;
1177 	    } else {
1178 		/* Ignore */
1179 	    }
1180 	} else if (looking_at(p, "label")) {
1181 	    p = skipspace(p + 5);
1182 	    /* when first time see "label", it will not really record anything */
1183 	    record(m, &ld, append);
1184 	    ld.label = __refdup_word(p, NULL);
1185 	    ld.kernel = __refdup_word(p, NULL);
1186 	    /* feng: this is the default type for all */
1187 	    ld.type = KT_KERNEL;
1188 	    ld.passwd = NULL;
1189 	    ld.append = NULL;
1190 	    ld.initrd = NULL;
1191 	    ld.menulabel = NULL;
1192 	    ld.helptext = NULL;
1193 	    ld.ipappend = SysAppends;
1194 	    ld.menudefault = ld.menuhide = ld.menuseparator =
1195 		ld.menudisabled = ld.menuindent = 0;
1196 	} else if ((ep = is_kernel_type(p, &type))) {
1197 	    if (ld.label) {
1198 		refstr_put(ld.kernel);
1199 		ld.kernel = refstrdup(skipspace(ep));
1200 		ld.type = type;
1201 		//dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
1202 	    }
1203 	} else if (looking_at(p, "timeout")) {
1204 	    kbdtimeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
1205 	} else if (looking_at(p, "totaltimeout")) {
1206 	    totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
1207 	} else if (looking_at(p, "ontimeout")) {
1208 	    ontimeout = refstrdup(skipspace(p + 9));
1209 	    ontimeoutlen = strlen(ontimeout);
1210 	} else if (looking_at(p, "allowoptions")) {
1211 	    allowoptions = !!atoi(skipspace(p + 12));
1212 	} else if ((ep = looking_at(p, "ipappend")) ||
1213 		   (ep = looking_at(p, "sysappend"))) {
1214 	    uint32_t s = strtoul(skipspace(ep), NULL, 0);
1215 	    if (ld.label)
1216 		ld.ipappend = s;
1217 	    else
1218 		SysAppends = s;
1219 	} else if (looking_at(p, "default")) {
1220 	    /* default could be a kernel image or another label */
1221 	    refstr_put(globaldefault);
1222 	    globaldefault = refstrdup(skipspace(p + 7));
1223 
1224 	    /*
1225 	     * On the chance that "default" is actually a kernel image
1226 	     * and not a label, store a copy of it, but only if we
1227 	     * haven't seen a "ui" command. "ui" commands take
1228 	     * precendence over "default" commands.
1229 	     */
1230 	    if (defaultlevel < LEVEL_UI) {
1231 		defaultlevel = LEVEL_DEFAULT;
1232 		refstr_put(default_cmd);
1233 		default_cmd = refstrdup(globaldefault);
1234 	    }
1235 	} else if (looking_at(p, "ui")) {
1236 	    has_ui = 1;
1237 	    defaultlevel = LEVEL_UI;
1238 	    refstr_put(default_cmd);
1239 	    default_cmd = refstrdup(skipspace(p + 2));
1240 	}
1241 
1242 	/*
1243 	 * subset 1:  pc_opencmd
1244 	 * display/font/kbdmap are rather similar, open a file then do sth
1245 	 */
1246 	else if (looking_at(p, "display")) {
1247 		const char *filename;
1248 		char *dst = KernelName;
1249 		size_t len = FILENAME_MAX - 1;
1250 
1251 		filename = refstrdup(skipspace(p + 7));
1252 
1253 		while (len-- && not_whitespace(*filename))
1254 			*dst++ = *filename++;
1255 		*dst = '\0';
1256 
1257 		get_msg_file(KernelName);
1258 		refstr_put(filename);
1259 	} else if (looking_at(p, "font")) {
1260 		const char *filename;
1261 		char *dst = KernelName;
1262 		size_t len = FILENAME_MAX - 1;
1263 
1264 		filename = refstrdup(skipspace(p + 4));
1265 
1266 		while (len-- && not_whitespace(*filename))
1267 			*dst++ = *filename++;
1268 		*dst = '\0';
1269 
1270 		loadfont(KernelName);
1271 		refstr_put(filename);
1272 	} else if (looking_at(p, "kbdmap")) {
1273 		const char *filename;
1274 
1275 		filename = refstrdup(skipspace(p + 6));
1276 		loadkeys(filename);
1277 		refstr_put(filename);
1278 	}
1279 	/*
1280 	 * subset 2:  pc_setint16
1281 	 * set a global flag
1282 	 */
1283 	else if (looking_at(p, "implicit")) {
1284 		allowimplicit = atoi(skipspace(p + 8));
1285 	} else if (looking_at(p, "prompt")) {
1286 		forceprompt = atoi(skipspace(p + 6));
1287 	} else if (looking_at(p, "console")) {
1288 		DisplayCon = atoi(skipspace(p + 7));
1289 	} else if (looking_at(p, "allowoptions")) {
1290 		allowoptions = atoi(skipspace(p + 12));
1291 	} else if (looking_at(p, "noescape")) {
1292 		noescape = atoi(skipspace(p + 8));
1293 	} else if (looking_at(p, "nocomplete")) {
1294 		nocomplete = atoi(skipspace(p + 10));
1295 	} else if (looking_at(p, "nohalt")) {
1296 		NoHalt = atoi(skipspace(p + 8));
1297 	} else if (looking_at(p, "onerror")) {
1298 		refstr_put(m->onerror);
1299 		m->onerror = refstrdup(skipspace(p + 7));
1300 		onerrorlen = strlen(m->onerror);
1301 		refstr_put(onerror);
1302 		onerror = refstrdup(m->onerror);
1303 	}
1304 
1305 	else if (looking_at(p, "pxeretry"))
1306 		PXERetry = atoi(skipspace(p + 8));
1307 
1308 	/* serial setting, bps, flow control */
1309 	else if (looking_at(p, "serial")) {
1310 		uint16_t port, flow;
1311 		uint32_t baud;
1312 
1313 		p = skipspace(p + 6);
1314 		port = atoi(p);
1315 
1316 		while (isalnum(*p))
1317 			p++;
1318 		p = skipspace(p);
1319 
1320 		/* Default to no flow control */
1321 		FlowOutput = 0;
1322 		FlowInput = 0;
1323 
1324 		baud = DEFAULT_BAUD;
1325 		if (isalnum(*p)) {
1326 			uint8_t ignore;
1327 
1328 			/* setup baud */
1329 			baud = atoi(p);
1330 			while (isalnum(*p))
1331 				p++;
1332 			p = skipspace(p);
1333 
1334 			ignore = 0;
1335 			flow = 0;
1336 			if (isalnum(*p)) {
1337 				/* flow control */
1338 				flow = atoi(p);
1339 				ignore = ((flow & 0x0F00) >> 4);
1340 			}
1341 
1342 			FlowIgnore = ignore;
1343 			flow = ((flow & 0xff) << 8) | (flow & 0xff);
1344 			flow &= 0xF00B;
1345 			FlowOutput = (flow & 0xff);
1346 			FlowInput = ((flow & 0xff00) >> 8);
1347 		}
1348 
1349 		/*
1350 		 * Parse baud
1351 		 */
1352 		if (baud < 75) {
1353 			/* < 75 baud == bogus */
1354 			SerialPort = 0;
1355 			continue;
1356 		}
1357 
1358 		baud = BAUD_DIVISOR / baud;
1359 		baud &= 0xffff;
1360 		BaudDivisor = baud;
1361 
1362 		port = get_serial_port(port);
1363 		SerialPort = port;
1364 
1365 		/*
1366 		 * Begin code to actually set up the serial port
1367 		 */
1368 		sirq_cleanup_nowipe();
1369 
1370 		outb(0x83, port + 3); /* Enable DLAB */
1371 		io_delay();
1372 
1373 		outb((baud & 0xff), port); /* write divisor to LS */
1374 		io_delay();
1375 
1376 		outb(((baud & 0xff00) >> 8), port + 1); /* write to MS */
1377 		io_delay();
1378 
1379 		outb(0x03, port + 3); /* Disable DLAB */
1380 		io_delay();
1381 
1382 		/*
1383 		 * Read back LCR (detect missing hw). If nothing here
1384 		 * we'll read 00 or FF.
1385 		 */
1386 		if (inb(port + 3) != 0x03) {
1387 			/* Assume serial port busted */
1388 			SerialPort = 0;
1389 			continue;
1390 		}
1391 
1392 		outb(0x01, port + 2); /* Enable FIFOs if present */
1393 		io_delay();
1394 
1395 		/* Disable FIFO if unusable */
1396 		if (inb(port + 2) < 0x0C0) {
1397 			outb(0, port + 2);
1398 			io_delay();
1399 		}
1400 
1401 		/* Assert bits in MCR */
1402 		outb(FlowOutput, port + 4);
1403 		io_delay();
1404 
1405 		/* Enable interrupts if requested */
1406 		if (FlowOutput & 0x8)
1407 			sirq_install();
1408 
1409 		/* Show some life */
1410 		if (SerialNotice != 0) {
1411 			SerialNotice = 0;
1412 
1413 			write_serial_str(syslinux_banner);
1414 			write_serial_str(copyright_str);
1415 		}
1416 
1417 	} else if (looking_at(p, "say")) {
1418 		printf("%s\n", p+4);
1419 	} else if (looking_at(p, "path")) {
1420 		if (parse_path(skipspace(p + 4)))
1421 			printf("Failed to parse PATH\n");
1422 	} else if (looking_at(p, "sendcookies")) {
1423 		const union syslinux_derivative_info *sdi;
1424 
1425 		p += strlen("sendcookies");
1426 		sdi = syslinux_derivative_info();
1427 
1428 		if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
1429 			SendCookies = strtoul(skipspace(p), NULL, 10);
1430 			http_bake_cookies();
1431 		}
1432 	}
1433     }
1434 }
1435 
parse_main_config(const char * filename)1436 static int parse_main_config(const char *filename)
1437 {
1438 	const char *mode = "r";
1439 	FILE *f;
1440 	int fd;
1441 
1442 	if (!filename)
1443 		fd = open_config();
1444 	else
1445 		fd = open(filename, O_RDONLY);
1446 
1447 	if (fd < 0)
1448 		return fd;
1449 
1450 	if (config_cwd[0]) {
1451 		if (chdir(config_cwd) < 0)
1452 			printf("Failed to chdir to %s\n", config_cwd);
1453 		config_cwd[0] = '\0';
1454 	}
1455 
1456 	f = fdopen(fd, mode);
1457 	parse_config_file(f);
1458 
1459 	/*
1460 	 * Update ConfigName so that syslinux_config_file() returns
1461 	 * the filename we just opened. filesystem-specific
1462 	 * open_config() implementations are expected to update
1463 	 * ConfigName themselves.
1464 	 */
1465 	if (filename)
1466 	    strcpy(ConfigName, filename);
1467 
1468 	return 0;
1469 }
1470 
resolve_gotos(void)1471 static void resolve_gotos(void)
1472 {
1473     struct menu_entry *me;
1474     struct menu *m;
1475 
1476     for (me = all_entries; me; me = me->next) {
1477 	if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) {
1478 	    m = find_menu(me->cmdline);
1479 	    refstr_put(me->cmdline);
1480 	    me->cmdline = NULL;
1481 	    if (m) {
1482 		me->submenu = m;
1483 		me->action--;	/* Drop the _UNRES */
1484 	    } else {
1485 		me->action = MA_DISABLED;
1486 	    }
1487 	}
1488     }
1489 }
1490 
parse_configs(char ** argv)1491 void parse_configs(char **argv)
1492 {
1493     const char *filename;
1494     struct menu *m;
1495     struct menu_entry *me;
1496     dprintf("enter");
1497 
1498     empty_string = refstrdup("");
1499 
1500     /* feng: reset current menu_list and entry list */
1501     menu_list = NULL;
1502     all_entries = NULL;
1503 
1504     /* Initialize defaults for the root and hidden menus */
1505     hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
1506     root_menu = new_menu(NULL, NULL, refstrdup(".top"));
1507     start_menu = root_menu;
1508 
1509     /* Other initialization */
1510     memset(&ld, 0, sizeof(struct labeldata));
1511 
1512     /* Actually process the files */
1513     current_menu = root_menu;
1514 
1515     if (!argv || !*argv) {
1516 	if (parse_main_config(NULL) < 0) {
1517 	    printf("WARNING: No configuration file found\n");
1518 	    return;
1519 	}
1520     } else {
1521 	while ((filename = *argv++)) {
1522 		dprintf("Parsing config: %s", filename);
1523 	    parse_main_config(filename);
1524 	}
1525     }
1526 
1527     /* On final EOF process the last label statement */
1528     record(current_menu, &ld, append);
1529 
1530     /* Common postprocessing */
1531     resolve_gotos();
1532 
1533     /* Handle global default */
1534     //if (has_ui && globaldefault) {
1535     if (globaldefault) {
1536 	dprintf("gloabldefault = %s", globaldefault);
1537 	me = find_label(globaldefault);
1538 	if (me && me->menu != hide_menu) {
1539 	    me->menu->defentry = me->entry;
1540 	    start_menu = me->menu;
1541 	    default_menu = me->menu;
1542 	}
1543     }
1544 
1545     /* If "menu save" is active, let the ADV override the global default */
1546     if (menusave) {
1547 	size_t len;
1548 	const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
1549 	char *lstr;
1550 	if (lbl && len) {
1551 	    lstr = refstr_alloc(len);
1552 	    memcpy(lstr, lbl, len);	/* refstr_alloc() adds the final null */
1553 	    me = find_label(lstr);
1554 	    if (me && me->menu != hide_menu) {
1555 		me->menu->defentry = me->entry;
1556 		start_menu = me->menu;
1557 	    }
1558 	    refstr_put(lstr);
1559 	}
1560     }
1561 
1562     /* Final per-menu initialization, with all labels known */
1563     for (m = menu_list; m; m = m->next) {
1564 	m->curentry = m->defentry;	/* All menus start at their defaults */
1565 
1566 	if (m->ontimeout)
1567 	    m->ontimeout = unlabel(m->ontimeout);
1568 	if (m->onerror)
1569 	    m->onerror = unlabel(m->onerror);
1570     }
1571 }
1572