diff options
Diffstat (limited to 'com32/elflink')
-rw-r--r-- | com32/elflink/ldlinux/Makefile | 38 | ||||
-rw-r--r-- | com32/elflink/ldlinux/adv.c | 49 | ||||
-rw-r--r-- | com32/elflink/ldlinux/cli.c | 438 | ||||
-rw-r--r-- | com32/elflink/ldlinux/colors.c | 184 | ||||
-rw-r--r-- | com32/elflink/ldlinux/getadv.c | 68 | ||||
-rw-r--r-- | com32/elflink/ldlinux/ipappend.c | 58 | ||||
-rw-r--r-- | com32/elflink/ldlinux/ldlinux.c | 34 | ||||
-rw-r--r-- | com32/elflink/ldlinux/readconfig.c | 1169 | ||||
-rw-r--r-- | com32/elflink/ldlinux/refstr.c | 106 | ||||
-rw-r--r-- | com32/elflink/ldlinux/refstr.h | 40 | ||||
-rw-r--r-- | com32/elflink/modules/Makefile | 2 | ||||
-rw-r--r-- | com32/elflink/modules/cli.h | 6 | ||||
-rw-r--r-- | com32/elflink/modules/menu.h | 17 | ||||
-rw-r--r-- | com32/elflink/modules/menumain.c | 1 |
14 files changed, 2191 insertions, 19 deletions
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile new file mode 100644 index 00000000..339e13ee --- /dev/null +++ b/com32/elflink/ldlinux/Makefile @@ -0,0 +1,38 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2011 Intel Corporation - 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., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +topdir = ../../.. +include ../modules/MCONFIG + +CFLAGS += -I../modules -I$(topdir)/core/elflink + +all: ldlinux.c32 + +ldlinux.c32 : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \ + adv.o ipappend.o + $(LD) $(LDFLAGS) -o $@ $^ + +tidy dist: + rm -f *.o *.lo *.a *.lst .*.d + +clean: tidy + rm -f *.lss *.lnx *.com *.c32 + +spotless: clean + rm -f *~ \#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR) + install -m 644 ldlinux.c32 $(INSTALLROOT)$(AUXDIR) + + +-include .*.d diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c new file mode 100644 index 00000000..be38e89d --- /dev/null +++ b/com32/elflink/ldlinux/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 <syslinux/adv.h> +#include <klibc/compiler.h> +#include <com32.h> + +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/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c new file mode 100644 index 00000000..551113f8 --- /dev/null +++ b/com32/elflink/ldlinux/cli.c @@ -0,0 +1,438 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <console.h> +#include <com32.h> +#include <syslinux/adv.h> +#include <syslinux/config.h> +#include <setjmp.h> +#include <netinet/in.h> +#include <limits.h> +#include <minmax.h> +#include <linux/list.h> +#include <sys/exec.h> +#include <sys/module.h> +#include <core-elf.h> + +#include "getkey.h" +#include "menu.h" +#include "cli.h" + +static jmp_buf timeout_jump; + +static struct list_head cli_history_head; + +void clear_screen(void) +{ + //mp("enter"); + 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; + + //mp("enter"); + if (!totaltimeout) + return get_key(stdin, timeout); + + for (;;) { + tto = min(totaltimeout, INT_MAX); + to = timeout ? min(tto, timeout) : tto; + + t0 = 0; + key = get_key(stdin, to); + t = 0 - t0; + + if (totaltimeout <= t) + longjmp(timeout_jump, 1); + + totaltimeout -= t; + + if (key != KEY_NONE) { + //mp("get key 0x%x", key); + return key; + } + + if (timeout) { + if (timeout <= t) { + //mp("timeout"); + 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; + } + + 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, bool history) +{ + 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; + } + printf("\n"); + + if (history) { + struct cli_command *comm; + + comm = (struct cli_command *)malloc(sizeof(struct cli_command *)); + comm->command = + (char *)malloc(sizeof(char) * (strlen(cmd) + 1)); + strcpy(comm->command, cmd); + list_add(&(comm->list), &cli_history_head); + } + + // mp("raw cmd = %s", cmd); + strcpy(temp_cmd, cmd); + module_name = strtok(cmd, COMMAND_DELIM); + len_mn = strlen(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"); + } + 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); +} + +static int cli_init(void) +{ + INIT_LIST_HEAD(&cli_history_head); + + return 0; +} + +static void cli_exit(void) +{ + /* Nothing to do */ +} + +MODULE_INIT(cli_init); +MODULE_EXIT(cli_exit); diff --git a/com32/elflink/ldlinux/colors.c b/com32/elflink/ldlinux/colors.c new file mode 100644 index 00000000..68732bdb --- /dev/null +++ b/com32/elflink/ldlinux/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 <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <colortbl.h> +#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/com32/elflink/ldlinux/getadv.c b/com32/elflink/ldlinux/getadv.c new file mode 100644 index 00000000..456084b0 --- /dev/null +++ b/com32/elflink/ldlinux/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 <syslinux/adv.h> +#include <klibc/compiler.h> +#include <inttypes.h> + +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/com32/elflink/ldlinux/ipappend.c b/com32/elflink/ldlinux/ipappend.c new file mode 100644 index 00000000..bd000920 --- /dev/null +++ b/com32/elflink/ldlinux/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 <syslinux/config.h> +#include <klibc/compiler.h> +#include <com32.h> + +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/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c new file mode 100644 index 00000000..967eebb9 --- /dev/null +++ b/com32/elflink/ldlinux/ldlinux.c @@ -0,0 +1,34 @@ +#include <linux/list.h> +#include <sys/times.h> +#include <stdbool.h> +#include "cli.h" +#include "console.h" + +#include <sys/module.h> + +static void enter_cmdline(void) +{ + struct cli_command *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)) { + process_command(cmdline, true); + //} + } +} + +static int ldlinux_main(int argc, char **argv) +{ + openconsole(&dev_rawcon_r, &dev_ansiserial_w); + + /* Should never return */ + enter_cmdline(); + + return 0; +} +MODULE_MAIN(ldlinux_main); diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c new file mode 100644 index 00000000..98572337 --- /dev/null +++ b/com32/elflink/ldlinux/readconfig.c @@ -0,0 +1,1169 @@ +/* ----------------------------------------------------------------------- * + * + * 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 <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <minmax.h> +#include <alloca.h> +#include <inttypes.h> +#include <colortbl.h> +#include <com32.h> +#include <syslinux/adv.h> +#include <syslinux/config.h> +#include <core-elf.h> + +#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 */ +extern char *globaldefault; +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; }) + +/* + * 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; +extern char *append; +//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; + mp("enter"); + + 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/com32/elflink/ldlinux/refstr.c b/com32/elflink/ldlinux/refstr.c new file mode 100644 index 00000000..f9d98e11 --- /dev/null +++ b/com32/elflink/ldlinux/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 <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/module.h> +#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/com32/elflink/ldlinux/refstr.h b/com32/elflink/ldlinux/refstr.h new file mode 100644 index 00000000..7001d407 --- /dev/null +++ b/com32/elflink/ldlinux/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 <stddef.h> +#include <stdarg.h> + +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/com32/elflink/modules/Makefile b/com32/elflink/modules/Makefile index 8a97835c..6cd0767f 100644 --- a/com32/elflink/modules/Makefile +++ b/com32/elflink/modules/Makefile @@ -13,6 +13,8 @@ topdir = ../../.. include MCONFIG +CFLAGS += -I$(topdir)/core/elflink + MODULES = hello.c32 sort.c32 mytest.c32 menumain.c32 printmsg.c32 background.c32 passwd.c32 sha1hash.c32 \ unbase64.c32 sha512crypt.c32 md5.c32 crypt-md5.c32 sha256crypt.c32 get_key.c32 ansiraw.c32 test.c32 \ meminfo.c32 menu.c32 drain.c32 dir.c32 pcitest.c32 vesainfo.c32 cpuid.c32 cpuidtest.c32 diff --git a/com32/elflink/modules/cli.h b/com32/elflink/modules/cli.h index c452643d..4ae9caf3 100644 --- a/com32/elflink/modules/cli.h +++ b/com32/elflink/modules/cli.h @@ -2,18 +2,20 @@ #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, bool history); +extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu; #endif diff --git a/com32/elflink/modules/menu.h b/com32/elflink/modules/menu.h index 5b05fe81..c7d70792 100644 --- a/com32/elflink/modules/menu.h +++ b/com32/elflink/modules/menu.h @@ -69,23 +69,6 @@ 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 */ diff --git a/com32/elflink/modules/menumain.c b/com32/elflink/modules/menumain.c index 86285857..265f4c4d 100644 --- a/com32/elflink/modules/menumain.c +++ b/com32/elflink/modules/menumain.c @@ -30,6 +30,7 @@ #include <com32.h> #include <syslinux/adv.h> #include <sys/module.h> +#include <core-elf.h> #include "menu.h" #include "cli.h" |