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>
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
) {
476 if (!strncmp(prefix
, me
->label
, len
))
477 printf(" %s", me
->label
);
482 struct menu_entry
*find_label(const char *str
)
485 struct menu_entry
*me
;
489 while (*p
&& !my_isspace(*p
))
492 /* p now points to the first byte beyond the kernel name */
495 for (me
= all_entries
; me
; me
= me
->next
) {
496 if (!strncmp(str
, me
->label
, pos
) && !me
->label
[pos
])
503 static const char *unlabel(const char *str
)
505 /* Convert a CLI-style command line to an executable command line */
508 struct menu_entry
*me
;
512 while (*p
&& !my_isspace(*p
))
515 /* p now points to the first byte beyond the kernel name */
518 for (me
= all_entries
; me
; me
= me
->next
) {
519 if (!strncmp(str
, me
->label
, pos
) && !me
->label
[pos
]) {
520 /* Found matching label */
521 rsprintf(&q
, "%s%s", me
->cmdline
, p
);
530 static const char *__refdup_word(char *p
, char **ref
)
535 while (*ep
&& !my_isspace(*ep
))
540 return refstrndup(sp
, ep
- sp
);
543 static const char *refdup_word(char **p
)
545 return __refdup_word(*p
, p
);
548 int my_isxdigit(char c
)
552 return (uc
- '0') < 10 || ((uc
| 0x20) - 'a') < 6;
555 unsigned int hexval(char c
)
557 unsigned char uc
= c
| 0x20;
564 return uc
- 'a' + 10;
567 unsigned int hexval2(const char *p
)
569 return (hexval(p
[0]) << 4) + hexval(p
[1]);
572 uint32_t parse_argb(char **p
)
584 while (my_isxdigit(*ep
))
594 (hexval(sp
[0]) * 0x11 << 16) +
595 (hexval(sp
[1]) * 0x11 << 8) + (hexval(sp
[2]) * 0x11);
599 (hexval(sp
[0]) * 0x11 << 24) +
600 (hexval(sp
[1]) * 0x11 << 16) +
601 (hexval(sp
[2]) * 0x11 << 8) + (hexval(sp
[3]) * 0x11);
603 case 6: /* #rrggbb */
604 case 9: /* #rrrgggbbb */
605 case 12: /* #rrrrggggbbbb */
609 (hexval2(sp
+ 0) << 16) +
610 (hexval2(sp
+ dl
) << 8) + hexval2(sp
+ dl
* 2);
612 case 8: /* #aarrggbb */
613 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
614 assume the latter is a more common format */
615 case 16: /* #aaaarrrrggggbbbb */
618 (hexval2(sp
+ 0) << 24) +
619 (hexval2(sp
+ dl
) << 16) +
620 (hexval2(sp
+ dl
* 2) << 8) + hexval2(sp
+ dl
* 3);
623 argb
= 0xffff0000; /* Bright red (error indication) */
631 * Parser state. This is global so that including multiple
632 * files work as expected, which is that everything works the
633 * same way as if the files had been concatenated together.
635 //static const char *append = NULL;
636 extern const char *append
;
637 extern uint16_t PXERetry
;
638 static struct labeldata ld
;
640 static int parse_one_config(const char *filename
);
642 static char *is_kernel_type(char *cmdstr
, enum kernel_type
*type
)
644 const char *const *p
;
646 enum kernel_type t
= KT_NONE
;
648 for (p
= kernel_types
; *p
; p
++, t
++) {
649 if ((q
= looking_at(cmdstr
, *p
))) {
658 static char *is_message_name(char *cmdstr
, enum message_number
*msgnr
)
661 enum message_number i
;
663 for (i
= 0; i
< MSG_COUNT
; i
++) {
664 if ((q
= looking_at(cmdstr
, messages
[i
].name
))) {
673 extern void get_msg_file(char *);
675 void cat_help_file(int key
)
677 struct menu
*cm
= current_menu
;
725 if (cm
->fkeyhelp
[fkey
].textname
) {
727 get_msg_file((char *)cm
->fkeyhelp
[fkey
].textname
);
731 static char *is_fkey(char *cmdstr
, int *fkeyno
)
736 if ((cmdstr
[0] | 0x20) != 'f')
739 no
= strtoul(cmdstr
+ 1, &q
, 10);
743 if (no
< 0 || no
> 12)
746 *fkeyno
= (no
== 0) ? 10 : no
- 1;
750 extern uint8_t FlowIgnore
;
751 extern uint8_t FlowInput
;
752 extern uint8_t FlowOutput
;
753 extern uint16_t SerialPort
;
754 extern uint16_t BaudDivisor
;
755 static uint8_t SerialNotice
= 1;
757 #define DEFAULT_BAUD 9600
758 #define BAUD_DIVISOR 115200
759 #define serial_base 0x0400
761 extern void sirq_cleanup_nowipe(void);
762 extern void sirq_install(void);
763 extern void write_serial_str(char *);
765 extern void loadfont(char *);
766 extern void loadkeys(char *);
768 extern char syslinux_banner
[];
769 extern char copyright_str
[];
771 static void parse_config_file(FILE * f
)
773 char line
[MAX_LINE
], *p
, *ep
, ch
;
774 enum kernel_type type
;
775 enum message_number msgnr
;
777 struct menu
*m
= current_menu
;
779 while (fgets(line
, sizeof line
, f
)) {
780 p
= strchr(line
, '\r');
783 p
= strchr(line
, '\n');
789 if (looking_at(p
, "menu")) {
791 p
= skipspace(p
+ 4);
793 if (looking_at(p
, "label")) {
795 refstr_put(ld
.menulabel
);
796 ld
.menulabel
= refstrdup(skipspace(p
+ 5));
797 } else if (m
->parent_entry
) {
798 refstr_put(m
->parent_entry
->displayname
);
799 m
->parent_entry
->displayname
= refstrdup(skipspace(p
+ 5));
800 consider_for_hotkey(m
->parent
, m
->parent_entry
);
802 /* MENU LABEL -> MENU TITLE on submenu */
803 refstr_put(m
->title
);
804 m
->title
= strip_caret(m
->parent_entry
->displayname
);
807 } else if (looking_at(p
, "title")) {
808 refstr_put(m
->title
);
809 m
->title
= refstrdup(skipspace(p
+ 5));
810 if (m
->parent_entry
) {
811 /* MENU TITLE -> MENU LABEL on submenu */
812 if (m
->parent_entry
->displayname
== m
->label
) {
813 refstr_put(m
->parent_entry
->displayname
);
814 m
->parent_entry
->displayname
= refstr_get(m
->title
);
817 } else if (looking_at(p
, "default")) {
820 } else if (m
->parent_entry
) {
821 m
->parent
->defentry
= m
->parent_entry
->entry
;
823 } else if (looking_at(p
, "hide")) {
825 } else if (looking_at(p
, "passwd")) {
827 refstr_put(ld
.passwd
);
828 ld
.passwd
= refstrdup(skipspace(p
+ 6));
829 } else if (m
->parent_entry
) {
830 refstr_put(m
->parent_entry
->passwd
);
831 m
->parent_entry
->passwd
= refstrdup(skipspace(p
+ 6));
833 } else if (looking_at(p
, "shiftkey")) {
835 } else if (looking_at(p
, "save")) {
841 } else if (looking_at(p
, "nosave")) {
846 } else if (looking_at(p
, "onerror")) {
847 refstr_put(m
->onerror
);
848 m
->onerror
= refstrdup(skipspace(p
+ 7));
849 onerrorlen
= strlen(m
->onerror
);
851 onerror
= refstrdup(m
->onerror
);
852 } else if (looking_at(p
, "master")) {
853 p
= skipspace(p
+ 6);
854 if (looking_at(p
, "passwd")) {
855 refstr_put(m
->menu_master_passwd
);
856 m
->menu_master_passwd
= refstrdup(skipspace(p
+ 6));
858 } else if ((ep
= looking_at(p
, "include"))) {
860 } else if ((ep
= looking_at(p
, "background"))) {
862 refstr_put(m
->menu_background
);
863 m
->menu_background
= refdup_word(&p
);
864 } else if ((ep
= looking_at(p
, "hidden"))) {
866 } else if ((ep
= is_message_name(p
, &msgnr
))) {
867 refstr_put(m
->messages
[msgnr
]);
868 m
->messages
[msgnr
] = refstrdup(skipspace(ep
));
869 } else if ((ep
= looking_at(p
, "color")) ||
870 (ep
= looking_at(p
, "colour"))) {
872 struct color_table
*cptr
;
874 cptr
= m
->color_table
;
875 for (i
= 0; i
< menu_color_table_size
; i
++) {
876 if ((ep
= looking_at(p
, cptr
->name
))) {
879 if (looking_at(p
, "*")) {
882 refstr_put(cptr
->ansi
);
883 cptr
->ansi
= refdup_word(&p
);
888 if (looking_at(p
, "*"))
891 cptr
->argb_fg
= parse_argb(&p
);
895 if (looking_at(p
, "*"))
898 cptr
->argb_bg
= parse_argb(&p
);
900 /* Parse a shadow mode */
903 if (ch
== 'n') /* none */
904 cptr
->shadow
= SHADOW_NONE
;
905 else if (ch
== 's') /* std, standard */
906 cptr
->shadow
= SHADOW_NORMAL
;
907 else if (ch
== 'a') /* all */
908 cptr
->shadow
= SHADOW_ALL
;
909 else if (ch
== 'r') /* rev, reverse */
910 cptr
->shadow
= SHADOW_REVERSE
;
918 } else if ((ep
= looking_at(p
, "msgcolor")) ||
919 (ep
= looking_at(p
, "msgcolour"))) {
920 unsigned int fg_mask
= MSG_COLORS_DEF_FG
;
921 unsigned int bg_mask
= MSG_COLORS_DEF_BG
;
922 enum color_table_shadow shadow
= MSG_COLORS_DEF_SHADOW
;
926 if (!looking_at(p
, "*"))
927 fg_mask
= parse_argb(&p
);
931 if (!looking_at(p
, "*"))
932 bg_mask
= parse_argb(&p
);
937 shadow
= SHADOW_NONE
;
940 shadow
= SHADOW_NORMAL
;
946 shadow
= SHADOW_REVERSE
;
949 /* go with default */
954 set_msg_colors_global(m
->color_table
, fg_mask
, bg_mask
, shadow
);
955 } else if (looking_at(p
, "separator")) {
956 record(m
, &ld
, append
);
957 ld
.label
= refstr_get(empty_string
);
958 ld
.menuseparator
= 1;
959 record(m
, &ld
, append
);
960 } else if (looking_at(p
, "disable") || looking_at(p
, "disabled")) {
962 } else if (looking_at(p
, "indent")) {
963 ld
.menuindent
= atoi(skipspace(p
+ 6));
964 } else if (looking_at(p
, "begin")) {
965 record(m
, &ld
, append
);
966 m
= current_menu
= begin_submenu(skipspace(p
+ 5));
967 } else if (looking_at(p
, "end")) {
968 record(m
, &ld
, append
);
969 m
= current_menu
= end_submenu();
970 } else if (looking_at(p
, "quit")) {
973 } else if (looking_at(p
, "goto")) {
975 ld
.action
= MA_GOTO_UNRES
;
976 refstr_put(ld
.kernel
);
977 ld
.kernel
= refstrdup(skipspace(p
+ 4));
979 } else if (looking_at(p
, "exit")) {
980 p
= skipspace(p
+ 4);
981 if (ld
.label
&& m
->parent
) {
983 /* This is really just a goto, except for the marker */
984 ld
.action
= MA_EXIT_UNRES
;
985 refstr_put(ld
.kernel
);
986 ld
.kernel
= refstrdup(p
);
989 ld
.submenu
= m
->parent
;
992 } else if (looking_at(p
, "start")) {
995 /* Unknown, check for layout parameters */
996 enum parameter_number mp
;
997 for (mp
= 0; mp
< NPARAMS
; mp
++) {
998 if ((ep
= looking_at(p
, mparm
[mp
].name
))) {
999 m
->mparm
[mp
] = atoi(skipspace(ep
));
1005 /* feng: menu handling end */
1006 else if (looking_at(p
, "text")) {
1008 /* loop till we fined the "endtext" */
1012 } cmd
= TEXT_UNKNOWN
;
1013 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
1016 p
= skipspace(p
+ 4);
1018 if (looking_at(p
, "help"))
1021 while (fgets(line
, sizeof line
, f
)) {
1022 p
= skipspace(line
);
1023 if (looking_at(p
, "endtext"))
1026 xlen
= strlen(line
);
1032 ld
.helptext
= realloc(ld
.helptext
, len
+ xlen
+ 1);
1033 memcpy(ld
.helptext
+ len
, line
, xlen
+ 1);
1038 } else if ((ep
= is_fkey(p
, &fkeyno
))) {
1040 if (m
->fkeyhelp
[fkeyno
].textname
) {
1041 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1042 m
->fkeyhelp
[fkeyno
].textname
= NULL
;
1044 if (m
->fkeyhelp
[fkeyno
].background
) {
1045 refstr_put(m
->fkeyhelp
[fkeyno
].background
);
1046 m
->fkeyhelp
[fkeyno
].background
= NULL
;
1049 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
1050 m
->fkeyhelp
[fkeyno
].textname
= refdup_word(&p
);
1053 m
->fkeyhelp
[fkeyno
].background
= refdup_word(&p
);
1055 } else if ((ep
= looking_at(p
, "include"))) {
1060 file
= refdup_word(&p
);
1063 record(m
, &ld
, append
);
1064 m
= current_menu
= begin_submenu(p
);
1065 parse_one_config(file
);
1066 record(m
, &ld
, append
);
1067 m
= current_menu
= end_submenu();
1069 parse_one_config(file
);
1073 } else if (looking_at(p
, "append")) {
1074 const char *a
= refstrdup(skipspace(p
+ 6));
1076 refstr_put(ld
.append
);
1082 //dprintf("we got a append: %s", a);
1083 } else if (looking_at(p
, "initrd")) {
1084 const char *a
= refstrdup(skipspace(p
+ 6));
1086 refstr_put(ld
.initrd
);
1091 } else if (looking_at(p
, "label")) {
1092 p
= skipspace(p
+ 5);
1093 /* when first time see "label", it will not really record anything */
1094 record(m
, &ld
, append
);
1095 ld
.label
= __refdup_word(p
, NULL
);
1096 ld
.kernel
= __refdup_word(p
, NULL
);
1097 /* feng: this is the default type for all */
1098 ld
.type
= KT_KERNEL
;
1102 ld
.menulabel
= NULL
;
1104 ld
.ipappend
= SysAppends
;
1105 ld
.menudefault
= ld
.menuhide
= ld
.menuseparator
=
1106 ld
.menudisabled
= ld
.menuindent
= 0;
1107 } else if ((ep
= is_kernel_type(p
, &type
))) {
1109 refstr_put(ld
.kernel
);
1110 ld
.kernel
= refstrdup(skipspace(ep
));
1112 //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
1114 } else if (looking_at(p
, "timeout")) {
1115 kbdtimeout
= (atoi(skipspace(p
+ 7)) * CLK_TCK
+ 9) / 10;
1116 } else if (looking_at(p
, "totaltimeout")) {
1117 totaltimeout
= (atoll(skipspace(p
+ 13)) * CLK_TCK
+ 9) / 10;
1118 } else if (looking_at(p
, "ontimeout")) {
1119 ontimeout
= refstrdup(skipspace(p
+ 9));
1120 ontimeoutlen
= strlen(ontimeout
);
1121 } else if (looking_at(p
, "allowoptions")) {
1122 allowoptions
= !!atoi(skipspace(p
+ 12));
1123 } else if ((ep
= looking_at(p
, "ipappend")) ||
1124 (ep
= looking_at(p
, "sysappend"))) {
1125 uint32_t s
= strtoul(skipspace(ep
), NULL
, 16);
1130 } else if (looking_at(p
, "default")) {
1131 /* default could be a kernel image or another label */
1132 refstr_put(globaldefault
);
1133 globaldefault
= refstrdup(skipspace(p
+ 7));
1136 * On the chance that "default" is actually a kernel image
1137 * and not a label, store a copy of it, but only if we
1138 * haven't seen a "ui" command. "ui" commands take
1139 * precendence over "default" commands.
1141 if (defaultlevel
< LEVEL_UI
) {
1142 defaultlevel
= LEVEL_DEFAULT
;
1143 refstr_put(default_cmd
);
1144 default_cmd
= refstrdup(globaldefault
);
1146 } else if (looking_at(p
, "ui")) {
1148 defaultlevel
= LEVEL_UI
;
1149 refstr_put(default_cmd
);
1150 default_cmd
= refstrdup(skipspace(p
+ 2));
1154 * subset 1: pc_opencmd
1155 * display/font/kbdmap are rather similar, open a file then do sth
1157 else if (looking_at(p
, "display")) {
1158 const char *filename
;
1159 char *dst
= KernelName
;
1160 size_t len
= FILENAME_MAX
- 1;
1162 filename
= refstrdup(skipspace(p
+ 7));
1164 while (len
-- && not_whitespace(*filename
))
1165 *dst
++ = *filename
++;
1168 get_msg_file(KernelName
);
1169 refstr_put(filename
);
1170 } else if (looking_at(p
, "font")) {
1171 const char *filename
;
1172 char *dst
= KernelName
;
1173 size_t len
= FILENAME_MAX
- 1;
1175 filename
= refstrdup(skipspace(p
+ 4));
1177 while (len
-- && not_whitespace(*filename
))
1178 *dst
++ = *filename
++;
1181 loadfont(KernelName
);
1182 refstr_put(filename
);
1183 } else if (looking_at(p
, "kbdmap")) {
1184 const char *filename
;
1185 char *dst
= KernelName
;
1186 size_t len
= FILENAME_MAX
- 1;
1188 filename
= refstrdup(skipspace(p
+ 4));
1190 while (len
-- && not_whitespace(*filename
))
1191 *dst
++ = *filename
++;
1194 loadkeys(KernelName
);
1195 refstr_put(filename
);
1198 * subset 2: pc_setint16
1201 else if (looking_at(p
, "implicit")) {
1202 allowimplicit
= atoi(skipspace(p
+ 8));
1203 } else if (looking_at(p
, "prompt")) {
1204 forceprompt
= atoi(skipspace(p
+ 6));
1205 } else if (looking_at(p
, "console")) {
1206 DisplayCon
= atoi(skipspace(p
+ 7));
1207 } else if (looking_at(p
, "allowoptions")) {
1208 allowoptions
= atoi(skipspace(p
+ 12));
1209 } else if (looking_at(p
, "noescape")) {
1210 noescape
= atoi(skipspace(p
+ 8));
1211 } else if (looking_at(p
, "nocomplete")) {
1212 nocomplete
= atoi(skipspace(p
+ 10));
1213 } else if (looking_at(p
, "nohalt")) {
1214 NoHalt
= atoi(skipspace(p
+ 8));
1215 } else if (looking_at(p
, "onerror")) {
1216 refstr_put(m
->onerror
);
1217 m
->onerror
= refstrdup(skipspace(p
+ 7));
1218 onerrorlen
= strlen(m
->onerror
);
1219 refstr_put(onerror
);
1220 onerror
= refstrdup(m
->onerror
);
1223 else if (looking_at(p
, "pxeretry"))
1224 PXERetry
= atoi(skipspace(p
+ 8));
1226 /* serial setting, bps, flow control */
1227 else if (looking_at(p
, "serial")) {
1228 uint16_t port
, flow
;
1231 p
= skipspace(p
+ 6);
1238 /* Default to no flow control */
1242 baud
= DEFAULT_BAUD
;
1257 ignore
= ((flow
& 0x0F00) >> 4);
1260 FlowIgnore
= ignore
;
1261 flow
= ((flow
& 0xff) << 8) | (flow
& 0xff);
1263 FlowOutput
= (flow
& 0xff);
1264 FlowInput
= ((flow
& 0xff00) >> 8);
1271 /* < 75 baud == bogus */
1276 baud
= BAUD_DIVISOR
/ baud
;
1281 * If port > 3 then port is I/O addr
1284 /* Get the I/O port from the BIOS */
1286 port
= *(volatile uint16_t *)serial_base
;
1293 * Begin code to actually set up the serial port
1295 sirq_cleanup_nowipe();
1297 outb(0x83, port
+ 3); /* Enable DLAB */
1300 outb((baud
& 0xff), port
); /* write divisor to LS */
1303 outb(((baud
& 0xff00) >> 8), port
+ 1); /* write to MS */
1306 outb(0x03, port
+ 3); /* Disable DLAB */
1310 * Read back LCR (detect missing hw). If nothing here
1311 * we'll read 00 or FF.
1313 if (inb(port
+ 3) != 0x03) {
1314 /* Assume serial port busted */
1319 outb(0x01, port
+ 2); /* Enable FIFOs if present */
1322 /* Disable FIFO if unusable */
1323 if (inb(port
+ 2) < 0x0C0) {
1328 /* Assert bits in MCR */
1329 outb(FlowOutput
, port
+ 4);
1332 /* Enable interrupts if requested */
1333 if (FlowOutput
& 0x8)
1336 /* Show some life */
1337 if (SerialNotice
!= 0) {
1340 write_serial_str(syslinux_banner
);
1341 write_serial_str(copyright_str
);
1344 } else if (looking_at(p
, "say")) {
1345 printf("%s\n", p
+4);
1346 } else if (looking_at(p
, "path")) {
1347 /* PATH-based lookup */
1348 const char *new_path
;
1350 size_t len
, new_len
;
1352 new_path
= refstrdup(skipspace(p
+ 4));
1354 new_len
= strlen(new_path
);
1355 _p
= malloc(len
+ new_len
+ 2);
1357 strncpy(_p
, PATH
, len
);
1359 strncpy(_p
+ len
, new_path
, new_len
);
1360 _p
[len
+ new_len
] = '\0';
1364 printf("Failed to realloc PATH\n");
1365 } else if (looking_at(p
, "sendcookies")) {
1366 const union syslinux_derivative_info
*sdi
;
1368 p
+= strlen("sendcookies");
1369 sdi
= syslinux_derivative_info();
1371 if (sdi
->c
.filesystem
== SYSLINUX_FS_PXELINUX
) {
1372 SendCookies
= strtoul(skipspace(p
), NULL
, 10);
1373 http_bake_cookies();
1379 static int parse_one_config(const char *filename
)
1381 const char *mode
= "r";
1388 fd
= open(filename
, O_RDONLY
);
1393 if (config_cwd
[0]) {
1394 if (chdir(config_cwd
) < 0)
1395 printf("Failed to chdir to %s\n", config_cwd
);
1396 config_cwd
[0] = '\0';
1399 f
= fdopen(fd
, mode
);
1400 parse_config_file(f
);
1403 * Update ConfigName so that syslinux_config_file() returns
1404 * the filename we just opened. filesystem-specific
1405 * open_config() implementations are expected to update
1406 * ConfigName themselves.
1409 strcpy(ConfigName
, filename
);
1414 static void resolve_gotos(void)
1416 struct menu_entry
*me
;
1419 for (me
= all_entries
; me
; me
= me
->next
) {
1420 if (me
->action
== MA_GOTO_UNRES
|| me
->action
== MA_EXIT_UNRES
) {
1421 m
= find_menu(me
->cmdline
);
1422 refstr_put(me
->cmdline
);
1426 me
->action
--; /* Drop the _UNRES */
1428 me
->action
= MA_DISABLED
;
1434 void parse_configs(char **argv
)
1436 const char *filename
;
1438 struct menu_entry
*me
;
1441 empty_string
= refstrdup("");
1443 /* feng: reset current menu_list and entry list */
1447 /* Initialize defaults for the root and hidden menus */
1448 hide_menu
= new_menu(NULL
, NULL
, refstrdup(".hidden"));
1449 root_menu
= new_menu(NULL
, NULL
, refstrdup(".top"));
1450 start_menu
= root_menu
;
1452 /* Other initialization */
1453 memset(&ld
, 0, sizeof(struct labeldata
));
1455 /* Actually process the files */
1456 current_menu
= root_menu
;
1458 if (!argv
|| !*argv
) {
1459 if (parse_one_config(NULL
) < 0) {
1460 printf("WARNING: No configuration file found\n");
1464 while ((filename
= *argv
++)) {
1465 dprintf("Parsing config: %s", filename
);
1466 parse_one_config(filename
);
1470 /* On final EOF process the last label statement */
1471 record(current_menu
, &ld
, append
);
1473 /* Common postprocessing */
1476 /* Handle global default */
1477 //if (has_ui && globaldefault) {
1478 if (globaldefault
) {
1479 dprintf("gloabldefault = %s", globaldefault
);
1480 me
= find_label(globaldefault
);
1481 if (me
&& me
->menu
!= hide_menu
) {
1482 me
->menu
->defentry
= me
->entry
;
1483 start_menu
= me
->menu
;
1484 default_menu
= me
->menu
;
1488 /* If "menu save" is active, let the ADV override the global default */
1491 const char *lbl
= syslinux_getadv(ADV_MENUSAVE
, &len
);
1494 lstr
= refstr_alloc(len
);
1495 memcpy(lstr
, lbl
, len
); /* refstr_alloc() adds the final null */
1496 me
= find_label(lstr
);
1497 if (me
&& me
->menu
!= hide_menu
) {
1498 me
->menu
->defentry
= me
->entry
;
1499 start_menu
= me
->menu
;
1505 /* Final per-menu initialization, with all labels known */
1506 for (m
= menu_list
; m
; m
= m
->next
) {
1507 m
->curentry
= m
->defentry
; /* All menus start at their defaults */
1510 m
->ontimeout
= unlabel(m
->ontimeout
);
1512 m
->onerror
= unlabel(m
->onerror
);