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(const char *);
768 extern void loadkeys(const 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
);
876 static void parse_config_file(FILE * f
)
878 char line
[MAX_LINE
], *p
, *ep
, ch
;
879 enum kernel_type type
;
880 enum message_number msgnr
;
882 struct menu
*m
= current_menu
;
884 while (fgets(line
, sizeof line
, f
)) {
885 p
= strchr(line
, '\r');
888 p
= strchr(line
, '\n');
894 if (looking_at(p
, "menu")) {
896 p
= skipspace(p
+ 4);
898 if (looking_at(p
, "label")) {
900 refstr_put(ld
.menulabel
);
901 ld
.menulabel
= refstrdup(skipspace(p
+ 5));
902 } else if (m
->parent_entry
) {
903 refstr_put(m
->parent_entry
->displayname
);
904 m
->parent_entry
->displayname
= refstrdup(skipspace(p
+ 5));
905 consider_for_hotkey(m
->parent
, m
->parent_entry
);
907 /* MENU LABEL -> MENU TITLE on submenu */
908 refstr_put(m
->title
);
909 m
->title
= strip_caret(m
->parent_entry
->displayname
);
912 } else if (looking_at(p
, "title")) {
913 refstr_put(m
->title
);
914 m
->title
= refstrdup(skipspace(p
+ 5));
915 if (m
->parent_entry
) {
916 /* MENU TITLE -> MENU LABEL on submenu */
917 if (m
->parent_entry
->displayname
== m
->label
) {
918 refstr_put(m
->parent_entry
->displayname
);
919 m
->parent_entry
->displayname
= refstr_get(m
->title
);
922 } else if (looking_at(p
, "default")) {
925 } else if (m
->parent_entry
) {
926 m
->parent
->defentry
= m
->parent_entry
->entry
;
928 } else if (looking_at(p
, "hide")) {
930 } else if (looking_at(p
, "passwd")) {
932 refstr_put(ld
.passwd
);
933 ld
.passwd
= refstrdup(skipspace(p
+ 6));
934 } else if (m
->parent_entry
) {
935 refstr_put(m
->parent_entry
->passwd
);
936 m
->parent_entry
->passwd
= refstrdup(skipspace(p
+ 6));
938 } else if (looking_at(p
, "shiftkey")) {
940 } else if (looking_at(p
, "save")) {
946 } else if (looking_at(p
, "nosave")) {
951 } else if (looking_at(p
, "onerror")) {
952 refstr_put(m
->onerror
);
953 m
->onerror
= refstrdup(skipspace(p
+ 7));
954 onerrorlen
= strlen(m
->onerror
);
956 onerror
= refstrdup(m
->onerror
);
957 } else if (looking_at(p
, "master")) {
958 p
= skipspace(p
+ 6);
959 if (looking_at(p
, "passwd")) {
960 refstr_put(m
->menu_master_passwd
);
961 m
->menu_master_passwd
= refstrdup(skipspace(p
+ 6));
963 } else if ((ep
= looking_at(p
, "include"))) {
964 do_include_menu(ep
, m
);
965 } else if ((ep
= looking_at(p
, "background"))) {
967 refstr_put(m
->menu_background
);
968 m
->menu_background
= refdup_word(&p
);
969 } else if ((ep
= looking_at(p
, "hidden"))) {
971 } else if ((ep
= is_message_name(p
, &msgnr
))) {
972 refstr_put(m
->messages
[msgnr
]);
973 m
->messages
[msgnr
] = refstrdup(skipspace(ep
));
974 } else if ((ep
= looking_at(p
, "color")) ||
975 (ep
= looking_at(p
, "colour"))) {
977 struct color_table
*cptr
;
979 cptr
= m
->color_table
;
980 for (i
= 0; i
< menu_color_table_size
; i
++) {
981 if ((ep
= looking_at(p
, cptr
->name
))) {
984 if (looking_at(p
, "*")) {
987 refstr_put(cptr
->ansi
);
988 cptr
->ansi
= refdup_word(&p
);
993 if (looking_at(p
, "*"))
996 cptr
->argb_fg
= parse_argb(&p
);
1000 if (looking_at(p
, "*"))
1003 cptr
->argb_bg
= parse_argb(&p
);
1005 /* Parse a shadow mode */
1008 if (ch
== 'n') /* none */
1009 cptr
->shadow
= SHADOW_NONE
;
1010 else if (ch
== 's') /* std, standard */
1011 cptr
->shadow
= SHADOW_NORMAL
;
1012 else if (ch
== 'a') /* all */
1013 cptr
->shadow
= SHADOW_ALL
;
1014 else if (ch
== 'r') /* rev, reverse */
1015 cptr
->shadow
= SHADOW_REVERSE
;
1023 } else if ((ep
= looking_at(p
, "msgcolor")) ||
1024 (ep
= looking_at(p
, "msgcolour"))) {
1025 unsigned int fg_mask
= MSG_COLORS_DEF_FG
;
1026 unsigned int bg_mask
= MSG_COLORS_DEF_BG
;
1027 enum color_table_shadow shadow
= MSG_COLORS_DEF_SHADOW
;
1031 if (!looking_at(p
, "*"))
1032 fg_mask
= parse_argb(&p
);
1036 if (!looking_at(p
, "*"))
1037 bg_mask
= parse_argb(&p
);
1040 switch (*p
| 0x20) {
1042 shadow
= SHADOW_NONE
;
1045 shadow
= SHADOW_NORMAL
;
1048 shadow
= SHADOW_ALL
;
1051 shadow
= SHADOW_REVERSE
;
1054 /* go with default */
1059 set_msg_colors_global(m
->color_table
, fg_mask
, bg_mask
, shadow
);
1060 } else if (looking_at(p
, "separator")) {
1061 record(m
, &ld
, append
);
1062 ld
.label
= refstr_get(empty_string
);
1063 ld
.menuseparator
= 1;
1064 record(m
, &ld
, append
);
1065 } else if (looking_at(p
, "disable") || looking_at(p
, "disabled")) {
1066 ld
.menudisabled
= 1;
1067 } else if (looking_at(p
, "indent")) {
1068 ld
.menuindent
= atoi(skipspace(p
+ 6));
1069 } else if (looking_at(p
, "begin")) {
1070 record(m
, &ld
, append
);
1071 m
= current_menu
= begin_submenu(skipspace(p
+ 5));
1072 } else if (looking_at(p
, "end")) {
1073 record(m
, &ld
, append
);
1074 m
= current_menu
= end_submenu();
1075 } else if (looking_at(p
, "quit")) {
1077 ld
.action
= MA_QUIT
;
1078 } else if (looking_at(p
, "goto")) {
1080 ld
.action
= MA_GOTO_UNRES
;
1081 refstr_put(ld
.kernel
);
1082 ld
.kernel
= refstrdup(skipspace(p
+ 4));
1084 } else if (looking_at(p
, "exit")) {
1085 p
= skipspace(p
+ 4);
1086 if (ld
.label
&& m
->parent
) {
1088 /* This is really just a goto, except for the marker */
1089 ld
.action
= MA_EXIT_UNRES
;
1090 refstr_put(ld
.kernel
);
1091 ld
.kernel
= refstrdup(p
);
1093 ld
.action
= MA_EXIT
;
1094 ld
.submenu
= m
->parent
;
1097 } else if (looking_at(p
, "start")) {
1100 /* Unknown, check for layout parameters */
1101 enum parameter_number mp
;
1102 for (mp
= 0; mp
< NPARAMS
; mp
++) {
1103 if ((ep
= looking_at(p
, mparm
[mp
].name
))) {
1104 m
->mparm
[mp
] = atoi(skipspace(ep
));
1110 /* feng: menu handling end */
1111 else if (looking_at(p
, "text")) {
1113 /* loop till we fined the "endtext" */
1117 } cmd
= TEXT_UNKNOWN
;
1118 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
1121 p
= skipspace(p
+ 4);
1123 if (looking_at(p
, "help"))
1126 while (fgets(line
, sizeof line
, f
)) {
1127 p
= skipspace(line
);
1128 if (looking_at(p
, "endtext"))
1131 xlen
= strlen(line
);
1137 ld
.helptext
= realloc(ld
.helptext
, len
+ xlen
+ 1);
1138 memcpy(ld
.helptext
+ len
, line
, xlen
+ 1);
1143 } else if ((ep
= is_fkey(p
, &fkeyno
))) {
1145 if (m
->fkeyhelp
[fkeyno
].textname
) {
1146 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1147 m
->fkeyhelp
[fkeyno
].textname
= NULL
;
1149 if (m
->fkeyhelp
[fkeyno
].background
) {
1150 refstr_put(m
->fkeyhelp
[fkeyno
].background
);
1151 m
->fkeyhelp
[fkeyno
].background
= NULL
;
1154 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1155 m
->fkeyhelp
[fkeyno
].textname
= refdup_word(&p
);
1158 m
->fkeyhelp
[fkeyno
].background
= refdup_word(&p
);
1160 } else if ((ep
= looking_at(p
, "include"))) {
1162 } else if (looking_at(p
, "append")) {
1163 const char *a
= refstrdup(skipspace(p
+ 6));
1165 refstr_put(ld
.append
);
1171 //dprintf("we got a append: %s", a);
1172 } else if (looking_at(p
, "initrd")) {
1173 const char *a
= refstrdup(skipspace(p
+ 6));
1175 refstr_put(ld
.initrd
);
1180 } else if (looking_at(p
, "label")) {
1181 p
= skipspace(p
+ 5);
1182 /* when first time see "label", it will not really record anything */
1183 record(m
, &ld
, append
);
1184 ld
.label
= __refdup_word(p
, NULL
);
1185 ld
.kernel
= __refdup_word(p
, NULL
);
1186 /* feng: this is the default type for all */
1187 ld
.type
= KT_KERNEL
;
1191 ld
.menulabel
= NULL
;
1193 ld
.ipappend
= SysAppends
;
1194 ld
.menudefault
= ld
.menuhide
= ld
.menuseparator
=
1195 ld
.menudisabled
= ld
.menuindent
= 0;
1196 } else if ((ep
= is_kernel_type(p
, &type
))) {
1198 refstr_put(ld
.kernel
);
1199 ld
.kernel
= refstrdup(skipspace(ep
));
1201 //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
1203 } else if (looking_at(p
, "timeout")) {
1204 kbdtimeout
= (atoi(skipspace(p
+ 7)) * CLK_TCK
+ 9) / 10;
1205 } else if (looking_at(p
, "totaltimeout")) {
1206 totaltimeout
= (atoll(skipspace(p
+ 13)) * CLK_TCK
+ 9) / 10;
1207 } else if (looking_at(p
, "ontimeout")) {
1208 ontimeout
= refstrdup(skipspace(p
+ 9));
1209 ontimeoutlen
= strlen(ontimeout
);
1210 } else if (looking_at(p
, "allowoptions")) {
1211 allowoptions
= !!atoi(skipspace(p
+ 12));
1212 } else if ((ep
= looking_at(p
, "ipappend")) ||
1213 (ep
= looking_at(p
, "sysappend"))) {
1214 uint32_t s
= strtoul(skipspace(ep
), NULL
, 0);
1219 } else if (looking_at(p
, "default")) {
1220 /* default could be a kernel image or another label */
1221 refstr_put(globaldefault
);
1222 globaldefault
= refstrdup(skipspace(p
+ 7));
1225 * On the chance that "default" is actually a kernel image
1226 * and not a label, store a copy of it, but only if we
1227 * haven't seen a "ui" command. "ui" commands take
1228 * precendence over "default" commands.
1230 if (defaultlevel
< LEVEL_UI
) {
1231 defaultlevel
= LEVEL_DEFAULT
;
1232 refstr_put(default_cmd
);
1233 default_cmd
= refstrdup(globaldefault
);
1235 } else if (looking_at(p
, "ui")) {
1237 defaultlevel
= LEVEL_UI
;
1238 refstr_put(default_cmd
);
1239 default_cmd
= refstrdup(skipspace(p
+ 2));
1243 * subset 1: pc_opencmd
1244 * display/font/kbdmap are rather similar, open a file then do sth
1246 else if (looking_at(p
, "display")) {
1247 const char *filename
;
1248 char *dst
= KernelName
;
1249 size_t len
= FILENAME_MAX
- 1;
1251 filename
= refstrdup(skipspace(p
+ 7));
1253 while (len
-- && not_whitespace(*filename
))
1254 *dst
++ = *filename
++;
1257 get_msg_file(KernelName
);
1258 refstr_put(filename
);
1259 } else if (looking_at(p
, "font")) {
1260 const char *filename
;
1261 char *dst
= KernelName
;
1262 size_t len
= FILENAME_MAX
- 1;
1264 filename
= refstrdup(skipspace(p
+ 4));
1266 while (len
-- && not_whitespace(*filename
))
1267 *dst
++ = *filename
++;
1270 loadfont(KernelName
);
1271 refstr_put(filename
);
1272 } else if (looking_at(p
, "kbdmap")) {
1273 const char *filename
;
1275 filename
= refstrdup(skipspace(p
+ 6));
1277 refstr_put(filename
);
1280 * subset 2: pc_setint16
1283 else if (looking_at(p
, "implicit")) {
1284 allowimplicit
= atoi(skipspace(p
+ 8));
1285 } else if (looking_at(p
, "prompt")) {
1286 forceprompt
= atoi(skipspace(p
+ 6));
1287 } else if (looking_at(p
, "console")) {
1288 DisplayCon
= atoi(skipspace(p
+ 7));
1289 } else if (looking_at(p
, "allowoptions")) {
1290 allowoptions
= atoi(skipspace(p
+ 12));
1291 } else if (looking_at(p
, "noescape")) {
1292 noescape
= atoi(skipspace(p
+ 8));
1293 } else if (looking_at(p
, "nocomplete")) {
1294 nocomplete
= atoi(skipspace(p
+ 10));
1295 } else if (looking_at(p
, "nohalt")) {
1296 NoHalt
= atoi(skipspace(p
+ 8));
1297 } else if (looking_at(p
, "onerror")) {
1298 refstr_put(m
->onerror
);
1299 m
->onerror
= refstrdup(skipspace(p
+ 7));
1300 onerrorlen
= strlen(m
->onerror
);
1301 refstr_put(onerror
);
1302 onerror
= refstrdup(m
->onerror
);
1305 else if (looking_at(p
, "pxeretry"))
1306 PXERetry
= atoi(skipspace(p
+ 8));
1308 /* serial setting, bps, flow control */
1309 else if (looking_at(p
, "serial")) {
1310 uint16_t port
, flow
;
1313 p
= skipspace(p
+ 6);
1320 /* Default to no flow control */
1324 baud
= DEFAULT_BAUD
;
1339 ignore
= ((flow
& 0x0F00) >> 4);
1342 FlowIgnore
= ignore
;
1343 flow
= ((flow
& 0xff) << 8) | (flow
& 0xff);
1345 FlowOutput
= (flow
& 0xff);
1346 FlowInput
= ((flow
& 0xff00) >> 8);
1353 /* < 75 baud == bogus */
1358 baud
= BAUD_DIVISOR
/ baud
;
1362 port
= get_serial_port(port
);
1366 * Begin code to actually set up the serial port
1368 sirq_cleanup_nowipe();
1370 outb(0x83, port
+ 3); /* Enable DLAB */
1373 outb((baud
& 0xff), port
); /* write divisor to LS */
1376 outb(((baud
& 0xff00) >> 8), port
+ 1); /* write to MS */
1379 outb(0x03, port
+ 3); /* Disable DLAB */
1383 * Read back LCR (detect missing hw). If nothing here
1384 * we'll read 00 or FF.
1386 if (inb(port
+ 3) != 0x03) {
1387 /* Assume serial port busted */
1392 outb(0x01, port
+ 2); /* Enable FIFOs if present */
1395 /* Disable FIFO if unusable */
1396 if (inb(port
+ 2) < 0x0C0) {
1401 /* Assert bits in MCR */
1402 outb(FlowOutput
, port
+ 4);
1405 /* Enable interrupts if requested */
1406 if (FlowOutput
& 0x8)
1409 /* Show some life */
1410 if (SerialNotice
!= 0) {
1413 write_serial_str(syslinux_banner
);
1414 write_serial_str(copyright_str
);
1417 } else if (looking_at(p
, "say")) {
1418 printf("%s\n", p
+4);
1419 } else if (looking_at(p
, "path")) {
1420 if (parse_path(skipspace(p
+ 4)))
1421 printf("Failed to parse PATH\n");
1422 } else if (looking_at(p
, "sendcookies")) {
1423 const union syslinux_derivative_info
*sdi
;
1425 p
+= strlen("sendcookies");
1426 sdi
= syslinux_derivative_info();
1428 if (sdi
->c
.filesystem
== SYSLINUX_FS_PXELINUX
) {
1429 SendCookies
= strtoul(skipspace(p
), NULL
, 10);
1430 http_bake_cookies();
1436 static int parse_main_config(const char *filename
)
1438 const char *mode
= "r";
1445 fd
= open(filename
, O_RDONLY
);
1450 if (config_cwd
[0]) {
1451 if (chdir(config_cwd
) < 0)
1452 printf("Failed to chdir to %s\n", config_cwd
);
1453 config_cwd
[0] = '\0';
1456 f
= fdopen(fd
, mode
);
1457 parse_config_file(f
);
1460 * Update ConfigName so that syslinux_config_file() returns
1461 * the filename we just opened. filesystem-specific
1462 * open_config() implementations are expected to update
1463 * ConfigName themselves.
1466 strcpy(ConfigName
, filename
);
1471 static void resolve_gotos(void)
1473 struct menu_entry
*me
;
1476 for (me
= all_entries
; me
; me
= me
->next
) {
1477 if (me
->action
== MA_GOTO_UNRES
|| me
->action
== MA_EXIT_UNRES
) {
1478 m
= find_menu(me
->cmdline
);
1479 refstr_put(me
->cmdline
);
1483 me
->action
--; /* Drop the _UNRES */
1485 me
->action
= MA_DISABLED
;
1491 void parse_configs(char **argv
)
1493 const char *filename
;
1495 struct menu_entry
*me
;
1498 empty_string
= refstrdup("");
1500 /* feng: reset current menu_list and entry list */
1504 /* Initialize defaults for the root and hidden menus */
1505 hide_menu
= new_menu(NULL
, NULL
, refstrdup(".hidden"));
1506 root_menu
= new_menu(NULL
, NULL
, refstrdup(".top"));
1507 start_menu
= root_menu
;
1509 /* Other initialization */
1510 memset(&ld
, 0, sizeof(struct labeldata
));
1512 /* Actually process the files */
1513 current_menu
= root_menu
;
1515 if (!argv
|| !*argv
) {
1516 if (parse_main_config(NULL
) < 0) {
1517 printf("WARNING: No configuration file found\n");
1521 while ((filename
= *argv
++)) {
1522 dprintf("Parsing config: %s", filename
);
1523 parse_main_config(filename
);
1527 /* On final EOF process the last label statement */
1528 record(current_menu
, &ld
, append
);
1530 /* Common postprocessing */
1533 /* Handle global default */
1534 //if (has_ui && globaldefault) {
1535 if (globaldefault
) {
1536 dprintf("gloabldefault = %s", globaldefault
);
1537 me
= find_label(globaldefault
);
1538 if (me
&& me
->menu
!= hide_menu
) {
1539 me
->menu
->defentry
= me
->entry
;
1540 start_menu
= me
->menu
;
1541 default_menu
= me
->menu
;
1545 /* If "menu save" is active, let the ADV override the global default */
1548 const char *lbl
= syslinux_getadv(ADV_MENUSAVE
, &len
);
1551 lstr
= refstr_alloc(len
);
1552 memcpy(lstr
, lbl
, len
); /* refstr_alloc() adds the final null */
1553 me
= find_label(lstr
);
1554 if (me
&& me
->menu
!= hide_menu
) {
1555 me
->menu
->defentry
= me
->entry
;
1556 start_menu
= me
->menu
;
1562 /* Final per-menu initialization, with all labels known */
1563 for (m
= menu_list
; m
; m
= m
->next
) {
1564 m
->curentry
= m
->defentry
; /* All menus start at their defaults */
1567 m
->ontimeout
= unlabel(m
->ontimeout
);
1569 m
->onerror
= unlabel(m
->onerror
);