From mboxrd@z Thu Jan 1 00:00:00 1970 From: Anthony Liguori Subject: RE: Building domains as a lesser user (was Re: boot loaders for domain != 0) Date: Fri, 04 Feb 2005 14:48:55 -0600 Message-ID: <1107550135.19648.22.camel@localhost> References: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-LMXpNvGFoSIqCeRbr84V" In-Reply-To: Sender: xen-devel-admin@lists.sourceforge.net Errors-To: xen-devel-admin@lists.sourceforge.net List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , List-Archive: To: Ian Pratt Cc: Jacob Gorm Hansen , xen-devel@lists.sourceforge.net, katzj@redhat.com List-Id: xen-devel@lists.xenproject.org --=-LMXpNvGFoSIqCeRbr84V Content-Type: text/plain Content-Transfer-Encoding: 7bit On Fri, 2005-02-04 at 06:33, Ian Pratt wrote: > We could implement the system call in arch Xen even though it isn't in > the mainstream kernel yet. Attached is a newer version of the grub menu. Also contains a /linuxrc that will kexec. Turns out that the menu code stays the same for doing it via kexec or in dom0. So all that's left is for someone to port kexec to Xen. I won't get to it for a while so hopefully someone else can jump in.. I looked at the kexec code and it looks like it will map to Xen fairly painlessly. Regards, -- Anthony Liguori Linux Technology Center (LTC) - IBM Austin E-mail: aliguori@us.ibm.com Phone: (512) 838-1208 Signed-off-by: Anthony Liguori --=-LMXpNvGFoSIqCeRbr84V Content-Disposition: attachment; filename=xenoloader.diff Content-Type: text/x-patch; name=xenoloader.diff; charset=ANSI_X3.4-1968 Content-Transfer-Encoding: 7bit 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@us.ibm.com) +## +## 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@us.ibm.com) +## +## 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@us.ibm.com) + * + * 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; +} --=-LMXpNvGFoSIqCeRbr84V-- ------------------------------------------------------- This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting Tool for open source databases. Create drag-&-drop reports. Save time by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc. Download a FREE copy at http://www.intelliview.com/go/osdn_nl