source: bootcd/isolinux/syslinux-6.03/com32/menu/readconfig.c @ dd1be7c

Last change on this file since dd1be7c was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 27.6 KB
Line 
1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
5 *
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.
11 *
12 * ----------------------------------------------------------------------- */
13
14#include <stdio.h>
15#include <stdbool.h>
16#include <stdlib.h>
17#include <string.h>
18#include <ctype.h>
19#include <minmax.h>
20#include <alloca.h>
21#include <inttypes.h>
22#include <colortbl.h>
23#include <com32.h>
24#include <syslinux/adv.h>
25#include <syslinux/config.h>
26
27#include "menu.h"
28
29/* Empty refstring */
30const char *empty_string;
31
32/* Root menu, starting menu, hidden menu, and list of all menus */
33struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
34
35/* These are global parameters regardless of which menu we're displaying */
36int shiftkey = 0;               /* Only display menu if shift key pressed */
37int hiddenmenu = 0;
38int clearmenu = 0;
39long long totaltimeout = 0;
40const char *hide_key[KEY_MAX];
41
42/* Keep track of global default */
43static int has_ui = 0;          /* DEFAULT only counts if UI is found */
44static const char *globaldefault = NULL;
45static bool menusave = false;   /* True if there is any "menu save" */
46
47/* Linked list of all entires, hidden or not; used by unlabel() */
48static struct menu_entry *all_entries;
49static struct menu_entry **all_entries_end = &all_entries;
50
51static const struct messages messages[MSG_COUNT] = {
52    [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
53    [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
54    [MSG_NOTAB] = {"notabmsg", ""},
55    [MSG_PASSPROMPT] = {"passprompt", "Password required"},
56};
57
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); \
62                      __p; })
63
64/* Must match enum kernel_type */
65static const char *const kernel_types[] = {
66    "none",
67    "localboot",
68    "kernel",
69    "linux",
70    "boot",
71    "bss",
72    "pxe",
73    "fdimage",
74    "comboot",
75    "com32",
76    "config",
77    NULL
78};
79
80/*
81 * Search the list of all menus for a specific label
82 */
83static struct menu *find_menu(const char *label)
84{
85    struct menu *m;
86
87    for (m = menu_list; m; m = m->next) {
88        if (!strcmp(label, m->label))
89            return m;
90    }
91
92    return NULL;
93}
94
95#define MAX_LINE 4096
96
97/* Strip ^ from a string, returning a new reference to the same refstring
98   if none present */
99static const char *strip_caret(const char *str)
100{
101    const char *p, *r;
102    char *q;
103    int carets = 0;
104
105    p = str;
106    for (;;) {
107        p = strchr(p, '^');
108        if (!p)
109            break;
110        carets++;
111        p++;
112    }
113
114    if (!carets)
115        return refstr_get(str);
116
117    r = q = refstr_alloc(strlen(str) - carets);
118    for (p = str; *p; p++)
119        if (*p != '^')
120            *q++ = *p;
121
122    *q = '\0';                  /* refstr_alloc() already did this... */
123
124    return r;
125}
126
127/* Check to see if we are at a certain keyword (case insensitive) */
128/* Returns a pointer to the first character past the keyword */
129static char *looking_at(char *line, const char *kwd)
130{
131    char *p = line;
132    const char *q = kwd;
133
134    while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
135        p++;
136        q++;
137    }
138
139    if (*q)
140        return NULL;            /* Didn't see the keyword */
141
142    return my_isspace(*p) ? p : NULL;   /* Must be EOL or whitespace */
143}
144
145/* Get a single word into a new refstr; advances the input pointer */
146static char *get_word(char *str, char **word)
147{
148    char *p = str;
149    char *q;
150
151    while (*p && !my_isspace(*p))
152        p++;
153
154    *word = q = refstr_alloc(p - str);
155    memcpy(q, str, p - str);
156    /* refstr_alloc() already inserted a terminating NUL */
157
158    return p;
159}
160
161static struct menu *new_menu(struct menu *parent,
162                             struct menu_entry *parent_entry, const char *label)
163{
164    struct menu *m = calloc(1, sizeof(struct menu));
165    int i;
166
167    m->label = label;
168    m->title = refstr_get(empty_string);
169
170    if (parent) {
171        /* Submenu */
172        m->parent = parent;
173        m->parent_entry = parent_entry;
174        parent_entry->action = MA_SUBMENU;
175        parent_entry->submenu = m;
176
177        for (i = 0; i < MSG_COUNT; i++)
178            m->messages[i] = refstr_get(parent->messages[i]);
179
180        memcpy(m->mparm, parent->mparm, sizeof m->mparm);
181
182        m->allowedit = parent->allowedit;
183        m->timeout = parent->timeout;
184        m->save = parent->save;
185        m->immediate = parent->immediate;
186
187        m->ontimeout = refstr_get(parent->ontimeout);
188        m->onerror = refstr_get(parent->onerror);
189        m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
190        m->menu_background = refstr_get(parent->menu_background);
191
192        m->color_table = copy_color_table(parent->color_table);
193
194        for (i = 0; i < 12; i++) {
195            m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
196            m->fkeyhelp[i].background =
197                refstr_get(parent->fkeyhelp[i].background);
198        }
199    } else {
200        /* Root menu */
201        for (i = 0; i < MSG_COUNT; i++)
202            m->messages[i] = refstrdup(messages[i].defmsg);
203        for (i = 0; i < NPARAMS; i++)
204            m->mparm[i] = mparm[i].value;
205
206        m->allowedit = true;    /* Allow edits of the command line */
207        m->color_table = default_color_table();
208    }
209
210    m->next = menu_list;
211    menu_list = m;
212
213    return m;
214}
215
216struct labeldata {
217    const char *label;
218    const char *kernel;
219    enum kernel_type type;
220    const char *append;
221    const char *initrd;
222    const char *menulabel;
223    const char *passwd;
224    char *helptext;
225    unsigned int ipappend;
226    unsigned int menuhide;
227    unsigned int menudefault;
228    unsigned int menuseparator;
229    unsigned int menudisabled;
230    unsigned int menuindent;
231    enum menu_action action;
232    int save;
233    int immediate;
234    struct menu *submenu;
235};
236
237/* Menu currently being parsed */
238static struct menu *current_menu;
239
240static void clear_label_data(struct labeldata *ld)
241{
242    refstr_put(ld->label);
243    refstr_put(ld->kernel);
244    refstr_put(ld->append);
245    refstr_put(ld->initrd);
246    refstr_put(ld->menulabel);
247    refstr_put(ld->passwd);
248
249    memset(ld, 0, sizeof *ld);
250}
251
252static struct menu_entry *new_entry(struct menu *m)
253{
254    struct menu_entry *me;
255
256    if (m->nentries >= m->nentries_space) {
257        if (!m->nentries_space)
258            m->nentries_space = 1;
259        else
260            m->nentries_space <<= 1;
261
262        m->menu_entries = realloc(m->menu_entries, m->nentries_space *
263                                  sizeof(struct menu_entry *));
264    }
265
266    me = calloc(1, sizeof(struct menu_entry));
267    me->menu = m;
268    me->entry = m->nentries;
269    m->menu_entries[m->nentries++] = me;
270    *all_entries_end = me;
271    all_entries_end = &me->next;
272
273    return me;
274}
275
276static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
277{
278    const char *p = strchr(me->displayname, '^');
279
280    if (me->action != MA_DISABLED) {
281        if (p && p[1]) {
282            unsigned char hotkey = p[1] & ~0x20;
283            if (!m->menu_hotkeys[hotkey]) {
284                me->hotkey = hotkey;
285                m->menu_hotkeys[hotkey] = me;
286            }
287        }
288    }
289}
290
291/*
292 * Copy a string, converting whitespace characters to underscores
293 * and compacting them.  Return a pointer to the final null.
294 */
295static char *copy_sysappend_string(char *dst, const char *src)
296{
297    bool was_space = true;      /* Kill leading whitespace */
298    char *end = dst;
299    char c;
300
301    while ((c = *src++)) {
302        if (c <= ' ' && c == '\x7f') {
303            if (!was_space)
304                *dst++ = '_';
305            was_space = true;
306        } else {
307            *dst++ = c;
308            end = dst;
309            was_space = false;
310        }
311    }
312    *end = '\0';
313    return end;
314}
315
316static void record(struct menu *m, struct labeldata *ld, const char *append)
317{
318    int i;
319    struct menu_entry *me;
320    const struct syslinux_ipappend_strings *ipappend;
321
322    if (!ld->label)
323        return;                 /* Nothing defined */
324
325    /* Hidden entries are recorded on a special "hidden menu" */
326    if (ld->menuhide)
327        m = hide_menu;
328
329    if (ld->label) {
330        char ipoptions[4096], *ipp;
331        const char *a;
332        char *s;
333
334        me = new_entry(m);
335
336        me->displayname = ld->menulabel
337            ? refstr_get(ld->menulabel) : refstr_get(ld->label);
338        me->label = refstr_get(ld->label);
339        me->passwd = refstr_get(ld->passwd);
340        me->helptext = ld->helptext;
341        me->hotkey = 0;
342        me->action = ld->action ? ld->action : MA_CMD;
343        me->save = ld->save ? (ld->save > 0) : m->save;
344        me->immediate = ld->immediate ? (ld->immediate > 0) : m->immediate;
345
346        if (ld->menuindent) {
347            const char *dn;
348
349            rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
350            refstr_put(me->displayname);
351            me->displayname = dn;
352        }
353
354        if (ld->menuseparator) {
355            refstr_put(me->displayname);
356            me->displayname = refstr_get(empty_string);
357        }
358
359        if (ld->menuseparator || ld->menudisabled) {
360            me->action = MA_DISABLED;
361            refstr_put(me->label);
362            me->label = NULL;
363            refstr_put(me->passwd);
364            me->passwd = NULL;
365        }
366
367        if (ld->menulabel)
368            consider_for_hotkey(m, me);
369
370        switch (me->action) {
371        case MA_CMD:
372            ipp = ipoptions;
373            *ipp = '\0';
374
375            if (ld->initrd)
376                ipp += sprintf(ipp, " initrd=%s", ld->initrd);
377
378            if (ld->ipappend) {
379                ipappend = syslinux_ipappend_strings();
380                for (i = 0; i < ipappend->count; i++) {
381                    if ((ld->ipappend & (1U << i)) &&
382                        ipappend->ptr[i] && ipappend->ptr[i][0]) {
383                        *ipp++ = ' ';
384                        ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
385                    }
386                }
387            }
388
389            a = ld->append;
390            if (!a)
391                a = append;
392            if (!a || (a[0] == '-' && !a[1]))
393                a = "";
394            s = a[0] ? " " : "";
395            if (ld->type == KT_KERNEL) {
396                rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
397            } else {
398                rsprintf(&me->cmdline, ".%s %s%s%s%s",
399                         kernel_types[ld->type], ld->kernel, s, a, ipoptions);
400            }
401            break;
402
403        case MA_GOTO_UNRES:
404        case MA_EXIT_UNRES:
405            me->cmdline = refstr_get(ld->kernel);
406            break;
407
408        case MA_GOTO:
409        case MA_EXIT:
410            me->submenu = ld->submenu;
411            break;
412
413        case MA_HELP:
414            me->cmdline = refstr_get(ld->kernel);
415            me->background = refstr_get(ld->append);
416            break;
417
418        default:
419            break;
420        }
421
422        if (ld->menudefault && (me->action == MA_CMD ||
423                                me->action == MA_GOTO ||
424                                me->action == MA_GOTO_UNRES))
425            m->defentry = m->nentries - 1;
426    }
427
428    clear_label_data(ld);
429}
430
431static struct menu *begin_submenu(const char *tag)
432{
433    struct menu_entry *me;
434
435    if (!tag[0])
436        tag = NULL;
437
438    me = new_entry(current_menu);
439    me->displayname = refstrdup(tag);
440    return new_menu(current_menu, me, refstr_get(me->displayname));
441}
442
443static struct menu *end_submenu(void)
444{
445    return current_menu->parent ? current_menu->parent : current_menu;
446}
447
448static struct menu_entry *find_label(const char *str)
449{
450    const char *p;
451    struct menu_entry *me;
452    int pos;
453
454    p = str;
455    while (*p && !my_isspace(*p))
456        p++;
457
458    /* p now points to the first byte beyond the kernel name */
459    pos = p - str;
460
461    for (me = all_entries; me; me = me->next) {
462        if (!strncmp(str, me->label, pos) && !me->label[pos])
463            return me;
464    }
465
466    return NULL;
467}
468
469static const char *unlabel(const char *str)
470{
471    /* Convert a CLI-style command line to an executable command line */
472    const char *p;
473    const char *q;
474    struct menu_entry *me;
475    int pos;
476
477    p = str;
478    while (*p && !my_isspace(*p))
479        p++;
480
481    /* p now points to the first byte beyond the kernel name */
482    pos = p - str;
483
484    for (me = all_entries; me; me = me->next) {
485        if (!strncmp(str, me->label, pos) && !me->label[pos]) {
486            /* Found matching label */
487            rsprintf(&q, "%s%s", me->cmdline, p);
488            refstr_put(str);
489            return q;
490        }
491    }
492
493    return str;
494}
495
496static const char *refdup_word(char **p)
497{
498    char *sp = *p;
499    char *ep = sp;
500
501    while (*ep && !my_isspace(*ep))
502        ep++;
503
504    *p = ep;
505    return refstrndup(sp, ep - sp);
506}
507
508int my_isxdigit(char c)
509{
510    unsigned int uc = c;
511
512    return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
513}
514
515unsigned int hexval(char c)
516{
517    unsigned char uc = c | 0x20;
518    unsigned int v;
519
520    v = uc - '0';
521    if (v < 10)
522        return v;
523
524    return uc - 'a' + 10;
525}
526
527unsigned int hexval2(const char *p)
528{
529    return (hexval(p[0]) << 4) + hexval(p[1]);
530}
531
532uint32_t parse_argb(char **p)
533{
534    char *sp = *p;
535    char *ep;
536    uint32_t argb;
537    size_t len, dl;
538
539    if (*sp == '#')
540        sp++;
541
542    ep = sp;
543
544    while (my_isxdigit(*ep))
545        ep++;
546
547    *p = ep;
548    len = ep - sp;
549
550    switch (len) {
551    case 3:                     /* #rgb */
552        argb =
553            0xff000000 +
554            (hexval(sp[0]) * 0x11 << 16) +
555            (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
556        break;
557    case 4:                     /* #argb */
558        argb =
559            (hexval(sp[0]) * 0x11 << 24) +
560            (hexval(sp[1]) * 0x11 << 16) +
561            (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
562        break;
563    case 6:                     /* #rrggbb */
564    case 9:                     /* #rrrgggbbb */
565    case 12:                    /* #rrrrggggbbbb */
566        dl = len / 3;
567        argb =
568            0xff000000 +
569            (hexval2(sp + 0) << 16) +
570            (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
571        break;
572    case 8:                     /* #aarrggbb */
573        /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
574           assume the latter is a more common format */
575    case 16:                    /* #aaaarrrrggggbbbb */
576        dl = len / 4;
577        argb =
578            (hexval2(sp + 0) << 24) +
579            (hexval2(sp + dl) << 16) +
580            (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
581        break;
582    default:
583        argb = 0xffff0000;      /* Bright red (error indication) */
584        break;
585    }
586
587    return argb;
588}
589
590/*
591 * Parser state.  This is global so that including multiple
592 * files work as expected, which is that everything works the
593 * same way as if the files had been concatenated together.
594 */
595static const char *append = NULL;
596static unsigned int ipappend = 0;
597static struct labeldata ld;
598
599static int parse_one_config(const char *filename);
600
601static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
602{
603    const char *const *p;
604    char *q;
605    enum kernel_type t = KT_NONE;
606
607    for (p = kernel_types; *p; p++, t++) {
608        if ((q = looking_at(cmdstr, *p))) {
609            *type = t;
610            return q;
611        }
612    }
613
614    return NULL;
615}
616
617static char *is_message_name(char *cmdstr, enum message_number *msgnr)
618{
619    char *q;
620    enum message_number i;
621
622    for (i = 0; i < MSG_COUNT; i++) {
623        if ((q = looking_at(cmdstr, messages[i].name))) {
624            *msgnr = i;
625            return q;
626        }
627    }
628
629    return NULL;
630}
631
632static char *is_fkey(char *cmdstr, int *fkeyno)
633{
634    char *q;
635    int no;
636
637    if ((cmdstr[0] | 0x20) != 'f')
638        return NULL;
639
640    no = strtoul(cmdstr + 1, &q, 10);
641    if (!my_isspace(*q))
642        return NULL;
643
644    if (no < 0 || no > 12)
645        return NULL;
646
647    *fkeyno = (no == 0) ? 10 : no - 1;
648    return q;
649}
650
651static void parse_config_file(FILE * f)
652{
653    char line[MAX_LINE], *p, *ep, ch;
654    enum kernel_type type = -1;
655    enum message_number msgnr = -1;
656    int fkeyno = 0;
657    struct menu *m = current_menu;
658
659    while (fgets(line, sizeof line, f)) {
660        p = strchr(line, '\r');
661        if (p)
662            *p = '\0';
663        p = strchr(line, '\n');
664        if (p)
665            *p = '\0';
666
667        p = skipspace(line);
668
669        if (looking_at(p, "menu")) {
670            p = skipspace(p + 4);
671
672            if (looking_at(p, "label")) {
673                if (ld.label) {
674                    refstr_put(ld.menulabel);
675                    ld.menulabel = refstrdup(skipspace(p + 5));
676                } else if (m->parent_entry) {
677                    refstr_put(m->parent_entry->displayname);
678                    m->parent_entry->displayname = refstrdup(skipspace(p + 5));
679                    consider_for_hotkey(m->parent, m->parent_entry);
680                    if (!m->title[0]) {
681                        /* MENU LABEL -> MENU TITLE on submenu */
682                        refstr_put(m->title);
683                        m->title = strip_caret(m->parent_entry->displayname);
684                    }
685                }
686            } else if (looking_at(p, "title")) {
687                refstr_put(m->title);
688                m->title = refstrdup(skipspace(p + 5));
689                if (m->parent_entry) {
690                    /* MENU TITLE -> MENU LABEL on submenu */
691                    if (m->parent_entry->displayname == m->label) {
692                        refstr_put(m->parent_entry->displayname);
693                        m->parent_entry->displayname = refstr_get(m->title);
694                    }
695                }
696            } else if (looking_at(p, "default")) {
697                if (ld.label) {
698                    ld.menudefault = 1;
699                } else if (m->parent_entry) {
700                    m->parent->defentry = m->parent_entry->entry;
701                }
702            } else if (looking_at(p, "hide")) {
703                ld.menuhide = 1;
704            } else if (looking_at(p, "passwd")) {
705                if (ld.label) {
706                    refstr_put(ld.passwd);
707                    ld.passwd = refstrdup(skipspace(p + 6));
708                } else if (m->parent_entry) {
709                    refstr_put(m->parent_entry->passwd);
710                    m->parent_entry->passwd = refstrdup(skipspace(p + 6));
711                }
712            } else if (looking_at(p, "shiftkey")) {
713                shiftkey = 1;
714            } else if (looking_at(p, "save")) {
715                menusave = true;
716                if (ld.label)
717                    ld.save = 1;
718                else
719                    m->save = true;
720            } else if (looking_at(p, "nosave")) {
721                if (ld.label)
722                    ld.save = -1;
723                else
724                    m->save = false;
725            } else if (looking_at(p, "immediate")) {
726                if (ld.label)
727                    ld.immediate = 1;
728                else
729                    m->immediate = true;
730            } else if (looking_at(p, "noimmediate")) {
731                if (ld.label)
732                    ld.immediate = -1;
733                else
734                    m->immediate = false;
735            } else if (looking_at(p, "onerror")) {
736                refstr_put(m->onerror);
737                m->onerror = refstrdup(skipspace(p + 7));
738            } else if (looking_at(p, "master")) {
739                p = skipspace(p + 6);
740                if (looking_at(p, "passwd")) {
741                    refstr_put(m->menu_master_passwd);
742                    m->menu_master_passwd = refstrdup(skipspace(p + 6));
743                }
744            } else if ((ep = looking_at(p, "include"))) {
745                goto do_include;
746            } else if ((ep = looking_at(p, "background"))) {
747                p = skipspace(ep);
748                refstr_put(m->menu_background);
749                m->menu_background = refdup_word(&p);
750            } else if ((ep = looking_at(p, "hidden"))) {
751                hiddenmenu = 1;
752            } else if (looking_at(p, "hiddenkey")) {
753                char *key_name, *k, *ek;
754                const char *command;
755                int key;
756                p = get_word(skipspace(p + 9), &key_name);
757                command = refstrdup(skipspace(p));
758                k = key_name;
759                for (;;) {
760                    ek = strchr(k+1, ',');
761                    if (ek)
762                        *ek = '\0';
763                    key = key_name_to_code(k);
764                    if (key >= 0) {
765                        refstr_put(hide_key[key]);
766                        hide_key[key] = refstr_get(command);
767                    }
768                    if (!ek)
769                        break;
770                    k = ek+1;
771                }
772                refstr_put(key_name);
773                refstr_put(command);
774            } else if ((ep = looking_at(p, "clear"))) {
775                clearmenu = 1;
776            } else if ((ep = is_message_name(p, &msgnr))) {
777                refstr_put(m->messages[msgnr]);
778                m->messages[msgnr] = refstrdup(skipspace(ep));
779            } else if ((ep = looking_at(p, "color")) ||
780                       (ep = looking_at(p, "colour"))) {
781                int i;
782                struct color_table *cptr;
783                p = skipspace(ep);
784                cptr = m->color_table;
785                for (i = 0; i < menu_color_table_size; i++) {
786                    if ((ep = looking_at(p, cptr->name))) {
787                        p = skipspace(ep);
788                        if (*p) {
789                            if (looking_at(p, "*")) {
790                                p++;
791                            } else {
792                                refstr_put(cptr->ansi);
793                                cptr->ansi = refdup_word(&p);
794                            }
795
796                            p = skipspace(p);
797                            if (*p) {
798                                if (looking_at(p, "*"))
799                                    p++;
800                                else
801                                    cptr->argb_fg = parse_argb(&p);
802
803                                p = skipspace(p);
804                                if (*p) {
805                                    if (looking_at(p, "*"))
806                                        p++;
807                                    else
808                                        cptr->argb_bg = parse_argb(&p);
809
810                                    /* Parse a shadow mode */
811                                    p = skipspace(p);
812                                    ch = *p | 0x20;
813                                    if (ch == 'n')      /* none */
814                                        cptr->shadow = SHADOW_NONE;
815                                    else if (ch == 's') /* std, standard */
816                                        cptr->shadow = SHADOW_NORMAL;
817                                    else if (ch == 'a') /* all */
818                                        cptr->shadow = SHADOW_ALL;
819                                    else if (ch == 'r') /* rev, reverse */
820                                        cptr->shadow = SHADOW_REVERSE;
821                                }
822                            }
823                        }
824                        break;
825                    }
826                    cptr++;
827                }
828            } else if ((ep = looking_at(p, "msgcolor")) ||
829                       (ep = looking_at(p, "msgcolour"))) {
830                unsigned int fg_mask = MSG_COLORS_DEF_FG;
831                unsigned int bg_mask = MSG_COLORS_DEF_BG;
832                enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
833
834                p = skipspace(ep);
835                if (*p) {
836                    if (!looking_at(p, "*"))
837                        fg_mask = parse_argb(&p);
838
839                    p = skipspace(p);
840                    if (*p) {
841                        if (!looking_at(p, "*"))
842                            bg_mask = parse_argb(&p);
843
844                        p = skipspace(p);
845                        switch (*p | 0x20) {
846                        case 'n':
847                            shadow = SHADOW_NONE;
848                            break;
849                        case 's':
850                            shadow = SHADOW_NORMAL;
851                            break;
852                        case 'a':
853                            shadow = SHADOW_ALL;
854                            break;
855                        case 'r':
856                            shadow = SHADOW_REVERSE;
857                            break;
858                        default:
859                            /* go with default */
860                            break;
861                        }
862                    }
863                }
864                set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
865            } else if (looking_at(p, "separator")) {
866                record(m, &ld, append);
867                ld.label = refstr_get(empty_string);
868                ld.menuseparator = 1;
869                record(m, &ld, append);
870            } else if (looking_at(p, "disable") || looking_at(p, "disabled")) {
871                ld.menudisabled = 1;
872            } else if (looking_at(p, "indent")) {
873                ld.menuindent = atoi(skipspace(p + 6));
874            } else if (looking_at(p, "begin")) {
875                record(m, &ld, append);
876                m = current_menu = begin_submenu(skipspace(p + 5));
877            } else if (looking_at(p, "end")) {
878                record(m, &ld, append);
879                m = current_menu = end_submenu();
880            } else if (looking_at(p, "quit")) {
881                if (ld.label)
882                    ld.action = MA_QUIT;
883            } else if (looking_at(p, "goto")) {
884                if (ld.label) {
885                    ld.action = MA_GOTO_UNRES;
886                    refstr_put(ld.kernel);
887                    ld.kernel = refstrdup(skipspace(p + 4));
888                }
889            } else if (looking_at(p, "exit")) {
890                p = skipspace(p + 4);
891                if (ld.label && m->parent) {
892                    if (*p) {
893                        /* This is really just a goto, except for the marker */
894                        ld.action = MA_EXIT_UNRES;
895                        refstr_put(ld.kernel);
896                        ld.kernel = refstrdup(p);
897                    } else {
898                        ld.action = MA_EXIT;
899                        ld.submenu = m->parent;
900                    }
901                }
902            } else if (looking_at(p, "start")) {
903                start_menu = m;
904            } else if (looking_at(p, "help")) {
905                if (ld.label) {
906                    ld.action = MA_HELP;
907                    p = skipspace(p + 4);
908
909                    refstr_put(ld.kernel);
910                    ld.kernel = refdup_word(&p);
911
912                    if (ld.append) {
913                        refstr_put(ld.append);
914                        ld.append = NULL;
915                    }
916
917                    if (*p) {
918                        p = skipspace(p);
919                        ld.append = refdup_word(&p); /* Background */
920                    }
921                }
922            } else if ((ep = looking_at(p, "resolution"))) {
923                int x, y;
924                x = strtoul(ep, &ep, 0);
925                y = strtoul(skipspace(ep), NULL, 0);
926                set_resolution(x, y);
927            } else {
928                /* Unknown, check for layout parameters */
929                enum parameter_number mp;
930                for (mp = 0; mp < NPARAMS; mp++) {
931                    if ((ep = looking_at(p, mparm[mp].name))) {
932                        m->mparm[mp] = atoi(skipspace(ep));
933                        break;
934                    }
935                }
936            }
937        } else if (looking_at(p, "text")) {
938            enum text_cmd {
939                TEXT_UNKNOWN,
940                TEXT_HELP
941            } cmd = TEXT_UNKNOWN;
942            int len = ld.helptext ? strlen(ld.helptext) : 0;
943            int xlen;
944
945            p = skipspace(p + 4);
946
947            if (looking_at(p, "help"))
948                cmd = TEXT_HELP;
949
950            while (fgets(line, sizeof line, f)) {
951                p = skipspace(line);
952                if (looking_at(p, "endtext"))
953                    break;
954
955                xlen = strlen(line);
956
957                switch (cmd) {
958                case TEXT_UNKNOWN:
959                    break;
960                case TEXT_HELP:
961                    ld.helptext = realloc(ld.helptext, len + xlen + 1);
962                    memcpy(ld.helptext + len, line, xlen + 1);
963                    len += xlen;
964                    break;
965                }
966            }
967        } else if ((ep = is_fkey(p, &fkeyno))) {
968            p = skipspace(ep);
969            if (m->fkeyhelp[fkeyno].textname) {
970                refstr_put(m->fkeyhelp[fkeyno].textname);
971                m->fkeyhelp[fkeyno].textname = NULL;
972            }
973            if (m->fkeyhelp[fkeyno].background) {
974                refstr_put(m->fkeyhelp[fkeyno].background);
975                m->fkeyhelp[fkeyno].background = NULL;
976            }
977
978            refstr_put(m->fkeyhelp[fkeyno].textname);
979            m->fkeyhelp[fkeyno].textname = refdup_word(&p);
980            if (*p) {
981                p = skipspace(p);
982                m->fkeyhelp[fkeyno].background = refdup_word(&p);
983            }
984        } else if ((ep = looking_at(p, "include"))) {
985do_include:
986            {
987                const char *file;
988                p = skipspace(ep);
989                file = refdup_word(&p);
990                p = skipspace(p);
991                if (*p) {
992                    record(m, &ld, append);
993                    m = current_menu = begin_submenu(p);
994                    parse_one_config(file);
995                    record(m, &ld, append);
996                    m = current_menu = end_submenu();
997                } else {
998                    parse_one_config(file);
999                }
1000                refstr_put(file);
1001            }
1002        } else if (looking_at(p, "append")) {
1003            const char *a = refstrdup(skipspace(p + 6));
1004            if (ld.label) {
1005                refstr_put(ld.append);
1006                ld.append = a;
1007            } else {
1008                refstr_put(append);
1009                append = a;
1010            }
1011        } else if (looking_at(p, "initrd")) {
1012            const char *a = refstrdup(skipspace(p + 6));
1013            if (ld.label) {
1014                refstr_put(ld.initrd);
1015                ld.initrd = a;
1016            } else {
1017                /* Ignore */
1018            }
1019        } else if (looking_at(p, "label")) {
1020            p = skipspace(p + 5);
1021            record(m, &ld, append);
1022            ld.label = refstrdup(p);
1023            ld.kernel = refstrdup(p);
1024            ld.type = KT_KERNEL;
1025            ld.passwd = NULL;
1026            ld.append = NULL;
1027            ld.initrd = NULL;
1028            ld.menulabel = NULL;
1029            ld.helptext = NULL;
1030            ld.ipappend = ipappend;
1031            ld.menudefault = ld.menuhide = ld.menuseparator =
1032                ld.menudisabled = ld.menuindent = 0;
1033        } else if ((ep = is_kernel_type(p, &type))) {
1034            if (ld.label) {
1035                refstr_put(ld.kernel);
1036                ld.kernel = refstrdup(skipspace(ep));
1037                ld.type = type;
1038            }
1039        } else if (looking_at(p, "timeout")) {
1040            m->timeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
1041        } else if (looking_at(p, "totaltimeout")) {
1042            totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
1043        } else if (looking_at(p, "ontimeout")) {
1044            m->ontimeout = refstrdup(skipspace(p + 9));
1045        } else if (looking_at(p, "allowoptions")) {
1046            m->allowedit = !!atoi(skipspace(p + 12));
1047        } else if ((ep = looking_at(p, "ipappend")) ||
1048                   (ep = looking_at(p, "sysappend"))) {
1049            uint32_t s = strtoul(skipspace(ep), NULL, 0);
1050            if (ld.label)
1051                ld.ipappend = s;
1052            else
1053                ipappend = s;
1054        } else if (looking_at(p, "default")) {
1055            refstr_put(globaldefault);
1056            globaldefault = refstrdup(skipspace(p + 7));
1057        } else if (looking_at(p, "ui")) {
1058            has_ui = 1;
1059        }
1060    }
1061}
1062
1063static int parse_one_config(const char *filename)
1064{
1065    FILE *f;
1066
1067    if (!strcmp(filename, "~"))
1068        filename = syslinux_config_file();
1069
1070    dprintf("Opening config file: %s ", filename);
1071
1072    f = fopen(filename, "r");
1073    dprintf("%s\n", f ? "ok" : "failed");
1074   
1075    if (!f)
1076        return -1;
1077
1078    parse_config_file(f);
1079    fclose(f);
1080
1081    return 0;
1082}
1083
1084static void resolve_gotos(void)
1085{
1086    struct menu_entry *me;
1087    struct menu *m;
1088
1089    for (me = all_entries; me; me = me->next) {
1090        if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) {
1091            m = find_menu(me->cmdline);
1092            refstr_put(me->cmdline);
1093            me->cmdline = NULL;
1094            if (m) {
1095                me->submenu = m;
1096                me->action--;   /* Drop the _UNRES */
1097            } else {
1098                me->action = MA_DISABLED;
1099            }
1100        }
1101    }
1102}
1103
1104void parse_configs(char **argv)
1105{
1106    const char *filename;
1107    struct menu *m;
1108    struct menu_entry *me;
1109    int k;
1110
1111    empty_string = refstrdup("");
1112
1113    /* Initialize defaults for the root and hidden menus */
1114    hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
1115    root_menu = new_menu(NULL, NULL, refstrdup(".top"));
1116    start_menu = root_menu;
1117
1118    /* Other initialization */
1119    memset(&ld, 0, sizeof(struct labeldata));
1120
1121    /* Actually process the files */
1122    current_menu = root_menu;
1123    if (!*argv) {
1124        parse_one_config("~");
1125    } else {
1126        while ((filename = *argv++))
1127            parse_one_config(filename);
1128    }
1129
1130    /* On final EOF process the last label statement */
1131    record(current_menu, &ld, append);
1132
1133    /* Common postprocessing */
1134    resolve_gotos();
1135
1136    /* Handle global default */
1137    if (has_ui && globaldefault) {
1138        me = find_label(globaldefault);
1139        if (me && me->menu != hide_menu) {
1140            me->menu->defentry = me->entry;
1141            start_menu = me->menu;
1142        }
1143    }
1144
1145    /* If "menu save" is active, let the ADV override the global default */
1146    if (menusave) {
1147        size_t len;
1148        const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
1149        char *lstr;
1150        if (lbl && len) {
1151            lstr = refstr_alloc(len);
1152            memcpy(lstr, lbl, len);     /* refstr_alloc() adds the final null */
1153            me = find_label(lstr);
1154            if (me && me->menu != hide_menu) {
1155                me->menu->defentry = me->entry;
1156                start_menu = me->menu;
1157            }
1158            refstr_put(lstr);
1159        }
1160    }
1161
1162    /* Final per-menu initialization, with all labels known */
1163    for (m = menu_list; m; m = m->next) {
1164        m->curentry = m->defentry;      /* All menus start at their defaults */
1165
1166        if (m->ontimeout)
1167            m->ontimeout = unlabel(m->ontimeout);
1168        if (m->onerror)
1169            m->onerror = unlabel(m->onerror);
1170    }
1171
1172    /* Final global initialization, with all labels known */
1173    for (k = 0; k < KEY_MAX; k++) {
1174        if (hide_key[k])
1175            hide_key[k] = unlabel(hide_key[k]);
1176    }
1177}
Note: See TracBrowser for help on using the repository browser.