1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2013 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>
32 #include <syslinux/pxe_api.h>
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},
57 /* Must match enum kernel_type */
58 static const char *const kernel_types
[] = {
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
86 const char *onerror
= NULL
; //"onerror" command line
87 const char *ontimeout
= NULL
; //"ontimeout" command line
89 __export
const char *default_cmd
= NULL
; //"default" command line
92 const char *empty_string
;
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
;
97 /* These are global parameters regardless of which menu we're displaying */
98 int shiftkey
= 0; /* Only display menu if shift key pressed */
100 long long totaltimeout
= 0;
101 unsigned int kbdtimeout
= 0;
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" */
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
;
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"},
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); \
126 * Search the list of all menus for a specific label
128 static struct menu
*find_menu(const char *label
)
132 for (m
= menu_list
; m
; m
= m
->next
) {
133 if (!strcmp(label
, m
->label
))
140 #define MAX_LINE 4096
142 /* Strip ^ from a string, returning a new reference to the same refstring
144 static const char *strip_caret(const char *str
)
160 return refstr_get(str
);
162 r
= q
= refstr_alloc(strlen(str
) - carets
);
163 for (p
= str
; *p
; p
++)
167 *q
= '\0'; /* refstr_alloc() already did this... */
172 /* Check to see if we are at a certain keyword (case insensitive) */
173 /* Returns a pointer to the first character past the keyword */
174 static char *looking_at(char *line
, const char *kwd
)
179 while (*p
&& *q
&& ((*p
^ *q
) & ~0x20) == 0) {
185 return NULL
; /* Didn't see the keyword */
187 return my_isspace(*p
) ? p
: NULL
; /* Must be EOL or whitespace */
190 static struct menu
*new_menu(struct menu
*parent
,
191 struct menu_entry
*parent_entry
, const char *label
)
193 struct menu
*m
= calloc(1, sizeof(struct menu
));
196 //dprintf("enter: menu_label = %s", label);
199 m
->title
= refstr_get(empty_string
);
204 m
->parent_entry
= parent_entry
;
205 parent_entry
->action
= MA_SUBMENU
;
206 parent_entry
->submenu
= m
;
208 for (i
= 0; i
< MSG_COUNT
; i
++)
209 m
->messages
[i
] = refstr_get(parent
->messages
[i
]);
211 memcpy(m
->mparm
, parent
->mparm
, sizeof m
->mparm
);
213 m
->allowedit
= parent
->allowedit
;
214 m
->timeout
= parent
->timeout
;
215 m
->save
= parent
->save
;
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
);
222 m
->color_table
= copy_color_table(parent
->color_table
);
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
);
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
;
236 m
->allowedit
= true; /* Allow edits of the command line */
237 m
->color_table
= default_color_table();
249 enum kernel_type type
;
252 const char *menulabel
;
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
;
263 struct menu
*submenu
;
266 /* Menu currently being parsed */
267 static struct menu
*current_menu
;
269 static void clear_label_data(struct labeldata
*ld
)
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
);
278 memset(ld
, 0, sizeof *ld
);
281 static struct menu_entry
*new_entry(struct menu
*m
)
283 struct menu_entry
*me
;
285 //dprintf("enter, call from menu %s", m->label);
287 if (m
->nentries
>= m
->nentries_space
) {
288 if (!m
->nentries_space
)
289 m
->nentries_space
= 1;
291 m
->nentries_space
<<= 1;
293 m
->menu_entries
= realloc(m
->menu_entries
, m
->nentries_space
*
294 sizeof(struct menu_entry
*));
297 me
= calloc(1, sizeof(struct menu_entry
));
299 me
->entry
= m
->nentries
;
300 m
->menu_entries
[m
->nentries
++] = me
;
301 *all_entries_end
= me
;
302 all_entries_end
= &me
->next
;
307 static void consider_for_hotkey(struct menu
*m
, struct menu_entry
*me
)
309 const char *p
= strchr(me
->displayname
, '^');
311 if (me
->action
!= MA_DISABLED
) {
313 unsigned char hotkey
= p
[1] & ~0x20;
314 if (!m
->menu_hotkeys
[hotkey
]) {
316 m
->menu_hotkeys
[hotkey
] = me
;
323 * Copy a string, converting whitespace characters to underscores
324 * and compacting them. Return a pointer to the final null.
326 static char *copy_sysappend_string(char *dst
, const char *src
)
328 bool was_space
= true; /* Kill leading whitespace */
332 while ((c
= *src
++)) {
333 if (c
<= ' ' && c
== '\x7f') {
347 static void record(struct menu
*m
, struct labeldata
*ld
, const char *append
)
350 struct menu_entry
*me
;
351 const struct syslinux_ipappend_strings
*ipappend
;
354 return; /* Nothing defined */
356 /* Hidden entries are recorded on a special "hidden menu" */
360 char ipoptions
[4096], *ipp
;
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
;
372 me
->action
= ld
->action
? ld
->action
: MA_CMD
;
373 me
->save
= ld
->save
? (ld
->save
> 0) : m
->save
;
375 if (ld
->menuindent
) {
378 rsprintf(&dn
, "%*s%s", ld
->menuindent
, "", me
->displayname
);
379 refstr_put(me
->displayname
);
380 me
->displayname
= dn
;
383 if (ld
->menuseparator
) {
384 refstr_put(me
->displayname
);
385 me
->displayname
= refstr_get(empty_string
);
388 if (ld
->menuseparator
|| ld
->menudisabled
) {
389 me
->action
= MA_DISABLED
;
390 refstr_put(me
->label
);
392 refstr_put(me
->passwd
);
397 consider_for_hotkey(m
, me
);
399 switch (me
->action
) {
405 ipp
+= sprintf(ipp
, " initrd=%s", ld
->initrd
);
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]) {
413 ipp
= copy_sysappend_string(ipp
, ipappend
->ptr
[i
]);
421 if (!a
|| (a
[0] == '-' && !a
[1]))
425 if (ld
->type
== KT_KERNEL
)
426 rsprintf(&me
->cmdline
, "%s%s%s%s", ld
->kernel
, s
, a
, ipoptions
);
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
);
435 me
->cmdline
= refstr_get(ld
->kernel
);
440 me
->submenu
= ld
->submenu
;
447 if (ld
->menudefault
&& me
->action
== MA_CMD
)
448 m
->defentry
= m
->nentries
- 1;
450 clear_label_data(ld
);
453 static struct menu
*begin_submenu(const char *tag
)
455 struct menu_entry
*me
;
460 me
= new_entry(current_menu
);
461 me
->displayname
= refstrdup(tag
);
462 return new_menu(current_menu
, me
, refstr_get(me
->displayname
));
465 static struct menu
*end_submenu(void)
467 return current_menu
->parent
? current_menu
->parent
: current_menu
;
470 void print_labels(const char *prefix
, size_t len
)
472 struct menu_entry
*me
;
475 for (me
= all_entries
; me
; me
= me
->next
) {
479 if (!strncmp(prefix
, me
->label
, len
))
480 printf(" %s", me
->label
);
485 struct menu_entry
*find_label(const char *str
)
488 struct menu_entry
*me
;
492 while (*p
&& !my_isspace(*p
))
495 /* p now points to the first byte beyond the kernel name */
498 for (me
= all_entries
; me
; me
= me
->next
) {
499 if (!strncmp(str
, me
->label
, pos
) && !me
->label
[pos
])
506 static const char *unlabel(const char *str
)
508 /* Convert a CLI-style command line to an executable command line */
511 struct menu_entry
*me
;
515 while (*p
&& !my_isspace(*p
))
518 /* p now points to the first byte beyond the kernel name */
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
);
533 static const char *__refdup_word(char *p
, char **ref
)
538 while (*ep
&& !my_isspace(*ep
))
543 return refstrndup(sp
, ep
- sp
);
546 static const char *refdup_word(char **p
)
548 return __refdup_word(*p
, p
);
551 int my_isxdigit(char c
)
555 return (uc
- '0') < 10 || ((uc
| 0x20) - 'a') < 6;
558 unsigned int hexval(char c
)
560 unsigned char uc
= c
| 0x20;
567 return uc
- 'a' + 10;
570 unsigned int hexval2(const char *p
)
572 return (hexval(p
[0]) << 4) + hexval(p
[1]);
575 uint32_t parse_argb(char **p
)
587 while (my_isxdigit(*ep
))
597 (hexval(sp
[0]) * 0x11 << 16) +
598 (hexval(sp
[1]) * 0x11 << 8) + (hexval(sp
[2]) * 0x11);
602 (hexval(sp
[0]) * 0x11 << 24) +
603 (hexval(sp
[1]) * 0x11 << 16) +
604 (hexval(sp
[2]) * 0x11 << 8) + (hexval(sp
[3]) * 0x11);
606 case 6: /* #rrggbb */
607 case 9: /* #rrrgggbbb */
608 case 12: /* #rrrrggggbbbb */
612 (hexval2(sp
+ 0) << 16) +
613 (hexval2(sp
+ dl
) << 8) + hexval2(sp
+ dl
* 2);
615 case 8: /* #aarrggbb */
616 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
617 assume the latter is a more common format */
618 case 16: /* #aaaarrrrggggbbbb */
621 (hexval2(sp
+ 0) << 24) +
622 (hexval2(sp
+ dl
) << 16) +
623 (hexval2(sp
+ dl
* 2) << 8) + hexval2(sp
+ dl
* 3);
626 argb
= 0xffff0000; /* Bright red (error indication) */
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.
638 //static const char *append = NULL;
639 extern const char *append
;
640 extern uint16_t PXERetry
;
641 static struct labeldata ld
;
643 static int parse_main_config(const char *filename
);
645 static char *is_kernel_type(char *cmdstr
, enum kernel_type
*type
)
647 const char *const *p
;
649 enum kernel_type t
= KT_NONE
;
651 for (p
= kernel_types
; *p
; p
++, t
++) {
652 if ((q
= looking_at(cmdstr
, *p
))) {
661 static char *is_message_name(char *cmdstr
, enum message_number
*msgnr
)
664 enum message_number i
;
666 for (i
= 0; i
< MSG_COUNT
; i
++) {
667 if ((q
= looking_at(cmdstr
, messages
[i
].name
))) {
676 extern void get_msg_file(char *);
678 void cat_help_file(int key
)
680 struct menu
*cm
= current_menu
;
728 if (cm
->fkeyhelp
[fkey
].textname
) {
730 get_msg_file((char *)cm
->fkeyhelp
[fkey
].textname
);
734 static char *is_fkey(char *cmdstr
, int *fkeyno
)
739 if ((cmdstr
[0] | 0x20) != 'f')
742 no
= strtoul(cmdstr
+ 1, &q
, 10);
746 if (no
< 0 || no
> 12)
749 *fkeyno
= (no
== 0) ? 10 : no
- 1;
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;
760 #define DEFAULT_BAUD 9600
761 #define BAUD_DIVISOR 115200
763 extern void sirq_cleanup_nowipe(void);
764 extern void sirq_install(void);
765 extern void write_serial_str(char *);
767 extern void loadfont(char *);
768 extern void loadkeys(char *);
770 extern char syslinux_banner
[];
771 extern char copyright_str
[];
776 * Each entry in the PATH directive is separated by a colon, e.g.
778 * PATH /bar:/bin/foo:/baz/bar/bin
780 static int parse_path(char *p
)
782 struct path_entry
*entry
;
788 /* Find the next directory */
789 while (*c
&& *c
!= ':')
792 str
= refstrndup(p
, c
- p
);
796 entry
= path_add(str
);
813 static void parse_config_file(FILE * f
);
815 static void do_include_menu(char *str
, struct menu
*m
)
823 file
= refdup_word(&p
);
826 fd
= open(file
, O_RDONLY
);
835 record(m
, &ld
, append
);
836 m
= current_menu
= begin_submenu(p
);
839 parse_config_file(f
);
842 record(m
, &ld
, append
);
843 m
= current_menu
= end_submenu();
853 static void do_include(char *str
)
861 file
= refdup_word(&p
);
863 fd
= open(file
, O_RDONLY
);
869 parse_config_file(f
);
877 static void parse_config_file(FILE * f
)
879 char line
[MAX_LINE
], *p
, *ep
, ch
;
880 enum kernel_type type
;
881 enum message_number msgnr
;
883 struct menu
*m
= current_menu
;
885 while (fgets(line
, sizeof line
, f
)) {
886 p
= strchr(line
, '\r');
889 p
= strchr(line
, '\n');
895 if (looking_at(p
, "menu")) {
897 p
= skipspace(p
+ 4);
899 if (looking_at(p
, "label")) {
901 refstr_put(ld
.menulabel
);
902 ld
.menulabel
= refstrdup(skipspace(p
+ 5));
903 } else if (m
->parent_entry
) {
904 refstr_put(m
->parent_entry
->displayname
);
905 m
->parent_entry
->displayname
= refstrdup(skipspace(p
+ 5));
906 consider_for_hotkey(m
->parent
, m
->parent_entry
);
908 /* MENU LABEL -> MENU TITLE on submenu */
909 refstr_put(m
->title
);
910 m
->title
= strip_caret(m
->parent_entry
->displayname
);
913 } else if (looking_at(p
, "title")) {
914 refstr_put(m
->title
);
915 m
->title
= refstrdup(skipspace(p
+ 5));
916 if (m
->parent_entry
) {
917 /* MENU TITLE -> MENU LABEL on submenu */
918 if (m
->parent_entry
->displayname
== m
->label
) {
919 refstr_put(m
->parent_entry
->displayname
);
920 m
->parent_entry
->displayname
= refstr_get(m
->title
);
923 } else if (looking_at(p
, "default")) {
926 } else if (m
->parent_entry
) {
927 m
->parent
->defentry
= m
->parent_entry
->entry
;
929 } else if (looking_at(p
, "hide")) {
931 } else if (looking_at(p
, "passwd")) {
933 refstr_put(ld
.passwd
);
934 ld
.passwd
= refstrdup(skipspace(p
+ 6));
935 } else if (m
->parent_entry
) {
936 refstr_put(m
->parent_entry
->passwd
);
937 m
->parent_entry
->passwd
= refstrdup(skipspace(p
+ 6));
939 } else if (looking_at(p
, "shiftkey")) {
941 } else if (looking_at(p
, "save")) {
947 } else if (looking_at(p
, "nosave")) {
952 } else if (looking_at(p
, "onerror")) {
953 refstr_put(m
->onerror
);
954 m
->onerror
= refstrdup(skipspace(p
+ 7));
955 onerrorlen
= strlen(m
->onerror
);
957 onerror
= refstrdup(m
->onerror
);
958 } else if (looking_at(p
, "master")) {
959 p
= skipspace(p
+ 6);
960 if (looking_at(p
, "passwd")) {
961 refstr_put(m
->menu_master_passwd
);
962 m
->menu_master_passwd
= refstrdup(skipspace(p
+ 6));
964 } else if ((ep
= looking_at(p
, "include"))) {
965 do_include_menu(ep
, m
);
966 } else if ((ep
= looking_at(p
, "background"))) {
968 refstr_put(m
->menu_background
);
969 m
->menu_background
= refdup_word(&p
);
970 } else if ((ep
= looking_at(p
, "hidden"))) {
972 } else if ((ep
= is_message_name(p
, &msgnr
))) {
973 refstr_put(m
->messages
[msgnr
]);
974 m
->messages
[msgnr
] = refstrdup(skipspace(ep
));
975 } else if ((ep
= looking_at(p
, "color")) ||
976 (ep
= looking_at(p
, "colour"))) {
978 struct color_table
*cptr
;
980 cptr
= m
->color_table
;
981 for (i
= 0; i
< menu_color_table_size
; i
++) {
982 if ((ep
= looking_at(p
, cptr
->name
))) {
985 if (looking_at(p
, "*")) {
988 refstr_put(cptr
->ansi
);
989 cptr
->ansi
= refdup_word(&p
);
994 if (looking_at(p
, "*"))
997 cptr
->argb_fg
= parse_argb(&p
);
1001 if (looking_at(p
, "*"))
1004 cptr
->argb_bg
= parse_argb(&p
);
1006 /* Parse a shadow mode */
1009 if (ch
== 'n') /* none */
1010 cptr
->shadow
= SHADOW_NONE
;
1011 else if (ch
== 's') /* std, standard */
1012 cptr
->shadow
= SHADOW_NORMAL
;
1013 else if (ch
== 'a') /* all */
1014 cptr
->shadow
= SHADOW_ALL
;
1015 else if (ch
== 'r') /* rev, reverse */
1016 cptr
->shadow
= SHADOW_REVERSE
;
1024 } else if ((ep
= looking_at(p
, "msgcolor")) ||
1025 (ep
= looking_at(p
, "msgcolour"))) {
1026 unsigned int fg_mask
= MSG_COLORS_DEF_FG
;
1027 unsigned int bg_mask
= MSG_COLORS_DEF_BG
;
1028 enum color_table_shadow shadow
= MSG_COLORS_DEF_SHADOW
;
1032 if (!looking_at(p
, "*"))
1033 fg_mask
= parse_argb(&p
);
1037 if (!looking_at(p
, "*"))
1038 bg_mask
= parse_argb(&p
);
1041 switch (*p
| 0x20) {
1043 shadow
= SHADOW_NONE
;
1046 shadow
= SHADOW_NORMAL
;
1049 shadow
= SHADOW_ALL
;
1052 shadow
= SHADOW_REVERSE
;
1055 /* go with default */
1060 set_msg_colors_global(m
->color_table
, fg_mask
, bg_mask
, shadow
);
1061 } else if (looking_at(p
, "separator")) {
1062 record(m
, &ld
, append
);
1063 ld
.label
= refstr_get(empty_string
);
1064 ld
.menuseparator
= 1;
1065 record(m
, &ld
, append
);
1066 } else if (looking_at(p
, "disable") || looking_at(p
, "disabled")) {
1067 ld
.menudisabled
= 1;
1068 } else if (looking_at(p
, "indent")) {
1069 ld
.menuindent
= atoi(skipspace(p
+ 6));
1070 } else if (looking_at(p
, "begin")) {
1071 record(m
, &ld
, append
);
1072 m
= current_menu
= begin_submenu(skipspace(p
+ 5));
1073 } else if (looking_at(p
, "end")) {
1074 record(m
, &ld
, append
);
1075 m
= current_menu
= end_submenu();
1076 } else if (looking_at(p
, "quit")) {
1078 ld
.action
= MA_QUIT
;
1079 } else if (looking_at(p
, "goto")) {
1081 ld
.action
= MA_GOTO_UNRES
;
1082 refstr_put(ld
.kernel
);
1083 ld
.kernel
= refstrdup(skipspace(p
+ 4));
1085 } else if (looking_at(p
, "exit")) {
1086 p
= skipspace(p
+ 4);
1087 if (ld
.label
&& m
->parent
) {
1089 /* This is really just a goto, except for the marker */
1090 ld
.action
= MA_EXIT_UNRES
;
1091 refstr_put(ld
.kernel
);
1092 ld
.kernel
= refstrdup(p
);
1094 ld
.action
= MA_EXIT
;
1095 ld
.submenu
= m
->parent
;
1098 } else if (looking_at(p
, "start")) {
1101 /* Unknown, check for layout parameters */
1102 enum parameter_number mp
;
1103 for (mp
= 0; mp
< NPARAMS
; mp
++) {
1104 if ((ep
= looking_at(p
, mparm
[mp
].name
))) {
1105 m
->mparm
[mp
] = atoi(skipspace(ep
));
1111 /* feng: menu handling end */
1112 else if (looking_at(p
, "text")) {
1114 /* loop till we fined the "endtext" */
1118 } cmd
= TEXT_UNKNOWN
;
1119 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
1122 p
= skipspace(p
+ 4);
1124 if (looking_at(p
, "help"))
1127 while (fgets(line
, sizeof line
, f
)) {
1128 p
= skipspace(line
);
1129 if (looking_at(p
, "endtext"))
1132 xlen
= strlen(line
);
1138 ld
.helptext
= realloc(ld
.helptext
, len
+ xlen
+ 1);
1139 memcpy(ld
.helptext
+ len
, line
, xlen
+ 1);
1144 } else if ((ep
= is_fkey(p
, &fkeyno
))) {
1146 if (m
->fkeyhelp
[fkeyno
].textname
) {
1147 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1148 m
->fkeyhelp
[fkeyno
].textname
= NULL
;
1150 if (m
->fkeyhelp
[fkeyno
].background
) {
1151 refstr_put(m
->fkeyhelp
[fkeyno
].background
);
1152 m
->fkeyhelp
[fkeyno
].background
= NULL
;
1155 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1156 m
->fkeyhelp
[fkeyno
].textname
= refdup_word(&p
);
1159 m
->fkeyhelp
[fkeyno
].background
= refdup_word(&p
);
1161 } else if ((ep
= looking_at(p
, "include"))) {
1163 } else if (looking_at(p
, "append")) {
1164 const char *a
= refstrdup(skipspace(p
+ 6));
1166 refstr_put(ld
.append
);
1172 //dprintf("we got a append: %s", a);
1173 } else if (looking_at(p
, "initrd")) {
1174 const char *a
= refstrdup(skipspace(p
+ 6));
1176 refstr_put(ld
.initrd
);
1181 } else if (looking_at(p
, "label")) {
1182 p
= skipspace(p
+ 5);
1183 /* when first time see "label", it will not really record anything */
1184 record(m
, &ld
, append
);
1185 ld
.label
= __refdup_word(p
, NULL
);
1186 ld
.kernel
= __refdup_word(p
, NULL
);
1187 /* feng: this is the default type for all */
1188 ld
.type
= KT_KERNEL
;
1192 ld
.menulabel
= NULL
;
1194 ld
.ipappend
= SysAppends
;
1195 ld
.menudefault
= ld
.menuhide
= ld
.menuseparator
=
1196 ld
.menudisabled
= ld
.menuindent
= 0;
1197 } else if ((ep
= is_kernel_type(p
, &type
))) {
1199 refstr_put(ld
.kernel
);
1200 ld
.kernel
= refstrdup(skipspace(ep
));
1202 //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
1204 } else if (looking_at(p
, "timeout")) {
1205 kbdtimeout
= (atoi(skipspace(p
+ 7)) * CLK_TCK
+ 9) / 10;
1206 } else if (looking_at(p
, "totaltimeout")) {
1207 totaltimeout
= (atoll(skipspace(p
+ 13)) * CLK_TCK
+ 9) / 10;
1208 } else if (looking_at(p
, "ontimeout")) {
1209 ontimeout
= refstrdup(skipspace(p
+ 9));
1210 ontimeoutlen
= strlen(ontimeout
);
1211 } else if (looking_at(p
, "allowoptions")) {
1212 allowoptions
= !!atoi(skipspace(p
+ 12));
1213 } else if ((ep
= looking_at(p
, "ipappend")) ||
1214 (ep
= looking_at(p
, "sysappend"))) {
1215 uint32_t s
= strtoul(skipspace(ep
), NULL
, 0);
1220 } else if (looking_at(p
, "default")) {
1221 /* default could be a kernel image or another label */
1222 refstr_put(globaldefault
);
1223 globaldefault
= refstrdup(skipspace(p
+ 7));
1226 * On the chance that "default" is actually a kernel image
1227 * and not a label, store a copy of it, but only if we
1228 * haven't seen a "ui" command. "ui" commands take
1229 * precendence over "default" commands.
1231 if (defaultlevel
< LEVEL_UI
) {
1232 defaultlevel
= LEVEL_DEFAULT
;
1233 refstr_put(default_cmd
);
1234 default_cmd
= refstrdup(globaldefault
);
1236 } else if (looking_at(p
, "ui")) {
1238 defaultlevel
= LEVEL_UI
;
1239 refstr_put(default_cmd
);
1240 default_cmd
= refstrdup(skipspace(p
+ 2));
1244 * subset 1: pc_opencmd
1245 * display/font/kbdmap are rather similar, open a file then do sth
1247 else if (looking_at(p
, "display")) {
1248 const char *filename
;
1249 char *dst
= KernelName
;
1250 size_t len
= FILENAME_MAX
- 1;
1252 filename
= refstrdup(skipspace(p
+ 7));
1254 while (len
-- && not_whitespace(*filename
))
1255 *dst
++ = *filename
++;
1258 get_msg_file(KernelName
);
1259 refstr_put(filename
);
1260 } else if (looking_at(p
, "font")) {
1261 const char *filename
;
1262 char *dst
= KernelName
;
1263 size_t len
= FILENAME_MAX
- 1;
1265 filename
= refstrdup(skipspace(p
+ 4));
1267 while (len
-- && not_whitespace(*filename
))
1268 *dst
++ = *filename
++;
1271 loadfont(KernelName
);
1272 refstr_put(filename
);
1273 } else if (looking_at(p
, "kbdmap")) {
1274 const char *filename
;
1276 filename
= refstrdup(skipspace(p
+ 6));
1278 refstr_put(filename
);
1281 * subset 2: pc_setint16
1284 else if (looking_at(p
, "implicit")) {
1285 allowimplicit
= atoi(skipspace(p
+ 8));
1286 } else if (looking_at(p
, "prompt")) {
1287 forceprompt
= atoi(skipspace(p
+ 6));
1288 } else if (looking_at(p
, "console")) {
1289 DisplayCon
= atoi(skipspace(p
+ 7));
1290 } else if (looking_at(p
, "allowoptions")) {
1291 allowoptions
= atoi(skipspace(p
+ 12));
1292 } else if (looking_at(p
, "noescape")) {
1293 noescape
= atoi(skipspace(p
+ 8));
1294 } else if (looking_at(p
, "nocomplete")) {
1295 nocomplete
= atoi(skipspace(p
+ 10));
1296 } else if (looking_at(p
, "nohalt")) {
1297 NoHalt
= atoi(skipspace(p
+ 8));
1298 } else if (looking_at(p
, "onerror")) {
1299 refstr_put(m
->onerror
);
1300 m
->onerror
= refstrdup(skipspace(p
+ 7));
1301 onerrorlen
= strlen(m
->onerror
);
1302 refstr_put(onerror
);
1303 onerror
= refstrdup(m
->onerror
);
1306 else if (looking_at(p
, "pxeretry"))
1307 PXERetry
= atoi(skipspace(p
+ 8));
1309 /* serial setting, bps, flow control */
1310 else if (looking_at(p
, "serial")) {
1311 uint16_t port
, flow
;
1314 p
= skipspace(p
+ 6);
1321 /* Default to no flow control */
1325 baud
= DEFAULT_BAUD
;
1340 ignore
= ((flow
& 0x0F00) >> 4);
1343 FlowIgnore
= ignore
;
1344 flow
= ((flow
& 0xff) << 8) | (flow
& 0xff);
1346 FlowOutput
= (flow
& 0xff);
1347 FlowInput
= ((flow
& 0xff00) >> 8);
1354 /* < 75 baud == bogus */
1359 baud
= BAUD_DIVISOR
/ baud
;
1363 port
= get_serial_port(port
);
1367 * Begin code to actually set up the serial port
1369 sirq_cleanup_nowipe();
1371 outb(0x83, port
+ 3); /* Enable DLAB */
1374 outb((baud
& 0xff), port
); /* write divisor to LS */
1377 outb(((baud
& 0xff00) >> 8), port
+ 1); /* write to MS */
1380 outb(0x03, port
+ 3); /* Disable DLAB */
1384 * Read back LCR (detect missing hw). If nothing here
1385 * we'll read 00 or FF.
1387 if (inb(port
+ 3) != 0x03) {
1388 /* Assume serial port busted */
1393 outb(0x01, port
+ 2); /* Enable FIFOs if present */
1396 /* Disable FIFO if unusable */
1397 if (inb(port
+ 2) < 0x0C0) {
1402 /* Assert bits in MCR */
1403 outb(FlowOutput
, port
+ 4);
1406 /* Enable interrupts if requested */
1407 if (FlowOutput
& 0x8)
1410 /* Show some life */
1411 if (SerialNotice
!= 0) {
1414 write_serial_str(syslinux_banner
);
1415 write_serial_str(copyright_str
);
1418 } else if (looking_at(p
, "say")) {
1419 printf("%s\n", p
+4);
1420 } else if (looking_at(p
, "path")) {
1421 if (parse_path(skipspace(p
+ 4)))
1422 printf("Failed to parse PATH\n");
1423 } else if (looking_at(p
, "sendcookies")) {
1424 const union syslinux_derivative_info
*sdi
;
1426 p
+= strlen("sendcookies");
1427 sdi
= syslinux_derivative_info();
1429 if (sdi
->c
.filesystem
== SYSLINUX_FS_PXELINUX
) {
1430 SendCookies
= strtoul(skipspace(p
), NULL
, 10);
1431 http_bake_cookies();
1437 static int parse_main_config(const char *filename
)
1439 const char *mode
= "r";
1446 fd
= open(filename
, O_RDONLY
);
1451 if (config_cwd
[0]) {
1452 if (chdir(config_cwd
) < 0)
1453 printf("Failed to chdir to %s\n", config_cwd
);
1454 config_cwd
[0] = '\0';
1457 f
= fdopen(fd
, mode
);
1458 parse_config_file(f
);
1461 * Update ConfigName so that syslinux_config_file() returns
1462 * the filename we just opened. filesystem-specific
1463 * open_config() implementations are expected to update
1464 * ConfigName themselves.
1467 strcpy(ConfigName
, filename
);
1472 static void resolve_gotos(void)
1474 struct menu_entry
*me
;
1477 for (me
= all_entries
; me
; me
= me
->next
) {
1478 if (me
->action
== MA_GOTO_UNRES
|| me
->action
== MA_EXIT_UNRES
) {
1479 m
= find_menu(me
->cmdline
);
1480 refstr_put(me
->cmdline
);
1484 me
->action
--; /* Drop the _UNRES */
1486 me
->action
= MA_DISABLED
;
1492 void parse_configs(char **argv
)
1494 const char *filename
;
1496 struct menu_entry
*me
;
1499 empty_string
= refstrdup("");
1501 /* feng: reset current menu_list and entry list */
1505 /* Initialize defaults for the root and hidden menus */
1506 hide_menu
= new_menu(NULL
, NULL
, refstrdup(".hidden"));
1507 root_menu
= new_menu(NULL
, NULL
, refstrdup(".top"));
1508 start_menu
= root_menu
;
1510 /* Other initialization */
1511 memset(&ld
, 0, sizeof(struct labeldata
));
1513 /* Actually process the files */
1514 current_menu
= root_menu
;
1516 if (!argv
|| !*argv
) {
1517 if (parse_main_config(NULL
) < 0) {
1518 printf("WARNING: No configuration file found\n");
1522 while ((filename
= *argv
++)) {
1523 dprintf("Parsing config: %s", filename
);
1524 parse_main_config(filename
);
1528 /* On final EOF process the last label statement */
1529 record(current_menu
, &ld
, append
);
1531 /* Common postprocessing */
1534 /* Handle global default */
1535 //if (has_ui && globaldefault) {
1536 if (globaldefault
) {
1537 dprintf("gloabldefault = %s", globaldefault
);
1538 me
= find_label(globaldefault
);
1539 if (me
&& me
->menu
!= hide_menu
) {
1540 me
->menu
->defentry
= me
->entry
;
1541 start_menu
= me
->menu
;
1542 default_menu
= me
->menu
;
1546 /* If "menu save" is active, let the ADV override the global default */
1549 const char *lbl
= syslinux_getadv(ADV_MENUSAVE
, &len
);
1552 lstr
= refstr_alloc(len
);
1553 memcpy(lstr
, lbl
, len
); /* refstr_alloc() adds the final null */
1554 me
= find_label(lstr
);
1555 if (me
&& me
->menu
!= hide_menu
) {
1556 me
->menu
->defentry
= me
->entry
;
1557 start_menu
= me
->menu
;
1563 /* Final per-menu initialization, with all labels known */
1564 for (m
= menu_list
; m
; m
= m
->next
) {
1565 m
->curentry
= m
->defentry
; /* All menus start at their defaults */
1568 m
->ontimeout
= unlabel(m
->ontimeout
);
1570 m
->onerror
= unlabel(m
->onerror
);