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 * ----------------------------------------------------------------------- */
25 #include <syslinux/adv.h>
26 #include <syslinux/config.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
[] = {
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
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 */
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); \
125 * Search the list of all menus for a specific label
127 static struct menu
*find_menu(const char *label
)
131 for (m
= menu_list
; m
; m
= m
->next
) {
132 if (!strcmp(label
, m
->label
))
139 #define MAX_LINE 4096
141 /* Strip ^ from a string, returning a new reference to the same refstring
143 static const char *strip_caret(const char *str
)
159 return refstr_get(str
);
161 r
= q
= refstr_alloc(strlen(str
) - carets
);
162 for (p
= str
; *p
; p
++)
166 *q
= '\0'; /* refstr_alloc() already did this... */
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
)
178 while (*p
&& *q
&& ((*p
^ *q
) & ~0x20) == 0) {
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
));
195 //dprintf("enter: menu_label = %s", label);
198 m
->title
= refstr_get(empty_string
);
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
);
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();
248 enum kernel_type type
;
251 const char *menulabel
;
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
;
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;
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
));
298 me
->entry
= m
->nentries
;
299 m
->menu_entries
[m
->nentries
++] = me
;
300 *all_entries_end
= me
;
301 all_entries_end
= &me
->next
;
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
) {
312 unsigned char hotkey
= p
[1] & ~0x20;
313 if (!m
->menu_hotkeys
[hotkey
]) {
315 m
->menu_hotkeys
[hotkey
] = me
;
321 static void record(struct menu
*m
, struct labeldata
*ld
, const char *append
)
324 struct menu_entry
*me
;
325 const struct syslinux_ipappend_strings
*ipappend
;
328 return; /* Nothing defined */
330 /* Hidden entries are recorded on a special "hidden menu" */
334 char ipoptions
[4096], *ipp
;
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
;
346 me
->action
= ld
->action
? ld
->action
: MA_CMD
;
347 me
->save
= ld
->save
? (ld
->save
> 0) : m
->save
;
349 if (ld
->menuindent
) {
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
);
366 refstr_put(me
->passwd
);
371 consider_for_hotkey(m
, me
);
373 switch (me
->action
) {
379 ipp
+= sprintf(ipp
, " initrd=%s", ld
->initrd
);
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
]);
392 if (!a
|| (a
[0] == '-' && !a
[1]))
396 if (ld
->type
== KT_KERNEL
)
397 rsprintf(&me
->cmdline
, "%s%s%s%s", ld
->kernel
, s
, a
, ipoptions
);
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
);
406 me
->cmdline
= refstr_get(ld
->kernel
);
411 me
->submenu
= ld
->submenu
;
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
;
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
;
446 for (me
= all_entries
; me
; me
= me
->next
) {
447 if (!strncmp(prefix
, me
->label
, len
))
448 printf(" %s", me
->label
);
453 struct menu_entry
*find_label(const char *str
)
456 struct menu_entry
*me
;
460 while (*p
&& !my_isspace(*p
))
463 /* p now points to the first byte beyond the kernel name */
466 for (me
= all_entries
; me
; me
= me
->next
) {
467 if (!strncmp(str
, me
->label
, pos
) && !me
->label
[pos
])
474 static const char *unlabel(const char *str
)
476 /* Convert a CLI-style command line to an executable command line */
479 struct menu_entry
*me
;
483 while (*p
&& !my_isspace(*p
))
486 /* p now points to the first byte beyond the kernel name */
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
);
501 static const char *__refdup_word(char *p
, char **ref
)
506 while (*ep
&& !my_isspace(*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
)
523 return (uc
- '0') < 10 || ((uc
| 0x20) - 'a') < 6;
526 unsigned int hexval(char c
)
528 unsigned char uc
= c
| 0x20;
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
)
555 while (my_isxdigit(*ep
))
565 (hexval(sp
[0]) * 0x11 << 16) +
566 (hexval(sp
[1]) * 0x11 << 8) + (hexval(sp
[2]) * 0x11);
570 (hexval(sp
[0]) * 0x11 << 24) +
571 (hexval(sp
[1]) * 0x11 << 16) +
572 (hexval(sp
[2]) * 0x11 << 8) + (hexval(sp
[3]) * 0x11);
574 case 6: /* #rrggbb */
575 case 9: /* #rrrgggbbb */
576 case 12: /* #rrrrggggbbbb */
580 (hexval2(sp
+ 0) << 16) +
581 (hexval2(sp
+ dl
) << 8) + hexval2(sp
+ dl
* 2);
583 case 8: /* #aarrggbb */
584 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
585 assume the latter is a more common format */
586 case 16: /* #aaaarrrrggggbbbb */
589 (hexval2(sp
+ 0) << 24) +
590 (hexval2(sp
+ dl
) << 16) +
591 (hexval2(sp
+ dl
* 2) << 8) + hexval2(sp
+ dl
* 3);
594 argb
= 0xffff0000; /* Bright red (error indication) */
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
;
619 enum kernel_type t
= KT_NONE
;
621 for (p
= kernel_types
; *p
; p
++, t
++) {
622 if ((q
= looking_at(cmdstr
, *p
))) {
631 static char *is_message_name(char *cmdstr
, enum message_number
*msgnr
)
634 enum message_number i
;
636 for (i
= 0; i
< MSG_COUNT
; i
++) {
637 if ((q
= looking_at(cmdstr
, messages
[i
].name
))) {
646 extern void get_msg_file(char *);
648 void cat_help_file(int key
)
650 struct menu
*cm
= current_menu
;
698 if (cm
->fkeyhelp
[fkey
].textname
) {
700 get_msg_file((char *)cm
->fkeyhelp
[fkey
].textname
);
704 static char *is_fkey(char *cmdstr
, int *fkeyno
)
709 if ((cmdstr
[0] | 0x20) != 'f')
712 no
= strtoul(cmdstr
+ 1, &q
, 10);
716 if (no
< 0 || no
> 12)
719 *fkeyno
= (no
== 0) ? 10 : no
- 1;
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
;
750 struct menu
*m
= current_menu
;
752 while (fgets(line
, sizeof line
, f
)) {
753 p
= strchr(line
, '\r');
756 p
= strchr(line
, '\n');
762 if (looking_at(p
, "menu")) {
764 p
= skipspace(p
+ 4);
766 if (looking_at(p
, "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
);
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")) {
793 } else if (m
->parent_entry
) {
794 m
->parent
->defentry
= m
->parent_entry
->entry
;
796 } else if (looking_at(p
, "hide")) {
798 } else if (looking_at(p
, "passwd")) {
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")) {
808 } else if (looking_at(p
, "save")) {
814 } else if (looking_at(p
, "nosave")) {
819 } else if (looking_at(p
, "onerror")) {
820 refstr_put(m
->onerror
);
821 m
->onerror
= refstrdup(skipspace(p
+ 7));
822 onerrorlen
= strlen(m
->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"))) {
833 } else if ((ep
= looking_at(p
, "background"))) {
835 refstr_put(m
->menu_background
);
836 m
->menu_background
= refdup_word(&p
);
837 } else if ((ep
= looking_at(p
, "hidden"))) {
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"))) {
845 struct color_table
*cptr
;
847 cptr
= m
->color_table
;
848 for (i
= 0; i
< menu_color_table_size
; i
++) {
849 if ((ep
= looking_at(p
, cptr
->name
))) {
852 if (looking_at(p
, "*")) {
855 refstr_put(cptr
->ansi
);
856 cptr
->ansi
= refdup_word(&p
);
861 if (looking_at(p
, "*"))
864 cptr
->argb_fg
= parse_argb(&p
);
868 if (looking_at(p
, "*"))
871 cptr
->argb_bg
= parse_argb(&p
);
873 /* Parse a shadow mode */
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
;
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
;
899 if (!looking_at(p
, "*"))
900 fg_mask
= parse_argb(&p
);
904 if (!looking_at(p
, "*"))
905 bg_mask
= parse_argb(&p
);
910 shadow
= SHADOW_NONE
;
913 shadow
= SHADOW_NORMAL
;
919 shadow
= SHADOW_REVERSE
;
922 /* go with default */
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")) {
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")) {
946 } else if (looking_at(p
, "goto")) {
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
) {
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
);
962 ld
.submenu
= m
->parent
;
965 } else if (looking_at(p
, "start")) {
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
));
978 /* feng: menu handling end */
979 else if (looking_at(p
, "text")) {
981 /* loop till we fined the "endtext" */
985 } cmd
= TEXT_UNKNOWN
;
986 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
989 p
= skipspace(p
+ 4);
991 if (looking_at(p
, "help"))
994 while (fgets(line
, sizeof line
, f
)) {
996 if (looking_at(p
, "endtext"))
1005 ld
.helptext
= realloc(ld
.helptext
, len
+ xlen
+ 1);
1006 memcpy(ld
.helptext
+ len
, line
, xlen
+ 1);
1011 } else if ((ep
= is_fkey(p
, &fkeyno
))) {
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
);
1026 m
->fkeyhelp
[fkeyno
].background
= refdup_word(&p
);
1028 } else if ((ep
= looking_at(p
, "include"))) {
1033 file
= refdup_word(&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();
1042 parse_one_config(file
);
1046 } else if (looking_at(p
, "append")) {
1047 const char *a
= refstrdup(skipspace(p
+ 6));
1049 refstr_put(ld
.append
);
1055 //dprintf("we got a append: %s", a);
1056 } else if (looking_at(p
, "initrd")) {
1057 const char *a
= refstrdup(skipspace(p
+ 6));
1059 refstr_put(ld
.initrd
);
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
;
1075 ld
.menulabel
= 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
))) {
1082 refstr_put(ld
.kernel
);
1083 ld
.kernel
= refstrdup(skipspace(ep
));
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")) {
1098 ld
.ipappend
= atoi(skipspace(p
+ 8));
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")) {
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
++;
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
++;
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
++;
1165 loadkeys(KernelName
);
1166 refstr_put(filename
);
1169 * subset 2: pc_setint16
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
;
1202 p
= skipspace(p
+ 6);
1209 /* Default to no flow control */
1213 baud
= DEFAULT_BAUD
;
1228 ignore
= ((flow
& 0x0F00) >> 4);
1231 FlowIgnore
= ignore
;
1232 flow
= ((flow
& 0xff) << 8) | (flow
& 0xff);
1234 FlowOutput
= (flow
& 0xff);
1235 FlowInput
= ((flow
& 0xff00) >> 8);
1242 /* < 75 baud == bogus */
1247 baud
= BAUD_DIVISOR
/ baud
;
1252 * If port > 3 then port is I/O addr
1255 /* Get the I/O port from the BIOS */
1257 port
= *(volatile uint16_t *)serial_base
;
1264 * Begin code to actually set up the serial port
1266 sirq_cleanup_nowipe();
1268 outb(0x83, port
+ 3); /* Enable DLAB */
1271 outb((baud
& 0xff), port
); /* write divisor to LS */
1274 outb(((baud
& 0xff00) >> 8), port
+ 1); /* write to MS */
1277 outb(0x03, port
+ 3); /* Disable DLAB */
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 */
1290 outb(0x01, port
+ 2); /* Enable FIFOs if present */
1293 /* Disable FIFO if unusable */
1294 if (inb(port
+ 2) < 0x0C0) {
1299 /* Assert bits in MCR */
1300 outb(FlowOutput
, port
+ 4);
1303 /* Enable interrupts if requested */
1304 if (FlowOutput
& 0x8)
1307 /* Show some life */
1308 if (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
;
1321 size_t len
, new_len
;
1323 new_path
= refstrdup(skipspace(p
+ 4));
1325 new_len
= strlen(new_path
);
1326 _p
= malloc(len
+ new_len
+ 2);
1328 strncpy(_p
, PATH
, len
);
1330 strncpy(_p
+ len
, new_path
, new_len
);
1331 _p
[len
+ new_len
] = '\0';
1335 printf("Failed to realloc PATH\n");
1340 static int parse_one_config(const char *filename
)
1342 const char *mode
= "r";
1349 fd
= open(filename
, O_RDONLY
);
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
);
1366 static void resolve_gotos(void)
1368 struct menu_entry
*me
;
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
);
1378 me
->action
--; /* Drop the _UNRES */
1380 me
->action
= MA_DISABLED
;
1386 void parse_configs(char **argv
)
1388 const char *filename
;
1390 struct menu_entry
*me
;
1393 empty_string
= refstrdup("");
1395 /* feng: reset current menu_list and entry list */
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");
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 */
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 */
1443 const char *lbl
= syslinux_getadv(ADV_MENUSAVE
, &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
;
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 */
1462 m
->ontimeout
= unlabel(m
->ontimeout
);
1464 m
->onerror
= unlabel(m
->onerror
);