diff -urN empty/Makefile xenoloader/Makefile --- empty/Makefile 1969-12-31 18:00:00.000000000 -0600 +++ xenoloader/Makefile 2005-02-04 14:37:31.560048000 -0600 @@ -0,0 +1,31 @@ +############################################################################### +## +## Makefile +## +## Copyright (C) International Business Machines Corp., 2005 +## Author(s): Anthony Liguori (aliguori@xxxxxxxxxx) +## +## Xen Psuedo-Boot Loader +## +## This library is free software; you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published +## by the Free Software Foundation; either version 2.1 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +## the GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## +############################################################################### + +CFLAGS=-Wall -g + +all: main.o + $(CC) $(CFLAGS) -o xenoloader main.o -lcurses + +clean:; $(RM) main.o xenoloader diff -urN empty/linuxrc xenoloader/linuxrc --- empty/linuxrc 1969-12-31 18:00:00.000000000 -0600 +++ xenoloader/linuxrc 2005-02-04 14:37:53.390048000 -0600 @@ -0,0 +1,38 @@ +#!/bin/sh + +## linuxrc +## +## Copyright (C) International Business Machines Corp., 2005 +## Author(s): Anthony Liguori (aliguori@xxxxxxxxxx) +## +## Xen Psuedo-Boot Loader +## +## This library is free software; you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published +## by the Free Software Foundation; either version 2.1 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +## the GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +# if xenoloader is not in your path, +# then use the following command: +# +# ./linuxrc XENPATH="./" + +eval "$@" + +${XENPATH}xenoloader -o /tmp/params || exit 1 + +KERNEL=`head -n 1 /tmp/params` +CLI=`tail -n 1 /tmp/params` + +kexec -l "$KERNEL" --command-line "$CLI" || exit 1 +kexec -e diff -urN empty/main.c xenoloader/main.c --- empty/main.c 1969-12-31 18:00:00.000000000 -0600 +++ xenoloader/main.c 2005-02-04 14:17:27.740048000 -0600 @@ -0,0 +1,363 @@ +/*\ + * xenoloader/main.c + * + * Copyright (C) International Business Machines Corp., 2005 + * Author(s): Anthony Liguori (aliguori@xxxxxxxxxx) + * + * Xen Psuedo-Boot Loader + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +\*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* simple structure representing a single grub + command. argv[0] is the name of the command. + Use CMD_REST to concatinate multiple arguments + while preserving original spacing */ +struct grub_cmd { + int argc; + char **argv; + char *line; +}; + +/* the x,y offset of the first entry to select */ +#define X_OFFSET 3 +#define Y_OFFSET 6 + +/* gets the concatination of the rest of the line + starting at argv[i] */ +#define CMD_REST(cmd, i) ((cmd).line + ((cmd).argv[(i)] - (cmd).argv[0])) + +/* reads a grub configuration file and returns a null-terminated array of + grub commands */ +struct grub_cmd *read_grub_conf(const char *file) +{ + FILE *f = fopen(file, "r"); + char buffer[4096]; + struct grub_cmd *cmds = 0; + size_t capacity = 0; + size_t size = 0; + + if (!f) return NULL; + + while(fgets(buffer, sizeof(buffer), f)) { + char *ptr = buffer; + int words = 0; + int in_word = 0; + + /* skip spaces */ + while (isspace(*ptr)) ptr++; + + /* skip comments and blank lines */ + if (*ptr == '#' || !*ptr) continue; + + /* make sure we have enough room for this command and the null terminator */ + if ((size + 2) > capacity) { + capacity += 100; + cmds = realloc(cmds, capacity * sizeof(cmds[0])); + } + + cmds[size].line = strdup(ptr); + + /* count number of words */ + for (ptr = cmds[size].line; *ptr; ptr++) { + if (isspace(*ptr)) { + in_word = 0; + } else if (!in_word) { + words++; + in_word = 1; + } + if (*ptr == '\r' || *ptr == '\n') *ptr = 0; + } + + /* allocate argc/argv */ + cmds[size].argc = words; + cmds[size].argv = malloc(sizeof(char*) * words); + + /* duplicate a string to tokenize */ + cmds[size].argv[0] = strdup(cmds[size].line); + words = 1; + in_word = 1; + + /* tokenize */ + for (ptr = cmds[size].argv[0]; *ptr; ptr++) { + if (isspace(*ptr)) { + if (in_word) *ptr = 0; + in_word = 0; + } else if (!in_word) { + cmds[size].argv[words] = ptr; + words++; + in_word = 1; + } + } + + size++; + } + + fclose(f); + + /* NULL terminate */ + cmds[size].argc = 0; + cmds[size].argv = 0; + cmds[size].line = 0; + + return cmds; +} + +/* quick routine that draws a box using ASCII art. There's + probably a better way to do this with curses */ +static void make_box(int x, int y, int width, int height) +{ + int i; + + mvaddch(y, x, 0xda); + for (i = x + 1; i < x + width; i++) { + mvaddch(y, i, 0xc4); + } + mvaddch(y, x+width, 0xbf); + + for (i = y + 1; i < y + height; i++) { + mvaddch(i, x, 0xb3); + mvaddch(i, x+width, 0xb3); + } + + mvaddch(y+height, x, 0xc0); + for (i = x + 1; i < x + width; i++) { + mvaddch(y+height, i, 0xc4); + } + mvaddch(y+height, x+width, 0xd9); +} + +/* signal handler */ +static void finish(int sig) +{ + endwin(); + exit(0); +} + +int main(int argc, char **argv) +{ + int ch; + int pos = 0; + struct grub_cmd *cmds; + int selected = -1; + int i; + int n = 0; + const char *fstype = "ext2"; + const char *device = 0; + const char *config = "/boot/grub/grub.conf"; + const char *output = 0; + + while ((ch = getopt(argc, argv, "t:o:d:c:")) != -1) { + switch (ch) { + case 'o': + output = optarg; + break; + case 't': + fstype = optarg; + break; + case 'd': + device = optarg; + break; + case 'c': + config = optarg; + break; + } + } + + if (mkdir("/tmp/xenoloader", 0700) == -1 && errno != EEXIST) { + perror("mkdir(/tmp/xenoloader"); + exit(1); + } + + if (device) { + if (mount(device, "/tmp/xenoloader", fstype, MS_RDONLY, NULL) == -1) { + perror("mount()"); + exit(1); + } + + cmds = read_grub_conf("/tmp/xenoloader/boot/grub/grub.conf"); + if (!cmds) cmds = read_grub_conf("/tmp/xenoloader/grub/grub.conf"); + } else { + /* Read the grub file */ + cmds = read_grub_conf(config); + } + + if (!cmds) { + fprintf(stderr, "Error reading `%s': %m\n", config); + exit(1); + } + + if (device) { + umount("/tmp/xenoloader"); + } + + /* Set up curses and signal handlers */ + signal(SIGINT, finish); + initscr(); + keypad(stdscr, TRUE); + intrflush(stdscr, FALSE); + nonl(); + cbreak(); + noecho(); + + /* Display banner */ + mvaddstr(2, 2, "XenoLoader v0.0.1"); + + /* Display box with choices */ + make_box(1, Y_OFFSET - 2, 74, 10); + for (i = 0; cmds[i].line; i++) { + if (!strcmp(cmds[i].argv[0], "title")) { + mvaddstr(Y_OFFSET + n, X_OFFSET + 2, CMD_REST(cmds[i], 1)); + n++; + } + } + + /* Display usage text */ + mvaddstr(18, 2, "Use the up and down keys to select which entry is highlighted."); + mvaddstr(19, 2, "Press enter to boot the selected OS."); + + /* Select the first choice */ + mvaddstr(Y_OFFSET + pos, X_OFFSET, " "); + + /* Input loop */ + while (selected == -1 && (ch = getch()) != EOF) { + int new_pos = pos; + switch (ch) { + case KEY_UP: + new_pos--; + break; + case KEY_DOWN: + new_pos++; + break; + case '\n': + case '\r': + selected = pos; + break; + } + + new_pos += n; + new_pos %= n; + + if (new_pos != pos) { + mvaddstr(Y_OFFSET + new_pos, X_OFFSET, " "); + pos = new_pos; + } + } + + /* Close the curses session */ + endwin(); + + /* This is all horribly inefficient but quick to write */ + + /* Find the index of the selected title */ + n = 0; + for (i = 0; cmds[i].line; i++) { + if (!strcmp(cmds[i].argv[0], "title")) { + if (n == selected) { + break; + } + n++; + } + } + + if (!cmds[i].line) { + printf("No kernel selected\n"); + return 1; + } + + { + const char *kernel = ""; + const char *cli = ""; + const char *root = ""; + + /* Read the options after the selected title until + the next title looking for the ones we care about + */ + for (i++; cmds[i].line; i++) { + if (!strcmp(cmds[i].argv[0], "title")) { + break; + } else if (!strcmp(cmds[i].argv[0], "kernel")) { + kernel = cmds[i].argv[1]; + if (cmds[i].argc > 2) { + cli = CMD_REST(cmds[i], 2); + } + } else if (!strcmp(cmds[i].argv[0], "root")) { + root = CMD_REST(cmds[i], 1); + } + } + + /* we really need to read in the device mapper but we need a lot of info + for that. For now, assume that the kernel is going to be on the same + partition as the grub.conf */ + if (*kernel == '(') { + kernel++; + while (*kernel && *kernel != ')') kernel++; + if (*kernel) kernel++; + } + { + char *buf; + + asprintf(&buf, "/boot/%s", kernel); + kernel = buf; + } + if (device) { + if (mount(device, "/tmp/xenoloader", fstype, MS_RDONLY, NULL) == -1) { + perror("mount()"); + exit(1); + } + + /* this is not very safe at all and prone to all sorts of race + conditions. */ + { + char *cmd; + + asprintf(&cmd, "cp /tmp/xenoloader/%s /tmp/xen-kernel", kernel); + system(cmd); + free(cmd); + } + kernel = "/tmp/xen-kernel"; + + umount("/tmp/xenoloader"); + } + + if (output) { + FILE *f = fopen(output, "w"); + if (f) { + fprintf(f, "%s\n", kernel); + fprintf(f, "%s\n", cli); + fclose(f); + } + } else { + printf("%s\n", kernel); + printf("%s\n", cli); + } + } + + return 0; +}