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)&current_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 + -
显示快捷键?