source: bootcd/isolinux/syslinux-6.03/com32/elflink/ldlinux/readconfig.c

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

bootstuff

  • Property mode set to 100644
File size: 35.5 KB
Line 
1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2009-2013 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 <sys/io.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdbool.h>
18#include <stdlib.h>
19#include <string.h>
20#include <minmax.h>
21#include <alloca.h>
22#include <inttypes.h>
23#include <colortbl.h>
24#include <com32.h>
25#include <syslinux/adv.h>
26#include <syslinux/config.h>
27#include <dprintf.h>
28#include <ctype.h>
29#include <bios.h>
30#include <core.h>
31#include <fs.h>
32#include <syslinux/pxe_api.h>
33
34#include "menu.h"
35#include "config.h"
36#include "getkey.h"
37#include "core.h"
38#include "fs.h"
39
40const 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},
55};
56
57/* Must match enum kernel_type */
58static const char *const kernel_types[] = {
59    "none",
60    "localboot",
61    "kernel",
62    "linux",
63    "boot",
64    "bss",
65    "pxe",
66    "fdimage",
67    "comboot",
68    "com32",
69    "config",
70    NULL
71};
72
73short uappendlen = 0;           //bytes in append= command
74short ontimeoutlen = 0;         //bytes in ontimeout command
75short onerrorlen = 0;           //bytes in onerror command
76short forceprompt = 0;          //force prompt
77short noescape = 0;             //no escape
78short nocomplete = 0;           //no label completion on TAB key
79short allowimplicit = 1;        //allow implicit kernels
80short allowoptions = 1;         //user-specified options allowed
81short includelevel = 1;         //nesting level
82short defaultlevel = 0;         //the current level of default
83short vkernel = 0;              //have we seen any "label" statements?
84extern short NoHalt;            //idle.c
85
86const char *onerror = NULL;     //"onerror" command line
87const char *ontimeout = NULL;   //"ontimeout" command line
88
89__export const char *default_cmd = NULL;        //"default" command line
90
91/* Empty refstring */
92const char *empty_string;
93
94/* Root menu, starting menu, hidden menu, and list of all menus */
95struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
96
97/* These are global parameters regardless of which menu we're displaying */
98int shiftkey = 0;               /* Only display menu if shift key pressed */
99int hiddenmenu = 0;
100long long totaltimeout = 0;
101unsigned int kbdtimeout = 0;
102
103/* Keep track of global default */
104static int has_ui = 0;          /* DEFAULT only counts if UI is found */
105extern const char *globaldefault;
106static bool menusave = false;   /* True if there is any "menu save" */
107
108/* Linked list of all entires, hidden or not; used by unlabel() */
109static struct menu_entry *all_entries;
110static struct menu_entry **all_entries_end = &all_entries;
111
112static 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"},
117};
118
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); \
123                      __p; })
124
125/*
126 * Search the list of all menus for a specific label
127 */
128static struct menu *find_menu(const char *label)
129{
130    struct menu *m;
131
132    for (m = menu_list; m; m = m->next) {
133        if (!strcmp(label, m->label))
134            return m;
135    }
136
137    return NULL;
138}
139
140#define MAX_LINE 4096
141
142/* Strip ^ from a string, returning a new reference to the same refstring
143   if none present */
144static const char *strip_caret(const char *str)
145{
146    const char *p, *r;
147    char *q;
148    int carets = 0;
149
150    p = str;
151    for (;;) {
152        p = strchr(p, '^');
153        if (!p)
154            break;
155        carets++;
156        p++;
157    }
158
159    if (!carets)
160        return refstr_get(str);
161
162    r = q = refstr_alloc(strlen(str) - carets);
163    for (p = str; *p; p++)
164        if (*p != '^')
165            *q++ = *p;
166
167    *q = '\0';                  /* refstr_alloc() already did this... */
168
169    return r;
170}
171
172/* Check to see if we are at a certain keyword (case insensitive) */
173/* Returns a pointer to the first character past the keyword */
174static char *looking_at(char *line, const char *kwd)
175{
176    char *p = line;
177    const char *q = kwd;
178
179    while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
180        p++;
181        q++;
182    }
183
184    if (*q)
185        return NULL;            /* Didn't see the keyword */
186
187    return my_isspace(*p) ? p : NULL;   /* Must be EOL or whitespace */
188}
189
190static struct menu *new_menu(struct menu *parent,
191                             struct menu_entry *parent_entry, const char *label)
192{
193    struct menu *m = calloc(1, sizeof(struct menu));
194    int i;
195       
196        //dprintf("enter: menu_label = %s", label);
197
198    m->label = label;
199    m->title = refstr_get(empty_string);
200
201    if (parent) {
202        /* Submenu */
203        m->parent = parent;
204        m->parent_entry = parent_entry;
205        parent_entry->action = MA_SUBMENU;
206        parent_entry->submenu = m;
207
208        for (i = 0; i < MSG_COUNT; i++)
209            m->messages[i] = refstr_get(parent->messages[i]);
210
211        memcpy(m->mparm, parent->mparm, sizeof m->mparm);
212
213        m->allowedit = parent->allowedit;
214        m->timeout = parent->timeout;
215        m->save = parent->save;
216
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);
221
222        m->color_table = copy_color_table(parent->color_table);
223
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);
228        }
229    } else {
230        /* Root menu */
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;
235
236        m->allowedit = true;    /* Allow edits of the command line */
237        m->color_table = default_color_table();
238    }
239
240    m->next = menu_list;
241    menu_list = m;
242
243    return m;
244}
245
246struct labeldata {
247    const char *label;
248    const char *kernel;
249    enum kernel_type type;
250    const char *append;
251    const char *initrd;
252    const char *menulabel;
253    const char *passwd;
254    char *helptext;
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;
262    int save;
263    struct menu *submenu;
264};
265
266/* Menu currently being parsed */
267static struct menu *current_menu;
268
269static void clear_label_data(struct labeldata *ld)
270{
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);
277
278    memset(ld, 0, sizeof *ld);
279}
280
281static struct menu_entry *new_entry(struct menu *m)
282{
283    struct menu_entry *me;
284
285    //dprintf("enter, call from menu %s", m->label);
286
287    if (m->nentries >= m->nentries_space) {
288        if (!m->nentries_space)
289            m->nentries_space = 1;
290        else
291            m->nentries_space <<= 1;
292
293        m->menu_entries = realloc(m->menu_entries, m->nentries_space *
294                                  sizeof(struct menu_entry *));
295    }
296
297    me = calloc(1, sizeof(struct menu_entry));
298    me->menu = m;
299    me->entry = m->nentries;
300    m->menu_entries[m->nentries++] = me;
301    *all_entries_end = me;
302    all_entries_end = &me->next;
303
304    return me;
305}
306
307static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
308{
309    const char *p = strchr(me->displayname, '^');
310
311    if (me->action != MA_DISABLED) {
312        if (p && p[1]) {
313            unsigned char hotkey = p[1] & ~0x20;
314            if (!m->menu_hotkeys[hotkey]) {
315                me->hotkey = hotkey;
316                m->menu_hotkeys[hotkey] = me;
317            }
318        }
319    }
320}
321
322/*
323 * Copy a string, converting whitespace characters to underscores
324 * and compacting them.  Return a pointer to the final null.
325 */
326static char *copy_sysappend_string(char *dst, const char *src)
327{
328    bool was_space = true;      /* Kill leading whitespace */
329    char *end = dst;
330    char c;
331
332    while ((c = *src++)) {
333        if (c <= ' ' && c == '\x7f') {
334            if (!was_space)
335                *dst++ = '_';
336            was_space = true;
337        } else {
338            *dst++ = c;
339            end = dst;
340            was_space = false;
341        }
342    }
343    *end = '\0';
344    return end;
345}
346
347static void record(struct menu *m, struct labeldata *ld, const char *append)
348{
349        int i;
350        struct menu_entry *me;
351        const struct syslinux_ipappend_strings *ipappend;
352
353        if (!ld->label)
354                return;                 /* Nothing defined */
355
356        /* Hidden entries are recorded on a special "hidden menu" */
357        if (ld->menuhide)
358                m = hide_menu;
359
360        char ipoptions[4096], *ipp;
361        const char *a;
362        char *s;
363
364        me = new_entry(m);
365
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;
371        me->hotkey = 0;
372        me->action = ld->action ? ld->action : MA_CMD;
373        me->save = ld->save ? (ld->save > 0) : m->save;
374
375        if (ld->menuindent) {
376            const char *dn;
377
378            rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
379            refstr_put(me->displayname);
380            me->displayname = dn;
381        }
382
383        if (ld->menuseparator) {
384            refstr_put(me->displayname);
385            me->displayname = refstr_get(empty_string);
386        }
387
388        if (ld->menuseparator || ld->menudisabled) {
389            me->action = MA_DISABLED;
390            refstr_put(me->label);
391            me->label = NULL;
392            refstr_put(me->passwd);
393            me->passwd = NULL;
394        }
395
396        if (ld->menulabel)
397            consider_for_hotkey(m, me);
398
399        switch (me->action) {
400        case MA_CMD:
401            ipp = ipoptions;
402            *ipp = '\0';
403
404            if (ld->initrd)
405                ipp += sprintf(ipp, " initrd=%s", ld->initrd);
406
407            if (ld->ipappend) {
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]) {
412                        *ipp++ = ' ';
413                        ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
414                    }
415                }
416            }
417
418            a = ld->append;
419            if (!a)
420                a = append;
421            if (!a || (a[0] == '-' && !a[1]))
422                a = "";
423            s = a[0] ? " " : "";
424
425            if (ld->type == KT_KERNEL)
426                rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
427            else
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);
431            break;
432
433        case MA_GOTO_UNRES:
434        case MA_EXIT_UNRES:
435            me->cmdline = refstr_get(ld->kernel);
436            break;
437
438        case MA_GOTO:
439        case MA_EXIT:
440            me->submenu = ld->submenu;
441            break;
442
443        default:
444            break;
445        }
446
447        if (ld->menudefault && me->action == MA_CMD)
448            m->defentry = m->nentries - 1;
449
450    clear_label_data(ld);
451}
452
453static struct menu *begin_submenu(const char *tag)
454{
455    struct menu_entry *me;
456
457    if (!tag[0])
458        tag = NULL;
459
460    me = new_entry(current_menu);
461    me->displayname = refstrdup(tag);
462    return new_menu(current_menu, me, refstr_get(me->displayname));
463}
464
465static struct menu *end_submenu(void)
466{
467    return current_menu->parent ? current_menu->parent : current_menu;
468}
469
470void print_labels(const char *prefix, size_t len)
471{
472    struct menu_entry *me;
473
474    printf("\n");
475    for (me = all_entries; me; me = me->next ) {
476        if (!me->label)
477            continue;
478
479        if (!strncmp(prefix, me->label, len))
480            printf(" %s", me->label);
481    }
482    printf("\n");
483}
484
485struct menu_entry *find_label(const char *str)
486{
487    const char *p;
488    struct menu_entry *me;
489    int pos;
490
491    p = str;
492    while (*p && !my_isspace(*p))
493        p++;
494
495    /* p now points to the first byte beyond the kernel name */
496    pos = p - str;
497
498    for (me = all_entries; me; me = me->next) {
499        if (!strncmp(str, me->label, pos) && !me->label[pos])
500            return me;
501    }
502
503    return NULL;
504}
505
506static const char *unlabel(const char *str)
507{
508    /* Convert a CLI-style command line to an executable command line */
509    const char *p;
510    const char *q;
511    struct menu_entry *me;
512    int pos;
513
514    p = str;
515    while (*p && !my_isspace(*p))
516        p++;
517
518    /* p now points to the first byte beyond the kernel name */
519    pos = p - str;
520
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);
525            refstr_put(str);
526            return q;
527        }
528    }
529
530    return str;
531}
532
533static const char *__refdup_word(char *p, char **ref)
534{
535    char *sp = p;
536    char *ep = sp;
537
538    while (*ep && !my_isspace(*ep))
539        ep++;
540
541    if (ref)
542        *ref = ep;
543    return refstrndup(sp, ep - sp);
544}
545
546static const char *refdup_word(char **p)
547{
548    return __refdup_word(*p, p);
549}
550
551int my_isxdigit(char c)
552{
553    unsigned int uc = c;
554
555    return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
556}
557
558unsigned int hexval(char c)
559{
560    unsigned char uc = c | 0x20;
561    unsigned int v;
562
563    v = uc - '0';
564    if (v < 10)
565        return v;
566
567    return uc - 'a' + 10;
568}
569
570unsigned int hexval2(const char *p)
571{
572    return (hexval(p[0]) << 4) + hexval(p[1]);
573}
574
575uint32_t parse_argb(char **p)
576{
577    char *sp = *p;
578    char *ep;
579    uint32_t argb;
580    size_t len, dl;
581
582    if (*sp == '#')
583        sp++;
584
585    ep = sp;
586
587    while (my_isxdigit(*ep))
588        ep++;
589
590    *p = ep;
591    len = ep - sp;
592
593    switch (len) {
594    case 3:                     /* #rgb */
595        argb =
596            0xff000000 +
597            (hexval(sp[0]) * 0x11 << 16) +
598            (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
599        break;
600    case 4:                     /* #argb */
601        argb =
602            (hexval(sp[0]) * 0x11 << 24) +
603            (hexval(sp[1]) * 0x11 << 16) +
604            (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
605        break;
606    case 6:                     /* #rrggbb */
607    case 9:                     /* #rrrgggbbb */
608    case 12:                    /* #rrrrggggbbbb */
609        dl = len / 3;
610        argb =
611            0xff000000 +
612            (hexval2(sp + 0) << 16) +
613            (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
614        break;
615    case 8:                     /* #aarrggbb */
616        /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
617           assume the latter is a more common format */
618    case 16:                    /* #aaaarrrrggggbbbb */
619        dl = len / 4;
620        argb =
621            (hexval2(sp + 0) << 24) +
622            (hexval2(sp + dl) << 16) +
623            (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
624        break;
625    default:
626        argb = 0xffff0000;      /* Bright red (error indication) */
627        break;
628    }
629
630    return argb;
631}
632
633/*
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.
637 */
638//static const char *append = NULL;
639extern const char *append;
640extern uint16_t PXERetry;
641static struct labeldata ld;
642
643static int parse_main_config(const char *filename);
644
645static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
646{
647    const char *const *p;
648    char *q;
649    enum kernel_type t = KT_NONE;
650
651    for (p = kernel_types; *p; p++, t++) {
652        if ((q = looking_at(cmdstr, *p))) {
653            *type = t;
654            return q;
655        }
656    }
657
658    return NULL;
659}
660
661static char *is_message_name(char *cmdstr, enum message_number *msgnr)
662{
663    char *q;
664    enum message_number i;
665
666    for (i = 0; i < MSG_COUNT; i++) {
667        if ((q = looking_at(cmdstr, messages[i].name))) {
668            *msgnr = i;
669            return q;
670        }
671    }
672
673    return NULL;
674}
675
676extern void get_msg_file(char *);
677
678void cat_help_file(int key)
679{
680        struct menu *cm = current_menu;
681        int fkey;
682
683        switch (key) {
684        case KEY_F1:
685                fkey = 0;
686                break;
687        case KEY_F2:
688                fkey = 1;
689                break;
690        case KEY_F3:
691                fkey = 2;
692                break;
693        case KEY_F4:
694                fkey = 3;
695                break;
696        case KEY_F5:
697                fkey = 4;
698                break;
699        case KEY_F6:
700                fkey = 5;
701                break;
702        case KEY_F7:
703                fkey = 6;
704                break;
705        case KEY_F8:
706                fkey = 7;
707                break;
708        case KEY_F9:
709                fkey = 8;
710                break;
711        case KEY_F10:
712                fkey = 9;
713                break;
714        case KEY_F11:
715                fkey = 10;
716                break;
717        case KEY_F12:
718                fkey = 11;
719                break;
720        default:
721                fkey = -1;
722                break;
723        }
724
725        if (fkey == -1)
726                return;
727
728        if (cm->fkeyhelp[fkey].textname) {
729                printf("\n");
730                get_msg_file((char *)cm->fkeyhelp[fkey].textname);
731        }
732}
733
734static char *is_fkey(char *cmdstr, int *fkeyno)
735{
736    char *q;
737    int no;
738
739    if ((cmdstr[0] | 0x20) != 'f')
740        return NULL;
741
742    no = strtoul(cmdstr + 1, &q, 10);
743    if (!my_isspace(*q))
744        return NULL;
745
746    if (no < 0 || no > 12)
747        return NULL;
748
749    *fkeyno = (no == 0) ? 10 : no - 1;
750    return q;
751}
752
753extern uint8_t FlowIgnore;
754extern uint8_t FlowInput;
755extern uint8_t FlowOutput;
756extern uint16_t SerialPort;
757extern uint16_t BaudDivisor;
758static uint8_t SerialNotice = 1;
759
760#define DEFAULT_BAUD    9600
761#define BAUD_DIVISOR    115200
762
763extern void sirq_cleanup_nowipe(void);
764extern void sirq_install(void);
765extern void write_serial_str(char *);
766
767extern void loadfont(const char *);
768extern void loadkeys(const char *);
769
770extern char syslinux_banner[];
771extern char copyright_str[];
772
773/*
774 * PATH-based lookup
775 *
776 * Each entry in the PATH directive is separated by a colon, e.g.
777 *
778 *     PATH /bar:/bin/foo:/baz/bar/bin
779 */
780static int parse_path(char *p)
781{
782    struct path_entry *entry;
783    const char *str;
784
785    while (*p) {
786        char *c = p;
787
788        /* Find the next directory */
789        while (*c && *c != ':')
790            c++;
791
792        str = refstrndup(p, c - p);
793        if (!str)
794            goto bail;
795
796        entry = path_add(str);
797        refstr_put(str);
798
799        if (!entry)
800            goto bail;
801
802        if (!*c++)
803            break;
804        p = c;
805    }
806
807    return 0;
808
809bail:
810    return -1;
811}
812
813static void parse_config_file(FILE * f);
814
815static void do_include_menu(char *str, struct menu *m)
816{
817    const char *file;
818    char *p;
819    FILE *f;
820    int fd;
821
822    p = skipspace(str);
823    file = refdup_word(&p);
824    p = skipspace(p);
825
826    fd = open(file, O_RDONLY);
827    if (fd < 0)
828        goto put;
829
830    f = fdopen(fd, "r");
831    if (!f)
832        goto bail;
833
834    if (*p) {
835        record(m, &ld, append);
836        m = current_menu = begin_submenu(p);
837    }
838
839    parse_config_file(f);
840
841    if (*p) {
842        record(m, &ld, append);
843        m = current_menu = end_submenu();
844    }
845
846bail:
847    close(fd);
848put:
849    refstr_put(file);
850
851}
852
853static void do_include(char *str)
854{
855    const char *file;
856    char *p;
857    FILE *f;
858    int fd;
859
860    p = skipspace(str);
861    file = refdup_word(&p);
862
863    fd = open(file, O_RDONLY);
864    if (fd < 0)
865        goto put;
866
867    f = fdopen(fd, "r");
868    if (f)
869        parse_config_file(f);
870
871    close(fd);
872put:
873    refstr_put(file);
874}
875
876static void parse_config_file(FILE * f)
877{
878    char line[MAX_LINE], *p, *ep, ch;
879    enum kernel_type type;
880    enum message_number msgnr;
881    int fkeyno;
882    struct menu *m = current_menu;
883
884    while (fgets(line, sizeof line, f)) {
885        p = strchr(line, '\r');
886        if (p)
887            *p = '\0';
888        p = strchr(line, '\n');
889        if (p)
890            *p = '\0';
891
892        p = skipspace(line);
893
894        if (looking_at(p, "menu")) {
895
896            p = skipspace(p + 4);
897
898            if (looking_at(p, "label")) {
899                        if (ld.label) {
900                                refstr_put(ld.menulabel);
901                                ld.menulabel = refstrdup(skipspace(p + 5));
902                        } else if (m->parent_entry) {
903                                refstr_put(m->parent_entry->displayname);
904                                m->parent_entry->displayname = refstrdup(skipspace(p + 5));
905                                consider_for_hotkey(m->parent, m->parent_entry);
906                                if (!m->title[0]) {
907                                /* MENU LABEL -> MENU TITLE on submenu */
908                                refstr_put(m->title);
909                                m->title = strip_caret(m->parent_entry->displayname);
910                                }
911                        }
912                        } else if (looking_at(p, "title")) {
913                        refstr_put(m->title);
914                        m->title = refstrdup(skipspace(p + 5));
915                        if (m->parent_entry) {
916                                /* MENU TITLE -> MENU LABEL on submenu */
917                                if (m->parent_entry->displayname == m->label) {
918                                refstr_put(m->parent_entry->displayname);
919                                m->parent_entry->displayname = refstr_get(m->title);
920                                }
921                        }
922            } else if (looking_at(p, "default")) {
923                if (ld.label) {
924                    ld.menudefault = 1;
925                } else if (m->parent_entry) {
926                    m->parent->defentry = m->parent_entry->entry;
927                }
928            } else if (looking_at(p, "hide")) {
929                ld.menuhide = 1;
930            } else if (looking_at(p, "passwd")) {
931                if (ld.label) {
932                    refstr_put(ld.passwd);
933                    ld.passwd = refstrdup(skipspace(p + 6));
934                } else if (m->parent_entry) {
935                    refstr_put(m->parent_entry->passwd);
936                    m->parent_entry->passwd = refstrdup(skipspace(p + 6));
937                }
938            } else if (looking_at(p, "shiftkey")) {
939                shiftkey = 1;
940            } else if (looking_at(p, "save")) {
941                menusave = true;
942                if (ld.label)
943                    ld.save = 1;
944                else
945                    m->save = true;
946            } else if (looking_at(p, "nosave")) {
947                if (ld.label)
948                    ld.save = -1;
949                else
950                    m->save = false;
951            } else if (looking_at(p, "onerror")) {
952                refstr_put(m->onerror);
953                m->onerror = refstrdup(skipspace(p + 7));
954                onerrorlen = strlen(m->onerror);
955                refstr_put(onerror);
956                onerror = refstrdup(m->onerror);
957            } else if (looking_at(p, "master")) {
958                p = skipspace(p + 6);
959                if (looking_at(p, "passwd")) {
960                    refstr_put(m->menu_master_passwd);
961                    m->menu_master_passwd = refstrdup(skipspace(p + 6));
962                }
963            } else if ((ep = looking_at(p, "include"))) {
964                do_include_menu(ep, m);
965            } else if ((ep = looking_at(p, "background"))) {
966                p = skipspace(ep);
967                refstr_put(m->menu_background);
968                m->menu_background = refdup_word(&p);
969            } else if ((ep = looking_at(p, "hidden"))) {
970                hiddenmenu = 1;
971            } else if ((ep = is_message_name(p, &msgnr))) {
972                refstr_put(m->messages[msgnr]);
973                m->messages[msgnr] = refstrdup(skipspace(ep));
974            } else if ((ep = looking_at(p, "color")) ||
975                       (ep = looking_at(p, "colour"))) {
976                int i;
977                struct color_table *cptr;
978                p = skipspace(ep);
979                cptr = m->color_table;
980                for (i = 0; i < menu_color_table_size; i++) {
981                    if ((ep = looking_at(p, cptr->name))) {
982                        p = skipspace(ep);
983                        if (*p) {
984                            if (looking_at(p, "*")) {
985                                p++;
986                            } else {
987                                refstr_put(cptr->ansi);
988                                cptr->ansi = refdup_word(&p);
989                            }
990
991                            p = skipspace(p);
992                            if (*p) {
993                                if (looking_at(p, "*"))
994                                    p++;
995                                else
996                                    cptr->argb_fg = parse_argb(&p);
997
998                                p = skipspace(p);
999                                if (*p) {
1000                                    if (looking_at(p, "*"))
1001                                        p++;
1002                                    else
1003                                        cptr->argb_bg = parse_argb(&p);
1004
1005                                    /* Parse a shadow mode */
1006                                    p = skipspace(p);
1007                                    ch = *p | 0x20;
1008                                    if (ch == 'n')      /* none */
1009                                        cptr->shadow = SHADOW_NONE;
1010                                    else if (ch == 's') /* std, standard */
1011                                        cptr->shadow = SHADOW_NORMAL;
1012                                    else if (ch == 'a') /* all */
1013                                        cptr->shadow = SHADOW_ALL;
1014                                    else if (ch == 'r') /* rev, reverse */
1015                                        cptr->shadow = SHADOW_REVERSE;
1016                                }
1017                            }
1018                        }
1019                        break;
1020                    }
1021                    cptr++;
1022                }
1023            } else if ((ep = looking_at(p, "msgcolor")) ||
1024                       (ep = looking_at(p, "msgcolour"))) {
1025                unsigned int fg_mask = MSG_COLORS_DEF_FG;
1026                unsigned int bg_mask = MSG_COLORS_DEF_BG;
1027                enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
1028
1029                p = skipspace(ep);
1030                if (*p) {
1031                    if (!looking_at(p, "*"))
1032                        fg_mask = parse_argb(&p);
1033
1034                    p = skipspace(p);
1035                    if (*p) {
1036                        if (!looking_at(p, "*"))
1037                            bg_mask = parse_argb(&p);
1038
1039                        p = skipspace(p);
1040                        switch (*p | 0x20) {
1041                        case 'n':
1042                            shadow = SHADOW_NONE;
1043                            break;
1044                        case 's':
1045                            shadow = SHADOW_NORMAL;
1046                            break;
1047                        case 'a':
1048                            shadow = SHADOW_ALL;
1049                            break;
1050                        case 'r':
1051                            shadow = SHADOW_REVERSE;
1052                            break;
1053                        default:
1054                            /* go with default */
1055                            break;
1056                        }
1057                    }
1058                }
1059                set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
1060            } else if (looking_at(p, "separator")) {
1061                record(m, &ld, append);
1062                ld.label = refstr_get(empty_string);
1063                ld.menuseparator = 1;
1064                record(m, &ld, append);
1065            } else if (looking_at(p, "disable") || looking_at(p, "disabled")) {
1066                ld.menudisabled = 1;
1067            } else if (looking_at(p, "indent")) {
1068                ld.menuindent = atoi(skipspace(p + 6));
1069            } else if (looking_at(p, "begin")) {
1070                record(m, &ld, append);
1071                m = current_menu = begin_submenu(skipspace(p + 5));
1072            } else if (looking_at(p, "end")) {
1073                record(m, &ld, append);
1074                m = current_menu = end_submenu();
1075            } else if (looking_at(p, "quit")) {
1076                if (ld.label)
1077                    ld.action = MA_QUIT;
1078            } else if (looking_at(p, "goto")) {
1079                if (ld.label) {
1080                    ld.action = MA_GOTO_UNRES;
1081                    refstr_put(ld.kernel);
1082                    ld.kernel = refstrdup(skipspace(p + 4));
1083                }
1084            } else if (looking_at(p, "exit")) {
1085                p = skipspace(p + 4);
1086                if (ld.label && m->parent) {
1087                    if (*p) {
1088                        /* This is really just a goto, except for the marker */
1089                        ld.action = MA_EXIT_UNRES;
1090                        refstr_put(ld.kernel);
1091                        ld.kernel = refstrdup(p);
1092                    } else {
1093                        ld.action = MA_EXIT;
1094                        ld.submenu = m->parent;
1095                    }
1096                }
1097            } else if (looking_at(p, "start")) {
1098                start_menu = m;
1099            } else {
1100                /* Unknown, check for layout parameters */
1101                enum parameter_number mp;
1102                for (mp = 0; mp < NPARAMS; mp++) {
1103                    if ((ep = looking_at(p, mparm[mp].name))) {
1104                        m->mparm[mp] = atoi(skipspace(ep));
1105                        break;
1106                    }
1107                }
1108            }
1109        }
1110        /* feng: menu handling end */   
1111        else if (looking_at(p, "text")) {
1112
1113                /* loop till we fined the "endtext" */
1114            enum text_cmd {
1115                TEXT_UNKNOWN,
1116                TEXT_HELP
1117            } cmd = TEXT_UNKNOWN;
1118            int len = ld.helptext ? strlen(ld.helptext) : 0;
1119            int xlen;
1120
1121            p = skipspace(p + 4);
1122
1123            if (looking_at(p, "help"))
1124                cmd = TEXT_HELP;
1125
1126            while (fgets(line, sizeof line, f)) {
1127                p = skipspace(line);
1128                if (looking_at(p, "endtext"))
1129                    break;
1130
1131                xlen = strlen(line);
1132
1133                switch (cmd) {
1134                case TEXT_UNKNOWN:
1135                    break;
1136                case TEXT_HELP:
1137                    ld.helptext = realloc(ld.helptext, len + xlen + 1);
1138                    memcpy(ld.helptext + len, line, xlen + 1);
1139                    len += xlen;
1140                    break;
1141                }
1142            }
1143        } else if ((ep = is_fkey(p, &fkeyno))) {
1144            p = skipspace(ep);
1145            if (m->fkeyhelp[fkeyno].textname) {
1146                refstr_put(m->fkeyhelp[fkeyno].textname);
1147                m->fkeyhelp[fkeyno].textname = NULL;
1148            }
1149            if (m->fkeyhelp[fkeyno].background) {
1150                refstr_put(m->fkeyhelp[fkeyno].background);
1151                m->fkeyhelp[fkeyno].background = NULL;
1152            }
1153
1154            refstr_put(m->fkeyhelp[fkeyno].textname);
1155            m->fkeyhelp[fkeyno].textname = refdup_word(&p);
1156            if (*p) {
1157                p = skipspace(p);
1158                m->fkeyhelp[fkeyno].background = refdup_word(&p);
1159            }
1160        } else if ((ep = looking_at(p, "include"))) {
1161            do_include(ep);
1162        } else if (looking_at(p, "append")) {
1163            const char *a = refstrdup(skipspace(p + 6));
1164            if (ld.label) {
1165                refstr_put(ld.append);
1166                ld.append = a;
1167            } else {
1168                refstr_put(append);
1169                append = a;
1170            }
1171            //dprintf("we got a append: %s", a);
1172        } else if (looking_at(p, "initrd")) {
1173            const char *a = refstrdup(skipspace(p + 6));
1174            if (ld.label) {
1175                refstr_put(ld.initrd);
1176                ld.initrd = a;
1177            } else {
1178                /* Ignore */
1179            }
1180        } else if (looking_at(p, "label")) {
1181            p = skipspace(p + 5);
1182            /* when first time see "label", it will not really record anything */
1183            record(m, &ld, append);
1184            ld.label = __refdup_word(p, NULL);
1185            ld.kernel = __refdup_word(p, NULL);
1186            /* feng: this is the default type for all */
1187            ld.type = KT_KERNEL;
1188            ld.passwd = NULL;
1189            ld.append = NULL;
1190            ld.initrd = NULL;
1191            ld.menulabel = NULL;
1192            ld.helptext = NULL;
1193            ld.ipappend = SysAppends;
1194            ld.menudefault = ld.menuhide = ld.menuseparator =
1195                ld.menudisabled = ld.menuindent = 0;
1196        } else if ((ep = is_kernel_type(p, &type))) {
1197            if (ld.label) {
1198                refstr_put(ld.kernel);
1199                ld.kernel = refstrdup(skipspace(ep));
1200                ld.type = type;
1201                //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
1202            }
1203        } else if (looking_at(p, "timeout")) {
1204            kbdtimeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
1205        } else if (looking_at(p, "totaltimeout")) {
1206            totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
1207        } else if (looking_at(p, "ontimeout")) {
1208            ontimeout = refstrdup(skipspace(p + 9));
1209            ontimeoutlen = strlen(ontimeout);
1210        } else if (looking_at(p, "allowoptions")) {
1211            allowoptions = !!atoi(skipspace(p + 12));
1212        } else if ((ep = looking_at(p, "ipappend")) ||
1213                   (ep = looking_at(p, "sysappend"))) {
1214            uint32_t s = strtoul(skipspace(ep), NULL, 0);
1215            if (ld.label)
1216                ld.ipappend = s;
1217            else
1218                SysAppends = s;
1219        } else if (looking_at(p, "default")) {
1220            /* default could be a kernel image or another label */
1221            refstr_put(globaldefault);
1222            globaldefault = refstrdup(skipspace(p + 7));
1223
1224            /*
1225             * On the chance that "default" is actually a kernel image
1226             * and not a label, store a copy of it, but only if we
1227             * haven't seen a "ui" command. "ui" commands take
1228             * precendence over "default" commands.
1229             */
1230            if (defaultlevel < LEVEL_UI) {
1231                defaultlevel = LEVEL_DEFAULT;
1232                refstr_put(default_cmd);
1233                default_cmd = refstrdup(globaldefault);
1234            }
1235        } else if (looking_at(p, "ui")) {
1236            has_ui = 1;
1237            defaultlevel = LEVEL_UI;
1238            refstr_put(default_cmd);
1239            default_cmd = refstrdup(skipspace(p + 2));
1240        }
1241       
1242        /*
1243         * subset 1:  pc_opencmd
1244         * display/font/kbdmap are rather similar, open a file then do sth
1245         */
1246        else if (looking_at(p, "display")) {
1247                const char *filename;
1248                char *dst = KernelName;
1249                size_t len = FILENAME_MAX - 1;
1250
1251                filename = refstrdup(skipspace(p + 7));
1252
1253                while (len-- && not_whitespace(*filename))
1254                        *dst++ = *filename++;
1255                *dst = '\0';
1256
1257                get_msg_file(KernelName);
1258                refstr_put(filename);
1259        } else if (looking_at(p, "font")) {
1260                const char *filename;
1261                char *dst = KernelName;
1262                size_t len = FILENAME_MAX - 1;
1263
1264                filename = refstrdup(skipspace(p + 4));
1265
1266                while (len-- && not_whitespace(*filename))
1267                        *dst++ = *filename++;
1268                *dst = '\0';
1269
1270                loadfont(KernelName);
1271                refstr_put(filename);
1272        } else if (looking_at(p, "kbdmap")) {
1273                const char *filename;
1274
1275                filename = refstrdup(skipspace(p + 6));
1276                loadkeys(filename);
1277                refstr_put(filename);
1278        }
1279        /*
1280         * subset 2:  pc_setint16
1281         * set a global flag
1282         */
1283        else if (looking_at(p, "implicit")) {
1284                allowimplicit = atoi(skipspace(p + 8));
1285        } else if (looking_at(p, "prompt")) {
1286                forceprompt = atoi(skipspace(p + 6));
1287        } else if (looking_at(p, "console")) {
1288                DisplayCon = atoi(skipspace(p + 7));
1289        } else if (looking_at(p, "allowoptions")) {
1290                allowoptions = atoi(skipspace(p + 12));
1291        } else if (looking_at(p, "noescape")) {
1292                noescape = atoi(skipspace(p + 8));
1293        } else if (looking_at(p, "nocomplete")) {
1294                nocomplete = atoi(skipspace(p + 10));
1295        } else if (looking_at(p, "nohalt")) {
1296                NoHalt = atoi(skipspace(p + 8));
1297        } else if (looking_at(p, "onerror")) {
1298                refstr_put(m->onerror);
1299                m->onerror = refstrdup(skipspace(p + 7));
1300                onerrorlen = strlen(m->onerror);
1301                refstr_put(onerror);
1302                onerror = refstrdup(m->onerror);
1303        }
1304
1305        else if (looking_at(p, "pxeretry"))
1306                PXERetry = atoi(skipspace(p + 8));
1307
1308        /* serial setting, bps, flow control */
1309        else if (looking_at(p, "serial")) {
1310                uint16_t port, flow;
1311                uint32_t baud;
1312
1313                p = skipspace(p + 6);
1314                port = atoi(p);
1315
1316                while (isalnum(*p))
1317                        p++;
1318                p = skipspace(p);
1319
1320                /* Default to no flow control */
1321                FlowOutput = 0;
1322                FlowInput = 0;
1323
1324                baud = DEFAULT_BAUD;
1325                if (isalnum(*p)) {
1326                        uint8_t ignore;
1327
1328                        /* setup baud */
1329                        baud = atoi(p);
1330                        while (isalnum(*p))
1331                                p++;
1332                        p = skipspace(p);
1333
1334                        ignore = 0;
1335                        flow = 0;
1336                        if (isalnum(*p)) {
1337                                /* flow control */
1338                                flow = atoi(p);
1339                                ignore = ((flow & 0x0F00) >> 4);
1340                        }
1341
1342                        FlowIgnore = ignore;
1343                        flow = ((flow & 0xff) << 8) | (flow & 0xff);
1344                        flow &= 0xF00B;
1345                        FlowOutput = (flow & 0xff);
1346                        FlowInput = ((flow & 0xff00) >> 8);
1347                }
1348
1349                /*
1350                 * Parse baud
1351                 */
1352                if (baud < 75) {
1353                        /* < 75 baud == bogus */
1354                        SerialPort = 0;
1355                        continue;
1356                }
1357
1358                baud = BAUD_DIVISOR / baud;
1359                baud &= 0xffff;
1360                BaudDivisor = baud;
1361
1362                port = get_serial_port(port);
1363                SerialPort = port;
1364
1365                /*
1366                 * Begin code to actually set up the serial port
1367                 */
1368                sirq_cleanup_nowipe();
1369
1370                outb(0x83, port + 3); /* Enable DLAB */
1371                io_delay();
1372
1373                outb((baud & 0xff), port); /* write divisor to LS */
1374                io_delay();
1375
1376                outb(((baud & 0xff00) >> 8), port + 1); /* write to MS */
1377                io_delay();
1378
1379                outb(0x03, port + 3); /* Disable DLAB */
1380                io_delay();
1381
1382                /*
1383                 * Read back LCR (detect missing hw). If nothing here
1384                 * we'll read 00 or FF.
1385                 */
1386                if (inb(port + 3) != 0x03) {
1387                        /* Assume serial port busted */
1388                        SerialPort = 0;
1389                        continue;
1390                }
1391
1392                outb(0x01, port + 2); /* Enable FIFOs if present */
1393                io_delay();
1394
1395                /* Disable FIFO if unusable */
1396                if (inb(port + 2) < 0x0C0) {
1397                        outb(0, port + 2);
1398                        io_delay();
1399                }
1400
1401                /* Assert bits in MCR */
1402                outb(FlowOutput, port + 4);
1403                io_delay();
1404
1405                /* Enable interrupts if requested */
1406                if (FlowOutput & 0x8)
1407                        sirq_install();
1408
1409                /* Show some life */
1410                if (SerialNotice != 0) {
1411                        SerialNotice = 0;
1412
1413                        write_serial_str(syslinux_banner);
1414                        write_serial_str(copyright_str);
1415                }
1416
1417        } else if (looking_at(p, "say")) {
1418                printf("%s\n", p+4);
1419        } else if (looking_at(p, "path")) {
1420                if (parse_path(skipspace(p + 4)))
1421                        printf("Failed to parse PATH\n");
1422        } else if (looking_at(p, "sendcookies")) {
1423                const union syslinux_derivative_info *sdi;
1424
1425                p += strlen("sendcookies");
1426                sdi = syslinux_derivative_info();
1427
1428                if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
1429                        SendCookies = strtoul(skipspace(p), NULL, 10);
1430                        http_bake_cookies();
1431                }
1432        }
1433    }
1434}
1435
1436static int parse_main_config(const char *filename)
1437{
1438        const char *mode = "r";
1439        FILE *f;
1440        int fd;
1441
1442        if (!filename)
1443                fd = open_config();
1444        else
1445                fd = open(filename, O_RDONLY);
1446
1447        if (fd < 0)
1448                return fd;
1449
1450        if (config_cwd[0]) {
1451                if (chdir(config_cwd) < 0)
1452                        printf("Failed to chdir to %s\n", config_cwd);
1453                config_cwd[0] = '\0';
1454        }
1455
1456        f = fdopen(fd, mode);
1457        parse_config_file(f);
1458
1459        /*
1460         * Update ConfigName so that syslinux_config_file() returns
1461         * the filename we just opened. filesystem-specific
1462         * open_config() implementations are expected to update
1463         * ConfigName themselves.
1464         */
1465        if (filename)
1466            strcpy(ConfigName, filename);
1467
1468        return 0;
1469}
1470
1471static void resolve_gotos(void)
1472{
1473    struct menu_entry *me;
1474    struct menu *m;
1475
1476    for (me = all_entries; me; me = me->next) {
1477        if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) {
1478            m = find_menu(me->cmdline);
1479            refstr_put(me->cmdline);
1480            me->cmdline = NULL;
1481            if (m) {
1482                me->submenu = m;
1483                me->action--;   /* Drop the _UNRES */
1484            } else {
1485                me->action = MA_DISABLED;
1486            }
1487        }
1488    }
1489}
1490
1491void parse_configs(char **argv)
1492{
1493    const char *filename;
1494    struct menu *m;
1495    struct menu_entry *me;
1496    dprintf("enter");
1497
1498    empty_string = refstrdup("");
1499
1500    /* feng: reset current menu_list and entry list */
1501    menu_list = NULL;
1502    all_entries = NULL;
1503
1504    /* Initialize defaults for the root and hidden menus */
1505    hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
1506    root_menu = new_menu(NULL, NULL, refstrdup(".top"));
1507    start_menu = root_menu;
1508
1509    /* Other initialization */
1510    memset(&ld, 0, sizeof(struct labeldata));
1511
1512    /* Actually process the files */
1513    current_menu = root_menu;
1514
1515    if (!argv || !*argv) {
1516        if (parse_main_config(NULL) < 0) {
1517            printf("WARNING: No configuration file found\n");
1518            return;
1519        }
1520    } else {
1521        while ((filename = *argv++)) {
1522                dprintf("Parsing config: %s", filename);
1523            parse_main_config(filename);
1524        }
1525    }
1526
1527    /* On final EOF process the last label statement */
1528    record(current_menu, &ld, append);
1529
1530    /* Common postprocessing */
1531    resolve_gotos();
1532
1533    /* Handle global default */
1534    //if (has_ui && globaldefault) {
1535    if (globaldefault) {
1536        dprintf("gloabldefault = %s", globaldefault);
1537        me = find_label(globaldefault);
1538        if (me && me->menu != hide_menu) {
1539            me->menu->defentry = me->entry;
1540            start_menu = me->menu;
1541            default_menu = me->menu;
1542        }
1543    }
1544
1545    /* If "menu save" is active, let the ADV override the global default */
1546    if (menusave) {
1547        size_t len;
1548        const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
1549        char *lstr;
1550        if (lbl && len) {
1551            lstr = refstr_alloc(len);
1552            memcpy(lstr, lbl, len);     /* refstr_alloc() adds the final null */
1553            me = find_label(lstr);
1554            if (me && me->menu != hide_menu) {
1555                me->menu->defentry = me->entry;
1556                start_menu = me->menu;
1557            }
1558            refstr_put(lstr);
1559        }
1560    }
1561
1562    /* Final per-menu initialization, with all labels known */
1563    for (m = menu_list; m; m = m->next) {
1564        m->curentry = m->defentry;      /* All menus start at their defaults */
1565
1566        if (m->ontimeout)
1567            m->ontimeout = unlabel(m->ontimeout);
1568        if (m->onerror)
1569            m->onerror = unlabel(m->onerror);
1570    }
1571}
Note: See TracBrowser for help on using the repository browser.