config.c
来自「EFI(Extensible Firmware Interface)是下一代BI」· C语言 代码 · 共 1,131 行 · 第 1/2 页
C
1,131 行
/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian <eranian@hpl.hp.com> * * This file is part of the ELILO, the EFI Linux boot loader. * * ELILO is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * ELILO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ELILO; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Please check out the elilo.txt for complete documentation on how * to use this program. * * Portions of this file are derived from the LILO/x86 * Copyright 1992-1997 Werner Almesberger. */#include <efi.h>#include <efilib.h>#include <efistdarg.h>#include "elilo.h"#include "config.h"/* * The first default config file is architecture dependent. This is useful * in case of network booting where the server is used for both types of * architectures. */#if defined(CONFIG_ia64)#define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf"#elif defined (CONFIG_ia32)#define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf"#else#error "You need to specfy your default arch config file"#endif/* * last resort config file. Common to all architectures */#define ELILO_DEFAULT_CONFIG L"elilo.conf"#define MAX_STRING CMDLINE_MAXLEN#define CONFIG_BUFSIZE 512 /* input buffer size *//* * maximum number of message files. * * main message= goes at entry 0, entries [1-12] are used for function keys * */#define MAX_MESSAGES 13typedef struct boot_image { struct boot_image *next; CHAR16 label[MAX_STRING]; CHAR16 kname[FILENAME_MAXLEN]; CHAR16 options[MAX_STRING]; CHAR16 initrd[FILENAME_MAXLEN]; CHAR16 root[FILENAME_MAXLEN]; CHAR16 fallback[MAX_STRING]; CHAR16 description[MAX_STRING]; UINTN ramdisk; UINTN readonly; UINTN literal; sys_img_options_t sys_img_opts; /* architecture specific image options */} boot_image_t;typedef enum { TOK_ERR, TOK_EQUAL, TOK_STR, TOK_EOF} token_t;/* * global shared options * architecture specific global options are private to each architecture */typedef struct { CHAR16 root[FILENAME_MAXLEN]; /* globally defined root fs */ CHAR16 initrd[FILENAME_MAXLEN];/* globally defined initrd */ CHAR16 options[MAX_STRING]; CHAR16 default_image_name[MAX_STRING]; CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN]; CHAR16 chooser[FILENAME_MAXLEN];/* which image chooser to use */ CHAR16 config_file[FILENAME_MAXLEN]; boot_image_t *default_image; UINTN readonly; /* * options that may affect global elilo options */ UINTN alt_check; UINTN debug; UINTN delay; UINTN prompt; UINTN timeout; UINTN verbose; UINTN edd30_no_force; /* don't force EDD30 if not set */} global_config_t;/* * structure used to point to a group of options. * Several group for the same category are supported via a linked list. */typedef struct _config_option_group { struct _config_option_group *next; /* pointer to next group */ config_option_t *options; /* the table of options for this group */ UINTN nentries; /* number of entries for this group */} config_option_group_t;static option_action_t do_image, do_literal, do_options;static INTN check_verbosity(VOID *), check_chooser(VOID *);static global_config_t global_config; /* options shared by all images *//* * Core global options: shared by all architectures, all modules */static config_option_t global_common_options[]={{OPT_STR, OPT_GLOBAL, L"default", NULL, NULL, global_config.default_image_name},{OPT_NUM, OPT_GLOBAL, L"timeout", NULL, NULL, &global_config.timeout},{OPT_NUM, OPT_GLOBAL, L"delay", NULL, NULL, &global_config.delay},{OPT_BOOL, OPT_GLOBAL, L"debug", NULL, NULL, &global_config.debug},{OPT_BOOL, OPT_GLOBAL, L"prompt", NULL, NULL, &global_config.prompt},{OPT_NUM, OPT_GLOBAL, L"verbose", NULL, check_verbosity, &global_config.verbose},{OPT_FILE, OPT_GLOBAL, L"root", NULL, NULL, global_config.root},{OPT_BOOL, OPT_GLOBAL, L"read-only", NULL, NULL, &global_config.readonly},{OPT_BOOL, OPT_GLOBAL, L"noedd30", NULL, NULL, &global_config.edd30_no_force},{OPT_CMD, OPT_GLOBAL, L"append", NULL, NULL, global_config.options},{OPT_FILE, OPT_GLOBAL, L"initrd", NULL, NULL, global_config.initrd},{OPT_FILE, OPT_GLOBAL, L"image", do_image, NULL, opt_offsetof(kname)},{OPT_BOOL, OPT_GLOBAL, L"checkalt", NULL, NULL, &global_config.alt_check},{OPT_STR, OPT_GLOBAL, L"chooser", NULL, check_chooser, global_config.chooser},{OPT_FILE, OPT_GLOBAL, L"message", NULL, NULL, global_config.message_file[0]},{OPT_FILE, OPT_GLOBAL, L"f1", NULL, NULL, global_config.message_file[1]},{OPT_FILE, OPT_GLOBAL, L"f2", NULL, NULL, global_config.message_file[2]},{OPT_FILE, OPT_GLOBAL, L"f3", NULL, NULL, global_config.message_file[3]},{OPT_FILE, OPT_GLOBAL, L"f4", NULL, NULL, global_config.message_file[4]},{OPT_FILE, OPT_GLOBAL, L"f5", NULL, NULL, global_config.message_file[5]},{OPT_FILE, OPT_GLOBAL, L"f6", NULL, NULL, global_config.message_file[6]},{OPT_FILE, OPT_GLOBAL, L"f7", NULL, NULL, global_config.message_file[7]},{OPT_FILE, OPT_GLOBAL, L"f8", NULL, NULL, global_config.message_file[8]},{OPT_FILE, OPT_GLOBAL, L"f9", NULL, NULL, global_config.message_file[9]},{OPT_FILE, OPT_GLOBAL, L"f10", NULL, NULL, global_config.message_file[10]},{OPT_FILE, OPT_GLOBAL, L"f11", NULL, NULL, global_config.message_file[11]},{OPT_FILE, OPT_GLOBAL, L"f12", NULL, NULL, global_config.message_file[12]}};static config_option_t image_common_options[]={ {OPT_FILE, OPT_IMAGE, L"root", NULL, NULL, opt_offsetof(root)}, {OPT_BOOL, OPT_IMAGE, L"read-only", NULL, NULL, opt_offsetof(readonly)}, {OPT_CMD, OPT_IMAGE, L"append", do_options, NULL, opt_offsetof(options)}, {OPT_CMD, OPT_IMAGE, L"literal", do_literal, NULL, NULL}, {OPT_FILE, OPT_IMAGE, L"initrd", NULL, NULL, opt_offsetof(initrd)}, {OPT_STR, OPT_IMAGE, L"label", NULL, NULL, opt_offsetof(label)}, {OPT_FILE, OPT_IMAGE, L"image", do_image, NULL, opt_offsetof(kname)}, {OPT_STR, OPT_IMAGE, L"description", NULL, NULL, opt_offsetof(description)},};#define OPTION_IS_GLOBAL(p) ((p)->scope == OPT_GLOBAL)#define OPTION_IS_IMG_SYS(p) ((p)->scope == OPT_IMAGE_SYS)#define CHAR_EOF (CHAR16)-1 /* Unicode version of EOF */#define CHAR_NUM0 L'0'#define CHAR_NUM9 L'9'static UINTN line_num;static INTN back; /* can go back by one char */static config_option_group_t *global_option_list;static config_option_group_t *image_option_list;static config_option_group_t *current_options;static boot_image_t *image_list, *first_image;static boot_image_t *current_img;static INT8 config_buf[CONFIG_BUFSIZE]; /* input buffer: file must be in ASCII! */static UINTN buf_max, buf_pos;static fops_fd_t config_fd;static VOID config_error(CHAR16 *msg,...){ va_list ap; extern UINTN _IPrint (UINTN, UINTN, SIMPLE_TEXT_OUTPUT_INTERFACE *, CHAR16 *, CHAR8 *, va_list); Print(L"near line %d: ",line_num); va_start(ap,msg); _IPrint((UINTN)-1, (UINTN)-1, systab->ConOut, msg, NULL, ap); va_end(ap); Print(L"\n");}/* * low level read routine * Return: * * Success: * - the next available unicode character * Error: * - CHAR_EOF : indicating error or EOF * * XXX: we suppose that the file is in ASCII format! */static CHAR16getc(VOID){ EFI_STATUS status; if (buf_pos == 0 || buf_pos == buf_max) { buf_max = CONFIG_BUFSIZE; status = fops_read(config_fd, config_buf, &buf_max); if (EFI_ERROR(status) || buf_max == 0) return CHAR_EOF; buf_pos = 0; } return (CHAR16)config_buf[buf_pos++];}/* * get the next unicode character with a one character * rewind buffer. */static CHAR16next(VOID){ CHAR16 ch; if (back) { ch = back; back = 0; return ch; } return getc();}/* * rewind by one character */static VOIDagain(CHAR16 ch){ if (back) { config_error(L"config: again invoked twice"); } back = ch;}/* * Look for matching option in the current group * * Return: * - pointer to option if found * - NULL if not found */static config_option_t *find_option(config_option_group_t *grp, CHAR16 *str){ config_option_t *p = NULL; config_option_t *end; while(grp) { p = grp->options; end = grp->options+grp->nentries; while (p != end) { if (!StrCmp(str, p->name)) return p; p++; } grp = grp->next; } return NULL;}/* * main parser function * Return: * - a token code representing the kind of element found * - TOK_EOF: end-of-file (or error) detected * - TOK_STR: if string is found * - TOK_EQUAL: for the '=' sign * - TOK_ERR: in case of (parsing) error */static token_tget_token(CHAR16 *str, UINTN maxlen){ INTN ch, escaped; CHAR16 *here; for (;;) { while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n') line_num++; if (ch == CHAR_EOF) return TOK_EOF; if (ch != '#') break; /* skip comment line */ while ((ch = next()), ch != '\n') if (ch == CHAR_EOF) return TOK_EOF; line_num++; } if (ch == '=') return TOK_EQUAL; if (ch == '"') { here = str; while (here-str < maxlen) { if ((ch = next()) == CHAR_EOF) { config_error(L"EOF in quoted string"); return TOK_ERR; } if (ch == '"') { *here = 0; return TOK_STR; } if (ch == '\\') { ch = next(); if (ch != '"' && ch != '\\' && ch != '\n') { config_error(L"Bad use of \\ in quoted string"); return TOK_ERR; } if (ch == '\n') continue;#if 0 while ((ch = next()), ch == ' ' || ch == '\t'); if (!ch) continue; again(ch); ch = ' '; }#endif } if (ch == '\n' || ch == '\t') { config_error(L"\\n and \\t are not allowed in quoted strings"); return TOK_ERR; } *here++ = ch; } config_error(L"Quoted string is too long"); return TOK_ERR; } here = str; escaped = 0; while (here-str < maxlen) { if (escaped) { if (ch == CHAR_EOF) { config_error(L"\\ precedes EOF"); return TOK_ERR; } if (ch == '\n') line_num++; else *here++ = ch == '\t' ? ' ' : ch; escaped = 0; } else { if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' || ch == '=' || ch == CHAR_EOF) { again(ch); *here = 0; return TOK_STR; } if (!(escaped = (ch == '\\'))) *here++ = ch; } ch = next(); } config_error(L"Token is too long"); return TOK_ERR;}static INTNimage_check(boot_image_t *img){ boot_image_t *b; if (img == NULL) return -1; /* do the obvious first */ if (img->label[0] == '\0') { config_error(L"image has no label"); return -1; } /* image_list points to the */ for(b=image_list; b; b = b->next) { if (img == b) continue; if (!StrCmp(img->label, b->label)) { config_error(L"image with label %s already defined", img->label); return -1; } } return 0;}static INTN global_check(VOID){ return 0;}static INTNfinal_check(VOID){ boot_image_t *b; if (global_config.default_image_name[0]) { for(b=image_list; b; b = b->next) { if (!StrCmp(b->label, global_config.default_image_name)) goto found; } config_error(L"default image '%s' not defined ", global_config.default_image_name); return -1; } global_config.default_image = first_image; return 0;found: global_config.default_image = b; return 0;}/* * depending on the active set of options * adjust the option data pointer to: * if global option set: * - just the straight value from p->data * if image option set: * - adjust as offset to image * Return: * - the adjusted pointer */static inline VOID *adjust_pointer(config_option_t *p){ /* * adjust pointer */ if (OPTION_IS_GLOBAL(p)) return p->data; if (OPTION_IS_IMG_SYS(p)) return (VOID *)((UINTN)¤t_img->sys_img_opts + p->data); return (VOID *)((UINTN)current_img + p->data);}/* * create a new image entry */static INTNdo_image(config_option_t *p, VOID *str){ boot_image_t *img; /* * if we move to a new image from the current one * then we need to check for validity of current. * * if this is the first image, then check the global * options. */ if (current_img) { if (image_check(current_img) == -1) return -1; } else if (global_check() == -1) return -1; img = (boot_image_t *)alloc(sizeof(boot_image_t), EfiLoaderData); if (img == NULL) return -1; Memset(img, 0, sizeof(boot_image_t)); DBG_PRT((L"must do image on %s", (CHAR16 *)str)); /* copy kernel file name */ StrCpy(img->kname, str); /* switch to image mode */ current_options = image_option_list; /* keep track of first image in case no default is defined */ if (image_list == NULL) first_image = img; /* append to end of image list, so when a chooser asks for the list * it gets them in the order they were in in the config file */ if (image_list == NULL) image_list = img; else { boot_image_t * p = image_list; while (p->next) p = p->next; p->next = img; } /* update current image */ current_img = img; return 0;}/* * by default all boolean options are defined * as false. This function sets the boolean * to true */static INTNdo_boolean(config_option_t *p){ INT8 *buf; buf = adjust_pointer(p); if (p->action) return p->action(p, NULL); /* set the field to true, overwrite if already defined */ *buf = 1; return 0;} /* * the image option 'literal' requires special handling * because it overrides any defined option be it global or * local. so we use the option field and record the fact that * it should be interpreted as literal */static INTNdo_literal(config_option_t *p, VOID *str){ /* * we know we have a valid current image at this point */ StrCpy(current_img->options, str); current_img->literal = 1; return 0;}static INTNdo_options(config_option_t *p, VOID *str){ /* we ignore append if literal is already defined */ if (current_img->literal) return 0; /* * we know we have a valid current image at this point */ StrCpy(current_img->options, str); return 0;}static INTNdo_numeric(config_option_t *p)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?