Merging upstream version 5.01+dfsg.
[syslinux-debian/hramrach.git] / com32 / elflink / ldlinux / readconfig.c
bloba2421e9527202a33c52bc90f3bf1e60ea2aca243
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
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.
12 * ----------------------------------------------------------------------- */
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>
33 #include "menu.h"
34 #include "config.h"
35 #include "getkey.h"
36 #include "core.h"
37 #include "fs.h"
39 const struct menu_parameter mparm[NPARAMS] = {
40 [P_WIDTH] = {"width", 0},
41 [P_MARGIN] = {"margin", 10},
42 [P_PASSWD_MARGIN] = {"passwordmargin", 3},
43 [P_MENU_ROWS] = {"rows", 12},
44 [P_TABMSG_ROW] = {"tabmsgrow", 18},
45 [P_CMDLINE_ROW] = {"cmdlinerow", 18},
46 [P_END_ROW] = {"endrow", -1},
47 [P_PASSWD_ROW] = {"passwordrow", 11},
48 [P_TIMEOUT_ROW] = {"timeoutrow", 20},
49 [P_HELPMSG_ROW] = {"helpmsgrow", 22},
50 [P_HELPMSGEND_ROW] = {"helpmsgendrow", -1},
51 [P_HSHIFT] = {"hshift", 0},
52 [P_VSHIFT] = {"vshift", 0},
53 [P_HIDDEN_ROW] = {"hiddenrow", -2},
56 /* Must match enum kernel_type */
57 static const char *const kernel_types[] = {
58 "none",
59 "localboot",
60 "kernel",
61 "linux",
62 "boot",
63 "bss",
64 "pxe",
65 "fdimage",
66 "comboot",
67 "com32",
68 "config",
69 NULL
72 short uappendlen = 0; //bytes in append= command
73 short ontimeoutlen = 0; //bytes in ontimeout command
74 short onerrorlen = 0; //bytes in onerror command
75 short forceprompt = 0; //force prompt
76 short noescape = 0; //no escape
77 short nocomplete = 0; //no label completion on TAB key
78 short allowimplicit = 1; //allow implicit kernels
79 short allowoptions = 1; //user-specified options allowed
80 short includelevel = 1; //nesting level
81 short defaultlevel = 0; //the current level of default
82 short vkernel = 0; //have we seen any "label" statements?
83 extern short NoHalt; //idle.c
85 const char *onerror = NULL; //"onerror" command line
86 const char *ontimeout = NULL; //"ontimeout" command line
88 __export const char *default_cmd = NULL; //"default" command line
90 /* Empty refstring */
91 const char *empty_string;
93 /* Root menu, starting menu, hidden menu, and list of all menus */
94 struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
96 /* These are global parameters regardless of which menu we're displaying */
97 int shiftkey = 0; /* Only display menu if shift key pressed */
98 int hiddenmenu = 0;
99 long long totaltimeout = 0;
100 unsigned int kbdtimeout = 0;
102 /* Keep track of global default */
103 static int has_ui = 0; /* DEFAULT only counts if UI is found */
104 extern const char *globaldefault;
105 static bool menusave = false; /* True if there is any "menu save" */
107 /* Linked list of all entires, hidden or not; used by unlabel() */
108 static struct menu_entry *all_entries;
109 static struct menu_entry **all_entries_end = &all_entries;
111 static const struct messages messages[MSG_COUNT] = {
112 [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
113 [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
114 [MSG_NOTAB] = {"notabmsg", ""},
115 [MSG_PASSPROMPT] = {"passprompt", "Password required"},
118 #define astrdup(x) ({ char *__x = (x); \
119 size_t __n = strlen(__x) + 1; \
120 char *__p = alloca(__n); \
121 if ( __p ) memcpy(__p, __x, __n); \
122 __p; })
125 * Search the list of all menus for a specific label
127 static struct menu *find_menu(const char *label)
129 struct menu *m;
131 for (m = menu_list; m; m = m->next) {
132 if (!strcmp(label, m->label))
133 return m;
136 return NULL;
139 #define MAX_LINE 4096
141 /* Strip ^ from a string, returning a new reference to the same refstring
142 if none present */
143 static const char *strip_caret(const char *str)
145 const char *p, *r;
146 char *q;
147 int carets = 0;
149 p = str;
150 for (;;) {
151 p = strchr(p, '^');
152 if (!p)
153 break;
154 carets++;
155 p++;
158 if (!carets)
159 return refstr_get(str);
161 r = q = refstr_alloc(strlen(str) - carets);
162 for (p = str; *p; p++)
163 if (*p != '^')
164 *q++ = *p;
166 *q = '\0'; /* refstr_alloc() already did this... */
168 return r;
171 /* Check to see if we are at a certain keyword (case insensitive) */
172 /* Returns a pointer to the first character past the keyword */
173 static char *looking_at(char *line, const char *kwd)
175 char *p = line;
176 const char *q = kwd;
178 while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
179 p++;
180 q++;
183 if (*q)
184 return NULL; /* Didn't see the keyword */
186 return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */
189 static struct menu *new_menu(struct menu *parent,
190 struct menu_entry *parent_entry, const char *label)
192 struct menu *m = calloc(1, sizeof(struct menu));
193 int i;
195 //dprintf("enter: menu_label = %s", label);
197 m->label = label;
198 m->title = refstr_get(empty_string);
200 if (parent) {
201 /* Submenu */
202 m->parent = parent;
203 m->parent_entry = parent_entry;
204 parent_entry->action = MA_SUBMENU;
205 parent_entry->submenu = m;
207 for (i = 0; i < MSG_COUNT; i++)
208 m->messages[i] = refstr_get(parent->messages[i]);
210 memcpy(m->mparm, parent->mparm, sizeof m->mparm);
212 m->allowedit = parent->allowedit;
213 m->timeout = parent->timeout;
214 m->save = parent->save;
216 m->ontimeout = refstr_get(parent->ontimeout);
217 m->onerror = refstr_get(parent->onerror);
218 m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
219 m->menu_background = refstr_get(parent->menu_background);
221 m->color_table = copy_color_table(parent->color_table);
223 for (i = 0; i < 12; i++) {
224 m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
225 m->fkeyhelp[i].background =
226 refstr_get(parent->fkeyhelp[i].background);
228 } else {
229 /* Root menu */
230 for (i = 0; i < MSG_COUNT; i++)
231 m->messages[i] = refstrdup(messages[i].defmsg);
232 for (i = 0; i < NPARAMS; i++)
233 m->mparm[i] = mparm[i].value;
235 m->allowedit = true; /* Allow edits of the command line */
236 m->color_table = default_color_table();
239 m->next = menu_list;
240 menu_list = m;
242 return m;
245 struct labeldata {
246 const char *label;
247 const char *kernel;
248 enum kernel_type type;
249 const char *append;
250 const char *initrd;
251 const char *menulabel;
252 const char *passwd;
253 char *helptext;
254 unsigned int ipappend;
255 unsigned int menuhide;
256 unsigned int menudefault;
257 unsigned int menuseparator;
258 unsigned int menudisabled;
259 unsigned int menuindent;
260 enum menu_action action;
261 int save;
262 struct menu *submenu;
265 /* Menu currently being parsed */
266 static struct menu *current_menu;
268 static void clear_label_data(struct labeldata *ld)
270 refstr_put(ld->label);
271 refstr_put(ld->kernel);
272 refstr_put(ld->append);
273 refstr_put(ld->initrd);
274 refstr_put(ld->menulabel);
275 refstr_put(ld->passwd);
277 memset(ld, 0, sizeof *ld);
280 static struct menu_entry *new_entry(struct menu *m)
282 struct menu_entry *me;
284 //dprintf("enter, call from menu %s", m->label);
286 if (m->nentries >= m->nentries_space) {
287 if (!m->nentries_space)
288 m->nentries_space = 1;
289 else
290 m->nentries_space <<= 1;
292 m->menu_entries = realloc(m->menu_entries, m->nentries_space *
293 sizeof(struct menu_entry *));
296 me = calloc(1, sizeof(struct menu_entry));
297 me->menu = m;
298 me->entry = m->nentries;
299 m->menu_entries[m->nentries++] = me;
300 *all_entries_end = me;
301 all_entries_end = &me->next;
303 return me;
306 static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
308 const char *p = strchr(me->displayname, '^');
310 if (me->action != MA_DISABLED) {
311 if (p && p[1]) {
312 unsigned char hotkey = p[1] & ~0x20;
313 if (!m->menu_hotkeys[hotkey]) {
314 me->hotkey = hotkey;
315 m->menu_hotkeys[hotkey] = me;
321 static void record(struct menu *m, struct labeldata *ld, const char *append)
323 int i;
324 struct menu_entry *me;
325 const struct syslinux_ipappend_strings *ipappend;
327 if (!ld->label)
328 return; /* Nothing defined */
330 /* Hidden entries are recorded on a special "hidden menu" */
331 if (ld->menuhide)
332 m = hide_menu;
334 char ipoptions[4096], *ipp;
335 const char *a;
336 char *s;
338 me = new_entry(m);
340 me->displayname = ld->menulabel
341 ? refstr_get(ld->menulabel) : refstr_get(ld->label);
342 me->label = refstr_get(ld->label);
343 me->passwd = refstr_get(ld->passwd);
344 me->helptext = ld->helptext;
345 me->hotkey = 0;
346 me->action = ld->action ? ld->action : MA_CMD;
347 me->save = ld->save ? (ld->save > 0) : m->save;
349 if (ld->menuindent) {
350 const char *dn;
352 rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
353 refstr_put(me->displayname);
354 me->displayname = dn;
357 if (ld->menuseparator) {
358 refstr_put(me->displayname);
359 me->displayname = refstr_get(empty_string);
362 if (ld->menuseparator || ld->menudisabled) {
363 me->action = MA_DISABLED;
364 refstr_put(me->label);
365 me->label = NULL;
366 refstr_put(me->passwd);
367 me->passwd = NULL;
370 if (ld->menulabel)
371 consider_for_hotkey(m, me);
373 switch (me->action) {
374 case MA_CMD:
375 ipp = ipoptions;
376 *ipp = '\0';
378 if (ld->initrd)
379 ipp += sprintf(ipp, " initrd=%s", ld->initrd);
381 if (ld->ipappend) {
382 ipappend = syslinux_ipappend_strings();
383 for (i = 0; i < ipappend->count; i++) {
384 if ((ld->ipappend & (1U << i)) && ipappend->ptr[i])
385 ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
389 a = ld->append;
390 if (!a)
391 a = append;
392 if (!a || (a[0] == '-' && !a[1]))
393 a = "";
394 s = a[0] ? " " : "";
396 if (ld->type == KT_KERNEL)
397 rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
398 else
399 rsprintf(&me->cmdline, ".%s %s%s%s%s",
400 kernel_types[ld->type], ld->kernel, s, a, ipoptions);
401 dprintf("type = %s, cmd = %s", kernel_types[ld->type], me->cmdline);
402 break;
404 case MA_GOTO_UNRES:
405 case MA_EXIT_UNRES:
406 me->cmdline = refstr_get(ld->kernel);
407 break;
409 case MA_GOTO:
410 case MA_EXIT:
411 me->submenu = ld->submenu;
412 break;
414 default:
415 break;
418 if (ld->menudefault && me->action == MA_CMD)
419 m->defentry = m->nentries - 1;
421 clear_label_data(ld);
424 static struct menu *begin_submenu(const char *tag)
426 struct menu_entry *me;
428 if (!tag[0])
429 tag = NULL;
431 me = new_entry(current_menu);
432 me->displayname = refstrdup(tag);
433 return new_menu(current_menu, me, refstr_get(me->displayname));
436 static struct menu *end_submenu(void)
438 return current_menu->parent ? current_menu->parent : current_menu;
441 void print_labels(const char *prefix, size_t len)
443 struct menu_entry *me;
445 printf("\n");
446 for (me = all_entries; me; me = me->next ) {
447 if (!strncmp(prefix, me->label, len))
448 printf(" %s", me->label);
450 printf("\n");
453 struct menu_entry *find_label(const char *str)
455 const char *p;
456 struct menu_entry *me;
457 int pos;
459 p = str;
460 while (*p && !my_isspace(*p))
461 p++;
463 /* p now points to the first byte beyond the kernel name */
464 pos = p - str;
466 for (me = all_entries; me; me = me->next) {
467 if (!strncmp(str, me->label, pos) && !me->label[pos])
468 return me;
471 return NULL;
474 static const char *unlabel(const char *str)
476 /* Convert a CLI-style command line to an executable command line */
477 const char *p;
478 const char *q;
479 struct menu_entry *me;
480 int pos;
482 p = str;
483 while (*p && !my_isspace(*p))
484 p++;
486 /* p now points to the first byte beyond the kernel name */
487 pos = p - str;
489 for (me = all_entries; me; me = me->next) {
490 if (!strncmp(str, me->label, pos) && !me->label[pos]) {
491 /* Found matching label */
492 rsprintf(&q, "%s%s", me->cmdline, p);
493 refstr_put(str);
494 return q;
498 return str;
501 static const char *__refdup_word(char *p, char **ref)
503 char *sp = p;
504 char *ep = sp;
506 while (*ep && !my_isspace(*ep))
507 ep++;
509 if (ref)
510 *ref = ep;
511 return refstrndup(sp, ep - sp);
514 static const char *refdup_word(char **p)
516 return __refdup_word(*p, p);
519 int my_isxdigit(char c)
521 unsigned int uc = c;
523 return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
526 unsigned int hexval(char c)
528 unsigned char uc = c | 0x20;
529 unsigned int v;
531 v = uc - '0';
532 if (v < 10)
533 return v;
535 return uc - 'a' + 10;
538 unsigned int hexval2(const char *p)
540 return (hexval(p[0]) << 4) + hexval(p[1]);
543 uint32_t parse_argb(char **p)
545 char *sp = *p;
546 char *ep;
547 uint32_t argb;
548 size_t len, dl;
550 if (*sp == '#')
551 sp++;
553 ep = sp;
555 while (my_isxdigit(*ep))
556 ep++;
558 *p = ep;
559 len = ep - sp;
561 switch (len) {
562 case 3: /* #rgb */
563 argb =
564 0xff000000 +
565 (hexval(sp[0]) * 0x11 << 16) +
566 (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
567 break;
568 case 4: /* #argb */
569 argb =
570 (hexval(sp[0]) * 0x11 << 24) +
571 (hexval(sp[1]) * 0x11 << 16) +
572 (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
573 break;
574 case 6: /* #rrggbb */
575 case 9: /* #rrrgggbbb */
576 case 12: /* #rrrrggggbbbb */
577 dl = len / 3;
578 argb =
579 0xff000000 +
580 (hexval2(sp + 0) << 16) +
581 (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
582 break;
583 case 8: /* #aarrggbb */
584 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
585 assume the latter is a more common format */
586 case 16: /* #aaaarrrrggggbbbb */
587 dl = len / 4;
588 argb =
589 (hexval2(sp + 0) << 24) +
590 (hexval2(sp + dl) << 16) +
591 (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
592 break;
593 default:
594 argb = 0xffff0000; /* Bright red (error indication) */
595 break;
598 return argb;
602 * Parser state. This is global so that including multiple
603 * files work as expected, which is that everything works the
604 * same way as if the files had been concatenated together.
606 //static const char *append = NULL;
607 extern const char *append;
608 //static unsigned int ipappend = 0;
609 __export unsigned int ipappend = 0;
610 extern uint16_t PXERetry;
611 static struct labeldata ld;
613 static int parse_one_config(const char *filename);
615 static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
617 const char *const *p;
618 char *q;
619 enum kernel_type t = KT_NONE;
621 for (p = kernel_types; *p; p++, t++) {
622 if ((q = looking_at(cmdstr, *p))) {
623 *type = t;
624 return q;
628 return NULL;
631 static char *is_message_name(char *cmdstr, enum message_number *msgnr)
633 char *q;
634 enum message_number i;
636 for (i = 0; i < MSG_COUNT; i++) {
637 if ((q = looking_at(cmdstr, messages[i].name))) {
638 *msgnr = i;
639 return q;
643 return NULL;
646 extern void get_msg_file(char *);
648 void cat_help_file(int key)
650 struct menu *cm = current_menu;
651 int fkey;
653 switch (key) {
654 case KEY_F1:
655 fkey = 0;
656 break;
657 case KEY_F2:
658 fkey = 1;
659 break;
660 case KEY_F3:
661 fkey = 2;
662 break;
663 case KEY_F4:
664 fkey = 3;
665 break;
666 case KEY_F5:
667 fkey = 4;
668 break;
669 case KEY_F6:
670 fkey = 5;
671 break;
672 case KEY_F7:
673 fkey = 6;
674 break;
675 case KEY_F8:
676 fkey = 7;
677 break;
678 case KEY_F9:
679 fkey = 8;
680 break;
681 case KEY_F10:
682 fkey = 9;
683 break;
684 case KEY_F11:
685 fkey = 10;
686 break;
687 case KEY_F12:
688 fkey = 11;
689 break;
690 default:
691 fkey = -1;
692 break;
695 if (fkey == -1)
696 return;
698 if (cm->fkeyhelp[fkey].textname) {
699 printf("\n");
700 get_msg_file((char *)cm->fkeyhelp[fkey].textname);
704 static char *is_fkey(char *cmdstr, int *fkeyno)
706 char *q;
707 int no;
709 if ((cmdstr[0] | 0x20) != 'f')
710 return NULL;
712 no = strtoul(cmdstr + 1, &q, 10);
713 if (!my_isspace(*q))
714 return NULL;
716 if (no < 0 || no > 12)
717 return NULL;
719 *fkeyno = (no == 0) ? 10 : no - 1;
720 return q;
723 extern uint8_t FlowIgnore;
724 extern uint8_t FlowInput;
725 extern uint8_t FlowOutput;
726 extern uint16_t SerialPort;
727 extern uint16_t BaudDivisor;
728 static uint8_t SerialNotice = 1;
730 #define DEFAULT_BAUD 9600
731 #define BAUD_DIVISOR 115200
732 #define serial_base 0x0400
734 extern void sirq_cleanup_nowipe(void);
735 extern void sirq_install(void);
736 extern void write_serial_str(char *);
738 extern void loadfont(char *);
739 extern void loadkeys(char *);
741 extern char syslinux_banner[];
742 extern char copyright_str[];
744 static void parse_config_file(FILE * f)
746 char line[MAX_LINE], *p, *ep, ch;
747 enum kernel_type type;
748 enum message_number msgnr;
749 int fkeyno;
750 struct menu *m = current_menu;
752 while (fgets(line, sizeof line, f)) {
753 p = strchr(line, '\r');
754 if (p)
755 *p = '\0';
756 p = strchr(line, '\n');
757 if (p)
758 *p = '\0';
760 p = skipspace(line);
762 if (looking_at(p, "menu")) {
764 p = skipspace(p + 4);
766 if (looking_at(p, "label")) {
767 if (ld.label) {
768 refstr_put(ld.menulabel);
769 ld.menulabel = refstrdup(skipspace(p + 5));
770 } else if (m->parent_entry) {
771 refstr_put(m->parent_entry->displayname);
772 m->parent_entry->displayname = refstrdup(skipspace(p + 5));
773 consider_for_hotkey(m->parent, m->parent_entry);
774 if (!m->title[0]) {
775 /* MENU LABEL -> MENU TITLE on submenu */
776 refstr_put(m->title);
777 m->title = strip_caret(m->parent_entry->displayname);
780 } else if (looking_at(p, "title")) {
781 refstr_put(m->title);
782 m->title = refstrdup(skipspace(p + 5));
783 if (m->parent_entry) {
784 /* MENU TITLE -> MENU LABEL on submenu */
785 if (m->parent_entry->displayname == m->label) {
786 refstr_put(m->parent_entry->displayname);
787 m->parent_entry->displayname = refstr_get(m->title);
790 } else if (looking_at(p, "default")) {
791 if (ld.label) {
792 ld.menudefault = 1;
793 } else if (m->parent_entry) {
794 m->parent->defentry = m->parent_entry->entry;
796 } else if (looking_at(p, "hide")) {
797 ld.menuhide = 1;
798 } else if (looking_at(p, "passwd")) {
799 if (ld.label) {
800 refstr_put(ld.passwd);
801 ld.passwd = refstrdup(skipspace(p + 6));
802 } else if (m->parent_entry) {
803 refstr_put(m->parent_entry->passwd);
804 m->parent_entry->passwd = refstrdup(skipspace(p + 6));
806 } else if (looking_at(p, "shiftkey")) {
807 shiftkey = 1;
808 } else if (looking_at(p, "save")) {
809 menusave = true;
810 if (ld.label)
811 ld.save = 1;
812 else
813 m->save = true;
814 } else if (looking_at(p, "nosave")) {
815 if (ld.label)
816 ld.save = -1;
817 else
818 m->save = false;
819 } else if (looking_at(p, "onerror")) {
820 refstr_put(m->onerror);
821 m->onerror = refstrdup(skipspace(p + 7));
822 onerrorlen = strlen(m->onerror);
823 refstr_put(onerror);
824 onerror = refstrdup(m->onerror);
825 } else if (looking_at(p, "master")) {
826 p = skipspace(p + 6);
827 if (looking_at(p, "passwd")) {
828 refstr_put(m->menu_master_passwd);
829 m->menu_master_passwd = refstrdup(skipspace(p + 6));
831 } else if ((ep = looking_at(p, "include"))) {
832 goto do_include;
833 } else if ((ep = looking_at(p, "background"))) {
834 p = skipspace(ep);
835 refstr_put(m->menu_background);
836 m->menu_background = refdup_word(&p);
837 } else if ((ep = looking_at(p, "hidden"))) {
838 hiddenmenu = 1;
839 } else if ((ep = is_message_name(p, &msgnr))) {
840 refstr_put(m->messages[msgnr]);
841 m->messages[msgnr] = refstrdup(skipspace(ep));
842 } else if ((ep = looking_at(p, "color")) ||
843 (ep = looking_at(p, "colour"))) {
844 int i;
845 struct color_table *cptr;
846 p = skipspace(ep);
847 cptr = m->color_table;
848 for (i = 0; i < menu_color_table_size; i++) {
849 if ((ep = looking_at(p, cptr->name))) {
850 p = skipspace(ep);
851 if (*p) {
852 if (looking_at(p, "*")) {
853 p++;
854 } else {
855 refstr_put(cptr->ansi);
856 cptr->ansi = refdup_word(&p);
859 p = skipspace(p);
860 if (*p) {
861 if (looking_at(p, "*"))
862 p++;
863 else
864 cptr->argb_fg = parse_argb(&p);
866 p = skipspace(p);
867 if (*p) {
868 if (looking_at(p, "*"))
869 p++;
870 else
871 cptr->argb_bg = parse_argb(&p);
873 /* Parse a shadow mode */
874 p = skipspace(p);
875 ch = *p | 0x20;
876 if (ch == 'n') /* none */
877 cptr->shadow = SHADOW_NONE;
878 else if (ch == 's') /* std, standard */
879 cptr->shadow = SHADOW_NORMAL;
880 else if (ch == 'a') /* all */
881 cptr->shadow = SHADOW_ALL;
882 else if (ch == 'r') /* rev, reverse */
883 cptr->shadow = SHADOW_REVERSE;
887 break;
889 cptr++;
891 } else if ((ep = looking_at(p, "msgcolor")) ||
892 (ep = looking_at(p, "msgcolour"))) {
893 unsigned int fg_mask = MSG_COLORS_DEF_FG;
894 unsigned int bg_mask = MSG_COLORS_DEF_BG;
895 enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
897 p = skipspace(ep);
898 if (*p) {
899 if (!looking_at(p, "*"))
900 fg_mask = parse_argb(&p);
902 p = skipspace(p);
903 if (*p) {
904 if (!looking_at(p, "*"))
905 bg_mask = parse_argb(&p);
907 p = skipspace(p);
908 switch (*p | 0x20) {
909 case 'n':
910 shadow = SHADOW_NONE;
911 break;
912 case 's':
913 shadow = SHADOW_NORMAL;
914 break;
915 case 'a':
916 shadow = SHADOW_ALL;
917 break;
918 case 'r':
919 shadow = SHADOW_REVERSE;
920 break;
921 default:
922 /* go with default */
923 break;
927 set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
928 } else if (looking_at(p, "separator")) {
929 record(m, &ld, append);
930 ld.label = refstr_get(empty_string);
931 ld.menuseparator = 1;
932 record(m, &ld, append);
933 } else if (looking_at(p, "disable") || looking_at(p, "disabled")) {
934 ld.menudisabled = 1;
935 } else if (looking_at(p, "indent")) {
936 ld.menuindent = atoi(skipspace(p + 6));
937 } else if (looking_at(p, "begin")) {
938 record(m, &ld, append);
939 m = current_menu = begin_submenu(skipspace(p + 5));
940 } else if (looking_at(p, "end")) {
941 record(m, &ld, append);
942 m = current_menu = end_submenu();
943 } else if (looking_at(p, "quit")) {
944 if (ld.label)
945 ld.action = MA_QUIT;
946 } else if (looking_at(p, "goto")) {
947 if (ld.label) {
948 ld.action = MA_GOTO_UNRES;
949 refstr_put(ld.kernel);
950 ld.kernel = refstrdup(skipspace(p + 4));
952 } else if (looking_at(p, "exit")) {
953 p = skipspace(p + 4);
954 if (ld.label && m->parent) {
955 if (*p) {
956 /* This is really just a goto, except for the marker */
957 ld.action = MA_EXIT_UNRES;
958 refstr_put(ld.kernel);
959 ld.kernel = refstrdup(p);
960 } else {
961 ld.action = MA_EXIT;
962 ld.submenu = m->parent;
965 } else if (looking_at(p, "start")) {
966 start_menu = m;
967 } else {
968 /* Unknown, check for layout parameters */
969 enum parameter_number mp;
970 for (mp = 0; mp < NPARAMS; mp++) {
971 if ((ep = looking_at(p, mparm[mp].name))) {
972 m->mparm[mp] = atoi(skipspace(ep));
973 break;
978 /* feng: menu handling end */
979 else if (looking_at(p, "text")) {
981 /* loop till we fined the "endtext" */
982 enum text_cmd {
983 TEXT_UNKNOWN,
984 TEXT_HELP
985 } cmd = TEXT_UNKNOWN;
986 int len = ld.helptext ? strlen(ld.helptext) : 0;
987 int xlen;
989 p = skipspace(p + 4);
991 if (looking_at(p, "help"))
992 cmd = TEXT_HELP;
994 while (fgets(line, sizeof line, f)) {
995 p = skipspace(line);
996 if (looking_at(p, "endtext"))
997 break;
999 xlen = strlen(line);
1001 switch (cmd) {
1002 case TEXT_UNKNOWN:
1003 break;
1004 case TEXT_HELP:
1005 ld.helptext = realloc(ld.helptext, len + xlen + 1);
1006 memcpy(ld.helptext + len, line, xlen + 1);
1007 len += xlen;
1008 break;
1011 } else if ((ep = is_fkey(p, &fkeyno))) {
1012 p = skipspace(ep);
1013 if (m->fkeyhelp[fkeyno].textname) {
1014 refstr_put(m->fkeyhelp[fkeyno].textname);
1015 m->fkeyhelp[fkeyno].textname = NULL;
1017 if (m->fkeyhelp[fkeyno].background) {
1018 refstr_put(m->fkeyhelp[fkeyno].background);
1019 m->fkeyhelp[fkeyno].background = NULL;
1022 refstr_put(m->fkeyhelp[fkeyno].textname);
1023 m->fkeyhelp[fkeyno].textname = refdup_word(&p);
1024 if (*p) {
1025 p = skipspace(p);
1026 m->fkeyhelp[fkeyno].background = refdup_word(&p);
1028 } else if ((ep = looking_at(p, "include"))) {
1029 do_include:
1031 const char *file;
1032 p = skipspace(ep);
1033 file = refdup_word(&p);
1034 p = skipspace(p);
1035 if (*p) {
1036 record(m, &ld, append);
1037 m = current_menu = begin_submenu(p);
1038 parse_one_config(file);
1039 record(m, &ld, append);
1040 m = current_menu = end_submenu();
1041 } else {
1042 parse_one_config(file);
1044 refstr_put(file);
1046 } else if (looking_at(p, "append")) {
1047 const char *a = refstrdup(skipspace(p + 6));
1048 if (ld.label) {
1049 refstr_put(ld.append);
1050 ld.append = a;
1051 } else {
1052 refstr_put(append);
1053 append = a;
1055 //dprintf("we got a append: %s", a);
1056 } else if (looking_at(p, "initrd")) {
1057 const char *a = refstrdup(skipspace(p + 6));
1058 if (ld.label) {
1059 refstr_put(ld.initrd);
1060 ld.initrd = a;
1061 } else {
1062 /* Ignore */
1064 } else if (looking_at(p, "label")) {
1065 p = skipspace(p + 5);
1066 /* when first time see "label", it will not really record anything */
1067 record(m, &ld, append);
1068 ld.label = __refdup_word(p, NULL);
1069 ld.kernel = __refdup_word(p, NULL);
1070 /* feng: this is the default type for all */
1071 ld.type = KT_KERNEL;
1072 ld.passwd = NULL;
1073 ld.append = NULL;
1074 ld.initrd = NULL;
1075 ld.menulabel = NULL;
1076 ld.helptext = NULL;
1077 ld.ipappend = ipappend;
1078 ld.menudefault = ld.menuhide = ld.menuseparator =
1079 ld.menudisabled = ld.menuindent = 0;
1080 } else if ((ep = is_kernel_type(p, &type))) {
1081 if (ld.label) {
1082 refstr_put(ld.kernel);
1083 ld.kernel = refstrdup(skipspace(ep));
1084 ld.type = type;
1085 //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
1087 } else if (looking_at(p, "timeout")) {
1088 kbdtimeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
1089 } else if (looking_at(p, "totaltimeout")) {
1090 totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
1091 } else if (looking_at(p, "ontimeout")) {
1092 ontimeout = refstrdup(skipspace(p + 9));
1093 ontimeoutlen = strlen(ontimeout);
1094 } else if (looking_at(p, "allowoptions")) {
1095 allowoptions = !!atoi(skipspace(p + 12));
1096 } else if (looking_at(p, "ipappend")) {
1097 if (ld.label)
1098 ld.ipappend = atoi(skipspace(p + 8));
1099 else
1100 ipappend = atoi(skipspace(p + 8));
1101 } else if (looking_at(p, "default")) {
1102 /* default could be a kernel image or another label */
1103 refstr_put(globaldefault);
1104 globaldefault = refstrdup(skipspace(p + 7));
1107 * On the chance that "default" is actually a kernel image
1108 * and not a label, store a copy of it, but only if we
1109 * haven't seen a "ui" command. "ui" commands take
1110 * precendence over "default" commands.
1112 if (defaultlevel < LEVEL_UI) {
1113 defaultlevel = LEVEL_DEFAULT;
1114 refstr_put(default_cmd);
1115 default_cmd = refstrdup(globaldefault);
1117 } else if (looking_at(p, "ui")) {
1118 has_ui = 1;
1119 defaultlevel = LEVEL_UI;
1120 refstr_put(default_cmd);
1121 default_cmd = refstrdup(skipspace(p + 2));
1125 * subset 1: pc_opencmd
1126 * display/font/kbdmap are rather similar, open a file then do sth
1128 else if (looking_at(p, "display")) {
1129 const char *filename;
1130 char *dst = KernelName;
1131 size_t len = FILENAME_MAX - 1;
1133 filename = refstrdup(skipspace(p + 7));
1135 while (len-- && not_whitespace(*filename))
1136 *dst++ = *filename++;
1137 *dst = '\0';
1139 get_msg_file(KernelName);
1140 refstr_put(filename);
1141 } else if (looking_at(p, "font")) {
1142 const char *filename;
1143 char *dst = KernelName;
1144 size_t len = FILENAME_MAX - 1;
1146 filename = refstrdup(skipspace(p + 4));
1148 while (len-- && not_whitespace(*filename))
1149 *dst++ = *filename++;
1150 *dst = '\0';
1152 loadfont(KernelName);
1153 refstr_put(filename);
1154 } else if (looking_at(p, "kbdmap")) {
1155 const char *filename;
1156 char *dst = KernelName;
1157 size_t len = FILENAME_MAX - 1;
1159 filename = refstrdup(skipspace(p + 4));
1161 while (len-- && not_whitespace(*filename))
1162 *dst++ = *filename++;
1163 *dst = '\0';
1165 loadkeys(KernelName);
1166 refstr_put(filename);
1169 * subset 2: pc_setint16
1170 * set a global flag
1172 else if (looking_at(p, "implicit")) {
1173 allowimplicit = atoi(skipspace(p + 8));
1174 } else if (looking_at(p, "prompt")) {
1175 forceprompt = atoi(skipspace(p + 6));
1176 } else if (looking_at(p, "console")) {
1177 DisplayCon = atoi(skipspace(p + 7));
1178 } else if (looking_at(p, "allowoptions")) {
1179 allowoptions = atoi(skipspace(p + 12));
1180 } else if (looking_at(p, "noescape")) {
1181 noescape = atoi(skipspace(p + 8));
1182 } else if (looking_at(p, "nocomplete")) {
1183 nocomplete = atoi(skipspace(p + 10));
1184 } else if (looking_at(p, "nohalt")) {
1185 NoHalt = atoi(skipspace(p + 8));
1186 } else if (looking_at(p, "onerror")) {
1187 refstr_put(m->onerror);
1188 m->onerror = refstrdup(skipspace(p + 7));
1189 onerrorlen = strlen(m->onerror);
1190 refstr_put(onerror);
1191 onerror = refstrdup(m->onerror);
1194 else if (looking_at(p, "pxeretry"))
1195 PXERetry = atoi(skipspace(p + 8));
1197 /* serial setting, bps, flow control */
1198 else if (looking_at(p, "serial")) {
1199 uint16_t port, flow;
1200 uint32_t baud;
1202 p = skipspace(p + 6);
1203 port = atoi(p);
1205 while (isalnum(*p))
1206 p++;
1207 p = skipspace(p);
1209 /* Default to no flow control */
1210 FlowOutput = 0;
1211 FlowInput = 0;
1213 baud = DEFAULT_BAUD;
1214 if (isalnum(*p)) {
1215 uint8_t ignore;
1217 /* setup baud */
1218 baud = atoi(p);
1219 while (isalnum(*p))
1220 p++;
1221 p = skipspace(p);
1223 ignore = 0;
1224 flow = 0;
1225 if (isalnum(*p)) {
1226 /* flow control */
1227 flow = atoi(p);
1228 ignore = ((flow & 0x0F00) >> 4);
1231 FlowIgnore = ignore;
1232 flow = ((flow & 0xff) << 8) | (flow & 0xff);
1233 flow &= 0xF00B;
1234 FlowOutput = (flow & 0xff);
1235 FlowInput = ((flow & 0xff00) >> 8);
1239 * Parse baud
1241 if (baud < 75) {
1242 /* < 75 baud == bogus */
1243 SerialPort = 0;
1244 continue;
1247 baud = BAUD_DIVISOR / baud;
1248 baud &= 0xffff;
1249 BaudDivisor = baud;
1252 * If port > 3 then port is I/O addr
1254 if (port <= 3) {
1255 /* Get the I/O port from the BIOS */
1256 port <<= 1;
1257 port = *(volatile uint16_t *)serial_base;
1261 SerialPort = port;
1264 * Begin code to actually set up the serial port
1266 sirq_cleanup_nowipe();
1268 outb(0x83, port + 3); /* Enable DLAB */
1269 io_delay();
1271 outb((baud & 0xff), port); /* write divisor to LS */
1272 io_delay();
1274 outb(((baud & 0xff00) >> 8), port + 1); /* write to MS */
1275 io_delay();
1277 outb(0x03, port + 3); /* Disable DLAB */
1278 io_delay();
1281 * Read back LCR (detect missing hw). If nothing here
1282 * we'll read 00 or FF.
1284 if (inb(port + 3) != 0x03) {
1285 /* Assume serial port busted */
1286 SerialPort = 0;
1287 continue;
1290 outb(0x01, port + 2); /* Enable FIFOs if present */
1291 io_delay();
1293 /* Disable FIFO if unusable */
1294 if (inb(port + 2) < 0x0C0) {
1295 outb(0, port + 2);
1296 io_delay();
1299 /* Assert bits in MCR */
1300 outb(FlowOutput, port + 4);
1301 io_delay();
1303 /* Enable interrupts if requested */
1304 if (FlowOutput & 0x8)
1305 sirq_install();
1307 /* Show some life */
1308 if (SerialNotice != 0) {
1309 SerialNotice = 0;
1311 write_serial_str(syslinux_banner);
1312 write_serial_str(copyright_str);
1315 } else if (looking_at(p, "say")) {
1316 printf("%s\n", p+4);
1317 } else if (looking_at(p, "path")) {
1318 /* PATH-based lookup */
1319 const char *new_path;
1320 char *_p;
1321 size_t len, new_len;
1323 new_path = refstrdup(skipspace(p + 4));
1324 len = strlen(PATH);
1325 new_len = strlen(new_path);
1326 _p = malloc(len + new_len + 2);
1327 if (_p) {
1328 strncpy(_p, PATH, len);
1329 _p[len++] = ':';
1330 strncpy(_p + len, new_path, new_len);
1331 _p[len + new_len] = '\0';
1332 free(PATH);
1333 PATH = _p;
1334 } else
1335 printf("Failed to realloc PATH\n");
1340 static int parse_one_config(const char *filename)
1342 const char *mode = "r";
1343 FILE *f;
1344 int fd;
1346 if (!filename)
1347 fd = open_config();
1348 else
1349 fd = open(filename, O_RDONLY);
1351 if (fd < 0)
1352 return fd;
1354 if (config_cwd[0]) {
1355 if (chdir(config_cwd) < 0)
1356 printf("Failed to chdir to %s\n", config_cwd);
1357 config_cwd[0] = '\0';
1360 f = fdopen(fd, mode);
1361 parse_config_file(f);
1363 return 0;
1366 static void resolve_gotos(void)
1368 struct menu_entry *me;
1369 struct menu *m;
1371 for (me = all_entries; me; me = me->next) {
1372 if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) {
1373 m = find_menu(me->cmdline);
1374 refstr_put(me->cmdline);
1375 me->cmdline = NULL;
1376 if (m) {
1377 me->submenu = m;
1378 me->action--; /* Drop the _UNRES */
1379 } else {
1380 me->action = MA_DISABLED;
1386 void parse_configs(char **argv)
1388 const char *filename;
1389 struct menu *m;
1390 struct menu_entry *me;
1391 dprintf("enter");
1393 empty_string = refstrdup("");
1395 /* feng: reset current menu_list and entry list */
1396 menu_list = NULL;
1397 all_entries = NULL;
1399 /* Initialize defaults for the root and hidden menus */
1400 hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
1401 root_menu = new_menu(NULL, NULL, refstrdup(".top"));
1402 start_menu = root_menu;
1404 /* Other initialization */
1405 memset(&ld, 0, sizeof(struct labeldata));
1407 /* Actually process the files */
1408 current_menu = root_menu;
1410 if (!argv || !*argv) {
1411 if (parse_one_config(NULL) < 0) {
1412 printf("WARNING: No configuration file found\n");
1413 return;
1415 } else {
1416 while ((filename = *argv++)) {
1417 dprintf("Parsing config: %s", filename);
1418 parse_one_config(filename);
1422 /* On final EOF process the last label statement */
1423 record(current_menu, &ld, append);
1425 /* Common postprocessing */
1426 resolve_gotos();
1428 /* Handle global default */
1429 //if (has_ui && globaldefault) {
1430 if (globaldefault) {
1431 dprintf("gloabldefault = %s", globaldefault);
1432 me = find_label(globaldefault);
1433 if (me && me->menu != hide_menu) {
1434 me->menu->defentry = me->entry;
1435 start_menu = me->menu;
1436 default_menu = me->menu;
1440 /* If "menu save" is active, let the ADV override the global default */
1441 if (menusave) {
1442 size_t len;
1443 const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
1444 char *lstr;
1445 if (lbl && len) {
1446 lstr = refstr_alloc(len);
1447 memcpy(lstr, lbl, len); /* refstr_alloc() adds the final null */
1448 me = find_label(lstr);
1449 if (me && me->menu != hide_menu) {
1450 me->menu->defentry = me->entry;
1451 start_menu = me->menu;
1453 refstr_put(lstr);
1457 /* Final per-menu initialization, with all labels known */
1458 for (m = menu_list; m; m = m->next) {
1459 m->curentry = m->defentry; /* All menus start at their defaults */
1461 if (m->ontimeout)
1462 m->ontimeout = unlabel(m->ontimeout);
1463 if (m->onerror)
1464 m->onerror = unlabel(m->onerror);