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_one_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 char line
[MAX_LINE
], *p
, *ep
, ch
;
816 enum kernel_type type
;
817 enum message_number msgnr
;
819 struct menu
*m
= current_menu
;
821 while (fgets(line
, sizeof line
, f
)) {
822 p
= strchr(line
, '\r');
825 p
= strchr(line
, '\n');
831 if (looking_at(p
, "menu")) {
833 p
= skipspace(p
+ 4);
835 if (looking_at(p
, "label")) {
837 refstr_put(ld
.menulabel
);
838 ld
.menulabel
= refstrdup(skipspace(p
+ 5));
839 } else if (m
->parent_entry
) {
840 refstr_put(m
->parent_entry
->displayname
);
841 m
->parent_entry
->displayname
= refstrdup(skipspace(p
+ 5));
842 consider_for_hotkey(m
->parent
, m
->parent_entry
);
844 /* MENU LABEL -> MENU TITLE on submenu */
845 refstr_put(m
->title
);
846 m
->title
= strip_caret(m
->parent_entry
->displayname
);
849 } else if (looking_at(p
, "title")) {
850 refstr_put(m
->title
);
851 m
->title
= refstrdup(skipspace(p
+ 5));
852 if (m
->parent_entry
) {
853 /* MENU TITLE -> MENU LABEL on submenu */
854 if (m
->parent_entry
->displayname
== m
->label
) {
855 refstr_put(m
->parent_entry
->displayname
);
856 m
->parent_entry
->displayname
= refstr_get(m
->title
);
859 } else if (looking_at(p
, "default")) {
862 } else if (m
->parent_entry
) {
863 m
->parent
->defentry
= m
->parent_entry
->entry
;
865 } else if (looking_at(p
, "hide")) {
867 } else if (looking_at(p
, "passwd")) {
869 refstr_put(ld
.passwd
);
870 ld
.passwd
= refstrdup(skipspace(p
+ 6));
871 } else if (m
->parent_entry
) {
872 refstr_put(m
->parent_entry
->passwd
);
873 m
->parent_entry
->passwd
= refstrdup(skipspace(p
+ 6));
875 } else if (looking_at(p
, "shiftkey")) {
877 } else if (looking_at(p
, "save")) {
883 } else if (looking_at(p
, "nosave")) {
888 } else if (looking_at(p
, "onerror")) {
889 refstr_put(m
->onerror
);
890 m
->onerror
= refstrdup(skipspace(p
+ 7));
891 onerrorlen
= strlen(m
->onerror
);
893 onerror
= refstrdup(m
->onerror
);
894 } else if (looking_at(p
, "master")) {
895 p
= skipspace(p
+ 6);
896 if (looking_at(p
, "passwd")) {
897 refstr_put(m
->menu_master_passwd
);
898 m
->menu_master_passwd
= refstrdup(skipspace(p
+ 6));
900 } else if ((ep
= looking_at(p
, "include"))) {
902 } else if ((ep
= looking_at(p
, "background"))) {
904 refstr_put(m
->menu_background
);
905 m
->menu_background
= refdup_word(&p
);
906 } else if ((ep
= looking_at(p
, "hidden"))) {
908 } else if ((ep
= is_message_name(p
, &msgnr
))) {
909 refstr_put(m
->messages
[msgnr
]);
910 m
->messages
[msgnr
] = refstrdup(skipspace(ep
));
911 } else if ((ep
= looking_at(p
, "color")) ||
912 (ep
= looking_at(p
, "colour"))) {
914 struct color_table
*cptr
;
916 cptr
= m
->color_table
;
917 for (i
= 0; i
< menu_color_table_size
; i
++) {
918 if ((ep
= looking_at(p
, cptr
->name
))) {
921 if (looking_at(p
, "*")) {
924 refstr_put(cptr
->ansi
);
925 cptr
->ansi
= refdup_word(&p
);
930 if (looking_at(p
, "*"))
933 cptr
->argb_fg
= parse_argb(&p
);
937 if (looking_at(p
, "*"))
940 cptr
->argb_bg
= parse_argb(&p
);
942 /* Parse a shadow mode */
945 if (ch
== 'n') /* none */
946 cptr
->shadow
= SHADOW_NONE
;
947 else if (ch
== 's') /* std, standard */
948 cptr
->shadow
= SHADOW_NORMAL
;
949 else if (ch
== 'a') /* all */
950 cptr
->shadow
= SHADOW_ALL
;
951 else if (ch
== 'r') /* rev, reverse */
952 cptr
->shadow
= SHADOW_REVERSE
;
960 } else if ((ep
= looking_at(p
, "msgcolor")) ||
961 (ep
= looking_at(p
, "msgcolour"))) {
962 unsigned int fg_mask
= MSG_COLORS_DEF_FG
;
963 unsigned int bg_mask
= MSG_COLORS_DEF_BG
;
964 enum color_table_shadow shadow
= MSG_COLORS_DEF_SHADOW
;
968 if (!looking_at(p
, "*"))
969 fg_mask
= parse_argb(&p
);
973 if (!looking_at(p
, "*"))
974 bg_mask
= parse_argb(&p
);
979 shadow
= SHADOW_NONE
;
982 shadow
= SHADOW_NORMAL
;
988 shadow
= SHADOW_REVERSE
;
991 /* go with default */
996 set_msg_colors_global(m
->color_table
, fg_mask
, bg_mask
, shadow
);
997 } else if (looking_at(p
, "separator")) {
998 record(m
, &ld
, append
);
999 ld
.label
= refstr_get(empty_string
);
1000 ld
.menuseparator
= 1;
1001 record(m
, &ld
, append
);
1002 } else if (looking_at(p
, "disable") || looking_at(p
, "disabled")) {
1003 ld
.menudisabled
= 1;
1004 } else if (looking_at(p
, "indent")) {
1005 ld
.menuindent
= atoi(skipspace(p
+ 6));
1006 } else if (looking_at(p
, "begin")) {
1007 record(m
, &ld
, append
);
1008 m
= current_menu
= begin_submenu(skipspace(p
+ 5));
1009 } else if (looking_at(p
, "end")) {
1010 record(m
, &ld
, append
);
1011 m
= current_menu
= end_submenu();
1012 } else if (looking_at(p
, "quit")) {
1014 ld
.action
= MA_QUIT
;
1015 } else if (looking_at(p
, "goto")) {
1017 ld
.action
= MA_GOTO_UNRES
;
1018 refstr_put(ld
.kernel
);
1019 ld
.kernel
= refstrdup(skipspace(p
+ 4));
1021 } else if (looking_at(p
, "exit")) {
1022 p
= skipspace(p
+ 4);
1023 if (ld
.label
&& m
->parent
) {
1025 /* This is really just a goto, except for the marker */
1026 ld
.action
= MA_EXIT_UNRES
;
1027 refstr_put(ld
.kernel
);
1028 ld
.kernel
= refstrdup(p
);
1030 ld
.action
= MA_EXIT
;
1031 ld
.submenu
= m
->parent
;
1034 } else if (looking_at(p
, "start")) {
1037 /* Unknown, check for layout parameters */
1038 enum parameter_number mp
;
1039 for (mp
= 0; mp
< NPARAMS
; mp
++) {
1040 if ((ep
= looking_at(p
, mparm
[mp
].name
))) {
1041 m
->mparm
[mp
] = atoi(skipspace(ep
));
1047 /* feng: menu handling end */
1048 else if (looking_at(p
, "text")) {
1050 /* loop till we fined the "endtext" */
1054 } cmd
= TEXT_UNKNOWN
;
1055 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
1058 p
= skipspace(p
+ 4);
1060 if (looking_at(p
, "help"))
1063 while (fgets(line
, sizeof line
, f
)) {
1064 p
= skipspace(line
);
1065 if (looking_at(p
, "endtext"))
1068 xlen
= strlen(line
);
1074 ld
.helptext
= realloc(ld
.helptext
, len
+ xlen
+ 1);
1075 memcpy(ld
.helptext
+ len
, line
, xlen
+ 1);
1080 } else if ((ep
= is_fkey(p
, &fkeyno
))) {
1082 if (m
->fkeyhelp
[fkeyno
].textname
) {
1083 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1084 m
->fkeyhelp
[fkeyno
].textname
= NULL
;
1086 if (m
->fkeyhelp
[fkeyno
].background
) {
1087 refstr_put(m
->fkeyhelp
[fkeyno
].background
);
1088 m
->fkeyhelp
[fkeyno
].background
= NULL
;
1091 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1092 m
->fkeyhelp
[fkeyno
].textname
= refdup_word(&p
);
1095 m
->fkeyhelp
[fkeyno
].background
= refdup_word(&p
);
1097 } else if ((ep
= looking_at(p
, "include"))) {
1102 file
= refdup_word(&p
);
1105 record(m
, &ld
, append
);
1106 m
= current_menu
= begin_submenu(p
);
1107 parse_one_config(file
);
1108 record(m
, &ld
, append
);
1109 m
= current_menu
= end_submenu();
1111 parse_one_config(file
);
1115 } else if (looking_at(p
, "append")) {
1116 const char *a
= refstrdup(skipspace(p
+ 6));
1118 refstr_put(ld
.append
);
1124 //dprintf("we got a append: %s", a);
1125 } else if (looking_at(p
, "initrd")) {
1126 const char *a
= refstrdup(skipspace(p
+ 6));
1128 refstr_put(ld
.initrd
);
1133 } else if (looking_at(p
, "label")) {
1134 p
= skipspace(p
+ 5);
1135 /* when first time see "label", it will not really record anything */
1136 record(m
, &ld
, append
);
1137 ld
.label
= __refdup_word(p
, NULL
);
1138 ld
.kernel
= __refdup_word(p
, NULL
);
1139 /* feng: this is the default type for all */
1140 ld
.type
= KT_KERNEL
;
1144 ld
.menulabel
= NULL
;
1146 ld
.ipappend
= SysAppends
;
1147 ld
.menudefault
= ld
.menuhide
= ld
.menuseparator
=
1148 ld
.menudisabled
= ld
.menuindent
= 0;
1149 } else if ((ep
= is_kernel_type(p
, &type
))) {
1151 refstr_put(ld
.kernel
);
1152 ld
.kernel
= refstrdup(skipspace(ep
));
1154 //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
1156 } else if (looking_at(p
, "timeout")) {
1157 kbdtimeout
= (atoi(skipspace(p
+ 7)) * CLK_TCK
+ 9) / 10;
1158 } else if (looking_at(p
, "totaltimeout")) {
1159 totaltimeout
= (atoll(skipspace(p
+ 13)) * CLK_TCK
+ 9) / 10;
1160 } else if (looking_at(p
, "ontimeout")) {
1161 ontimeout
= refstrdup(skipspace(p
+ 9));
1162 ontimeoutlen
= strlen(ontimeout
);
1163 } else if (looking_at(p
, "allowoptions")) {
1164 allowoptions
= !!atoi(skipspace(p
+ 12));
1165 } else if ((ep
= looking_at(p
, "ipappend")) ||
1166 (ep
= looking_at(p
, "sysappend"))) {
1167 uint32_t s
= strtoul(skipspace(ep
), NULL
, 16);
1172 } else if (looking_at(p
, "default")) {
1173 /* default could be a kernel image or another label */
1174 refstr_put(globaldefault
);
1175 globaldefault
= refstrdup(skipspace(p
+ 7));
1178 * On the chance that "default" is actually a kernel image
1179 * and not a label, store a copy of it, but only if we
1180 * haven't seen a "ui" command. "ui" commands take
1181 * precendence over "default" commands.
1183 if (defaultlevel
< LEVEL_UI
) {
1184 defaultlevel
= LEVEL_DEFAULT
;
1185 refstr_put(default_cmd
);
1186 default_cmd
= refstrdup(globaldefault
);
1188 } else if (looking_at(p
, "ui")) {
1190 defaultlevel
= LEVEL_UI
;
1191 refstr_put(default_cmd
);
1192 default_cmd
= refstrdup(skipspace(p
+ 2));
1196 * subset 1: pc_opencmd
1197 * display/font/kbdmap are rather similar, open a file then do sth
1199 else if (looking_at(p
, "display")) {
1200 const char *filename
;
1201 char *dst
= KernelName
;
1202 size_t len
= FILENAME_MAX
- 1;
1204 filename
= refstrdup(skipspace(p
+ 7));
1206 while (len
-- && not_whitespace(*filename
))
1207 *dst
++ = *filename
++;
1210 get_msg_file(KernelName
);
1211 refstr_put(filename
);
1212 } else if (looking_at(p
, "font")) {
1213 const char *filename
;
1214 char *dst
= KernelName
;
1215 size_t len
= FILENAME_MAX
- 1;
1217 filename
= refstrdup(skipspace(p
+ 4));
1219 while (len
-- && not_whitespace(*filename
))
1220 *dst
++ = *filename
++;
1223 loadfont(KernelName
);
1224 refstr_put(filename
);
1225 } else if (looking_at(p
, "kbdmap")) {
1226 const char *filename
;
1227 char *dst
= KernelName
;
1228 size_t len
= FILENAME_MAX
- 1;
1230 filename
= refstrdup(skipspace(p
+ 4));
1232 while (len
-- && not_whitespace(*filename
))
1233 *dst
++ = *filename
++;
1236 loadkeys(KernelName
);
1237 refstr_put(filename
);
1240 * subset 2: pc_setint16
1243 else if (looking_at(p
, "implicit")) {
1244 allowimplicit
= atoi(skipspace(p
+ 8));
1245 } else if (looking_at(p
, "prompt")) {
1246 forceprompt
= atoi(skipspace(p
+ 6));
1247 } else if (looking_at(p
, "console")) {
1248 DisplayCon
= atoi(skipspace(p
+ 7));
1249 } else if (looking_at(p
, "allowoptions")) {
1250 allowoptions
= atoi(skipspace(p
+ 12));
1251 } else if (looking_at(p
, "noescape")) {
1252 noescape
= atoi(skipspace(p
+ 8));
1253 } else if (looking_at(p
, "nocomplete")) {
1254 nocomplete
= atoi(skipspace(p
+ 10));
1255 } else if (looking_at(p
, "nohalt")) {
1256 NoHalt
= atoi(skipspace(p
+ 8));
1257 } else if (looking_at(p
, "onerror")) {
1258 refstr_put(m
->onerror
);
1259 m
->onerror
= refstrdup(skipspace(p
+ 7));
1260 onerrorlen
= strlen(m
->onerror
);
1261 refstr_put(onerror
);
1262 onerror
= refstrdup(m
->onerror
);
1265 else if (looking_at(p
, "pxeretry"))
1266 PXERetry
= atoi(skipspace(p
+ 8));
1268 /* serial setting, bps, flow control */
1269 else if (looking_at(p
, "serial")) {
1270 uint16_t port
, flow
;
1273 p
= skipspace(p
+ 6);
1280 /* Default to no flow control */
1284 baud
= DEFAULT_BAUD
;
1299 ignore
= ((flow
& 0x0F00) >> 4);
1302 FlowIgnore
= ignore
;
1303 flow
= ((flow
& 0xff) << 8) | (flow
& 0xff);
1305 FlowOutput
= (flow
& 0xff);
1306 FlowInput
= ((flow
& 0xff00) >> 8);
1313 /* < 75 baud == bogus */
1318 baud
= BAUD_DIVISOR
/ baud
;
1322 port
= get_serial_port(port
);
1326 * Begin code to actually set up the serial port
1328 sirq_cleanup_nowipe();
1330 outb(0x83, port
+ 3); /* Enable DLAB */
1333 outb((baud
& 0xff), port
); /* write divisor to LS */
1336 outb(((baud
& 0xff00) >> 8), port
+ 1); /* write to MS */
1339 outb(0x03, port
+ 3); /* Disable DLAB */
1343 * Read back LCR (detect missing hw). If nothing here
1344 * we'll read 00 or FF.
1346 if (inb(port
+ 3) != 0x03) {
1347 /* Assume serial port busted */
1352 outb(0x01, port
+ 2); /* Enable FIFOs if present */
1355 /* Disable FIFO if unusable */
1356 if (inb(port
+ 2) < 0x0C0) {
1361 /* Assert bits in MCR */
1362 outb(FlowOutput
, port
+ 4);
1365 /* Enable interrupts if requested */
1366 if (FlowOutput
& 0x8)
1369 /* Show some life */
1370 if (SerialNotice
!= 0) {
1373 write_serial_str(syslinux_banner
);
1374 write_serial_str(copyright_str
);
1377 } else if (looking_at(p
, "say")) {
1378 printf("%s\n", p
+4);
1379 } else if (looking_at(p
, "path")) {
1380 if (parse_path(skipspace(p
+ 4)))
1381 printf("Failed to parse PATH\n");
1382 } else if (looking_at(p
, "sendcookies")) {
1383 const union syslinux_derivative_info
*sdi
;
1385 p
+= strlen("sendcookies");
1386 sdi
= syslinux_derivative_info();
1388 if (sdi
->c
.filesystem
== SYSLINUX_FS_PXELINUX
) {
1389 SendCookies
= strtoul(skipspace(p
), NULL
, 10);
1390 http_bake_cookies();
1396 static int parse_one_config(const char *filename
)
1398 const char *mode
= "r";
1405 fd
= open(filename
, O_RDONLY
);
1410 if (config_cwd
[0]) {
1411 if (chdir(config_cwd
) < 0)
1412 printf("Failed to chdir to %s\n", config_cwd
);
1413 config_cwd
[0] = '\0';
1416 f
= fdopen(fd
, mode
);
1417 parse_config_file(f
);
1420 * Update ConfigName so that syslinux_config_file() returns
1421 * the filename we just opened. filesystem-specific
1422 * open_config() implementations are expected to update
1423 * ConfigName themselves.
1426 strcpy(ConfigName
, filename
);
1431 static void resolve_gotos(void)
1433 struct menu_entry
*me
;
1436 for (me
= all_entries
; me
; me
= me
->next
) {
1437 if (me
->action
== MA_GOTO_UNRES
|| me
->action
== MA_EXIT_UNRES
) {
1438 m
= find_menu(me
->cmdline
);
1439 refstr_put(me
->cmdline
);
1443 me
->action
--; /* Drop the _UNRES */
1445 me
->action
= MA_DISABLED
;
1451 void parse_configs(char **argv
)
1453 const char *filename
;
1455 struct menu_entry
*me
;
1458 empty_string
= refstrdup("");
1460 /* feng: reset current menu_list and entry list */
1464 /* Initialize defaults for the root and hidden menus */
1465 hide_menu
= new_menu(NULL
, NULL
, refstrdup(".hidden"));
1466 root_menu
= new_menu(NULL
, NULL
, refstrdup(".top"));
1467 start_menu
= root_menu
;
1469 /* Other initialization */
1470 memset(&ld
, 0, sizeof(struct labeldata
));
1472 /* Actually process the files */
1473 current_menu
= root_menu
;
1475 if (!argv
|| !*argv
) {
1476 if (parse_one_config(NULL
) < 0) {
1477 printf("WARNING: No configuration file found\n");
1481 while ((filename
= *argv
++)) {
1482 dprintf("Parsing config: %s", filename
);
1483 parse_one_config(filename
);
1487 /* On final EOF process the last label statement */
1488 record(current_menu
, &ld
, append
);
1490 /* Common postprocessing */
1493 /* Handle global default */
1494 //if (has_ui && globaldefault) {
1495 if (globaldefault
) {
1496 dprintf("gloabldefault = %s", globaldefault
);
1497 me
= find_label(globaldefault
);
1498 if (me
&& me
->menu
!= hide_menu
) {
1499 me
->menu
->defentry
= me
->entry
;
1500 start_menu
= me
->menu
;
1501 default_menu
= me
->menu
;
1505 /* If "menu save" is active, let the ADV override the global default */
1508 const char *lbl
= syslinux_getadv(ADV_MENUSAVE
, &len
);
1511 lstr
= refstr_alloc(len
);
1512 memcpy(lstr
, lbl
, len
); /* refstr_alloc() adds the final null */
1513 me
= find_label(lstr
);
1514 if (me
&& me
->menu
!= hide_menu
) {
1515 me
->menu
->defentry
= me
->entry
;
1516 start_menu
= me
->menu
;
1522 /* Final per-menu initialization, with all labels known */
1523 for (m
= menu_list
; m
; m
= m
->next
) {
1524 m
->curentry
= m
->defentry
; /* All menus start at their defaults */
1527 m
->ontimeout
= unlabel(m
->ontimeout
);
1529 m
->onerror
= unlabel(m
->onerror
);