From 8f33a3dff6cd44fa2d12e626354479e020e25bdc Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 1 Jun 2010 16:18:42 +0800 Subject: [PATCH] move core/elflink over --- MCONFIG.devel | 2 - core/elflink/abort_new.c | 29 ++ core/elflink/adv.c | 49 ++ core/elflink/advwrite.c | 45 ++ core/elflink/cli.c | 406 ++++++++++++++++ core/elflink/cli.h | 23 + core/elflink/colors.c | 184 +++++++ core/elflink/common.h | 62 +++ core/elflink/config.c | 41 ++ core/elflink/core-elf.h | 16 + core/elflink/elfutils.h | 67 +++ core/elflink/execute.c | 85 ++++ core/elflink/get_key.c | 172 +++++++ core/elflink/getadv.c | 68 +++ core/elflink/getkey.h | 80 +++ core/elflink/ipappend.c | 58 +++ core/elflink/kernel.c | 130 +++++ core/elflink/load_env32.c | 128 +++++ core/elflink/menu.h | 229 +++++++++ core/elflink/readconfig.c | 1183 +++++++++++++++++++++++++++++++++++++++++++++ core/elflink/refstr.c | 106 ++++ core/elflink/refstr.h | 40 ++ core/elflink/setadv.c | 116 +++++ 23 files changed, 3317 insertions(+), 2 deletions(-) delete mode 100644 MCONFIG.devel create mode 100644 core/elflink/abort_new.c create mode 100644 core/elflink/adv.c create mode 100644 core/elflink/advwrite.c create mode 100644 core/elflink/cli.c create mode 100644 core/elflink/cli.h create mode 100644 core/elflink/colors.c create mode 100644 core/elflink/common.h create mode 100644 core/elflink/config.c create mode 100644 core/elflink/core-elf.h create mode 100644 core/elflink/elfutils.h create mode 100644 core/elflink/execute.c create mode 100644 core/elflink/get_key.c create mode 100644 core/elflink/getadv.c create mode 100644 core/elflink/getkey.h create mode 100644 core/elflink/ipappend.c create mode 100644 core/elflink/kernel.c create mode 100644 core/elflink/load_env32.c create mode 100644 core/elflink/menu.h create mode 100644 core/elflink/readconfig.c create mode 100644 core/elflink/refstr.c create mode 100644 core/elflink/refstr.h create mode 100644 core/elflink/setadv.c diff --git a/MCONFIG.devel b/MCONFIG.devel deleted file mode 100644 index 104207f..0000000 --- a/MCONFIG.devel +++ /dev/null @@ -1,2 +0,0 @@ -# Useful while doing development, but not for production. -GCCWARN += -Wno-clobbered -Werror diff --git a/core/elflink/abort_new.c b/core/elflink/abort_new.c new file mode 100644 index 0000000..39ba226 --- /dev/null +++ b/core/elflink/abort_new.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +//#include +//#include +//#include + +#include "core.h" +#include "core-elf.h" +#include "menu.h" + +void abort_load_new(com32sys_t *reg) +{ + char *str; + + str = (void *)reg->esi.l; + + printf("Error!\n"); + if (str) + printf("%s\n", str); + + if (onerrorlen) + execute(start_menu->onerror, KT_NONE); + enter_cmdline(); + return; +} diff --git a/core/elflink/adv.c b/core/elflink/adv.c new file mode 100644 index 0000000..be38e89 --- /dev/null +++ b/core/elflink/adv.c @@ -0,0 +1,49 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux/adv.c + * + * Access the syslinux auxilliary data vector + */ + +#include +#include +#include + +void *__syslinux_adv_ptr; +size_t __syslinux_adv_size; + +void __constructor __syslinux_get_adv(void) +{ + static com32sys_t reg; + + reg.eax.w[0] = 0x001c; + __intcall(0x22, ®, ®); + __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]); + __syslinux_adv_size = reg.ecx.w[0]; +} diff --git a/core/elflink/advwrite.c b/core/elflink/advwrite.c new file mode 100644 index 0000000..4152eea --- /dev/null +++ b/core/elflink/advwrite.c @@ -0,0 +1,45 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux/advwrite.c + * + * Write back the ADV + */ + +#include +#include +#include + +int syslinux_adv_write(void) +{ + static com32sys_t reg; + + reg.eax.w[0] = 0x001d; + __intcall(0x22, ®, ®); + return (reg.eflags.l & EFLAGS_CF) ? -1 : 0; +} diff --git a/core/elflink/cli.c b/core/elflink/cli.c new file mode 100644 index 0000000..2e223ae --- /dev/null +++ b/core/elflink/cli.c @@ -0,0 +1,406 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "getkey.h" + +#include "common.h" +#include "menu.h" +#include "cli.h" + +void clear_screen(void) +{ + fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout); +} + +int mygetkey(clock_t timeout) +{ + clock_t t0, t; + clock_t tto, to; + int key; + + if (!totaltimeout) + return get_key(stdin, timeout); + + for (;;) { + tto = min(totaltimeout, INT_MAX); + to = timeout ? min(tto, timeout) : tto; + + t0 = times(NULL); + key = get_key(stdin, to); + t = times(NULL) - t0; + + if (totaltimeout <= t) + longjmp(timeout_jump, 1); + + totaltimeout -= t; + + if (key != KEY_NONE) + return key; + + if (timeout) { + if (timeout <= t) + return KEY_NONE; + + timeout -= t; + } + } +} + +const char *edit_cmdline(const char *input, int top /*, int width */ , + int (*pDraw_Menu) (int, int, int), + void (*show_fkey) (int)) +{ + static char cmdline[MAX_CMDLINE_LEN]; + char temp_cmdline[MAX_CMDLINE_LEN] = { }; + int key, len, prev_len, cursor; + int redraw = 1; /* We enter with the menu already drawn */ + int x, y; + bool done = false; + const char *ret; + int width = 0; + struct cli_command *comm_counter; + comm_counter = + list_entry(cli_history_head.next->prev, typeof(*comm_counter), list); + + if (!width) { + int height; + if (getscreensize(1, &height, &width)) + width = 80; + } + //printf("width = %d\n", width); + + strncpy(cmdline, input, MAX_CMDLINE_LEN); + cmdline[MAX_CMDLINE_LEN - 1] = '\0'; + + len = cursor = strlen(cmdline); + prev_len = 0; + x = y = 0; + + while (!done) { + if (redraw > 1 && pDraw_Menu != NULL) { + /* Clear and redraw whole screen */ + /* Enable ASCII on G0 and DEC VT on G1; do it in this order + to avoid confusing the Linux console */ + /* clear_screen(); + draw_menu(-1, top, 1); */ + clear_screen(); + (*pDraw_Menu) (-1, top, 1); + prev_len = 0; + // printf("\033[0m\033[2J\033[H"); + } + + if (redraw > 0) { + int dy, at; + + prev_len = max(len, prev_len); + + /* Redraw the command line */ + printf("\033[?7l\033[?25l"); + if (y) + printf("\033[%dA", y); + printf("\033[1G\033[1;36m> \033[0m"); + + x = 2; + y = 0; + at = 0; + while (at < prev_len) { + putchar(at >= len ? ' ' : cmdline[at]); + at++; + x++; + if (x >= width) { + printf("\r\n"); + x = 0; + y++; + } + } + printf("\033[K\r"); + + dy = y - (cursor + 2) / width; + x = (cursor + 2) % width; + + if (dy) { + printf("\033[%dA", dy); + y -= dy; + } + if (x) + printf("\033[%dC", x); + printf("\033[?25h"); + prev_len = len; + redraw = 0; + } + + key = mygetkey(0); + + switch (key) { + case KEY_CTRL('L'): + redraw = 2; + break; + + case KEY_ENTER: + case KEY_CTRL('J'): + ret = cmdline; + done = true; + break; + + case KEY_ESC: + case KEY_CTRL('C'): + ret = NULL; + done = true; + break; + + case KEY_BACKSPACE: + case KEY_DEL: + if (cursor) { + memmove(cmdline + cursor - 1, cmdline + cursor, + len - cursor + 1); + len--; + cursor--; + redraw = 1; + } + break; + + case KEY_CTRL('D'): + case KEY_DELETE: + if (cursor < len) { + memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor); + len--; + redraw = 1; + } + break; + + case KEY_CTRL('U'): + if (len) { + len = cursor = 0; + cmdline[len] = '\0'; + redraw = 1; + } + break; + + case KEY_CTRL('W'): + if (cursor) { + int prevcursor = cursor; + + while (cursor && my_isspace(cmdline[cursor - 1])) + cursor--; + + while (cursor && !my_isspace(cmdline[cursor - 1])) + cursor--; + +#if 0 + memmove(cmdline + cursor, cmdline + prevcursor, + len - prevcursor + 1); +#else + { + int i; + char *q = cmdline + cursor; + char *p = cmdline + prevcursor; + for (i = 0; i < len - prevcursor + 1; i++) + *q++ = *p++; + } +#endif + len -= (prevcursor - cursor); + redraw = 1; + } + break; + + case KEY_LEFT: + case KEY_CTRL('B'): + if (cursor) { + cursor--; + redraw = 1; + } + break; + + case KEY_RIGHT: + case KEY_CTRL('F'): + if (cursor < len) { + putchar(cmdline[cursor]); + cursor++; + x++; + if (x >= width) { + printf("\r\n"); + y++; + x = 0; + } + } + break; + + case KEY_CTRL('K'): + if (cursor < len) { + cmdline[len = cursor] = '\0'; + redraw = 1; + } + break; + + case KEY_HOME: + case KEY_CTRL('A'): + if (cursor) { + cursor = 0; + redraw = 1; + } + break; + + case KEY_END: + case KEY_CTRL('E'): + if (cursor != len) { + cursor = len; + redraw = 1; + } + break; + + case KEY_F1: + case KEY_F2: + case KEY_F3: + case KEY_F4: + case KEY_F5: + case KEY_F6: + case KEY_F7: + case KEY_F8: + case KEY_F9: + case KEY_F10: + case KEY_F11: + case KEY_F12: + if (show_fkey != NULL) { + (*show_fkey) (key); + redraw = 1; + } + break; + case KEY_UP: + { + if (!list_empty(&cli_history_head)) { + comm_counter = + list_entry(comm_counter->list.next, + typeof(*comm_counter), list); + if (&comm_counter->list == &cli_history_head) { + strcpy(cmdline, temp_cmdline); + } else { + strcpy(cmdline, comm_counter->command); + } + cursor = len = strlen(cmdline); + redraw = 1; + } + } + break; + case KEY_DOWN: + { + if (!list_empty(&cli_history_head)) { + comm_counter = + list_entry(comm_counter->list.prev, + typeof(*comm_counter), list); + if (&comm_counter->list == &cli_history_head) { + strcpy(cmdline, temp_cmdline); + } else { + strcpy(cmdline, comm_counter->command); + } + cursor = len = strlen(cmdline); + redraw = 1; + } + } + break; + default: + if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) { + if (cursor == len) { + temp_cmdline[len] = key; + cmdline[len++] = key; + temp_cmdline[len] = cmdline[len] = '\0'; + putchar(key); + cursor++; + x++; + if (x >= width) { + printf("\r\n\033[K"); + y++; + x = 0; + } + prev_len++; + } else { + memmove(cmdline + cursor + 1, cmdline + cursor, + len - cursor + 1); + memmove(temp_cmdline + cursor + 1, temp_cmdline + cursor, + len - cursor + 1); + temp_cmdline[cursor] = key; + cmdline[cursor++] = key; + len++; + redraw = 1; + } + } + break; + } + } + + printf("\033[?7h"); + return ret; +} + +void process_command(const char *cmd) +{ + char **argv = malloc((MAX_COMMAND_ARGS + 1) * sizeof(char *)); + char *temp_cmd = (char *)malloc(sizeof(char) * (strlen(cmd) + 1)); + int argc = 1, len_mn; + char *crt_arg, *module_name; + + /* return if user only press enter */ + if (cmd[0] == '\0') { + printf("\n"); + return; + } + + strcpy(temp_cmd, cmd); + module_name = strtok(cmd, COMMAND_DELIM); + len_mn = strlen(module_name); + + printf("\n"); + mp("enter, cmd = %s, module_name = %s",cmd, module_name); + + if (!strcmp(module_name + len_mn - 4, ".c32")) { + if (module_find(module_name) != NULL) { + /* make module re-enterable */ + mp("Module %s is already running"); + //goto cleanup; + } + do { + argv[0] = module_name; + crt_arg = strtok(NULL, COMMAND_DELIM); + if (crt_arg != NULL && strlen(crt_arg) > 0) { + argv[argc] = crt_arg; + argc++; + } else + break; + } while (argc < MAX_COMMAND_ARGS); + argv[argc] = NULL; + module_load_dependencies(module_name, MODULES_DEP); + spawn_load(module_name, argv); + } else if (!strcmp(module_name + len_mn - 2, ".0")) { + execute(cmd, KT_PXE); + } else if (!strcmp(module_name + len_mn - 3, ".bs")) { + } else if (!strcmp(module_name + len_mn - 4, ".img")) { + execute(cmd, KT_FDIMAGE); + } else if (!strcmp(module_name + len_mn - 4, ".bin")) { + } else if (!strcmp(module_name + len_mn - 4, ".bss")) { + execute(cmd, KT_BSS); + } else if (!strcmp(module_name + len_mn - 4, ".com") + || !strcmp(module_name + len_mn - 4, ".cbt")) { + execute(cmd, KT_COMBOOT); + } else if (!strcmp(module_name + len_mn - 4, ".cfg") + || !strcmp(module_name + len_mn - 5, ".conf") + || !strcmp(module_name + len_mn - 7, ".config")) { + execute(module_name, KT_CONFIG); + } + /* use KT_KERNEL as default */ + else + execute(temp_cmd, KT_KERNEL); + +cleanup: + free(argv); + free(temp_cmd); +} diff --git a/core/elflink/cli.h b/core/elflink/cli.h new file mode 100644 index 0000000..9cd8c16 --- /dev/null +++ b/core/elflink/cli.h @@ -0,0 +1,23 @@ +#ifndef CLI_H +#define CLI_H + +#define MAX_CMD_HISTORY 64 +#define COMMAND_DELIM " \t\n" // Whitespace delimiters +#define MAX_COMMAND_ARGS 40 + +struct cli_command { + struct list_head list; + char *command; +}; + +struct list_head cli_history_head; + +extern void clear_screen(void); +extern int mygetkey(clock_t timeout); +extern const char *edit_cmdline(const char *input, int top /*, int width */ , + int (*pDraw_Menu) (int, int, int), + void (*show_fkey) (int)); +extern void process_command(const char *cmd); + +extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu; +#endif diff --git a/core/elflink/colors.c b/core/elflink/colors.c new file mode 100644 index 0000000..68732bd --- /dev/null +++ b/core/elflink/colors.c @@ -0,0 +1,184 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * This program 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "menu.h" + +/* + * The color/attribute indexes (\1#X, \2#XX, \3#XXX) are as follows + * + * 00 - screen Rest of the screen + * 01 - border Border area + * 02 - title Title bar + * 03 - unsel Unselected menu item + * 04 - hotkey Unselected hotkey + * 05 - sel Selection bar + * 06 - hotsel Selected hotkey + * 07 - scrollbar Scroll bar + * 08 - tabmsg Press [Tab] message + * 09 - cmdmark Command line marker + * 10 - cmdline Command line + * 11 - pwdborder Password box border + * 12 - pwdheader Password box header + * 13 - pwdentry Password box contents + * 14 - timeout_msg Timeout message + * 15 - timeout Timeout counter + * 16 - help Current entry help text + * 17 - disabled Disabled menu item + */ + +static const struct color_table default_colors[] = { + {"screen", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL}, + {"border", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL}, + {"title", "1;36;44", 0xc00090f0, 0x00000000, SHADOW_NORMAL}, + {"unsel", "37;44", 0x90ffffff, 0x00000000, SHADOW_NORMAL}, + {"hotkey", "1;37;44", 0xffffffff, 0x00000000, SHADOW_NORMAL}, + {"sel", "7;37;40", 0xe0000000, 0x20ff8000, SHADOW_ALL}, + {"hotsel", "1;7;37;40", 0xe0400000, 0x20ff8000, SHADOW_ALL}, + {"scrollbar", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL}, + {"tabmsg", "31;40", 0x90ffff00, 0x00000000, SHADOW_NORMAL}, + {"cmdmark", "1;36;40", 0xc000ffff, 0x00000000, SHADOW_NORMAL}, + {"cmdline", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL}, + {"pwdborder", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL}, + {"pwdheader", "31;47", 0x80ff8080, 0x20ffffff, SHADOW_NORMAL}, + {"pwdentry", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL}, + {"timeout_msg", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL}, + {"timeout", "1;37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL}, + {"help", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL}, + {"disabled", "1;30;44", 0x60cccccc, 0x00000000, SHADOW_NORMAL}, +}; + +#define NCOLORS (sizeof default_colors/sizeof default_colors[0]) +const int message_base_color = NCOLORS; +const int menu_color_table_size = NCOLORS + 256; + +/* Algorithmically generate the msgXX colors */ +void set_msg_colors_global(struct color_table *tbl, + unsigned int fg, unsigned int bg, + enum color_table_shadow shadow) +{ + struct color_table *cp = tbl + message_base_color; + unsigned int i; + unsigned int fga, bga; + unsigned int fgh, bgh; + unsigned int fg_idx, bg_idx; + unsigned int fg_rgb, bg_rgb; + + static const unsigned int pc2rgb[8] = + { 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00, + 0xffffff + }; + + /* Converting PC RGBI to sensible RGBA values is an "interesting" + proposition. This algorithm may need plenty of tweaking. */ + + fga = fg & 0xff000000; + fgh = ((fg >> 1) & 0xff000000) | 0x80000000; + + bga = bg & 0xff000000; + bgh = ((bg >> 1) & 0xff000000) | 0x80000000; + + for (i = 0; i < 256; i++) { + fg_idx = i & 15; + bg_idx = i >> 4; + + fg_rgb = pc2rgb[fg_idx & 7] & fg; + bg_rgb = pc2rgb[bg_idx & 7] & bg; + + if (fg_idx & 8) { + /* High intensity foreground */ + fg_rgb |= fgh; + } else { + fg_rgb |= fga; + } + + if (bg_idx == 0) { + /* Default black background, assume transparent */ + bg_rgb = 0; + } else if (bg_idx & 8) { + bg_rgb |= bgh; + } else { + bg_rgb |= bga; + } + + cp->argb_fg = fg_rgb; + cp->argb_bg = bg_rgb; + cp->shadow = shadow; + cp++; + } +} + +struct color_table *default_color_table(void) +{ + unsigned int i; + const struct color_table *dp; + struct color_table *cp; + struct color_table *color_table; + static const int pc2ansi[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + static char msg_names[6 * 256]; + char *mp; + + color_table = calloc(NCOLORS + 256, sizeof(struct color_table)); + + dp = default_colors; + cp = color_table; + + for (i = 0; i < NCOLORS; i++) { + *cp = *dp; + cp->ansi = refstrdup(dp->ansi); + cp++; + dp++; + } + + mp = msg_names; + for (i = 0; i < 256; i++) { + cp->name = mp; + mp += sprintf(mp, "msg%02x", i) + 1; + + rsprintf(&cp->ansi, "%s3%d;4%d", (i & 8) ? "1;" : "", + pc2ansi[i & 7], pc2ansi[(i >> 4) & 7]); + cp++; + } + + /*** XXX: This needs to move to run_menu() ***/ + console_color_table = color_table; + console_color_table_size = NCOLORS + 256; + + set_msg_colors_global(color_table, MSG_COLORS_DEF_FG, + MSG_COLORS_DEF_BG, MSG_COLORS_DEF_SHADOW); + + return color_table; +} + +struct color_table *copy_color_table(const struct color_table *master) +{ + const struct color_table *dp; + struct color_table *color_table, *cp; + unsigned int i; + + color_table = calloc(NCOLORS + 256, sizeof(struct color_table)); + + dp = master; + cp = color_table; + + for (i = 0; i < NCOLORS + 256; i++) { + *cp = *dp; + cp->ansi = refstr_get(dp->ansi); + cp++; + dp++; + } + + return color_table; +} diff --git a/core/elflink/common.h b/core/elflink/common.h new file mode 100644 index 0000000..e288d1e --- /dev/null +++ b/core/elflink/common.h @@ -0,0 +1,62 @@ +/* + * common.h - Common internal operations performed by the module subsystem + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur + */ + +#ifndef COMMON_H_ +#define COMMON_H_ + +#include + +#include +#include + +#include "elfutils.h" + +// Performs an operation and jumps to a given label if an error occurs +#define CHECKED(res, expr, error) \ + do { \ + (res) = (expr); \ + if ((res) < 0) \ + goto error; \ + } while (0) + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +//#define ELF_DEBUG + +#ifdef ELF_DEBUG +#define DBG_PRINT(fmt, args...) fprintf(stderr, "[ELF] " fmt, ##args) +#else +#define DBG_PRINT(fmt, args...) // Expand to nothing +#endif + +// User-space debugging routines +#ifdef ELF_DEBUG +extern void print_elf_ehdr(Elf32_Ehdr * ehdr); +extern void print_elf_symbols(struct elf_module *module); +#endif //ELF_DEBUG + +/* + * Image files manipulation routines + */ + +extern int image_load(struct elf_module *module); +extern int image_unload(struct elf_module *module); +extern int image_read(void *buff, size_t size, struct elf_module *module); +extern int image_skip(size_t size, struct elf_module *module); +extern int image_seek(Elf32_Off offset, struct elf_module *module); + +extern struct module_dep *module_dep_alloc(struct elf_module *module); + +extern int check_header_common(Elf32_Ehdr * elf_hdr); + +extern int enforce_dependency(struct elf_module *req, struct elf_module *dep); +extern int clear_dependency(struct elf_module *req, struct elf_module *dep); + +extern int check_symbols(struct elf_module *module); + +#endif /* COMMON_H_ */ diff --git a/core/elflink/config.c b/core/elflink/config.c new file mode 100644 index 0000000..b27aa82 --- /dev/null +++ b/core/elflink/config.c @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include +#include +#include + +const char *__syslinux_config_file; + +void __constructor __syslinux_get_config_file_name(void) +{ + static com32sys_t reg; + + reg.eax.w[0] = 0x000e; + __intcall(0x22, ®, ®); + __syslinux_config_file = MK_PTR(reg.es, reg.ebx.w[0]); +} diff --git a/core/elflink/core-elf.h b/core/elflink/core-elf.h new file mode 100644 index 0000000..1edd174 --- /dev/null +++ b/core/elflink/core-elf.h @@ -0,0 +1,16 @@ +#ifndef _CORE_ELF_H +#define _coRE_ELF_H + +extern char *append; +extern char *ippappend; +extern char *globaldefault; +extern short onerrorlen; + +extern void parse_configs(char **argv); +extern int new_linux_kernel(char *okernel, char *ocmdline); + +/* load_env32.c, should be moved out */ +extern void enter_cmdline(void); + +extern void start_ui(char *config_file); +#endif diff --git a/core/elflink/elfutils.h b/core/elflink/elfutils.h new file mode 100644 index 0000000..3c8e70f --- /dev/null +++ b/core/elflink/elfutils.h @@ -0,0 +1,67 @@ +#ifndef ELF_UTILS_H_ +#define ELF_UTILS_H_ + +#include +#include + +/** + * elf_get_header - Returns a pointer to the ELF header structure. + * @elf_image: pointer to the ELF file image in memory + */ +static inline Elf32_Ehdr *elf_get_header(void *elf_image) +{ + return (Elf32_Ehdr *) elf_image; +} + +/** + * elf_get_pht - Returns a pointer to the first entry in the PHT. + * @elf_image: pointer to the ELF file image in memory + */ +static inline Elf32_Phdr *elf_get_pht(void *elf_image) +{ + Elf32_Ehdr *elf_hdr = elf_get_header(elf_image); + + return (Elf32_Phdr *) ((Elf32_Off) elf_hdr + elf_hdr->e_phoff); +} + +// +/** + * elf_get_ph - Returns the element with the given index in the PTH + * @elf_image: pointer to the ELF file image in memory + * @index: the index of the PHT entry to look for + */ +static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) +{ + Elf32_Phdr *elf_pht = elf_get_pht(elf_image); + Elf32_Ehdr *elf_hdr = elf_get_header(elf_image); + + return (Elf32_Phdr *) ((Elf32_Off) elf_pht + index * elf_hdr->e_phentsize); +} + +/** + * elf_hash - Returns the index in a SysV hash table for the symbol name. + * @name: the name of the symbol to look for + */ +extern unsigned long elf_hash(const unsigned char *name); + +/** + * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name. + * @name: the name of the symbol to look for + */ +extern unsigned long elf_gnu_hash(const unsigned char *name); + +/** + * elf_malloc - Allocates memory to be used by ELF module contents. + * @memptr: pointer to a variable to hold the address of the allocated block. + * @alignment: alignment constraints of the block + * @size: the required size of the block + */ +extern int elf_malloc(void **memptr, size_t alignment, size_t size); + +/** + * elf_free - Releases memory previously allocated by elf_malloc. + * @memptr: the address of the allocated block + */ +extern void elf_free(void *memptr); + +#endif /*ELF_UTILS_H_ */ diff --git a/core/elflink/execute.c b/core/elflink/execute.c new file mode 100644 index 0000000..1a7ce79 --- /dev/null +++ b/core/elflink/execute.c @@ -0,0 +1,85 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * This program 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include +#include +#include + +#include +#include "menu.h" + +void execute(const char *cmdline, enum kernel_type type) +{ + com32sys_t ireg; + const char *p, *const *pp; + char *q = __com32.cs_bounce; + const char *kernel, *args; + + /* work around for spawn_load parameter */ + char *spawn_load_param[2] = { NULL, NULL}; + + memset(&ireg, 0, sizeof ireg); + + kernel = q; + p = cmdline; + while (*p && !my_isspace(*p)) + *q++ = *p++; + *q++ = '\0'; + + args = q; + while (*p && my_isspace(*p)) + p++; + + strcpy(q, p); + + mp("kernel is %s, args = %s type = %d \n", kernel, args, type); + + if (kernel[0] == '.' && type == KT_NONE) { + /* It might be a type specifier */ + enum kernel_type type = KT_NONE; + for (pp = kernel_types; *pp; pp++, type++) { + if (!strcmp(kernel + 1, *pp)) + execute(p, type); /* Strip the type specifier and retry */ + } + } + + if (type == KT_COM32) { + /* new entry for elf format c32 */ + spawn_load_param[0] = args; + module_load_dependencies(kernel, "modules.dep"); + spawn_load(kernel, spawn_load_param); + } else if (type <= KT_KERNEL) { + /* Need add one item for kernel load, as we don't use + * the assembly runkernel.inc any more */ + new_linux_kernel(kernel, cmdline); + } else if (type == KT_CONFIG) { + /* kernel contains the config file name */ + start_ui(kernel); + } else { + /* process the image need int 22 support */ + if (type == KT_LOCALBOOT) { + ireg.eax.w[0] = 0x0014; /* Local boot */ + ireg.edx.w[0] = strtoul(kernel, NULL, 0); + } + ireg.eax.w[0] = 0x0016; /* Run kernel image */ + ireg.esi.w[0] = OFFS(kernel); + ireg.ds = SEG(kernel); + ireg.ebx.w[0] = OFFS(args); + ireg.es = SEG(args); + ireg.edx.l = type - KT_KERNEL; + /* ireg.ecx.l = 0; *//* We do ipappend "manually" */ + + __intcall(0x22, &ireg, NULL); + } + + /* If this returns, something went bad; return to menu */ +} diff --git a/core/elflink/get_key.c b/core/elflink/get_key.c new file mode 100644 index 0000000..ce82fd1 --- /dev/null +++ b/core/elflink/get_key.c @@ -0,0 +1,172 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * get_key.c + * + * Get a single key, and try to pick apart function key codes. + * This doesn't decode anywhere close to all possiblities, but + * hopefully is enough to be useful. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "getkey.h" + +struct keycode { + int code; + int seqlen; + const unsigned char *seq; +}; + +#define MAXLEN 8 +#define CODE(x,y) { x, (sizeof y)-1, y } + +static const struct keycode keycodes[] = { + /* First, the BIOS combined codes */ + CODE(KEY_F1, "\0\x3B"), + CODE(KEY_F2, "\0\x3C"), + CODE(KEY_F3, "\0\x3D"), + CODE(KEY_F4, "\0\x3E"), + CODE(KEY_F5, "\0\x3F"), + CODE(KEY_F6, "\0\x40"), + CODE(KEY_F7, "\0\x41"), + CODE(KEY_F8, "\0\x42"), + CODE(KEY_F9, "\0\x43"), + CODE(KEY_F10, "\0\x44"), + CODE(KEY_F11, "\0\x85"), + CODE(KEY_F12, "\0\x86"), + + CODE(KEY_UP, "\0\x48"), + CODE(KEY_DOWN, "\0\x50"), + CODE(KEY_LEFT, "\0\x4B"), + CODE(KEY_RIGHT, "\0\x4D"), + CODE(KEY_PGUP, "\0\x49"), + CODE(KEY_PGDN, "\0\x51"), + CODE(KEY_HOME, "\0\x47"), + CODE(KEY_END, "\0\x4F"), + CODE(KEY_INSERT, "\0\x52"), + CODE(KEY_DELETE, "\0\x53"), + + /* Now, VT/xterm/Linux codes */ + CODE(KEY_F1, "\033[[A"), + CODE(KEY_F1, "\033OP"), + CODE(KEY_F2, "\033[[B"), + CODE(KEY_F2, "\033OQ"), + CODE(KEY_F3, "\033[[C"), + CODE(KEY_F3, "\033OR"), + CODE(KEY_F4, "\033[[D"), + CODE(KEY_F4, "\033OS"), + CODE(KEY_F5, "\033[[E"), + CODE(KEY_F5, "\033[15~"), + CODE(KEY_F6, "\033[17~"), + CODE(KEY_F7, "\033[18~"), + CODE(KEY_F8, "\033[19~"), + CODE(KEY_F9, "\033[20~"), + CODE(KEY_F10, "\033[21~"), + CODE(KEY_F11, "\033[23~"), + CODE(KEY_F12, "\033[24~"), + + CODE(KEY_UP, "\033[A"), + CODE(KEY_DOWN, "\033[B"), + CODE(KEY_LEFT, "\033[D"), + CODE(KEY_RIGHT, "\033[C"), + CODE(KEY_PGUP, "\033[5~"), + CODE(KEY_PGUP, "\033[V"), + CODE(KEY_PGDN, "\033[6~"), + CODE(KEY_PGDN, "\033[U"), + CODE(KEY_HOME, "\033[1~"), + CODE(KEY_HOME, "\033[H"), + CODE(KEY_END, "\033[4~"), + CODE(KEY_END, "\033[F"), + CODE(KEY_END, "\033OF"), + CODE(KEY_INSERT, "\033[2~"), + CODE(KEY_INSERT, "\033[@"), + CODE(KEY_DELETE, "\033[3~"), +}; + +#define NCODES ((int)(sizeof keycodes/sizeof(struct keycode))) + +#define KEY_TIMEOUT ((CLK_TCK+9)/10) + +int get_key(FILE * f, clock_t timeout) +{ + unsigned char buffer[MAXLEN]; + int nc, i, rv; + const struct keycode *kc; + int another; + unsigned char ch; + clock_t start; + + /* We typically start in the middle of a clock tick */ + if (timeout) + timeout++; + + nc = 0; + start = times(NULL); + do { + rv = read(fileno(f), &ch, 1); + if (rv == 0 || (rv == -1 && errno == EAGAIN)) { + clock_t lateness = times(NULL) - start; + if (nc && lateness > 1 + KEY_TIMEOUT) { + if (nc == 1) + return buffer[0]; /* timeout in sequence */ + else if (timeout && lateness > timeout) + return KEY_NONE; + } else if (!nc && timeout && lateness > timeout) + return KEY_NONE; /* timeout before sequence */ + + syslinux_idle(); + + another = 1; + continue; + } + + start = times(NULL); + + buffer[nc++] = ch; + + another = 0; + for (i = 0, kc = keycodes; i < NCODES; i++, kc++) { + if (nc == kc->seqlen && !memcmp(buffer, kc->seq, nc)) + return kc->code; + else if (nc < kc->seqlen && !memcmp(buffer, kc->seq, nc)) { + another = 1; + break; + } + } + } while (another); + + /* We got an unrecognized sequence; return the first character */ + /* We really should remember this and return subsequent characters later */ + return buffer[0]; +} diff --git a/core/elflink/getadv.c b/core/elflink/getadv.c new file mode 100644 index 0000000..456084b --- /dev/null +++ b/core/elflink/getadv.c @@ -0,0 +1,68 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux/getadv.c + * + * Get a data item from the auxilliary data vector. Returns a pointer + * and sets *size on success; NULL on failure. + */ + +#include +#include +#include + +const void *syslinux_getadv(int tag, size_t * size) +{ + const uint8_t *p; + size_t left, len; + + p = syslinux_adv_ptr(); + left = syslinux_adv_size(); + + while (left >= 2) { + uint8_t ptag = *p++; + size_t plen = *p++; + left -= 2; + + if (ptag == ADV_END) + return NULL; /* Not found */ + + if (left < plen) + return NULL; /* Item overrun */ + + if (ptag == tag) { + *size = plen; + return p; + } + + p += plen; + left -= plen; + } + + return NULL; +} diff --git a/core/elflink/getkey.h b/core/elflink/getkey.h new file mode 100644 index 0000000..52312a2 --- /dev/null +++ b/core/elflink/getkey.h @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * getkey.h + * + * Function to get a key symbol and parse it + */ + +#ifndef LIBUTIL_GETKEY_H +#define LIBUTIL_GETKEY_H + +#include +#include +#include + +#ifndef CLK_TCK +# define CLK_TCK sysconf(_SC_CLK_TCK) +#endif + +#define KEY_NONE (-1) + +#define KEY_CTRL(x) ((x) & 0x001f) +#define KEY_BACKSPACE 0x0008 +#define KEY_TAB 0x0009 +#define KEY_ENTER 0x000d +#define KEY_ESC 0x001b +#define KEY_DEL 0x007f + +#define KEY_F1 0x0100 +#define KEY_F2 0x0101 +#define KEY_F3 0x0102 +#define KEY_F4 0x0103 +#define KEY_F5 0x0104 +#define KEY_F6 0x0105 +#define KEY_F7 0x0106 +#define KEY_F8 0x0107 +#define KEY_F9 0x0108 +#define KEY_F10 0x0109 +#define KEY_F11 0x010A +#define KEY_F12 0x010B + +#define KEY_UP 0x0120 +#define KEY_DOWN 0x0121 +#define KEY_LEFT 0x0122 +#define KEY_RIGHT 0x0123 +#define KEY_PGUP 0x0124 +#define KEY_PGDN 0x0125 +#define KEY_HOME 0x0126 +#define KEY_END 0x0127 +#define KEY_INSERT 0x0128 +#define KEY_DELETE 0x0129 + +int get_key(FILE *, clock_t); + +#endif /* LIBUTIL_GETKEY_H */ diff --git a/core/elflink/ipappend.c b/core/elflink/ipappend.c new file mode 100644 index 0000000..bd00092 --- /dev/null +++ b/core/elflink/ipappend.c @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux/ipappend.c + * + * Get ipappend strings + */ + +#include +#include +#include + +struct syslinux_ipappend_strings __syslinux_ipappend_strings; +static const char *syslinux_ipappend_string_list[32]; + +void __constructor __syslinux_get_ipappend_strings(void) +{ + static com32sys_t reg; + int i; + + reg.eax.w[0] = 0x000f; + __intcall(0x22, ®, ®); + + if (!(reg.eflags.l & EFLAGS_CF)) { + __syslinux_ipappend_strings.count = reg.ecx.w[0]; + __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list; + for (i = 0; i < reg.ecx.w[0]; i++) { + syslinux_ipappend_string_list[i] = + MK_PTR(reg.es, + *(uint16_t *) MK_PTR(reg.es, reg.ebx.w[0] + i * 2)); + } + } +} diff --git a/core/elflink/kernel.c b/core/elflink/kernel.c new file mode 100644 index 0000000..f8efa16 --- /dev/null +++ b/core/elflink/kernel.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "core-elf.h" + +/* Will be called from readconfig.c */ +int new_linux_kernel(char *okernel, char *ocmdline) +{ + const char *kernel_name; + struct initramfs *initramfs; + char *temp; + void *kernel_data; + size_t kernel_len; + bool opt_quiet = false; + char initrd_name[256]; + char cmdline_buf[256], *cmdline; + int i; + + /* to make malloc works for code in com32/lib */ + /* + openconsole(&dev_null_r, &dev_stdcon_w); + init_memory_arena(); + */ + + mp("okernel = %s, ocmdline = %s", okernel, ocmdline); + + cmdline = cmdline_buf; + + temp = cmdline; + /* + strcpy(temp, "BOOT_IMAGE="); + temp += 11; + */ + + if (okernel) + kernel_name = okernel; + else if (globaldefault) + kernel_name = globaldefault; + + strcpy(temp, kernel_name); + temp += strlen(kernel_name); + + /* in elflink branch, KernelCName no more exist */ + /* + else { + strcpy(temp, KernelCName); + temp += strlen(KernelCName); + kernel_name = KernelCName; + } + */ + + *temp = ' '; + temp++; + if (ocmdline) + strcpy(temp, ocmdline); + else if (append) + strcpy(temp, append); + /* + else if (*(char *)CmdOptPtr) + strcpy(temp, (char *)CmdOptPtr); + else if (AppendLen) { + for (i = 0; i < AppendLen; i++) + *temp++ = AppendBuf[i]; + *temp = '\0'; + } + */ + + printf("cmdline = %s\n", cmdline); + /* + printf("VkernelEnd = %x\n", VKernelEnd); + printf("HighMemSize = %x\n", __com32.cs_memsize); + */ + + /* "keeppxe" handling */ +#if IS_PXELINUX + extern char KeepPXE; + + if (strstr(cmdline, "keeppxe")) + KeepPXE |= 1; +#endif + + if (strstr(cmdline, "quiet")) + opt_quiet = true; + + if (!opt_quiet) + printf("Loading %s... ", kernel_name); + + if (loadfile(kernel_name, &kernel_data, &kernel_len)) { + if (opt_quiet) + printf("Loading %s ", kernel_name); + printf("failed!\n"); + goto bail; + } + + if (!opt_quiet) + printf("ok\n"); + + /* Initialize the initramfs chain */ + initramfs = initramfs_init(); + if (!initramfs) + goto bail; + + /* Find and load initramfs */ + temp = strstr(cmdline, "initrd="); + if (temp) { + i = 0; + + temp += strlen("initrd="); + while (*temp != ' ' && *temp) + initrd_name[i++] = *temp++; + initrd_name[i] = '\0'; + + initramfs_load_archive(initramfs, initrd_name); + } + + //mp("loading initrd done"); + + /* This should not return... */ + syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline); + +bail: + printf("Kernel load failure (insufficient memory?)\n"); + return 1; +} diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c new file mode 100644 index 0000000..4004162 --- /dev/null +++ b/core/elflink/load_env32.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "common.h" +#include "menu.h" +#include "cli.h" +#include "core-elf.h" + +typedef void (*constructor_t) (void); +constructor_t __ctors_start[], __ctors_end[]; + +extern char __dynstr_start[]; +extern char __dynstr_len[], __dynsym_len[]; +extern char __dynsym_start[]; +extern char __got_start[]; +extern Elf32_Dyn __dynamic_start[]; +extern Elf32_Word __gnu_hash_start[]; + +struct elf_module core_module = { + .name = "(core)", + .shallow = true, + .required = LIST_HEAD_INIT((core_module.required)), + .dependants = LIST_HEAD_INIT((core_module.dependants)), + .list = LIST_HEAD_INIT((core_module.list)), + .module_addr = (void *)0x0, + .base_addr = (Elf32_Addr) 0x0, + .ghash_table = __gnu_hash_start, + .str_table = __dynstr_start, + .sym_table = __dynsym_start, + .got = __got_start, + .dyn_table = __dynamic_start, + .strtable_size = (size_t) __dynstr_len, + .syment_size = sizeof(Elf32_Sym), + .symtable_size = (size_t) __dynsym_len +}; + +/* + Initializes the module subsystem by taking the core module ( shallow module ) and placing + it on top of the modules_head_list. Since the core module is initialized when declared + we technically don't need the exec_init() and module_load_shallow() procedures +*/ +void init_module_subsystem(struct elf_module *module) +{ + list_add(&module->list, &modules_head); +} + +/* call_constr: initializes sme things related */ +static void call_constr(void) +{ + constructor_t *p; + + for (p = __ctors_start; p < __ctors_end; p++) + (*p) (); +} + +void enter_cmdline(void) +{ + struct cli_command *comm, *aux; + char *cmdline; + + /* Enter endless command line prompt, should support "exit" */ + while (1) { + cmdline = edit_cmdline("", 1, NULL, NULL); + /* feng: give up the aux check here */ + //aux = list_entry(cli_history_head.next, typeof(*aux), list); + //if (strcmp(aux->command, cmdline)) { + comm = (struct cli_command *)malloc(sizeof(struct cli_command *)); + comm->command = + (char *)malloc(sizeof(char) * (strlen(cmdline) + 1)); + strcpy(comm->command, cmdline); + list_add(&(comm->list), &cli_history_head); + process_command(cmdline); + //} + } +} + +/* parameter is the config file name if any */ +void start_ui(char *config_file) +{ + char *cmdline; + char *argv[2] = {config_file, NULL}; + + parse_configs(argv); + /* run the default menu if found */ + /* + if (default_menu) { + cmdline = default_menu->menu_entries[default_menu->defentry]->cmdline; + if (*cmdline == '.') { + while (*cmdline++ != ' '); + } + process_command(cmdline); + } + */ + + /* try to run a default linux kernel */ + /* + if (append || globaldefault) + new_linux_kernel(NULL, NULL); + */ + + /* Should never return */ + enter_cmdline(); +} + +/* note to self: do _*NOT*_ use static key word on this function */ +void load_env32(com32sys_t * regs) +{ + call_constr(); + openconsole(&dev_rawcon_r, &dev_ansiserial_w); + INIT_LIST_HEAD(&cli_history_head); + + printf("Starting 32 bit elf module subsystem...\n"); + init_module_subsystem(&core_module); + + start_ui(NULL); +} diff --git a/core/elflink/menu.h b/core/elflink/menu.h new file mode 100644 index 0000000..3bdf2d4 --- /dev/null +++ b/core/elflink/menu.h @@ -0,0 +1,229 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * This program 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * menu.h + * + * Header file for the simple menu system + */ + +#ifndef MENU_H +#define MENU_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "refstr.h" + +#ifndef CLK_TCK +# define CLK_TCK sysconf(_SC_CLK_TCK) +#endif + +struct menu; + +/* Note: the _UNRES variants must always be immediately after their + "normal" versions. */ +enum menu_action { + MA_NONE, /* Undefined value */ + MA_CMD, /* Execute a command */ + MA_DISABLED, /* Disabled menu entry */ + MA_SUBMENU, /* This is a submenu entry */ + MA_GOTO, /* Go to another menu */ + MA_GOTO_UNRES, /* Unresolved go to */ + MA_QUIT, /* Quit to CLI */ + MA_EXIT, /* Exit to higher-level menu */ + MA_EXIT_UNRES, /* Unresolved exit */ +}; + +struct menu_entry { + struct menu *menu; /* Parent menu */ + const char *displayname; + const char *label; + const char *passwd; + char *helptext; + const char *cmdline; + struct menu *submenu; + struct menu_entry *next; /* Linked list of all labels across menus */ + int entry; /* Entry number inside menu */ + enum menu_action action; + unsigned char hotkey; + bool save; /* Save this entry if selected */ +}; + +static inline bool is_disabled(struct menu_entry *me) +{ + return me->action == MA_DISABLED; +} + +enum kernel_type { + /* Meta-types for internal use */ + KT_NONE, + KT_LOCALBOOT, + + /* The ones we can pass off to SYSLINUX, in order */ + KT_KERNEL, /* Undefined type */ + KT_LINUX, /* Linux kernel */ + KT_BOOT, /* Bootstrap program */ + KT_BSS, /* Boot sector with patch */ + KT_PXE, /* PXE NBP */ + KT_FDIMAGE, /* Floppy disk image */ + KT_COMBOOT, /* COMBOOT image */ + KT_COM32, /* COM32 image */ + KT_CONFIG, /* Configuration file */ +}; + +extern const char *const kernel_types[]; + +/* Configurable integer parameters */ +enum parameter_number { + P_WIDTH, + P_MARGIN, + P_PASSWD_MARGIN, + P_MENU_ROWS, + P_TABMSG_ROW, + P_CMDLINE_ROW, + P_END_ROW, + P_PASSWD_ROW, + P_TIMEOUT_ROW, + P_HELPMSG_ROW, + P_HELPMSGEND_ROW, + P_HSHIFT, + P_VSHIFT, + P_HIDDEN_ROW, + + NPARAMS +}; + +/* Configurable messages */ +enum message_number { + MSG_TITLE, + MSG_AUTOBOOT, + MSG_TAB, + MSG_NOTAB, + MSG_PASSPROMPT, + + MSG_COUNT +}; + +struct messages { + const char *name; /* Message configuration name */ + const char *defmsg; /* Default message text */ +}; + +struct menu_parameter { + const char *name; + int value; +}; + +extern const struct menu_parameter mparm[NPARAMS]; + +struct fkey_help { + const char *textname; + const char *background; +}; + +struct menu { + struct menu *next; /* Linked list of all menus */ + const char *label; /* Goto label for this menu */ + struct menu *parent; + struct menu_entry *parent_entry; /* Entry for self in parent */ + + struct menu_entry **menu_entries; + struct menu_entry *menu_hotkeys[256]; + + const char *messages[MSG_COUNT]; + int mparm[NPARAMS]; + + int nentries; + int nentries_space; + int defentry; + int timeout; + + bool allowedit; + bool save; /* MENU SAVE default for this menu */ + + int curentry; + int curtop; + + const char *title; + const char *ontimeout; + const char *onerror; + const char *menu_master_passwd; + const char *menu_background; + + struct color_table *color_table; + + struct fkey_help fkeyhelp[12]; +}; + +extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list; + +/* 2048 is the current definition inside syslinux */ +#define MAX_CMDLINE_LEN 2048 + +/* These are global parameters regardless of which menu we're displaying */ +extern int shiftkey; +extern int hiddenmenu; +extern long long totaltimeout; +jmp_buf timeout_jump; + +void parse_configs(char **argv); +extern int draw_background(const char *filename); + +static inline int my_isspace(char c) +{ + return (unsigned char)c <= ' '; +} + +int my_isxdigit(char c); +unsigned int hexval(char c); +unsigned int hexval2(const char *p); +uint32_t parse_argb(char **p); + +int menu_main(int argc, char *argv[]); +void console_prepare(void); +void console_cleanup(void); + +extern const int message_base_color, menu_color_table_size; +int mygetkey(clock_t timeout); +int show_message_file(const char *filename, const char *background); + +/* passwd.c */ +int passwd_compare(const char *passwd, const char *entry); + +/* colors.c */ +#define MSG_COLORS_DEF_FG 0x90ffffff +#define MSG_COLORS_DEF_BG 0x80ffffff +#define MSG_COLORS_DEF_SHADOW SHADOW_NORMAL +void set_msg_colors_global(struct color_table *tbl, + unsigned int fg, unsigned int bg, + enum color_table_shadow shadow); +struct color_table *default_color_table(void); +struct color_table *copy_color_table(const struct color_table *master); +extern const int message_base_color; + +/* background.c */ +extern const char *current_background; +void set_background(const char *new_background); + +/* execute.c */ +void execute(const char *cmdline, enum kernel_type type); + +/* drain.c */ +void drain_keyboard(void); + +#endif /* MENU_H */ diff --git a/core/elflink/readconfig.c b/core/elflink/readconfig.c new file mode 100644 index 0000000..faeda02 --- /dev/null +++ b/core/elflink/readconfig.c @@ -0,0 +1,1183 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This program 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "menu.h" + +const struct menu_parameter mparm[NPARAMS] = { + [P_WIDTH] = {"width", 0}, + [P_MARGIN] = {"margin", 10}, + [P_PASSWD_MARGIN] = {"passwordmargin", 3}, + [P_MENU_ROWS] = {"rows", 12}, + [P_TABMSG_ROW] = {"tabmsgrow", 18}, + [P_CMDLINE_ROW] = {"cmdlinerow", 18}, + [P_END_ROW] = {"endrow", -1}, + [P_PASSWD_ROW] = {"passwordrow", 11}, + [P_TIMEOUT_ROW] = {"timeoutrow", 20}, + [P_HELPMSG_ROW] = {"helpmsgrow", 22}, + [P_HELPMSGEND_ROW] = {"helpmsgendrow", -1}, + [P_HSHIFT] = {"hshift", 0}, + [P_VSHIFT] = {"vshift", 0}, + [P_HIDDEN_ROW] = {"hiddenrow", -2}, +}; + +short uappendlen; //bytes in append= command +short ontimeoutlen; //bytes in ontimeout command +short onerrorlen; //bytes in onerror command +short forceprompt; //force prompt +short noescape; //no escape +short nocomplete; //no label completion on TAB key +short allowimplicit = 1; //allow implicit kernels +short allowoptions = 1; //user-specified options allowed +short includelevel = 1; //nesting level +short defaultlevel; //the current level of default +short vkernel; //have we seen any "label" statements? +short displaycon = 1; //conio.inc +short nohalt = 1; //idle.inc + + +/* Empty refstring */ +const char *empty_string; + +/* Root menu, starting menu, hidden menu, and list of all menus */ +struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu; + +/* These are global parameters regardless of which menu we're displaying */ +int shiftkey = 0; /* Only display menu if shift key pressed */ +int hiddenmenu = 0; +long long totaltimeout = 0; + +/* Keep track of global default */ +static int has_ui = 0; /* DEFAULT only counts if UI is found */ +char *globaldefault = NULL; +static bool menusave = false; /* True if there is any "menu save" */ + +/* Linked list of all entires, hidden or not; used by unlabel() */ +static struct menu_entry *all_entries; +static struct menu_entry **all_entries_end = &all_entries; + +static const struct messages messages[MSG_COUNT] = { + [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."}, + [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"}, + [MSG_NOTAB] = {"notabmsg", ""}, + [MSG_PASSPROMPT] = {"passprompt", "Password required"}, +}; + +#define astrdup(x) ({ char *__x = (x); \ + size_t __n = strlen(__x) + 1; \ + char *__p = alloca(__n); \ + if ( __p ) memcpy(__p, __x, __n); \ + __p; }) + +/* Must match enum kernel_type */ +const char *const kernel_types[] = { + "none", + "localboot", + "kernel", + "linux", + "boot", + "bss", + "pxe", + "fdimage", + "comboot", + "com32", + "config", + NULL +}; + +/* + * Search the list of all menus for a specific label + */ +static struct menu *find_menu(const char *label) +{ + struct menu *m; + + for (m = menu_list; m; m = m->next) { + if (!strcmp(label, m->label)) + return m; + } + + return NULL; +} + +#define MAX_LINE 4096 + +static char *skipspace(char *p) +{ + while (*p && my_isspace(*p)) + p++; + + return p; +} + +/* Strip ^ from a string, returning a new reference to the same refstring + if none present */ +static const char *strip_caret(const char *str) +{ + const char *p, *r; + char *q; + int carets = 0; + + p = str; + for (;;) { + p = strchr(p, '^'); + if (!p) + break; + carets++; + p++; + } + + if (!carets) + return refstr_get(str); + + r = q = refstr_alloc(strlen(str) - carets); + for (p = str; *p; p++) + if (*p != '^') + *q++ = *p; + + *q = '\0'; /* refstr_alloc() already did this... */ + + return r; +} + +/* Check to see if we are at a certain keyword (case insensitive) */ +/* Returns a pointer to the first character past the keyword */ +static char *looking_at(char *line, const char *kwd) +{ + char *p = line; + const char *q = kwd; + + while (*p && *q && ((*p ^ *q) & ~0x20) == 0) { + p++; + q++; + } + + if (*q) + return NULL; /* Didn't see the keyword */ + + return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */ +} + +static struct menu *new_menu(struct menu *parent, + struct menu_entry *parent_entry, const char *label) +{ + struct menu *m = calloc(1, sizeof(struct menu)); + int i; + + //mp("enter: menu_label = %s", label); + + m->label = label; + m->title = refstr_get(empty_string); + + if (parent) { + /* Submenu */ + m->parent = parent; + m->parent_entry = parent_entry; + parent_entry->action = MA_SUBMENU; + parent_entry->submenu = m; + + for (i = 0; i < MSG_COUNT; i++) + m->messages[i] = refstr_get(parent->messages[i]); + + memcpy(m->mparm, parent->mparm, sizeof m->mparm); + + m->allowedit = parent->allowedit; + m->timeout = parent->timeout; + m->save = parent->save; + + m->ontimeout = refstr_get(parent->ontimeout); + m->onerror = refstr_get(parent->onerror); + m->menu_master_passwd = refstr_get(parent->menu_master_passwd); + m->menu_background = refstr_get(parent->menu_background); + + m->color_table = copy_color_table(parent->color_table); + + for (i = 0; i < 12; i++) { + m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname); + m->fkeyhelp[i].background = + refstr_get(parent->fkeyhelp[i].background); + } + } else { + /* Root menu */ + for (i = 0; i < MSG_COUNT; i++) + m->messages[i] = refstrdup(messages[i].defmsg); + for (i = 0; i < NPARAMS; i++) + m->mparm[i] = mparm[i].value; + + m->allowedit = true; /* Allow edits of the command line */ + m->color_table = default_color_table(); + } + + m->next = menu_list; + menu_list = m; + + return m; +} + +struct labeldata { + const char *label; + const char *kernel; + enum kernel_type type; + const char *append; + const char *initrd; + const char *menulabel; + const char *passwd; + char *helptext; + unsigned int ipappend; + unsigned int menuhide; + unsigned int menudefault; + unsigned int menuseparator; + unsigned int menudisabled; + unsigned int menuindent; + enum menu_action action; + int save; + struct menu *submenu; +}; + +/* Menu currently being parsed */ +static struct menu *current_menu; + +static void clear_label_data(struct labeldata *ld) +{ + refstr_put(ld->label); + refstr_put(ld->kernel); + refstr_put(ld->append); + refstr_put(ld->initrd); + refstr_put(ld->menulabel); + refstr_put(ld->passwd); + + memset(ld, 0, sizeof *ld); +} + +static struct menu_entry *new_entry(struct menu *m) +{ + struct menu_entry *me; + + //mp("enter, call from menu %s", m->label); + + if (m->nentries >= m->nentries_space) { + if (!m->nentries_space) + m->nentries_space = 1; + else + m->nentries_space <<= 1; + + m->menu_entries = realloc(m->menu_entries, m->nentries_space * + sizeof(struct menu_entry *)); + } + + me = calloc(1, sizeof(struct menu_entry)); + me->menu = m; + me->entry = m->nentries; + m->menu_entries[m->nentries++] = me; + *all_entries_end = me; + all_entries_end = &me->next; + + return me; +} + +static void consider_for_hotkey(struct menu *m, struct menu_entry *me) +{ + const char *p = strchr(me->displayname, '^'); + + if (me->action != MA_DISABLED) { + if (p && p[1]) { + unsigned char hotkey = p[1] & ~0x20; + if (!m->menu_hotkeys[hotkey]) { + me->hotkey = hotkey; + m->menu_hotkeys[hotkey] = me; + } + } + } +} + +static void record(struct menu *m, struct labeldata *ld, const char *append) +{ + int i; + struct menu_entry *me; + const struct syslinux_ipappend_strings *ipappend; + + if (!ld->label) + return; /* Nothing defined */ + + /* Hidden entries are recorded on a special "hidden menu" */ + if (ld->menuhide) + m = hide_menu; + + char ipoptions[4096], *ipp; + const char *a; + char *s; + + me = new_entry(m); + + me->displayname = ld->menulabel + ? refstr_get(ld->menulabel) : refstr_get(ld->label); + me->label = refstr_get(ld->label); + me->passwd = refstr_get(ld->passwd); + me->helptext = ld->helptext; + me->hotkey = 0; + me->action = ld->action ? ld->action : MA_CMD; + me->save = ld->save ? (ld->save > 0) : m->save; + + if (ld->menuindent) { + const char *dn; + + rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname); + refstr_put(me->displayname); + me->displayname = dn; + } + + if (ld->menuseparator) { + refstr_put(me->displayname); + me->displayname = refstr_get(empty_string); + } + + if (ld->menuseparator || ld->menudisabled) { + me->action = MA_DISABLED; + refstr_put(me->label); + me->label = NULL; + refstr_put(me->passwd); + me->passwd = NULL; + } + + if (ld->menulabel) + consider_for_hotkey(m, me); + + switch (me->action) { + case MA_CMD: + ipp = ipoptions; + *ipp = '\0'; + + if (ld->initrd) + ipp += sprintf(ipp, " initrd=%s", ld->initrd); + + if (ld->ipappend) { + ipappend = syslinux_ipappend_strings(); + for (i = 0; i < ipappend->count; i++) { + if ((ld->ipappend & (1U << i)) && ipappend->ptr[i]) + ipp += sprintf(ipp, " %s", ipappend->ptr[i]); + } + } + + a = ld->append; + if (!a) + a = append; + if (!a || (a[0] == '-' && !a[1])) + a = ""; + s = a[0] ? " " : ""; + + if (ld->type == KT_KERNEL) + rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions); + else + rsprintf(&me->cmdline, ".%s %s%s%s%s", + kernel_types[ld->type], ld->kernel, s, a, ipoptions); + mp("type = %s, cmd = %s", kernel_types[ld->type], me->cmdline); + break; + + case MA_GOTO_UNRES: + case MA_EXIT_UNRES: + me->cmdline = refstr_get(ld->kernel); + break; + + case MA_GOTO: + case MA_EXIT: + me->submenu = ld->submenu; + break; + + default: + break; + } + + if (ld->menudefault && me->action == MA_CMD) + m->defentry = m->nentries - 1; + + clear_label_data(ld); +} + +static struct menu *begin_submenu(const char *tag) +{ + struct menu_entry *me; + + if (!tag[0]) + tag = NULL; + + me = new_entry(current_menu); + me->displayname = refstrdup(tag); + return new_menu(current_menu, me, refstr_get(me->displayname)); +} + +static struct menu *end_submenu(void) +{ + return current_menu->parent ? current_menu->parent : current_menu; +} + +static struct menu_entry *find_label(const char *str) +{ + const char *p; + struct menu_entry *me; + int pos; + + p = str; + while (*p && !my_isspace(*p)) + p++; + + /* p now points to the first byte beyond the kernel name */ + pos = p - str; + + for (me = all_entries; me; me = me->next) { + if (!strncmp(str, me->label, pos) && !me->label[pos]) + return me; + } + + return NULL; +} + +static const char *unlabel(const char *str) +{ + /* Convert a CLI-style command line to an executable command line */ + const char *p; + const char *q; + struct menu_entry *me; + int pos; + + p = str; + while (*p && !my_isspace(*p)) + p++; + + /* p now points to the first byte beyond the kernel name */ + pos = p - str; + + for (me = all_entries; me; me = me->next) { + if (!strncmp(str, me->label, pos) && !me->label[pos]) { + /* Found matching label */ + rsprintf(&q, "%s%s", me->cmdline, p); + refstr_put(str); + return q; + } + } + + return str; +} + +static const char *refdup_word(char **p) +{ + char *sp = *p; + char *ep = sp; + + while (*ep && !my_isspace(*ep)) + ep++; + + *p = ep; + return refstrndup(sp, ep - sp); +} + +int my_isxdigit(char c) +{ + unsigned int uc = c; + + return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6; +} + +unsigned int hexval(char c) +{ + unsigned char uc = c | 0x20; + unsigned int v; + + v = uc - '0'; + if (v < 10) + return v; + + return uc - 'a' + 10; +} + +unsigned int hexval2(const char *p) +{ + return (hexval(p[0]) << 4) + hexval(p[1]); +} + +uint32_t parse_argb(char **p) +{ + char *sp = *p; + char *ep; + uint32_t argb; + size_t len, dl; + + if (*sp == '#') + sp++; + + ep = sp; + + while (my_isxdigit(*ep)) + ep++; + + *p = ep; + len = ep - sp; + + switch (len) { + case 3: /* #rgb */ + argb = + 0xff000000 + + (hexval(sp[0]) * 0x11 << 16) + + (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11); + break; + case 4: /* #argb */ + argb = + (hexval(sp[0]) * 0x11 << 24) + + (hexval(sp[1]) * 0x11 << 16) + + (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11); + break; + case 6: /* #rrggbb */ + case 9: /* #rrrgggbbb */ + case 12: /* #rrrrggggbbbb */ + dl = len / 3; + argb = + 0xff000000 + + (hexval2(sp + 0) << 16) + + (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2); + break; + case 8: /* #aarrggbb */ + /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb, + assume the latter is a more common format */ + case 16: /* #aaaarrrrggggbbbb */ + dl = len / 4; + argb = + (hexval2(sp + 0) << 24) + + (hexval2(sp + dl) << 16) + + (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3); + break; + default: + argb = 0xffff0000; /* Bright red (error indication) */ + break; + } + + return argb; +} + +/* + * Parser state. This is global so that including multiple + * files work as expected, which is that everything works the + * same way as if the files had been concatenated together. + */ +//static const char *append = NULL; +char *append = NULL; +//static unsigned int ipappend = 0; +unsigned int ipappend = 0; +static struct labeldata ld; + +static int parse_one_config(const char *filename); + +static char *is_kernel_type(char *cmdstr, enum kernel_type *type) +{ + const char *const *p; + char *q; + enum kernel_type t = KT_NONE; + + for (p = kernel_types; *p; p++, t++) { + if ((q = looking_at(cmdstr, *p))) { + *type = t; + return q; + } + } + + return NULL; +} + +static char *is_message_name(char *cmdstr, enum message_number *msgnr) +{ + char *q; + enum message_number i; + + for (i = 0; i < MSG_COUNT; i++) { + if ((q = looking_at(cmdstr, messages[i].name))) { + *msgnr = i; + return q; + } + } + + return NULL; +} + +static char *is_fkey(char *cmdstr, int *fkeyno) +{ + char *q; + int no; + + if ((cmdstr[0] | 0x20) != 'f') + return NULL; + + no = strtoul(cmdstr + 1, &q, 10); + if (!my_isspace(*q)) + return NULL; + + if (no < 0 || no > 12) + return NULL; + + *fkeyno = (no == 0) ? 10 : no - 1; + return q; +} + +static void parse_config_file(FILE * f) +{ + char line[MAX_LINE], *p, *ep, ch; + enum kernel_type type; + enum message_number msgnr; + int fkeyno; + struct menu *m = current_menu; + + while (fgets(line, sizeof line, f)) { + p = strchr(line, '\r'); + if (p) + *p = '\0'; + p = strchr(line, '\n'); + if (p) + *p = '\0'; + + p = skipspace(line); + + if (looking_at(p, "menu")) { + + p = skipspace(p + 4); + + if (looking_at(p, "label")) { + if (ld.label) { + refstr_put(ld.menulabel); + ld.menulabel = refstrdup(skipspace(p + 5)); + } else if (m->parent_entry) { + refstr_put(m->parent_entry->displayname); + m->parent_entry->displayname = refstrdup(skipspace(p + 5)); + consider_for_hotkey(m->parent, m->parent_entry); + if (!m->title[0]) { + /* MENU LABEL -> MENU TITLE on submenu */ + refstr_put(m->title); + m->title = strip_caret(m->parent_entry->displayname); + } + } + } else if (looking_at(p, "title")) { + refstr_put(m->title); + m->title = refstrdup(skipspace(p + 5)); + if (m->parent_entry) { + /* MENU TITLE -> MENU LABEL on submenu */ + if (m->parent_entry->displayname == m->label) { + refstr_put(m->parent_entry->displayname); + m->parent_entry->displayname = refstr_get(m->title); + } + } + } else if (looking_at(p, "default")) { + if (ld.label) { + ld.menudefault = 1; + } else if (m->parent_entry) { + m->parent->defentry = m->parent_entry->entry; + } + } else if (looking_at(p, "hide")) { + ld.menuhide = 1; + } else if (looking_at(p, "passwd")) { + if (ld.label) { + refstr_put(ld.passwd); + ld.passwd = refstrdup(skipspace(p + 6)); + } else if (m->parent_entry) { + refstr_put(m->parent_entry->passwd); + m->parent_entry->passwd = refstrdup(skipspace(p + 6)); + } + } else if (looking_at(p, "shiftkey")) { + shiftkey = 1; + } else if (looking_at(p, "save")) { + menusave = true; + if (ld.label) + ld.save = 1; + else + m->save = true; + } else if (looking_at(p, "nosave")) { + if (ld.label) + ld.save = -1; + else + m->save = false; + } else if (looking_at(p, "onerror")) { + refstr_put(m->onerror); + m->onerror = refstrdup(skipspace(p + 7)); + onerrorlen = strlen(m->onerror); + } else if (looking_at(p, "master")) { + p = skipspace(p + 6); + if (looking_at(p, "passwd")) { + refstr_put(m->menu_master_passwd); + m->menu_master_passwd = refstrdup(skipspace(p + 6)); + } + } else if ((ep = looking_at(p, "include"))) { + goto do_include; + } else if ((ep = looking_at(p, "background"))) { + p = skipspace(ep); + refstr_put(m->menu_background); + m->menu_background = refdup_word(&p); + } else if ((ep = looking_at(p, "hidden"))) { + hiddenmenu = 1; + } else if ((ep = is_message_name(p, &msgnr))) { + refstr_put(m->messages[msgnr]); + m->messages[msgnr] = refstrdup(skipspace(ep)); + } else if ((ep = looking_at(p, "color")) || + (ep = looking_at(p, "colour"))) { + int i; + struct color_table *cptr; + p = skipspace(ep); + cptr = m->color_table; + for (i = 0; i < menu_color_table_size; i++) { + if ((ep = looking_at(p, cptr->name))) { + p = skipspace(ep); + if (*p) { + if (looking_at(p, "*")) { + p++; + } else { + refstr_put(cptr->ansi); + cptr->ansi = refdup_word(&p); + } + + p = skipspace(p); + if (*p) { + if (looking_at(p, "*")) + p++; + else + cptr->argb_fg = parse_argb(&p); + + p = skipspace(p); + if (*p) { + if (looking_at(p, "*")) + p++; + else + cptr->argb_bg = parse_argb(&p); + + /* Parse a shadow mode */ + p = skipspace(p); + ch = *p | 0x20; + if (ch == 'n') /* none */ + cptr->shadow = SHADOW_NONE; + else if (ch == 's') /* std, standard */ + cptr->shadow = SHADOW_NORMAL; + else if (ch == 'a') /* all */ + cptr->shadow = SHADOW_ALL; + else if (ch == 'r') /* rev, reverse */ + cptr->shadow = SHADOW_REVERSE; + } + } + } + break; + } + cptr++; + } + } else if ((ep = looking_at(p, "msgcolor")) || + (ep = looking_at(p, "msgcolour"))) { + unsigned int fg_mask = MSG_COLORS_DEF_FG; + unsigned int bg_mask = MSG_COLORS_DEF_BG; + enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW; + + p = skipspace(ep); + if (*p) { + if (!looking_at(p, "*")) + fg_mask = parse_argb(&p); + + p = skipspace(p); + if (*p) { + if (!looking_at(p, "*")) + bg_mask = parse_argb(&p); + + p = skipspace(p); + switch (*p | 0x20) { + case 'n': + shadow = SHADOW_NONE; + break; + case 's': + shadow = SHADOW_NORMAL; + break; + case 'a': + shadow = SHADOW_ALL; + break; + case 'r': + shadow = SHADOW_REVERSE; + break; + default: + /* go with default */ + break; + } + } + } + set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow); + } else if (looking_at(p, "separator")) { + record(m, &ld, append); + ld.label = refstr_get(empty_string); + ld.menuseparator = 1; + record(m, &ld, append); + } else if (looking_at(p, "disable") || looking_at(p, "disabled")) { + ld.menudisabled = 1; + } else if (looking_at(p, "indent")) { + ld.menuindent = atoi(skipspace(p + 6)); + } else if (looking_at(p, "begin")) { + record(m, &ld, append); + m = current_menu = begin_submenu(skipspace(p + 5)); + } else if (looking_at(p, "end")) { + record(m, &ld, append); + m = current_menu = end_submenu(); + } else if (looking_at(p, "quit")) { + if (ld.label) + ld.action = MA_QUIT; + } else if (looking_at(p, "goto")) { + if (ld.label) { + ld.action = MA_GOTO_UNRES; + refstr_put(ld.kernel); + ld.kernel = refstrdup(skipspace(p + 4)); + } + } else if (looking_at(p, "exit")) { + p = skipspace(p + 4); + if (ld.label && m->parent) { + if (*p) { + /* This is really just a goto, except for the marker */ + ld.action = MA_EXIT_UNRES; + refstr_put(ld.kernel); + ld.kernel = refstrdup(p); + } else { + ld.action = MA_EXIT; + ld.submenu = m->parent; + } + } + } else if (looking_at(p, "start")) { + start_menu = m; + } else { + /* Unknown, check for layout parameters */ + enum parameter_number mp; + for (mp = 0; mp < NPARAMS; mp++) { + if ((ep = looking_at(p, mparm[mp].name))) { + m->mparm[mp] = atoi(skipspace(ep)); + break; + } + } + } + } + /* feng: menu handling end */ + else if (looking_at(p, "text")) { + + /* loop till we fined the "endtext" */ + enum text_cmd { + TEXT_UNKNOWN, + TEXT_HELP + } cmd = TEXT_UNKNOWN; + int len = ld.helptext ? strlen(ld.helptext) : 0; + int xlen; + + p = skipspace(p + 4); + + if (looking_at(p, "help")) + cmd = TEXT_HELP; + + while (fgets(line, sizeof line, f)) { + p = skipspace(line); + if (looking_at(p, "endtext")) + break; + + xlen = strlen(line); + + switch (cmd) { + case TEXT_UNKNOWN: + break; + case TEXT_HELP: + ld.helptext = realloc(ld.helptext, len + xlen + 1); + memcpy(ld.helptext + len, line, xlen + 1); + len += xlen; + break; + } + } + } else if ((ep = is_fkey(p, &fkeyno))) { + p = skipspace(ep); + if (m->fkeyhelp[fkeyno].textname) { + refstr_put(m->fkeyhelp[fkeyno].textname); + m->fkeyhelp[fkeyno].textname = NULL; + } + if (m->fkeyhelp[fkeyno].background) { + refstr_put(m->fkeyhelp[fkeyno].background); + m->fkeyhelp[fkeyno].background = NULL; + } + + refstr_put(m->fkeyhelp[fkeyno].textname); + m->fkeyhelp[fkeyno].textname = refdup_word(&p); + if (*p) { + p = skipspace(p); + m->fkeyhelp[fkeyno].background = refdup_word(&p); + } + } else if ((ep = looking_at(p, "include"))) { +do_include: + { + const char *file; + p = skipspace(ep); + file = refdup_word(&p); + p = skipspace(p); + if (*p) { + record(m, &ld, append); + m = current_menu = begin_submenu(p); + parse_one_config(file); + record(m, &ld, append); + m = current_menu = end_submenu(); + } else { + parse_one_config(file); + } + refstr_put(file); + } + } else if (looking_at(p, "append")) { + const char *a = refstrdup(skipspace(p + 6)); + if (ld.label) { + refstr_put(ld.append); + ld.append = a; + } else { + refstr_put(append); + append = a; + } + //mp("we got a append: %s", a); + } else if (looking_at(p, "initrd")) { + const char *a = refstrdup(skipspace(p + 6)); + if (ld.label) { + refstr_put(ld.initrd); + ld.initrd = a; + } else { + /* Ignore */ + } + } else if (looking_at(p, "label")) { + p = skipspace(p + 5); + /* when first time see "label", it will not really record anything */ + record(m, &ld, append); + ld.label = refstrdup(p); + ld.kernel = refstrdup(p); + /* feng: this is the default type for all */ + ld.type = KT_KERNEL; + ld.passwd = NULL; + ld.append = NULL; + ld.initrd = NULL; + ld.menulabel = NULL; + ld.helptext = NULL; + ld.ipappend = ipappend; + ld.menudefault = ld.menuhide = ld.menuseparator = + ld.menudisabled = ld.menuindent = 0; + } else if ((ep = is_kernel_type(p, &type))) { + if (ld.label) { + refstr_put(ld.kernel); + ld.kernel = refstrdup(skipspace(ep)); + ld.type = type; + //mp("got a kernel: %s, type = %d", ld.kernel, ld.type); + } + } else if (looking_at(p, "timeout")) { + m->timeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10; + } else if (looking_at(p, "totaltimeout")) { + totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10; + } else if (looking_at(p, "ontimeout")) { + m->ontimeout = refstrdup(skipspace(p + 9)); + } else if (looking_at(p, "allowoptions")) { + m->allowedit = !!atoi(skipspace(p + 12)); + } else if (looking_at(p, "ipappend")) { + if (ld.label) + ld.ipappend = atoi(skipspace(p + 8)); + else + ipappend = atoi(skipspace(p + 8)); + } else if (looking_at(p, "default")) { + /* default could be a kernel image or another label */ + refstr_put(globaldefault); + globaldefault = refstrdup(skipspace(p + 7)); + } else if (looking_at(p, "ui")) { + has_ui = 1; + } + + /* + * subset 1: pc_opencmd + * display/font/kbdmap are rather similar, open a file then do sth + */ + else if (looking_at(p, "display")) { + + } else if (looking_at(p, "font")) { + + } else if (looking_at(p, "kbdmap")) { + + } + /* + * subset 2: pc_setint16 + * set a global flag + */ + else if (looking_at(p, "implicit")) { + allowimplicit = atoi(skipspace(p + 8)); + } else if (looking_at(p, "prompt")) { + forceprompt = atoi(skipspace(p + 8)); + } else if (looking_at(p, "console")) { + displaycon = atoi(skipspace(p + 7)); + } else if (looking_at(p, "allowoptions")) { + allowoptions = atoi(skipspace(p + 12)); + } else if (looking_at(p, "noescape")) { + noescape = atoi(skipspace(p + 8)); + } else if (looking_at(p, "nocomplete")) { + nocomplete = atoi(skipspace(p + 10)); + } else if (looking_at(p, "nohalt")) { + nohalt = atoi(skipspace(p + 8)); + } + + /* serial setting, bps, flow control */ + else if (looking_at(p, "serial")) { + /* core/conio.inc + * should be able to find some code in com32 + */ + + } else if (looking_at(p, "say")) { + printf("%s\n", p + 4); + } + } +} + +static int parse_one_config(const char *filename) +{ + FILE *f; + int i; + + /* + if (!strcmp(filename, "~")) + filename = syslinux_config_file(); + */ + + f = fopen(filename, "r"); + if (f) + goto config_found; + + /* force to use hard coded config file name */ + f = fopen("extlinux.conf", "r"); + if (f) + goto config_found; + + f = fopen("isolinux.cfg", "r"); + if (f) + goto config_found; + + return -1; +config_found: + parse_config_file(f); + fclose(f); + return 0; +} + +static void resolve_gotos(void) +{ + struct menu_entry *me; + struct menu *m; + + for (me = all_entries; me; me = me->next) { + if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) { + m = find_menu(me->cmdline); + refstr_put(me->cmdline); + me->cmdline = NULL; + if (m) { + me->submenu = m; + me->action--; /* Drop the _UNRES */ + } else { + me->action = MA_DISABLED; + } + } + } +} + +static void dump_menu(struct menu *menu) +{ + mp("will dump menu for %s:", menu->label); + printf("entries num: %d\n", menu->nentries); + printf("defentry: %d, nam = %s\n", + menu->defentry, menu->menu_entries[menu->defentry]->label); + printf("save: %d\n", menu->save); + //printf("", menu->); + //printf("", menu->); + //printf("", menu->); +} + +void parse_configs(char **argv) +{ + const char *filename; + struct menu *m; + struct menu_entry *me; + char *cmdline; + + empty_string = refstrdup(""); + + /* feng: reset current menu_list and entry list */ + menu_list = NULL; + all_entries = NULL; + + /* Initialize defaults for the root and hidden menus */ + hide_menu = new_menu(NULL, NULL, refstrdup(".hidden")); + root_menu = new_menu(NULL, NULL, refstrdup(".top")); + start_menu = root_menu; + + /* Other initialization */ + memset(&ld, 0, sizeof(struct labeldata)); + + /* Actually process the files */ + current_menu = root_menu; + + if (!argv || !*argv) { + parse_one_config("~"); + } else { + while ((filename = *argv++)) { + mp("Parsing config: %s", filename); + parse_one_config(filename); + } + } + + /* On final EOF process the last label statement */ + record(current_menu, &ld, append); + + /* Common postprocessing */ + resolve_gotos(); + + /* Handle global default */ + //if (has_ui && globaldefault) { + if (globaldefault) { + mp("gloabldefault = %s", globaldefault); + me = find_label(globaldefault); + if (me && me->menu != hide_menu) { + me->menu->defentry = me->entry; + start_menu = me->menu; + default_menu = me->menu; + } + } + + /* If "menu save" is active, let the ADV override the global default */ + if (menusave) { + size_t len; + const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len); + char *lstr; + if (lbl && len) { + lstr = refstr_alloc(len); + memcpy(lstr, lbl, len); /* refstr_alloc() adds the final null */ + me = find_label(lstr); + if (me && me->menu != hide_menu) { + me->menu->defentry = me->entry; + start_menu = me->menu; + } + refstr_put(lstr); + } + } + + /* Final per-menu initialization, with all labels known */ + for (m = menu_list; m; m = m->next) { + m->curentry = m->defentry; /* All menus start at their defaults */ + + if (m->ontimeout) + m->ontimeout = unlabel(m->ontimeout); + if (m->onerror) + m->onerror = unlabel(m->onerror); + } +} diff --git a/core/elflink/refstr.c b/core/elflink/refstr.c new file mode 100644 index 0000000..f9d98e1 --- /dev/null +++ b/core/elflink/refstr.c @@ -0,0 +1,106 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2008 H. Peter Anvin - All Rights Reserved + * + * This program 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * refstr.c + * + * Simple reference-counted strings + */ + +#include +#include +#include +#include +#include "refstr.h" + +/* Allocate space for a refstring of len bytes, plus final null */ +/* The final null is inserted in the string; the rest is uninitialized. */ +char *refstr_alloc(size_t len) +{ + char *r = malloc(sizeof(unsigned int) + len + 1); + if (!r) + return NULL; + *(unsigned int *)r = 1; + r += sizeof(unsigned int); + r[len] = '\0'; + return r; +} + +const char *refstrndup(const char *str, size_t len) +{ + char *r; + + if (!str) + return NULL; + + len = strnlen(str, len); + r = refstr_alloc(len); + if (r) + memcpy(r, str, len); + return r; +} + +const char *refstrdup(const char *str) +{ + char *r; + size_t len; + + if (!str) + return NULL; + + len = strlen(str); + r = refstr_alloc(len); + if (r) + memcpy(r, str, len); + return r; +} + +int vrsprintf(const char **bufp, const char *fmt, va_list ap) +{ + va_list ap1; + int len; + char *p; + + va_copy(ap1, ap); + len = vsnprintf(NULL, 0, fmt, ap1); + va_end(ap1); + + *bufp = p = refstr_alloc(len); + if (!p) + return -1; + + return vsnprintf(p, len + 1, fmt, ap); +} + +int rsprintf(const char **bufp, const char *fmt, ...) +{ + int rv; + va_list ap; + + va_start(ap, fmt); + rv = vrsprintf(bufp, fmt, ap); + va_end(ap); + + return rv; +} + +void refstr_put(const char *r) +{ + unsigned int *ref; + + if (r) { + ref = (unsigned int *)r - 1; + + if (!--*ref) + free(ref); + } +} diff --git a/core/elflink/refstr.h b/core/elflink/refstr.h new file mode 100644 index 0000000..7001d40 --- /dev/null +++ b/core/elflink/refstr.h @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2008 H. Peter Anvin - All Rights Reserved + * + * This program 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * refstr.h + * + * Simple reference-counted strings + */ + +#ifndef REFSTR_H +#define REFSTR_H + +#include +#include + +static inline __attribute__ ((always_inline)) +const char *refstr_get(const char *r) +{ + if (r) + ((unsigned int *)r)[-1]++; + return r; +} + +void refstr_put(const char *); +char *refstr_alloc(size_t); +const char *refstrdup(const char *); +const char *refstrndup(const char *, size_t); +int rsprintf(const char **, const char *, ...); +int vrsprintf(const char **, const char *, va_list); + +#endif diff --git a/core/elflink/setadv.c b/core/elflink/setadv.c new file mode 100644 index 0000000..40f00a4 --- /dev/null +++ b/core/elflink/setadv.c @@ -0,0 +1,116 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux/setadv.c + * + * (Over)write a data item in the auxilliary data vector. To + * delete an item, set its length to zero. + * + * Return 0 on success, -1 on error, and set errno. + * + * NOTE: Data is not written to disk unless + * syslinux_adv_write() is called. + */ + +#include +#include +#include +#include +#include +#include + +int syslinux_setadv(int tag, size_t size, const void *data) +{ + uint8_t *p, *advtmp; + size_t rleft, left; + + if ((unsigned)tag - 1 > 254) { + errno = EINVAL; + return -1; /* Impossible tag value */ + } + + if (size > 255) { + errno = ENOSPC; /* Max 255 bytes for a data item */ + return -1; + } + + rleft = left = syslinux_adv_size(); + p = advtmp = alloca(left); + memcpy(p, syslinux_adv_ptr(), left); /* Make working copy */ + + while (rleft >= 2) { + uint8_t ptag = p[0]; + size_t plen = p[1] + 2; + + if (ptag == ADV_END) + break; + + if (ptag == tag) { + /* Found our tag. Delete it. */ + + if (plen >= rleft) { + /* Entire remainder is our tag */ + break; + } + memmove(p, p + plen, rleft - plen); + rleft -= plen; /* Fewer bytes to read, but not to write */ + } else { + /* Not our tag */ + if (plen > rleft) + break; /* Corrupt tag (overrun) - overwrite it */ + + left -= plen; + rleft -= plen; + p += plen; + } + } + + /* Now (p, left) reflects the position to write in and how much space + we have for our data. */ + + if (size) { + if (left < size + 2) { + errno = ENOSPC; /* Not enough space for data */ + return -1; + } + + *p++ = tag; + *p++ = size; + memcpy(p, data, size); + p += size; + left -= size + 2; + } + + memset(p, 0, left); + + /* If we got here, everything went OK, commit the write to low memory */ + memcpy(syslinux_adv_ptr(), advtmp, syslinux_adv_size()); + + return 0; +} -- 2.7.4