1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
13 #define _GNU_SOURCE /* Needed for asprintf() on Linux */
30 int allowedit
= 1; /* Allow edits of the command line */
32 int shiftkey
= 0; /* Only display menu if shift key pressed */
34 long long totaltimeout
= 0;
36 char *ontimeout
= NULL
;
39 char *menu_master_passwd
= NULL
;
40 char *menu_background
= NULL
;
42 struct fkey_help fkeyhelp
[12];
44 struct menu_entry menu_entries
[MAX_ENTRIES
];
45 struct menu_entry hide_entries
[MAX_ENTRIES
];
46 struct menu_entry
*menu_hotkeys
[256];
48 struct messages messages
[MSG_COUNT
] = {
50 { "title", "", NULL
},
52 { "autoboot", "Automatic boot in # second{,s}...", NULL
},
54 { "tabmsg", "Press [Tab] to edit options", NULL
},
56 { "notabmsg", "", NULL
},
58 { "passprompt", "Password required", NULL
},
61 #define astrdup(x) ({ char *__x = (x); \
62 size_t __n = strlen(__x) + 1; \
63 char *__p = alloca(__n); \
64 if ( __p ) memcpy(__p, __x, __n); \
67 /* Must match enum kernel_type */
68 const char *kernel_types
[] = {
83 const char *ipappends
[32];
95 __intcall(0x22, &r
, &r
);
97 nipappends
= min(r
.ecx
.w
[0], 32);
98 ipp
= MK_PTR(r
.es
, r
.ebx
.w
[0]);
99 for ( i
= 0 ; i
< nipappends
; i
++ ) {
100 ipappends
[i
] = MK_PTR(r
.es
, *ipp
++);
103 ipappends
[0] = "ip=foo:bar:baz:quux";
104 ipappends
[1] = "BOOTIF=01-aa-bb-cc-dd-ee-ff";
115 __intcall(0x22, &r
, &r
);
117 return MK_PTR(r
.es
, r
.ebx
.w
[0]);
119 return "syslinux.cfg"; /* Dummy default name */
128 while (*p
&& my_isspace(*p
))
134 /* Check to see if we are at a certain keyword (case insensitive) */
135 /* Returns a pointer to the first character past the keyword */
137 looking_at(char *line
, const char *kwd
)
142 while ( *p
&& *q
&& ((*p
^*q
) & ~0x20) == 0 ) {
148 return NULL
; /* Didn't see the keyword */
150 return my_isspace(*p
) ? p
: NULL
; /* Must be EOL or whitespace */
156 enum kernel_type type
;
161 unsigned int ipappend
;
162 unsigned int menuhide
;
163 unsigned int menudefault
;
164 unsigned int menuseparator
;
165 unsigned int menudisabled
;
166 unsigned int menuindent
;
170 record(struct labeldata
*ld
, char *append
)
172 char ipoptions
[256], *ipp
;
174 struct menu_entry
*me
= &menu_entries
[nentries
];
178 me
->displayname
= ld
->menulabel
? ld
->menulabel
: ld
->label
;
179 me
->label
= ld
->label
;
180 me
->passwd
= ld
->passwd
;
181 me
->helptext
= ld
->helptext
;
185 if ( ld
->menuindent
) {
186 char *n
= (char *)malloc(ld
->menuindent
+ strlen(me
->displayname
) + 1);
187 memset(n
, 32, ld
->menuindent
);
188 strcpy(n
+ ld
->menuindent
, me
->displayname
);
192 if ( ld
->menulabel
) {
193 unsigned char *p
= (unsigned char *)strchr(ld
->menulabel
, '^');
195 int hotkey
= p
[1] & ~0x20;
196 if ( !menu_hotkeys
[hotkey
] ) {
204 for ( i
= 0 ; i
< 32 ; i
++ ) {
205 if ( (ld
->ipappend
& (1U << i
)) && ipappends
[i
] )
206 ipp
+= sprintf(ipp
, " %s", ipappends
[i
]);
210 if ( !a
) a
= append
;
211 if ( !a
|| (a
[0] == '-' && !a
[1]) ) a
= "";
213 if (ld
->type
== KT_KERNEL
) {
214 asprintf(&me
->cmdline
, "%s%s%s%s",
215 ld
->kernel
, s
, a
, ipoptions
);
217 asprintf(&me
->cmdline
, ".%s %s%s%s%s",
218 kernel_types
[ld
->type
], ld
->kernel
, s
, a
, ipoptions
);
221 if ( ld
->menuseparator
)
222 me
->displayname
= "";
224 if ( ld
->menuseparator
|| ld
->menudisabled
) {
246 if ( !ld
->menuhide
) {
248 menu_hotkeys
[me
->hotkey
] = me
;
250 if ( ld
->menudefault
&& !ld
->menudisabled
&& !ld
->menuseparator
)
256 hide_entries
[nhidden
].displayname
= me
->displayname
;
257 hide_entries
[nhidden
].label
= me
->label
;
258 hide_entries
[nhidden
].cmdline
= me
->cmdline
;
259 hide_entries
[nhidden
].passwd
= me
->passwd
;
261 me
->displayname
= NULL
;
274 /* Convert a CLI-style command line to an executable command line */
277 struct menu_entry
*me
;
281 while ( *p
&& !my_isspace(*p
) )
284 /* p now points to the first byte beyond the kernel name */
287 for ( i
= 0 ; i
< nentries
; i
++ ) {
288 me
= &menu_entries
[i
];
290 if ( !strncmp(str
, me
->label
, pos
) && !me
->label
[pos
] ) {
291 /* Found matching label */
292 q
= malloc(strlen(me
->cmdline
) + strlen(p
) + 1);
293 strcpy(q
, me
->cmdline
);
302 for ( i
= 0 ; i
< nhidden
; i
++ ) {
303 me
= &hide_entries
[i
];
305 if ( !strncmp(str
, me
->label
, pos
) && !me
->label
[pos
] ) {
306 /* Found matching label */
307 q
= malloc(strlen(me
->cmdline
) + strlen(p
) + 1);
308 strcpy(q
, me
->cmdline
);
328 while (*ep
&& !my_isspace(*ep
))
341 int my_isxdigit(char c
)
345 return (uc
-'0') < 10 ||
349 unsigned int hexval(char c
)
351 unsigned char uc
= c
| 0x20;
361 unsigned int hexval2(const char *p
)
363 return (hexval(p
[0]) << 4)+hexval(p
[1]);
366 uint32_t parse_argb(char **p
)
378 while (my_isxdigit(*ep
))
388 (hexval(sp
[0])*0x11 << 16) +
389 (hexval(sp
[1])*0x11 << 8) +
390 (hexval(sp
[2])*0x11);
394 (hexval(sp
[0])*0x11 << 24) +
395 (hexval(sp
[1])*0x11 << 16) +
396 (hexval(sp
[2])*0x11 << 8) +
397 (hexval(sp
[3])*0x11);
399 case 6: /* #rrggbb */
400 case 9: /* #rrrgggbbb */
401 case 12: /* #rrrrggggbbbb */
405 (hexval2(sp
+0) << 16) +
406 (hexval2(sp
+dl
) << 8) +
409 case 8: /* #aarrggbb */
410 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
411 assume the latter is a more common format */
412 case 16: /* #aaaarrrrggggbbbb */
415 (hexval2(sp
+0) << 24) +
416 (hexval2(sp
+dl
) << 16) +
417 (hexval2(sp
+dl
*2) << 8) +
421 argb
= 0xffff0000; /* Bright red (error indication) */
429 * Parser state. This is global so that including multiple
430 * files work as expected, which is that everything works the
431 * same way as if the files had been concatenated together.
433 static char *append
= NULL
;
434 static unsigned int ipappend
= 0;
435 static struct labeldata ld
;
437 static int parse_one_config(const char *filename
);
439 static char *is_kernel_type(char *cmdstr
, enum kernel_type
*type
)
443 enum kernel_type t
= KT_NONE
;
445 for (p
= kernel_types
; *p
; p
++, t
++) {
446 if ((q
= looking_at(cmdstr
, *p
))) {
455 static char *is_message_name(char *cmdstr
, struct messages
**msgptr
)
460 for (i
= 0; i
< MSG_COUNT
; i
++) {
461 if ((q
= looking_at(cmdstr
, messages
[i
].name
))) {
462 *msgptr
= &messages
[i
];
470 static char *is_fkey(char *cmdstr
, int *fkeyno
)
475 if ((cmdstr
[0]|0x20) != 'f')
478 no
= strtoul(cmdstr
+1, &q
, 10);
482 if (no
< 0 || no
> 12)
485 *fkeyno
= (no
== 0) ? 10 : no
-1;
489 static void parse_config_file(FILE *f
)
491 char line
[MAX_LINE
], *p
, *ep
, ch
;
492 enum kernel_type type
;
493 struct messages
*msgptr
;
496 while ( fgets(line
, sizeof line
, f
) ) {
497 p
= strchr(line
, '\r');
500 p
= strchr(line
, '\n');
506 if ( looking_at(p
, "menu") ) {
509 if ( looking_at(p
, "label") ) {
511 ld
.menulabel
= strdup(skipspace(p
+5));
512 } else if ( looking_at(p
, "default") ) {
514 } else if ( looking_at(p
, "hide") ) {
516 } else if ( looking_at(p
, "passwd") ) {
517 ld
.passwd
= strdup(skipspace(p
+6));
518 } else if ( looking_at(p
, "shiftkey") ) {
520 } else if ( looking_at(p
, "onerror") ) {
521 onerror
= strdup(skipspace(p
+7));
522 } else if ( looking_at(p
, "master") ) {
524 if ( looking_at(p
, "passwd") ) {
525 menu_master_passwd
= strdup(skipspace(p
+6));
527 } else if ( (ep
= looking_at(p
, "include")) ) {
530 } else if ( (ep
= looking_at(p
, "background")) ) {
533 free(menu_background
);
534 menu_background
= dup_word(&p
);
535 } else if ( (ep
= looking_at(p
, "hidden")) ) {
537 } else if ( (ep
= is_message_name(p
, &msgptr
)) ) {
539 msgptr
->msg
= strdup(skipspace(ep
));
540 } else if ((ep
= looking_at(p
, "color")) ||
541 (ep
= looking_at(p
, "colour"))) {
543 struct color_table
*cptr
;
545 cptr
= console_color_table
;
546 for ( i
= 0; i
< console_color_table_size
; i
++ ) {
547 if ( (ep
= looking_at(p
, cptr
->name
)) ) {
550 if (looking_at(p
, "*")) {
553 free((void *)cptr
->ansi
);
554 cptr
->ansi
= dup_word(&p
);
559 if (looking_at(p
, "*"))
562 cptr
->argb_fg
= parse_argb(&p
);
566 if (looking_at(p
, "*"))
569 cptr
->argb_bg
= parse_argb(&p
);
571 /* Parse a shadow mode */
574 if (ch
== 'n') /* none */
575 cptr
->shadow
= SHADOW_NONE
;
576 else if (ch
== 's') /* std, standard */
577 cptr
->shadow
= SHADOW_NORMAL
;
578 else if (ch
== 'a') /* all */
579 cptr
->shadow
= SHADOW_ALL
;
580 else if (ch
== 'r') /* rev, reverse */
581 cptr
->shadow
= SHADOW_REVERSE
;
589 } else if ((ep
= looking_at(p
, "msgcolor")) ||
590 (ep
= looking_at(p
, "msgcolour"))) {
591 unsigned int fg_mask
= MSG_COLORS_DEF_FG
;
592 unsigned int bg_mask
= MSG_COLORS_DEF_BG
;
593 enum color_table_shadow shadow
= MSG_COLORS_DEF_SHADOW
;
597 if (!looking_at(p
, "*"))
598 fg_mask
= parse_argb(&p
);
602 if (!looking_at(p
, "*"))
603 bg_mask
= parse_argb(&p
);
608 shadow
= SHADOW_NONE
;
611 shadow
= SHADOW_NORMAL
;
617 shadow
= SHADOW_REVERSE
;
620 /* go with default */
625 set_msg_colors_global(fg_mask
, bg_mask
, shadow
);
626 } else if ( looking_at(p
, "separator") ) {
628 memset(&ld
, 0, sizeof(struct labeldata
));
630 ld
.menuseparator
= 1;
632 memset(&ld
, 0, sizeof(struct labeldata
));
633 } else if ( looking_at(p
, "disable") ||
634 looking_at(p
, "disabled")) {
636 } else if ( looking_at(p
, "indent") ) {
637 ld
.menuindent
= atoi(skipspace(p
+6));
639 /* Unknown, check for layout parameters */
640 struct menu_parameter
*pp
;
641 for ( pp
= mparm
; pp
->name
; pp
++ ) {
642 if ( (ep
= looking_at(p
, pp
->name
)) ) {
643 pp
->value
= atoi(skipspace(ep
));
648 } else if ( looking_at(p
, "text") ) {
652 } cmd
= TEXT_UNKNOWN
;
653 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
658 if (looking_at(p
, "help"))
661 while ( fgets(line
, sizeof line
, f
) ) {
663 if (looking_at(p
, "endtext"))
672 ld
.helptext
= realloc(ld
.helptext
, len
+xlen
+1);
673 memcpy(ld
.helptext
+len
, line
, xlen
+1);
678 } else if ( (ep
= is_fkey(p
, &fkeyno
)) ) {
680 if (fkeyhelp
[fkeyno
].textname
) {
681 free((void *)fkeyhelp
[fkeyno
].textname
);
682 fkeyhelp
[fkeyno
].textname
= NULL
;
684 if (fkeyhelp
[fkeyno
].background
) {
685 free((void *)fkeyhelp
[fkeyno
].background
);
686 fkeyhelp
[fkeyno
].background
= NULL
;
689 fkeyhelp
[fkeyno
].textname
= dup_word(&p
);
692 fkeyhelp
[fkeyno
].background
= dup_word(&p
);
694 } else if ( (ep
= looking_at(p
, "include")) ) {
697 } else if ( looking_at(p
, "append") ) {
698 char *a
= strdup(skipspace(p
+6));
703 } else if ( looking_at(p
, "label") ) {
706 ld
.label
= strdup(p
);
707 ld
.kernel
= strdup(p
);
713 ld
.ipappend
= ipappend
;
714 ld
.menudefault
= ld
.menuhide
= ld
.menuseparator
=
715 ld
.menudisabled
= ld
.menuindent
= 0;
716 } else if ( (ep
= is_kernel_type(p
, &type
)) ) {
719 ld
.kernel
= strdup(skipspace(ep
));
722 } else if ( looking_at(p
, "timeout") ) {
723 timeout
= (atoi(skipspace(p
+7))*CLK_TCK
+9)/10;
724 } else if ( looking_at(p
, "totaltimeout") ) {
725 totaltimeout
= (atoll(skipspace(p
+13))*CLK_TCK
+9)/10;
726 } else if ( looking_at(p
, "ontimeout") ) {
727 ontimeout
= strdup(skipspace(p
+9));
728 } else if ( looking_at(p
, "allowoptions") ) {
729 allowedit
= atoi(skipspace(p
+12));
730 } else if ( looking_at(p
, "ipappend") ) {
732 ld
.ipappend
= atoi(skipspace(p
+8));
734 ipappend
= atoi(skipspace(p
+8));
739 static int parse_one_config(const char *filename
)
743 if (!strcmp(filename
, "~"))
744 filename
= get_config();
746 f
= fopen(filename
, "r");
750 parse_config_file(f
);
756 void parse_configs(char **argv
)
758 const char *filename
;
761 /* Initialize defaults */
763 for (i
= 0; i
< MSG_COUNT
; i
++) {
765 free(messages
[i
].msg
);
766 messages
[i
].msg
= strdup(messages
[i
].defmsg
);
769 /* Other initialization */
772 memset(&ld
, 0, sizeof(struct labeldata
));
774 /* Actually process the files */
777 parse_one_config("~");
779 while ( (filename
= *argv
++) )
780 parse_one_config(filename
);
783 /* On final EOF process the last label statement */
787 /* Common postprocessing */
790 ontimeout
= unlabel(ontimeout
);
792 onerror
= unlabel(onerror
);