1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2007 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 */
33 long long totaltimeout
= 0;
35 char *ontimeout
= NULL
;
38 char *menu_master_passwd
= NULL
;
39 char *menu_background
= NULL
;
41 struct menu_entry menu_entries
[MAX_ENTRIES
];
42 struct menu_entry hide_entries
[MAX_ENTRIES
];
43 struct menu_entry
*menu_hotkeys
[256];
45 struct messages messages
[MSG_COUNT
] = {
47 { "title", "", NULL
},
49 { "autoboot", "Automatic boot in # seconds", NULL
},
51 { "tabmsg", "Press [Tab] to edit options", NULL
},
53 { "notabmsg", "", NULL
},
55 { "passprompt", "Password required", NULL
},
58 #define astrdup(x) ({ char *__x = (x); \
59 size_t __n = strlen(__x) + 1; \
60 char *__p = alloca(__n); \
61 if ( __p ) memcpy(__p, __x, __n); \
64 /* Must match enum kernel_type */
65 const char *kernel_types
[] = {
80 const char *ipappends
[32];
92 __intcall(0x22, &r
, &r
);
94 nipappends
= min(r
.ecx
.w
[0], 32);
95 ipp
= MK_PTR(r
.es
, r
.ebx
.w
[0]);
96 for ( i
= 0 ; i
< nipappends
; i
++ ) {
97 ipappends
[i
] = MK_PTR(r
.es
, *ipp
++);
100 ipappends
[0] = "ip=foo:bar:baz:quux";
101 ipappends
[1] = "BOOTIF=01-aa-bb-cc-dd-ee-ff";
112 __intcall(0x22, &r
, &r
);
114 return MK_PTR(r
.es
, r
.ebx
.w
[0]);
116 return "syslinux.cfg"; /* Dummy default name */
125 while (*p
&& my_isspace(*p
))
131 /* Check to see if we are at a certain keyword (case insensitive) */
132 /* Returns a pointer to the first character past the keyword */
134 looking_at(char *line
, const char *kwd
)
139 while ( *p
&& *q
&& ((*p
^*q
) & ~0x20) == 0 ) {
145 return NULL
; /* Didn't see the keyword */
147 return my_isspace(*p
) ? p
: NULL
; /* Must be EOL or whitespace */
153 enum kernel_type type
;
158 unsigned int ipappend
;
159 unsigned int menuhide
;
160 unsigned int menudefault
;
164 record(struct labeldata
*ld
, char *append
)
166 char ipoptions
[256], *ipp
;
168 struct menu_entry
*me
= &menu_entries
[nentries
];
172 me
->displayname
= ld
->menulabel
? ld
->menulabel
: ld
->label
;
173 me
->label
= ld
->label
;
174 me
->passwd
= ld
->passwd
;
175 me
->helptext
= ld
->helptext
;
178 if ( ld
->menulabel
) {
179 unsigned char *p
= (unsigned char *)strchr(ld
->menulabel
, '^');
181 int hotkey
= p
[1] & ~0x20;
182 if ( !menu_hotkeys
[hotkey
] ) {
190 for ( i
= 0 ; i
< 32 ; i
++ ) {
191 if ( (ld
->ipappend
& (1U << i
)) && ipappends
[i
] )
192 ipp
+= sprintf(ipp
, " %s", ipappends
[i
]);
196 if ( !a
) a
= append
;
197 if ( !a
|| (a
[0] == '-' && !a
[1]) ) a
= "";
199 if (ld
->type
== KT_KERNEL
) {
200 asprintf(&me
->cmdline
, "%s%s%s%s",
201 ld
->kernel
, s
, a
, ipoptions
);
203 asprintf(&me
->cmdline
, ".%s %s%s%s%s",
204 kernel_types
[ld
->type
], ld
->kernel
, s
, a
, ipoptions
);
218 if ( !ld
->menuhide
) {
220 menu_hotkeys
[me
->hotkey
] = me
;
222 if ( ld
->menudefault
)
228 hide_entries
[nhidden
].displayname
= me
->displayname
;
229 hide_entries
[nhidden
].label
= me
->label
;
230 hide_entries
[nhidden
].cmdline
= me
->cmdline
;
231 hide_entries
[nhidden
].passwd
= me
->passwd
;
233 me
->displayname
= NULL
;
246 /* Convert a CLI-style command line to an executable command line */
249 struct menu_entry
*me
;
253 while ( *p
&& !my_isspace(*p
) )
256 /* p now points to the first byte beyond the kernel name */
259 for ( i
= 0 ; i
< nentries
; i
++ ) {
260 me
= &menu_entries
[i
];
262 if ( !strncmp(str
, me
->label
, pos
) && !me
->label
[pos
] ) {
263 /* Found matching label */
264 q
= malloc(strlen(me
->cmdline
) + strlen(p
) + 1);
265 strcpy(q
, me
->cmdline
);
274 for ( i
= 0 ; i
< nhidden
; i
++ ) {
275 me
= &hide_entries
[i
];
277 if ( !strncmp(str
, me
->label
, pos
) && !me
->label
[pos
] ) {
278 /* Found matching label */
279 q
= malloc(strlen(me
->cmdline
) + strlen(p
) + 1);
280 strcpy(q
, me
->cmdline
);
300 while (*ep
&& !my_isspace(*ep
))
313 static int my_isxdigit(char c
)
317 return (uc
-'0') < 10 ||
321 static unsigned int hexval(char c
)
323 unsigned char uc
= c
| 0x20;
333 static unsigned int hexval2(const char *p
)
335 return (hexval(p
[0]) << 4)+hexval(p
[1]);
338 static uint32_t parse_argb(char **p
)
350 while (my_isxdigit(*ep
))
360 (hexval(sp
[0])*0x11 << 16) +
361 (hexval(sp
[1])*0x11 << 8) +
362 (hexval(sp
[2])*0x11);
366 (hexval(sp
[0])*0x11 << 24) +
367 (hexval(sp
[1])*0x11 << 16) +
368 (hexval(sp
[2])*0x11 << 8) +
369 (hexval(sp
[3])*0x11);
371 case 6: /* #rrggbb */
372 case 9: /* #rrrgggbbb */
373 case 12: /* #rrrrggggbbbb */
377 (hexval2(sp
+0) << 16) +
378 (hexval2(sp
+dl
) << 8) +
381 case 8: /* #aarrggbb */
382 /* 12 is indistinguishable from #rrrrggggbbbb,
383 assume that is a more common format */
384 case 16: /* #aaaarrrrggggbbbb */
387 (hexval2(sp
+0) << 24) +
388 (hexval2(sp
+dl
) << 16) +
389 (hexval2(sp
+dl
*2) << 8) +
393 argb
= 0xffff0000; /* Bright red (error indication) */
401 * Parser state. This is global so that including multiple
402 * files work as expected, which is that everything works the
403 * same way as if the files had been concatenated together.
405 static char *append
= NULL
;
406 static unsigned int ipappend
= 0;
407 static struct labeldata ld
;
409 static int parse_one_config(const char *filename
);
411 static char *is_kernel_type(char *cmdstr
, enum kernel_type
*type
)
415 enum kernel_type t
= KT_NONE
;
417 for (p
= kernel_types
; *p
; p
++, t
++) {
418 if ((q
= looking_at(cmdstr
, *p
))) {
427 static char *is_message_name(char *cmdstr
, struct messages
**msgptr
)
432 for (i
= 0; i
< MSG_COUNT
; i
++) {
433 if ((q
= looking_at(cmdstr
, messages
[i
].name
))) {
434 *msgptr
= &messages
[i
];
442 static void parse_config_file(FILE *f
)
444 char line
[MAX_LINE
], *p
, *ep
, ch
;
445 enum kernel_type type
;
446 struct messages
*msgptr
;
448 while ( fgets(line
, sizeof line
, f
) ) {
449 p
= strchr(line
, '\r');
452 p
= strchr(line
, '\n');
458 if ( looking_at(p
, "menu") ) {
461 if ( looking_at(p
, "label") ) {
463 ld
.menulabel
= strdup(skipspace(p
+5));
464 } else if ( looking_at(p
, "default") ) {
466 } else if ( looking_at(p
, "hide") ) {
468 } else if ( looking_at(p
, "passwd") ) {
469 ld
.passwd
= strdup(skipspace(p
+6));
470 } else if ( looking_at(p
, "shiftkey") ) {
472 } else if ( looking_at(p
, "onerror") ) {
473 onerror
= strdup(skipspace(p
+7));
474 } else if ( looking_at(p
, "master") ) {
476 if ( looking_at(p
, "passwd") ) {
477 menu_master_passwd
= strdup(skipspace(p
+6));
479 } else if ( (ep
= looking_at(p
, "include")) ) {
482 } else if ( (ep
= looking_at(p
, "background")) ) {
485 free(menu_background
);
486 menu_background
= dup_word(&p
);
487 } else if ( (ep
= is_message_name(p
, &msgptr
)) ) {
489 msgptr
->msg
= strdup(skipspace(ep
));
490 } else if ((ep
= looking_at(p
, "color")) ||
491 (ep
= looking_at(p
, "colour"))) {
493 struct color_table
*cptr
;
495 cptr
= console_color_table
;
496 for ( i
= 0; i
< console_color_table_size
; i
++ ) {
497 if ( (ep
= looking_at(p
, cptr
->name
)) ) {
500 if (looking_at(p
, "*")) {
503 free((void *)cptr
->ansi
);
504 cptr
->ansi
= dup_word(&p
);
509 if (looking_at(p
, "*"))
512 cptr
->argb_fg
= parse_argb(&p
);
516 if (looking_at(p
, "*"))
519 cptr
->argb_bg
= parse_argb(&p
);
521 /* Parse a shadow mode */
524 if (ch
== 'n') /* none */
525 cptr
->shadow
= SHADOW_NONE
;
526 else if (ch
== 's') /* std, standard */
527 cptr
->shadow
= SHADOW_NORMAL
;
528 else if (ch
== 'a') /* all */
529 cptr
->shadow
= SHADOW_ALL
;
530 else if (ch
== 'r') /* rev, reverse */
531 cptr
->shadow
= SHADOW_REVERSE
;
540 /* Unknown, check for layout parameters */
541 struct menu_parameter
*pp
;
542 for ( pp
= mparm
; pp
->name
; pp
++ ) {
543 if ( (ep
= looking_at(p
, pp
->name
)) ) {
544 pp
->value
= atoi(skipspace(ep
));
549 } else if ( looking_at(p
, "text") ) {
553 } cmd
= TEXT_UNKNOWN
;
554 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
559 if (looking_at(p
, "help"))
562 while ( fgets(line
, sizeof line
, f
) ) {
564 if (looking_at(p
, "endtext"))
573 ld
.helptext
= realloc(ld
.helptext
, len
+xlen
+1);
574 memcpy(ld
.helptext
+len
, line
, xlen
+1);
579 } else if ( looking_at(p
, "append") ) {
580 char *a
= strdup(skipspace(p
+6));
585 } else if ( looking_at(p
, "label") ) {
588 ld
.label
= strdup(p
);
589 ld
.kernel
= strdup(p
);
595 ld
.ipappend
= ipappend
;
596 ld
.menudefault
= ld
.menuhide
= 0;
597 } else if ( (ep
= is_kernel_type(p
, &type
)) ) {
600 ld
.kernel
= strdup(skipspace(ep
));
603 } else if ( looking_at(p
, "timeout") ) {
604 timeout
= (atoi(skipspace(p
+7))*CLK_TCK
+9)/10;
605 } else if ( looking_at(p
, "totaltimeout") ) {
606 totaltimeout
= (atoll(skipspace(p
+13))*CLK_TCK
+9)/10;
607 } else if ( looking_at(p
, "ontimeout") ) {
608 ontimeout
= strdup(skipspace(p
+9));
609 } else if ( looking_at(p
, "allowoptions") ) {
610 allowedit
= atoi(skipspace(p
+12));
611 } else if ( looking_at(p
, "ipappend") ) {
613 ld
.ipappend
= atoi(skipspace(p
+8));
615 ipappend
= atoi(skipspace(p
+8));
620 static int parse_one_config(const char *filename
)
624 if (!strcmp(filename
, "~"))
625 filename
= get_config();
627 f
= fopen(filename
, "r");
631 parse_config_file(f
);
637 void parse_configs(char **argv
)
639 const char *filename
;
642 /* Initialize defaults */
644 for (i
= 0; i
< MSG_COUNT
; i
++) {
646 free(messages
[i
].msg
);
647 messages
[i
].msg
= strdup(messages
[i
].defmsg
);
650 /* Other initialization */
654 /* Actually process the files */
657 parse_one_config("~");
659 while ( (filename
= *argv
++) )
660 parse_one_config(filename
);
663 /* On final EOF process the last label statement */
667 /* Common postprocessing */
670 ontimeout
= unlabel(ontimeout
);
672 onerror
= unlabel(onerror
);