]> git.ozlabs.org Git - petitboot/commitdiff
Initial support for multiple UIs
authorJeremy Kerr <jk@ozlabs.org>
Mon, 15 Dec 2008 04:22:34 +0000 (15:22 +1100)
committerJeremy Kerr <jk@ozlabs.org>
Mon, 15 Dec 2008 04:22:34 +0000 (15:22 +1100)
Move the device discovery code from separate udev helpers to a single
process to listen on two sockets: one SOCK_DGRAM for incoming udev
events, and one SOCK_STREAM for UIs to connect.

Initial support for client/server infrastructure, still need to wire-up
the udev messages.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
98 files changed:
Makefile.in
artwork/background.jpg [deleted file]
artwork/cdrom.png [deleted file]
artwork/cursor.gz [deleted file]
artwork/hdd.png [deleted file]
artwork/tux.png [deleted file]
artwork/usbpen.png [deleted file]
configure.ac
devices.c [deleted file]
devices/kboot-parser.c [deleted file]
devices/message.h [deleted file]
devices/native-parser.c [deleted file]
devices/params.c [deleted file]
devices/params.h [deleted file]
devices/parser-test.c [deleted file]
devices/parser-test.sh [deleted file]
devices/parser-tests/001/expected-output [deleted file]
devices/parser-tests/001/ps3da1/etc/kboot.conf [deleted file]
devices/parser-tests/002/expected-output [deleted file]
devices/parser-tests/002/ps3da1/etc/yaboot.conf [deleted file]
devices/parser-tests/003/expected-output [deleted file]
devices/parser-tests/003/ps3da1/etc/kboot.conf [deleted file]
devices/parser-tests/004/expected-output [deleted file]
devices/parser-tests/004/rootdev [deleted file]
devices/parser-tests/004/sda1/etc/kboot.conf [deleted file]
devices/parser-tests/005/expected-output [deleted file]
devices/parser-tests/005/ps3da1/etc/kboot.conf [deleted file]
devices/parser-tests/101/expected-output [deleted file]
devices/parser-tests/101/ps3da1/etc/kboot.conf [deleted file]
devices/parser-tests/102/expected-output [deleted file]
devices/parser-tests/102/ps3da1/etc/kboot.conf [deleted file]
devices/parser.c [deleted file]
devices/parser.h [deleted file]
devices/paths.c [deleted file]
devices/paths.h [deleted file]
devices/petitboot-udev-helper.c [deleted file]
devices/yaboot-cfg.c [deleted file]
devices/yaboot-cfg.h [deleted file]
devices/yaboot-parser.c [deleted file]
discover/discover-server.c [new file with mode: 0644]
discover/discover-server.h [new file with mode: 0644]
discover/kboot-parser.c [new file with mode: 0644]
discover/log.c [new file with mode: 0644]
discover/log.h [new file with mode: 0644]
discover/message.h [new file with mode: 0644]
discover/native-parser.c [new file with mode: 0644]
discover/params.c [new file with mode: 0644]
discover/params.h [new file with mode: 0644]
discover/parser.c [new file with mode: 0644]
discover/parser.h [new file with mode: 0644]
discover/paths.c [new file with mode: 0644]
discover/paths.h [new file with mode: 0644]
discover/pb-discover.c [new file with mode: 0644]
discover/pb-discover.h [new file with mode: 0644]
discover/udev.c [new file with mode: 0644]
discover/udev.h [new file with mode: 0644]
discover/waiter.c [new file with mode: 0644]
discover/waiter.h [new file with mode: 0644]
discover/yaboot-cfg.c [new file with mode: 0644]
discover/yaboot-cfg.h [new file with mode: 0644]
discover/yaboot-parser.c [new file with mode: 0644]
lib/list/list.c [new file with mode: 0644]
lib/list/list.h [new file with mode: 0644]
lib/pb-protocol/pb-protocol.c [new file with mode: 0644]
lib/pb-protocol/pb-protocol.h [new file with mode: 0644]
lib/talloc/talloc.c [new file with mode: 0644]
lib/talloc/talloc.h [new file with mode: 0644]
petitboot-paths.h [deleted file]
petitboot.c [deleted file]
petitboot.h [deleted file]
rules.mk
test/parser-test.c [new file with mode: 0644]
test/parser-test.sh [new file with mode: 0755]
test/parser/001/expected-output [new file with mode: 0644]
test/parser/001/ps3da1/etc/kboot.conf [new file with mode: 0644]
test/parser/002/expected-output [new file with mode: 0644]
test/parser/002/ps3da1/etc/yaboot.conf [new file with mode: 0644]
test/parser/003/expected-output [new file with mode: 0644]
test/parser/003/ps3da1/etc/kboot.conf [new file with mode: 0644]
test/parser/004/expected-output [new file with mode: 0644]
test/parser/004/rootdev [new file with mode: 0644]
test/parser/004/sda1/etc/kboot.conf [new file with mode: 0644]
test/parser/005/expected-output [new file with mode: 0644]
test/parser/005/ps3da1/etc/kboot.conf [new file with mode: 0644]
test/parser/101/expected-output [new file with mode: 0644]
test/parser/101/ps3da1/etc/kboot.conf [new file with mode: 0644]
test/parser/102/expected-output [new file with mode: 0644]
test/parser/102/ps3da1/etc/kboot.conf [new file with mode: 0644]
ui/common/discover-client.c [new file with mode: 0644]
ui/common/discover-client.h [new file with mode: 0644]
ui/test/pb-test.c [new file with mode: 0644]
ui/twin/artwork/background.jpg [new file with mode: 0644]
ui/twin/artwork/cdrom.png [new file with mode: 0644]
ui/twin/artwork/cursor.gz [new file with mode: 0644]
ui/twin/artwork/hdd.png [new file with mode: 0644]
ui/twin/artwork/tux.png [new file with mode: 0644]
ui/twin/artwork/usbpen.png [new file with mode: 0644]
ui/twin/pb-twin.c [new file with mode: 0644]

index 0da5a4e4920be8bdd33270c8141513b0993a8a12..e537e9db7251ac54e361348d9c746481cfe482b8 100644 (file)
@@ -24,6 +24,7 @@ sbindir = @sbindir@
 datarootdir = @datarootdir@
 datadir = @datadir@
 pkgdatadir = ${datadir}/${PACKAGE}
+builddir = @builddir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 
diff --git a/artwork/background.jpg b/artwork/background.jpg
deleted file mode 100644 (file)
index 9d54d31..0000000
Binary files a/artwork/background.jpg and /dev/null differ
diff --git a/artwork/cdrom.png b/artwork/cdrom.png
deleted file mode 100644 (file)
index 8b3eeb6..0000000
Binary files a/artwork/cdrom.png and /dev/null differ
diff --git a/artwork/cursor.gz b/artwork/cursor.gz
deleted file mode 100644 (file)
index b73b72f..0000000
Binary files a/artwork/cursor.gz and /dev/null differ
diff --git a/artwork/hdd.png b/artwork/hdd.png
deleted file mode 100644 (file)
index 2b1594c..0000000
Binary files a/artwork/hdd.png and /dev/null differ
diff --git a/artwork/tux.png b/artwork/tux.png
deleted file mode 100644 (file)
index 99f3465..0000000
Binary files a/artwork/tux.png and /dev/null differ
diff --git a/artwork/usbpen.png b/artwork/usbpen.png
deleted file mode 100644 (file)
index 53a365e..0000000
Binary files a/artwork/usbpen.png and /dev/null differ
index 5ef5aa081b95283214a593598150d190a320b24b..2e85b26fc90d4830a1d2a3b313a50adae77cc990 100644 (file)
@@ -30,6 +30,6 @@ AC_PROG_INSTALL
 
 PKG_CHECK_MODULES([twin], [libtwin])
 
-mkdir devices
+mkdir -p discover ui/test ui/common lib/talloc lib/pb-protocol lib/list
 
 AC_OUTPUT
diff --git a/devices.c b/devices.c
deleted file mode 100644 (file)
index 77860d0..0000000
--- a/devices.c
+++ /dev/null
@@ -1,313 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <asm/byteorder.h>
-
-#include <libtwin/twin_png.h>
-#include "petitboot.h"
-#include "petitboot-paths.h"
-#include "devices/message.h"
-
-#define PBOOT_DEFAULT_ICON     "tux.png"
-
-static const char *default_icon = artwork_pathname(PBOOT_DEFAULT_ICON);
-
-struct discovery_context {
-       /* nothing at present */
-       int pad;
-} _ctx;
-
-struct device_context {
-       struct discovery_context *discovery_ctx;
-       uint8_t action;
-       int device_idx;
-};
-
-static twin_pixmap_t *get_icon(const char *filename)
-{
-       /* todo: cache */
-       twin_pixmap_t *icon;
-
-       if (!filename)
-               filename = default_icon;
-
-retry:
-       LOG("loading icon %s ... ", filename);
-       icon = twin_png_to_pixmap(filename, TWIN_ARGB32);
-       LOG("%s\n", icon ? "ok" : "failed");
-
-       if (!icon && filename != default_icon) {
-               filename = default_icon;
-               LOG("reverting to default icon %s\n", filename);
-               goto retry;
-       }
-
-       return icon;
-}
-
-#define MAX_LEN 4096
-static char *read_string(int fd)
-{
-       int len;
-       uint32_t len_buf;
-       char *str, *pos;
-
-       if (read(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
-               perror("read");
-               return NULL;
-       }
-
-       len = __be32_to_cpu(len_buf);
-       if (len + 1 > MAX_LEN) {
-               /* todo: truncate instead */
-               return NULL;
-       }
-
-       pos = str = malloc(len + 1);
-
-       while (len) {
-               int rc = read(fd, pos, len);
-               if (rc <= 0) {
-                       free(str);
-                       LOG("read failed: %s\n", strerror(errno));
-                       return NULL;
-               }
-               pos += rc;
-               len -= rc;
-       }
-       *pos = '\0';
-
-       return str;
-}
-
-static int _read_strings(int fd, void *ptr, int n_strings)
-{
-       char **strings = ptr;
-       int i, ret = TWIN_TRUE;
-
-       for (i = 0; i < n_strings; i++) {
-               strings[i] = read_string(fd);
-               if (!strings[i]) {
-                       ret = TWIN_FALSE;
-                       break;
-               }
-       }
-
-       if (!ret)
-               while (i-- > 0) {
-                       free(strings[i]);
-                       strings[i] = NULL;
-               }
-
-       return ret;
-}
-
-static void _free_strings(void *ptr, int n_strings)
-{
-       char **strings = ptr;
-       int i;
-
-       for (i = 0; i < n_strings; i++)
-               free(strings[i]);
-
-}
-
-#define n_strings(x) (sizeof((x)) / sizeof(char *))
-#define read_strings(f,x) _read_strings((f), &(x), n_strings(x))
-#define free_strings(x) _free_strings(&(x), n_strings(x))
-
-static int read_action(int fd, uint8_t *action)
-{
-       return read(fd, action, sizeof(*action)) != sizeof(*action);
-}
-
-static int read_device(int fd, struct device_context *dev_ctx)
-{
-       /* name, description, icon_file */
-       struct device dev;
-       twin_pixmap_t *icon;
-       int index = -1;
-
-       if (!read_strings(fd, dev))
-               return TWIN_FALSE;
-
-       LOG("got device: '%s'\n", dev.name);
-
-       icon = get_icon(dev.icon_file);
-
-       if (!icon)
-               goto out;
-
-       index = dev_ctx->device_idx = pboot_add_device(dev.id, dev.name, icon);
-
-out:
-       free_strings(dev);
-
-       return index != -1;
-}
-
-static int read_option(int fd, struct device_context *dev_ctx)
-{
-       struct boot_option *opt = malloc(sizeof(*opt));
-       twin_pixmap_t *icon;
-       int index = -1;
-
-       if (!opt)
-               return TWIN_FALSE;
-
-       if (!read_strings(fd, (*opt)))
-               return TWIN_FALSE;
-
-       LOG("got option: '%s'\n", opt->name);
-       icon = get_icon(opt->icon_file);
-
-       if (icon)
-               index = pboot_add_option(dev_ctx->device_idx, opt->name,
-                                        opt->description, icon, opt);
-
-       return index != -1;
-}
-
-static twin_bool_t pboot_proc_client_sock(int sock, twin_file_op_t ops,
-               void *closure)
-{
-       struct device_context *dev_ctx = closure;
-       uint8_t action;
-
-       if (read_action(sock, &action))
-               goto out_err;
-
-       if (action == DEV_ACTION_ADD_DEVICE) {
-               if (!read_device(sock, dev_ctx))
-                       goto out_err;
-
-       } else if (action == DEV_ACTION_ADD_OPTION) {
-               if (dev_ctx->device_idx == -1) {
-                       LOG("option, but no device has been sent?\n");
-                       goto out_err;
-               }
-
-               if (!read_option(sock, dev_ctx))
-                       goto out_err;
-
-       } else if (action == DEV_ACTION_REMOVE_DEVICE) {
-               char *dev_id = read_string(sock);
-               if (!dev_id)
-                       goto out_err;
-               
-               LOG("remove device %s\n", dev_id);
-               pboot_remove_device(dev_id);
-
-       } else {
-               LOG("unsupported action %d\n", action);
-               goto out_err;
-       }
-
-       return TWIN_TRUE;
-
-out_err:
-       close(sock);
-       return TWIN_FALSE;
-}
-
-static twin_bool_t pboot_proc_server_sock(int sock, twin_file_op_t ops,
-               void *closure)
-{
-       int fd;
-       struct discovery_context *disc_ctx = closure;
-       struct device_context *dev_ctx;
-
-       fd = accept(sock, NULL, 0);
-       if (fd < 0) {
-               LOG("accept failed: %s", strerror(errno));
-               return TWIN_FALSE;
-       }
-
-       dev_ctx = malloc(sizeof(*dev_ctx));
-       dev_ctx->discovery_ctx = disc_ctx;
-       dev_ctx->device_idx = -1;
-       dev_ctx->action = 0xff;
-
-       twin_set_file(pboot_proc_client_sock, fd, TWIN_READ, dev_ctx);
-
-       return TWIN_TRUE;
-}
-
-int pboot_start_device_discovery(int udev_trigger)
-{
-       int sock;
-       struct sockaddr_un addr;
-
-       unlink(PBOOT_DEVICE_SOCKET);
-
-       sock = socket(PF_UNIX, SOCK_STREAM, 0);
-       if (sock < 0) {
-               perror("socket");
-               return TWIN_FALSE;
-       }
-
-       addr.sun_family = AF_UNIX;
-       strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
-
-       if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
-               LOG("can't bind to %s: %s", addr.sun_path, strerror(errno));
-               return TWIN_FALSE;
-       }
-
-       if (listen(sock, 1)) {
-               LOG("can't listen on socket %s: %s",
-                               addr.sun_path, strerror(errno));
-               return TWIN_FALSE;
-       }
-
-       LOG("listening on %s\n", addr.sun_path);
-
-       twin_set_file(pboot_proc_server_sock, sock, TWIN_READ, &_ctx);
-
-       if (udev_trigger) {
-               int rc = system("udevtrigger");
-               if (rc)
-                       LOG("udevtrigger failed, rc %d\n", rc);
-       }
-
-       return TWIN_TRUE;
-}
-
-void pboot_exec_option(void *data)
-{
-       struct boot_option *opt = data;
-       char *kexec_opts[10];
-       int i, nr_opts = 2;
-
-       kexec_opts[0] = "/usr/sbin/kexec";
-       kexec_opts[1] = "-f";
-       if (opt->initrd_file && *opt->initrd_file) {
-               kexec_opts[nr_opts] = malloc(10 + strlen(opt->initrd_file));
-               sprintf(kexec_opts[nr_opts], "--initrd=%s", opt->initrd_file);
-               nr_opts++;
-       }
-       if (opt->boot_args && *opt->boot_args)  {
-               kexec_opts[nr_opts] = malloc(10 + strlen(opt->boot_args));
-               sprintf(kexec_opts[nr_opts], "--command-line=%s",
-                       opt->boot_args);
-               nr_opts++;
-       }
-
-       kexec_opts[nr_opts++] = opt->boot_image_file;
-       kexec_opts[nr_opts] = NULL;
-
-       LOG("calling kexec:\n");
-       for (i = 0; i < nr_opts; i++) {
-               LOG("\t'%s'\n", kexec_opts[i]);
-       }
-       fflush(stdout);
-
-       execv(kexec_opts[0], kexec_opts);
-       pboot_message("kexec failed: %s", strerror(errno));
-       LOG("execv() failed: %s", strerror(errno));
-}
diff --git a/devices/kboot-parser.c b/devices/kboot-parser.c
deleted file mode 100644 (file)
index df2e762..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-#define _GNU_SOURCE
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "parser.h"
-#include "params.h"
-
-#define buf_size 1024
-
-static const char *devpath;
-
-static int param_is_ignored(const char *param)
-{
-       static const char *ignored_options[] =
-               { "message", "timeout", "default", NULL };
-       const char **str;
-
-       for (str = ignored_options; *str; str++)
-               if (streq(*str, param))
-                       return 1;
-       return 0;
-}
-
-/**
- * Splits a name=value pair, with value terminated by @term (or nul). if there
- * is no '=', then only the value is populated, and *name is set to NULL. The
- * string is modified in place.
- *
- * Returns the next byte to process, or null if we've hit the end of the
- * string.
- *
- * */
-static char *get_param_pair(char *str, char **name_out, char **value_out,
-               char terminator)
-{
-       char *sep, *tmp, *name, *value;
-
-       /* terminate the value */
-       tmp = strchr(str, terminator);
-       if (tmp)
-               *tmp = 0;
-       else
-               tmp = NULL;
-
-       sep = strchr(str, '=');
-       if (!sep) {
-               *name_out = NULL;
-               *value_out = str;
-               return tmp ? tmp + 1 : NULL;
-       }
-
-       /* terminate the name */
-       *sep = 0;
-
-       /* remove leading spaces */
-       for (name = str; isspace(*name); name++);
-       for (value = sep + 1; isspace(*value); value++);
-
-       /* .. and trailing ones.. */
-       for (sep--; isspace(*sep); sep--)
-               *sep = 0;
-       for (sep = value + strlen(value) - 1; isspace(*sep); sep--)
-               *sep = 0;
-
-       *name_out = name;
-       *value_out = value;
-
-       return tmp ? tmp + 1 : NULL;
-}
-
-struct global_option {
-       char *name;
-       char *value;
-};
-
-
-static struct global_option global_options[] = {
-       { .name = "root" },
-       { .name = "initrd" },
-       { .name = "video" },
-       { .name = NULL }
-};
-
-/*
- * Check if an option (name=value) is a global option. If so, store it in
- * the global options table, and return 1. Otherwise, return 0.
- */
-static int check_for_global_option(const char *name, const char *value)
-{
-       int i;
-
-       for (i = 0; global_options[i].name ;i++) {
-               if (!strcmp(name, global_options[i].name)) {
-                       global_options[i].value = strdup(value);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static char *get_global_option(const char *name)
-{
-       int i;
-
-       for (i = 0; global_options[i].name ;i++)
-               if (!strcmp(name, global_options[i].name))
-                       return global_options[i].value;
-
-       return NULL;
-}
-
-static int parse_option(struct boot_option *opt, char *config)
-{
-       char *pos, *name, *value, *root, *initrd, *cmdline, *tmp;
-
-       root = initrd = cmdline = NULL;
-
-       /* remove quotes around the value */
-       while (*config == '"' || *config == '\'')
-               config++;
-
-       pos = config + strlen(config) - 1;
-       while (*pos == '"' || *pos == '\'')
-               *(pos--) = 0;
-
-       if (!strlen(pos))
-               return 0;
-
-       pos = strchr(config, ' ');
-
-       /* if there's no space, it's only a kernel image with no params */
-       if (!pos) {
-               opt->boot_image_file = resolve_path(config, devpath);
-               opt->description = strdup(config);
-               return 1;
-       }
-
-       *pos = 0;
-       opt->boot_image_file = resolve_path(config, devpath);
-
-       cmdline = malloc(buf_size);
-       *cmdline = 0;
-
-       for (pos++; pos;) {
-               pos = get_param_pair(pos, &name, &value, ' ');
-
-               if (!name) {
-                       strcat(cmdline, " ");
-                       strcat(cmdline, value);
-
-               } else if (streq(name, "initrd")) {
-                       initrd = value;
-
-               } else if (streq(name, "root")) {
-                       root = value;
-
-               } else {
-                       strcat(cmdline, " ");
-                       *(value - 1) = '=';
-                       strcat(cmdline, name);
-               }
-       }
-
-       if (!root)
-               root = get_global_option("root");
-       if (!initrd)
-               initrd = get_global_option("initrd");
-
-       if (initrd) {
-               asprintf(&tmp, "initrd=%s %s", initrd, cmdline);
-               free(cmdline);
-               cmdline = tmp;
-
-               opt->initrd_file = resolve_path(initrd, devpath);
-       }
-
-       if (root) {
-               asprintf(&tmp, "root=%s %s", root, cmdline);
-               free(cmdline);
-               cmdline = tmp;
-
-       } else if (initrd) {
-               /* if there's an initrd but no root, fake up /dev/ram0 */
-               asprintf(&tmp, "root=/dev/ram0 %s", cmdline);
-               free(cmdline);
-               cmdline = tmp;
-       }
-
-       pb_log("kboot cmdline: %s\n", cmdline);
-       opt->boot_args = cmdline;
-
-       asprintf(&opt->description, "%s %s",
-                       config, opt->boot_args);
-
-       return 1;
-}
-
-static void parse_buf(struct device *dev, char *buf)
-{
-       char *pos, *name, *value;
-       int sent_device = 0;
-
-       for (pos = buf; pos;) {
-               struct boot_option opt;
-
-               pos = get_param_pair(pos, &name, &value, '\n');
-
-               pb_log("kboot param: '%s' = '%s'\n", name, value);
-
-               if (name == NULL || param_is_ignored(name))
-                       continue;
-
-               if (*name == '#')
-                       continue;
-
-               if (check_for_global_option(name, value))
-                       continue;
-
-               memset(&opt, 0, sizeof(opt));
-               opt.name = strdup(name);
-
-               if (parse_option(&opt, value))
-                       if (!sent_device++)
-                               add_device(dev);
-                       add_boot_option(&opt);
-
-               free(opt.name);
-       }
-}
-
-static int parse(const char *device)
-{
-       char *filepath, *buf;
-       int fd, len, rc = 0;
-       struct stat stat;
-       struct device *dev;
-
-       devpath = device;
-
-       filepath = resolve_path("/etc/kboot.conf", devpath);
-
-       fd = open(filepath, O_RDONLY);
-       if (fd < 0)
-               goto out_free_path;
-
-       if (fstat(fd, &stat))
-               goto out_close;
-
-       buf = malloc(stat.st_size + 1);
-       if (!buf)
-               goto out_close;;
-
-       len = read(fd, buf, stat.st_size);
-       if (len < 0)
-               goto out_free_buf;
-       buf[len] = 0;
-
-       dev = malloc(sizeof(*dev));
-       memset(dev, 0, sizeof(*dev));
-       dev->id = strdup(device);
-       dev->icon_file = strdup(generic_icon_file(guess_device_type()));
-
-       parse_buf(dev, buf);
-
-       rc = 1;
-
-out_free_buf:
-       free(buf);
-out_close:
-       close(fd);
-out_free_path:
-       free(filepath);
-       return rc;
-}
-
-struct parser kboot_parser = {
-       .name = "kboot.conf parser",
-       .priority = 98,
-       .parse    = parse
-};
diff --git a/devices/message.h b/devices/message.h
deleted file mode 100644 (file)
index 7a5d4f2..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-
-#ifndef _MESSAGE_H
-#define _MESSAGE_H
-
-enum device_action {
-       DEV_ACTION_ADD_DEVICE = 0,
-       DEV_ACTION_ADD_OPTION = 1,
-       DEV_ACTION_REMOVE_DEVICE = 2,
-       DEV_ACTION_REMOVE_OPTION = 3
-};
-
-struct device {
-       char *id;
-       char *name;
-       char *description;
-       char *icon_file;
-};
-
-struct boot_option {
-       char *id;
-       char *name;
-       char *description;
-       char *icon_file;
-       char *boot_image_file;
-       char *initrd_file;
-       char *boot_args;
-};
-
-
-#endif /* _MESSAGE_H */
diff --git a/devices/native-parser.c b/devices/native-parser.c
deleted file mode 100644 (file)
index 24713b1..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-
-#include "parser.h"
-#include "params.h"
-#include "paths.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-const char *conf_filename = "/boot/petitboot.conf";
-
-static struct boot_option *cur_opt;
-static struct device *dev;
-static const char *devpath;
-int device_added;
-
-int check_and_add_device(struct device *dev)
-{
-       if (!dev->icon_file)
-               dev->icon_file = strdup(generic_icon_file(guess_device_type()));
-
-       return !add_device(dev);
-}
-
-static int section(char *section_name)
-{
-       if (!device_added++ && !check_and_add_device(dev))
-               return 0;
-
-       if (cur_opt) {
-               add_boot_option(cur_opt);
-               free_boot_option(cur_opt);
-       }
-
-       cur_opt = malloc(sizeof(*cur_opt));
-       memset(cur_opt, 0, sizeof(*cur_opt));
-       return 1;
-}
-
-
-static void set_boot_option_parameter(struct boot_option *opt,
-               const char *name, const char *value)
-{
-       if (streq(name, "name"))
-               opt->name = strdup(value);
-
-       else if (streq(name, "description"))
-               opt->description = strdup(value);
-
-       else if (streq(name, "image"))
-               opt->boot_image_file = resolve_path(value, devpath);
-
-       else if (streq(name, "icon"))
-               opt->icon_file = resolve_path(value, devpath);
-
-       else if (streq(name, "initrd"))
-               opt->initrd_file =resolve_path(value, devpath);
-
-       else if (streq(name, "args"))
-               opt->boot_args = strdup(value);
-
-       else
-               fprintf(stderr, "Unknown parameter %s\n", name);
-}
-
-static void set_device_parameter(struct device *dev,
-               const char *name, const char *value)
-{
-       if (streq(name, "name"))
-               dev->name = strdup(value);
-
-       else if (streq(name, "description"))
-               dev->description = strdup(value);
-
-       else if (streq(name, "icon"))
-               dev->icon_file = resolve_path(value, devpath);
-}
-
-static int parameter(char *param_name, char *param_value)
-{
-       if (cur_opt)
-               set_boot_option_parameter(cur_opt, param_name, param_value);
-       else
-               set_device_parameter(dev, param_name, param_value);
-       return 1;
-}
-
-
-int parse(const char *device)
-{
-       char *filepath;
-       int rc;
-
-       filepath = resolve_path(conf_filename, device);
-
-       cur_opt = NULL;
-       dev = malloc(sizeof(*dev));
-       memset(dev, 0, sizeof(*dev));
-       dev->id = strdup(device);
-
-       rc = pm_process(filepath, section, parameter);
-       if (!rc)
-               return 0;
-
-       if (cur_opt) {
-               add_boot_option(cur_opt);
-               free_boot_option(cur_opt);
-       }
-
-       cur_opt = NULL;
-
-       free(filepath);
-
-       return 1;
-}
-
-struct parser native_parser = {
-       .name = "native petitboot parser",
-       .priority = 100,
-       .parse    = parse
-};
-
-
-
diff --git a/devices/params.c b/devices/params.c
deleted file mode 100644 (file)
index 76a1451..0000000
+++ /dev/null
@@ -1,595 +0,0 @@
-/* This modules is based on the params.c module from Samba, written by Karl Auer
-   and much modifed by Christopher Hertel. */
-
-/*
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "params.h"
-
-#define new_array(type, num) ((type *)_new_array(sizeof(type), (num)))
-#define realloc_array(ptr, type, num) \
-       ((type *)_realloc_array((ptr), sizeof(type), (num)))
-
-#define rprintf(x, ...) do { fprintf(stderr, ##__VA_ARGS__);   \
-                               fprintf(stderr, "\n"); } while (0)
-#define rsyserr(x, y, ...) do { fprintf(stderr, ##__VA_ARGS__);        \
-                               fprintf(stderr, "\n"); } while (0)
-
-#define MALLOC_MAX 0x40000000
-#define False 0
-#define True 1
-
-void *_new_array(unsigned int size, unsigned long num)
-{
-       if (num >= MALLOC_MAX/size)
-               return NULL;
-       return malloc(size * num);
-}
-
-void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
-{
-       if (num >= MALLOC_MAX/size)
-               return NULL;
-       /* No realloc should need this, but just in case... */
-       if (!ptr)
-               return malloc(size * num);
-       return realloc(ptr, size * num);
-}
-
-
-/* -------------------------------------------------------------------------- **
- *
- * Module name: params
- *
- * -------------------------------------------------------------------------- **
- *
- *  This module performs lexical analysis and initial parsing of a
- *  Windows-like parameter file.  It recognizes and handles four token
- *  types:  section-name, parameter-name, parameter-value, and
- *  end-of-file.  Comments and line continuation are handled
- *  internally.
- *
- *  The entry point to the module is function pm_process().  This
- *  function opens the source file, calls the Parse() function to parse
- *  the input, and then closes the file when either the EOF is reached
- *  or a fatal error is encountered.
- *
- *  A sample parameter file might look like this:
- *
- *  [section one]
- *  parameter one = value string
- *  parameter two = another value
- *  [section two]
- *  new parameter = some value or t'other
- *
- *  The parameter file is divided into sections by section headers:
- *  section names enclosed in square brackets (eg. [section one]).
- *  Each section contains parameter lines, each of which consist of a
- *  parameter name and value delimited by an equal sign.  Roughly, the
- *  syntax is:
- *
- *    <file>            :==  { <section> } EOF
- *
- *    <section>         :==  <section header> { <parameter line> }
- *
- *    <section header>  :==  '[' NAME ']'
- *
- *    <parameter line>  :==  NAME '=' VALUE '\n'
- *
- *  Blank lines and comment lines are ignored.  Comment lines are lines
- *  beginning with either a semicolon (';') or a pound sign ('#').
- *
- *  All whitespace in section names and parameter names is compressed
- *  to single spaces.  Leading and trailing whitespace is stipped from
- *  both names and values.
- *
- *  Only the first equals sign in a parameter line is significant.
- *  Parameter values may contain equals signs, square brackets and
- *  semicolons.  Internal whitespace is retained in parameter values,
- *  with the exception of the '\r' character, which is stripped for
- *  historic reasons.  Parameter names may not start with a left square
- *  bracket, an equal sign, a pound sign, or a semicolon, because these
- *  are used to identify other tokens.
- *
- * -------------------------------------------------------------------------- **
- */
-
-/* -------------------------------------------------------------------------- **
- * Constants...
- */
-
-#define BUFR_INC 1024
-
-
-/* -------------------------------------------------------------------------- **
- * Variables...
- *
- *  bufr        - pointer to a global buffer.  This is probably a kludge,
- *                but it was the nicest kludge I could think of (for now).
- *  bSize       - The size of the global buffer <bufr>.
- */
-
-static char *bufr  = NULL;
-static int   bSize = 0;
-
-/* -------------------------------------------------------------------------- **
- * Functions...
- */
-
-static int EatWhitespace( FILE *InFile )
-  /* ------------------------------------------------------------------------ **
-   * Scan past whitespace (see ctype(3C)) and return the first non-whitespace
-   * character, or newline, or EOF.
-   *
-   *  Input:  InFile  - Input source.
-   *
-   *  Output: The next non-whitespace character in the input stream.
-   *
-   *  Notes:  Because the config files use a line-oriented grammar, we
-   *          explicitly exclude the newline character from the list of
-   *          whitespace characters.
-   *        - Note that both EOF (-1) and the nul character ('\0') are
-   *          considered end-of-file markers.
-   *
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  int c;
-
-  for( c = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) )
-    ;
-  return( c );
-  } /* EatWhitespace */
-
-static int EatComment( FILE *InFile )
-  /* ------------------------------------------------------------------------ **
-   * Scan to the end of a comment.
-   *
-   *  Input:  InFile  - Input source.
-   *
-   *  Output: The character that marks the end of the comment.  Normally,
-   *          this will be a newline, but it *might* be an EOF.
-   *
-   *  Notes:  Because the config files use a line-oriented grammar, we
-   *          explicitly exclude the newline character from the list of
-   *          whitespace characters.
-   *        - Note that both EOF (-1) and the nul character ('\0') are
-   *          considered end-of-file markers.
-   *
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  int c;
-
-  for( c = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) )
-    ;
-  return( c );
-  } /* EatComment */
-
-static int Continuation( char *line, int pos )
-  /* ------------------------------------------------------------------------ **
-   * Scan backards within a string to discover if the last non-whitespace
-   * character is a line-continuation character ('\\').
-   *
-   *  Input:  line  - A pointer to a buffer containing the string to be
-   *                  scanned.
-   *          pos   - This is taken to be the offset of the end of the
-   *                  string.  This position is *not* scanned.
-   *
-   *  Output: The offset of the '\\' character if it was found, or -1 to
-   *          indicate that it was not.
-   *
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  pos--;
-  while( (pos >= 0) && isspace(((unsigned char *)line)[pos]) )
-     pos--;
-
-  return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
-  } /* Continuation */
-
-
-static BOOL Section( FILE *InFile, BOOL (*sfunc)(char *) )
-  /* ------------------------------------------------------------------------ **
-   * Scan a section name, and pass the name to function sfunc().
-   *
-   *  Input:  InFile  - Input source.
-   *          sfunc   - Pointer to the function to be called if the section
-   *                    name is successfully read.
-   *
-   *  Output: True if the section name was read and True was returned from
-   *          <sfunc>.  False if <sfunc> failed or if a lexical error was
-   *          encountered.
-   *
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  int   c;
-  int   i;
-  int   end;
-  char *func  = "params.c:Section() -";
-
-  i = 0;      /* <i> is the offset of the next free byte in bufr[] and  */
-  end = 0;    /* <end> is the current "end of string" offset.  In most  */
-              /* cases these will be the same, but if the last          */
-              /* character written to bufr[] is a space, then <end>     */
-              /* will be one less than <i>.                             */
-
-  c = EatWhitespace( InFile );    /* We've already got the '['.  Scan */
-                                  /* past initial white space.        */
-
-  while( (EOF != c) && (c > 0) )
-    {
-
-    /* Check that the buffer is big enough for the next character. */
-    if( i > (bSize - 2) )
-      {
-      bSize += BUFR_INC;
-      bufr   = realloc_array( bufr, char, bSize );
-      if( NULL == bufr )
-        {
-        rprintf(FERROR, "%s Memory re-allocation failure.", func);
-        return( False );
-        }
-      }
-
-    /* Handle a single character. */
-    switch( c )
-      {
-      case ']':                       /* Found the closing bracket.         */
-        bufr[end] = '\0';
-        if( 0 == end )                  /* Don't allow an empty name.       */
-          {
-          rprintf(FERROR, "%s Empty section name in configuration file.\n", func );
-          return( False );
-          }
-        if( !sfunc( bufr ) )            /* Got a valid name.  Deal with it. */
-          return( False );
-        (void)EatComment( InFile );     /* Finish off the line.             */
-        return( True );
-
-      case '\n':                      /* Got newline before closing ']'.    */
-        i = Continuation( bufr, i );    /* Check for line continuation.     */
-        if( i < 0 )
-          {
-          bufr[end] = '\0';
-          rprintf(FERROR, "%s Badly formed line in configuration file: %s\n",
-                   func, bufr );
-          return( False );
-          }
-        end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
-        c = getc( InFile );             /* Continue with next line.         */
-        break;
-
-      default:                        /* All else are a valid name chars.   */
-        if( isspace( c ) )              /* One space per whitespace region. */
-          {
-          bufr[end] = ' ';
-          i = end + 1;
-          c = EatWhitespace( InFile );
-          }
-        else                            /* All others copy verbatim.        */
-          {
-          bufr[i++] = c;
-          end = i;
-          c = getc( InFile );
-          }
-      }
-    }
-
-  /* We arrive here if we've met the EOF before the closing bracket. */
-  rprintf(FERROR, "%s Unexpected EOF in the configuration file: %s\n", func, bufr );
-  return( False );
-  } /* Section */
-
-static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
-  /* ------------------------------------------------------------------------ **
-   * Scan a parameter name and value, and pass these two fields to pfunc().
-   *
-   *  Input:  InFile  - The input source.
-   *          pfunc   - A pointer to the function that will be called to
-   *                    process the parameter, once it has been scanned.
-   *          c       - The first character of the parameter name, which
-   *                    would have been read by Parse().  Unlike a comment
-   *                    line or a section header, there is no lead-in
-   *                    character that can be discarded.
-   *
-   *  Output: True if the parameter name and value were scanned and processed
-   *          successfully, else False.
-   *
-   *  Notes:  This function is in two parts.  The first loop scans the
-   *          parameter name.  Internal whitespace is compressed, and an
-   *          equal sign (=) terminates the token.  Leading and trailing
-   *          whitespace is discarded.  The second loop scans the parameter
-   *          value.  When both have been successfully identified, they are
-   *          passed to pfunc() for processing.
-   *
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  int   i       = 0;    /* Position within bufr. */
-  int   end     = 0;    /* bufr[end] is current end-of-string. */
-  int   vstart  = 0;    /* Starting position of the parameter value. */
-  char *func    = "params.c:Parameter() -";
-
-  /* Read the parameter name. */
-  while( 0 == vstart )  /* Loop until we've found the start of the value. */
-    {
-
-    if( i > (bSize - 2) )       /* Ensure there's space for next char.    */
-      {
-      bSize += BUFR_INC;
-      bufr   = realloc_array( bufr, char, bSize );
-      if( NULL == bufr )
-        {
-        rprintf(FERROR, "%s Memory re-allocation failure.", func) ;
-        return( False );
-        }
-      }
-
-    switch( c )
-      {
-      case '=':                 /* Equal sign marks end of param name. */
-        if( 0 == end )              /* Don't allow an empty name.      */
-          {
-          rprintf(FERROR, "%s Invalid parameter name in config. file.\n", func );
-          return( False );
-          }
-        bufr[end++] = '\0';         /* Mark end of string & advance.   */
-        i       = end;              /* New string starts here.         */
-        vstart  = end;              /* New string is parameter value.  */
-        bufr[i] = '\0';             /* New string is nul, for now.     */
-        break;
-
-      case '\n':                /* Find continuation char, else error. */
-        i = Continuation( bufr, i );
-        if( i < 0 )
-          {
-          bufr[end] = '\0';
-          rprintf(FERROR, "%s Ignoring badly formed line in configuration file: %s\n",
-                   func, bufr );
-          return( True );
-          }
-        end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
-        c = getc( InFile );       /* Read past eoln.                   */
-        break;
-
-      case '\0':                /* Shouldn't have EOF within param name. */
-      case EOF:
-        bufr[i] = '\0';
-        rprintf(FERROR, "%s Unexpected end-of-file at: %s\n", func, bufr );
-        return( True );
-
-      default:
-        if( isspace( c ) )     /* One ' ' per whitespace region.       */
-          {
-          bufr[end] = ' ';
-          i = end + 1;
-          c = EatWhitespace( InFile );
-          }
-        else                   /* All others verbatim.                 */
-          {
-          bufr[i++] = c;
-          end = i;
-          c = getc( InFile );
-          }
-      }
-    }
-
-  /* Now parse the value. */
-  c = EatWhitespace( InFile );  /* Again, trim leading whitespace. */
-  while( (EOF !=c) && (c > 0) )
-    {
-
-    if( i > (bSize - 2) )       /* Make sure there's enough room. */
-      {
-      bSize += BUFR_INC;
-      bufr   = realloc_array( bufr, char, bSize );
-      if( NULL == bufr )
-        {
-        rprintf(FERROR, "%s Memory re-allocation failure.", func) ;
-        return( False );
-        }
-      }
-
-    switch( c )
-      {
-      case '\r':              /* Explicitly remove '\r' because the older */
-        c = getc( InFile );   /* version called fgets_slash() which also  */
-        break;                /* removes them.                            */
-
-      case '\n':              /* Marks end of value unless there's a '\'. */
-        i = Continuation( bufr, i );
-        if( i < 0 )
-          c = 0;
-        else
-          {
-          for( end = i; (end >= 0) && isspace(((unsigned char *) bufr)[end]); end-- )
-            ;
-          c = getc( InFile );
-          }
-        break;
-
-      default:               /* All others verbatim.  Note that spaces do */
-        bufr[i++] = c;       /* not advance <end>.  This allows trimming  */
-        if( !isspace( c ) )  /* of whitespace at the end of the line.     */
-          end = i;
-        c = getc( InFile );
-        break;
-      }
-    }
-  bufr[end] = '\0';          /* End of value. */
-
-  return( pfunc( bufr, &bufr[vstart] ) );   /* Pass name & value to pfunc().  */
-  } /* Parameter */
-
-static BOOL Parse( FILE *InFile,
-                   BOOL (*sfunc)(char *),
-                   BOOL (*pfunc)(char *, char *) )
-  /* ------------------------------------------------------------------------ **
-   * Scan & parse the input.
-   *
-   *  Input:  InFile  - Input source.
-   *          sfunc   - Function to be called when a section name is scanned.
-   *                    See Section().
-   *          pfunc   - Function to be called when a parameter is scanned.
-   *                    See Parameter().
-   *
-   *  Output: True if the file was successfully scanned, else False.
-   *
-   *  Notes:  The input can be viewed in terms of 'lines'.  There are four
-   *          types of lines:
-   *            Blank      - May contain whitespace, otherwise empty.
-   *            Comment    - First non-whitespace character is a ';' or '#'.
-   *                         The remainder of the line is ignored.
-   *            Section    - First non-whitespace character is a '['.
-   *            Parameter  - The default case.
-   * 
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  int    c;
-
-  c = EatWhitespace( InFile );
-  while( (EOF != c) && (c > 0) )
-    {
-    switch( c )
-      {
-      case '\n':                        /* Blank line. */
-        c = EatWhitespace( InFile );
-        break;
-
-      case ';':                         /* Comment line. */
-      case '#':
-        c = EatComment( InFile );
-        break;
-
-      case '[':                         /* Section Header. */
-             if (!sfunc) return True;
-             if( !Section( InFile, sfunc ) )
-                     return( False );
-             c = EatWhitespace( InFile );
-             break;
-
-      case '\\':                        /* Bogus backslash. */
-        c = EatWhitespace( InFile );
-        break;
-
-      default:                          /* Parameter line. */
-        if( !Parameter( InFile, pfunc, c ) )
-          return( False );
-        c = EatWhitespace( InFile );
-        break;
-      }
-    }
-  return( True );
-  } /* Parse */
-
-static FILE *OpenConfFile( char *FileName )
-  /* ------------------------------------------------------------------------ **
-   * Open a configuration file.
-   *
-   *  Input:  FileName  - The pathname of the config file to be opened.
-   *
-   *  Output: A pointer of type (FILE *) to the opened file, or NULL if the
-   *          file could not be opened.
-   *
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  FILE *OpenedFile;
-  char *func = "params.c:OpenConfFile() -";
-
-  if( NULL == FileName || 0 == *FileName )
-    {
-    rprintf(FERROR,"%s No configuration filename specified.\n", func);
-    return( NULL );
-    }
-
-  OpenedFile = fopen( FileName, "r" );
-  if( NULL == OpenedFile )
-    {
-    rsyserr(FERROR, errno, "unable to open configuration file \"%s\"",
-           FileName);
-    }
-
-  return( OpenedFile );
-  } /* OpenConfFile */
-
-BOOL pm_process( char *FileName,
-                 BOOL (*sfunc)(char *),
-                 BOOL (*pfunc)(char *, char *) )
-  /* ------------------------------------------------------------------------ **
-   * Process the named parameter file.
-   *
-   *  Input:  FileName  - The pathname of the parameter file to be opened.
-   *          sfunc     - A pointer to a function that will be called when
-   *                      a section name is discovered.
-   *          pfunc     - A pointer to a function that will be called when
-   *                      a parameter name and value are discovered.
-   *
-   *  Output: TRUE if the file was successfully parsed, else FALSE.
-   *
-   * ------------------------------------------------------------------------ **
-   */
-  {
-  int   result;
-  FILE *InFile;
-  char *func = "params.c:pm_process() -";
-
-  InFile = OpenConfFile( FileName );          /* Open the config file. */
-  if( NULL == InFile )
-    return( False );
-
-  if( NULL != bufr )                          /* If we already have a buffer */
-    result = Parse( InFile, sfunc, pfunc );   /* (recursive call), then just */
-                                              /* use it.                     */
-
-  else                                        /* If we don't have a buffer   */
-    {                                         /* allocate one, then parse,   */
-    bSize = BUFR_INC;                         /* then free.                  */
-    bufr = new_array( char, bSize );
-    if( NULL == bufr )
-      {
-      rprintf(FERROR,"%s memory allocation failure.\n", func);
-      fclose(InFile);
-      return( False );
-      }
-    result = Parse( InFile, sfunc, pfunc );
-    free( bufr );
-    bufr  = NULL;
-    bSize = 0;
-    }
-
-  fclose(InFile);
-
-  if( !result )                               /* Generic failure. */
-    {
-    rprintf(FERROR,"%s Failed.  Error returned from params.c:parse().\n", func);
-    return( False );
-    }
-
-  return( True );                             /* Generic success. */
-  } /* pm_process */
-
-/* -------------------------------------------------------------------------- */
-
diff --git a/devices/params.h b/devices/params.h
deleted file mode 100644 (file)
index 02a39c9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-#define BOOL int
-
-BOOL pm_process( char *FileName,
-                 BOOL (*sfunc)(char *),
-                 BOOL (*pfunc)(char *, char *) );
diff --git a/devices/parser-test.c b/devices/parser-test.c
deleted file mode 100644 (file)
index 8c94d3f..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#define _GNU_SOURCE
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "parser.h"
-#include "paths.h"
-
-void pb_log(const char *fmt, ...)
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       vfprintf(stderr, fmt, ap);
-       va_end(ap);
-}
-
-int mount_device(const char *dev_path)
-{
-       printf("[mount] %s\n", dev_path);
-       return 0;
-}
-
-static int device_idx;
-static int option_idx;
-
-int add_device(const struct device *dev)
-{
-       printf("[dev %2d] id: %s\n", device_idx, dev->id);
-       printf("[dev %2d] name: %s\n", device_idx, dev->name);
-       printf("[dev %2d] description: %s\n", device_idx, dev->description);
-       printf("[dev %2d] boot_image: %s\n", device_idx, dev->icon_file);
-
-       device_idx++;
-       option_idx = 0;
-       return 0;
-}
-
-
-int add_boot_option(const struct boot_option *opt)
-{
-       if (!device_idx) {
-               fprintf(stderr, "Option (%s) added before device\n",
-                               opt->name);
-               exit(EXIT_FAILURE);
-       }
-
-       printf("[opt %2d] name: %s\n", option_idx, opt->name);
-       printf("[opt %2d] description: %s\n", option_idx, opt->description);
-       printf("[opt %2d] boot_image: %s\n", option_idx, opt->boot_image_file);
-       printf("[opt %2d] initrd: %s\n", option_idx, opt->initrd_file);
-       printf("[opt %2d] boot_args: %s\n", option_idx, opt->boot_args);
-
-       option_idx++;
-
-       return 0;
-}
-
-enum generic_icon_type guess_device_type(void)
-{
-       return ICON_TYPE_UNKNOWN;
-}
-
-int main(int argc, char **argv)
-{
-       char *mountpoint, *dev;
-
-       if (argc != 3) {
-               fprintf(stderr, "usage: %s <basedir> <devname>\n", argv[0]);
-               return EXIT_FAILURE;
-       }
-
-       mountpoint = argv[1];
-       dev = argv[2];
-
-       set_mount_base(mountpoint);
-
-       iterate_parsers(dev, mountpoint);
-
-
-       return EXIT_SUCCESS;
-}
diff --git a/devices/parser-test.sh b/devices/parser-test.sh
deleted file mode 100755 (executable)
index 140601e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-testdir=devices/parser-tests
-default_rootdev=ps3da1
-
-function test_dir()
-{
-       dir="$1"
-       rootdev=$default_rootdev
-       if [ -e "$dir/rootdev" ]
-       then
-               rootdev=$(cat "$dir/rootdev")
-       fi
-       ./parser-test "$dir" /dev/$rootdev 2>/dev/null |
-               diff -u "$dir/expected-output" -
-}
-
-set -ex
-
-for test in $testdir/*
-do
-       echo $test
-       test_dir "$test"
-done
-
-echo "All tests passed"
diff --git a/devices/parser-tests/001/expected-output b/devices/parser-tests/001/expected-output
deleted file mode 100644 (file)
index bace9f7..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-[dev  0] id: /dev/ps3da1
-[dev  0] name: (null)
-[dev  0] description: (null)
-[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
-[opt  0] name: live
-[opt  0] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
-[opt  0] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
-[opt  0] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
-[opt  0] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
-[opt  1] name: live_nosplash
-[opt  1] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
-[opt  1] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
-[opt  1] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
-[opt  1] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
-[opt  2] name: driverupdates
-[opt  2] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
-[opt  2] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
-[opt  2] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
-[opt  2] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
-[opt  3] name: check
-[opt  3] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
-[opt  3] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
-[opt  3] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
-[opt  3] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
diff --git a/devices/parser-tests/001/ps3da1/etc/kboot.conf b/devices/parser-tests/001/ps3da1/etc/kboot.conf
deleted file mode 100644 (file)
index 591c51b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Ubuntu feisty kboot.conf
-message=/etc/kboot.msg
-timeout=300
-default=live
-live='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --'
-live_nosplash='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet --'
-driverupdates='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --'
-check='/casper/vmlinux initrd=/casper/initrd.gz  boot=casper integrity-check quiet splash --'
-
diff --git a/devices/parser-tests/002/expected-output b/devices/parser-tests/002/expected-output
deleted file mode 100644 (file)
index 304f15c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[dev  0] id: /dev/ps3da1
-[dev  0] name: (null)
-[dev  0] description: 
-[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
-[opt  0] name: linux
-[opt  0] description: (null)
-[opt  0] boot_image: devices/parser-tests/002/ps3da1/ppc/ppc64/vmlinux
-[opt  0] initrd: devices/parser-tests/002/ps3da1/ppc/ppc64/ramdisk.image.gz
-[opt  0] boot_args: ro 
diff --git a/devices/parser-tests/002/ps3da1/etc/yaboot.conf b/devices/parser-tests/002/ps3da1/etc/yaboot.conf
deleted file mode 100644 (file)
index f13b1b3..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-init-message = "\nWelcome to the 64-bit Yellow Dog Linux 5.0 installer!\nHit <TAB> for boot options.\n\n"
-timeout=6000
-default=linux
-
-image=/ppc/ppc64/vmlinux
-       label=linux
-       initrd=/ppc/ppc64/ramdisk.image.gz
-       read-only
diff --git a/devices/parser-tests/003/expected-output b/devices/parser-tests/003/expected-output
deleted file mode 100644 (file)
index 4f60310..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[dev  0] id: /dev/ps3da1
-[dev  0] name: (null)
-[dev  0] description: (null)
-[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
-[opt  0] name: test
-[opt  0] description: /dev/sda1:/vmlinux
-[opt  0] boot_image: devices/parser-tests/003/ps3da1/vmlinux
-[opt  0] initrd: (null)
-[opt  0] boot_args: (null)
diff --git a/devices/parser-tests/003/ps3da1/etc/kboot.conf b/devices/parser-tests/003/ps3da1/etc/kboot.conf
deleted file mode 100644 (file)
index a7bb199..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# test remapping sda to ps3da, when mounted from a ps3da device
-
-test='/dev/sda1:/vmlinux'
-
diff --git a/devices/parser-tests/004/expected-output b/devices/parser-tests/004/expected-output
deleted file mode 100644 (file)
index 76a90a2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[dev  0] id: /dev/sda1
-[dev  0] name: (null)
-[dev  0] description: (null)
-[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
-[opt  0] name: test
-[opt  0] description: /dev/sda1:/vmlinux
-[opt  0] boot_image: devices/parser-tests/004/sda1/vmlinux
-[opt  0] initrd: (null)
-[opt  0] boot_args: (null)
diff --git a/devices/parser-tests/004/rootdev b/devices/parser-tests/004/rootdev
deleted file mode 100644 (file)
index 36cfa0d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sda1
diff --git a/devices/parser-tests/004/sda1/etc/kboot.conf b/devices/parser-tests/004/sda1/etc/kboot.conf
deleted file mode 100644 (file)
index 9755f77..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# test remapping sda to ps3da, when mounted from a plain sd device
-
-test='/dev/sda1:/vmlinux'
-
diff --git a/devices/parser-tests/005/expected-output b/devices/parser-tests/005/expected-output
deleted file mode 100644 (file)
index bfaccc8..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[dev  0] id: /dev/ps3da1
-[dev  0] name: (null)
-[dev  0] description: (null)
-[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
-[opt  0] name: test_uuid
-[opt  0] description: UUID=meep:/vmlinux
-[opt  0] boot_image: devices/parser-tests/005/disk/by-uuid/meep/vmlinux
-[opt  0] initrd: (null)
-[opt  0] boot_args: (null)
-[opt  1] name: test_label
-[opt  1] description: LABEL=meep:/vmlinux
-[opt  1] boot_image: devices/parser-tests/005/disk/by-label/meep/vmlinux
-[opt  1] initrd: (null)
-[opt  1] boot_args: (null)
diff --git a/devices/parser-tests/005/ps3da1/etc/kboot.conf b/devices/parser-tests/005/ps3da1/etc/kboot.conf
deleted file mode 100644 (file)
index 72b7db8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-# test for LABEL= and UUID= lookups
-
-test_uuid='UUID=meep:/vmlinux'
-test_label='LABEL=meep:/vmlinux'
-
diff --git a/devices/parser-tests/101/expected-output b/devices/parser-tests/101/expected-output
deleted file mode 100644 (file)
index 45d99a1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-[dev  0] id: /dev/ps3da1
-[dev  0] name: (null)
-[dev  0] description: (null)
-[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
-[opt  0] name: ydl
-[opt  0] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:3 rhgb
-[opt  0] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
-[opt  0] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
-[opt  0] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:3 rhgb
-[opt  1] name: ydl480i
-[opt  1] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:1 rhgb
-[opt  1] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
-[opt  1] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
-[opt  1] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:1 rhgb
-[opt  2] name: ydl1080i
-[opt  2] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:4 rhgb
-[opt  2] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
-[opt  2] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
-[opt  2] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:4 rhgb
-[opt  3] name: ydltext
-[opt  3] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init 3
-[opt  3] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
-[opt  3] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
-[opt  3] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init 3
diff --git a/devices/parser-tests/101/ps3da1/etc/kboot.conf b/devices/parser-tests/101/ps3da1/etc/kboot.conf
deleted file mode 100644 (file)
index 4a986c0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# kboot.conf for ydl
-
-default=ydl
-timeout=10
-root=/dev/sda1
-ydl='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init video=ps3fb:mode:3 rhgb'
-ydl480i='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init video=ps3fb:mode:1 rhgb'
-ydl1080i='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init video=ps3fb:mode:4 rhgb'
-ydltext='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init 3'
-
-
-
diff --git a/devices/parser-tests/102/expected-output b/devices/parser-tests/102/expected-output
deleted file mode 100644 (file)
index cc0d096..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-[dev  0] id: /dev/ps3da1
-[dev  0] name: (null)
-[dev  0] description: (null)
-[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
-[opt  0] name: live
-[opt  0] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
-[opt  0] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
-[opt  0] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
-[opt  0] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
-[opt  1] name: live_nosplash
-[opt  1] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
-[opt  1] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
-[opt  1] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
-[opt  1] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
-[opt  2] name: driverupdates
-[opt  2] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
-[opt  2] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
-[opt  2] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
-[opt  2] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
-[opt  3] name: check
-[opt  3] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
-[opt  3] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
-[opt  3] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
-[opt  3] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
diff --git a/devices/parser-tests/102/ps3da1/etc/kboot.conf b/devices/parser-tests/102/ps3da1/etc/kboot.conf
deleted file mode 100644 (file)
index 591c51b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Ubuntu feisty kboot.conf
-message=/etc/kboot.msg
-timeout=300
-default=live
-live='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --'
-live_nosplash='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet --'
-driverupdates='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --'
-check='/casper/vmlinux initrd=/casper/initrd.gz  boot=casper integrity-check quiet splash --'
-
diff --git a/devices/parser.c b/devices/parser.c
deleted file mode 100644 (file)
index 5e50dcb..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-
-#include <petitboot-paths.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "parser.h"
-
-extern struct parser native_parser;
-extern struct parser yaboot_parser;
-extern struct parser kboot_parser;
-
-/* array of parsers, ordered by priority */
-static struct parser *parsers[] = {
-       &native_parser,
-       &yaboot_parser,
-       &kboot_parser,
-       NULL
-};
-
-void iterate_parsers(const char *devpath, const char *mountpoint)
-{
-       int i;
-
-       pb_log("trying parsers for %s\n", devpath);
-
-       for (i = 0; parsers[i]; i++) {
-               pb_log("\ttrying parser '%s'\n", parsers[i]->name);
-               /* just use a dummy device path for now */
-               if (parsers[i]->parse(devpath))
-                       return;
-       }
-       pb_log("\tno boot_options found\n");
-}
-
-/* convenience functions for parsers */
-void free_device(struct device *dev)
-{
-       if (!dev)
-               return;
-       if (dev->id)
-               free(dev->id);
-       if (dev->name)
-               free(dev->name);
-       if (dev->description)
-               free(dev->description);
-       if (dev->icon_file)
-               free(dev->icon_file);
-       free(dev);
-}
-
-void free_boot_option(struct boot_option *opt)
-{
-       if (!opt)
-               return;
-       if (opt->name)
-               free(opt->name);
-       if (opt->description)
-               free(opt->description);
-       if (opt->icon_file)
-               free(opt->icon_file);
-       if (opt->boot_image_file)
-               free(opt->boot_image_file);
-       if (opt->initrd_file)
-               free(opt->initrd_file);
-       if (opt->boot_args)
-               free(opt->boot_args);
-       free(opt);
-}
-
-const char *generic_icon_file(enum generic_icon_type type)
-{
-       switch (type) {
-       case ICON_TYPE_DISK:
-               return artwork_pathname("hdd.png");
-       case ICON_TYPE_USB:
-               return artwork_pathname("usbpen.png");
-       case ICON_TYPE_OPTICAL:
-               return artwork_pathname("cdrom.png");
-       case ICON_TYPE_NETWORK:
-       case ICON_TYPE_UNKNOWN:
-               break;
-       }
-       return artwork_pathname("hdd.png");
-}
-
diff --git a/devices/parser.h b/devices/parser.h
deleted file mode 100644 (file)
index 9c6fb35..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-
-#ifndef _PARSERS_H
-#define _PARSERS_H
-
-#include <stdarg.h>
-#include "message.h"
-
-struct parser {
-       char *name;
-       int priority;
-       int (*parse)(const char *device);
-       struct parser *next;
-};
-
-enum generic_icon_type {
-       ICON_TYPE_DISK,
-       ICON_TYPE_USB,
-       ICON_TYPE_OPTICAL,
-       ICON_TYPE_NETWORK,
-       ICON_TYPE_UNKNOWN
-};
-
-#define streq(a,b) (!strcasecmp((a),(b)))
-
-/* general functions provided by parsers.c */
-void iterate_parsers(const char *devpath, const char *mountpoint);
-
-void free_device(struct device *dev);
-void free_boot_option(struct boot_option *opt);
-
-const char *generic_icon_file(enum generic_icon_type type);
-
-/* functions provided by udev-helper or the test wrapper */
-void pb_log(const char *fmt, ...);
-
-int mount_device(const char *dev_path);
-
-char *resolve_path(const char *path, const char *current_dev);
-const char *mountpoint_for_device(const char *dev_path);
-
-enum generic_icon_type guess_device_type(void);
-
-int add_device(const struct device *dev);
-int add_boot_option(const struct boot_option *opt);
-
-#endif /* _PARSERS_H */
diff --git a/devices/paths.c b/devices/paths.c
deleted file mode 100644 (file)
index 2373c28..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#define _GNU_SOURCE
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "paths.h"
-
-static char *mount_base;
-
-struct device_map {
-       char *dev, *mnt;
-};
-
-#define DEVICE_MAP_SIZE 32
-static struct device_map device_map[DEVICE_MAP_SIZE];
-
-char *encode_label(const char *label)
-{
-       char *str, *c;
-       int i;
-
-       /* the label can be expanded by up to four times */
-       str = malloc(strlen(label) * 4 + 1);
-       c = str;
-
-       for (i = 0; i < strlen(label); i++) {
-
-               if (label[i] == '/' || label[i] == '\\') {
-                       sprintf(c, "\\x%02x", label[i]);
-                       c += 4;
-                       continue;
-               }
-
-               *(c++) = label[i];
-       }
-
-       *c = '\0';
-
-       return str;
-}
-
-char *parse_device_path(const char *dev_str, const char *cur_dev)
-{
-       char *dev, tmp[256], *enc;
-
-       if (!strncasecmp(dev_str, "uuid=", 5)) {
-               asprintf(&dev, "/dev/disk/by-uuid/%s", dev_str + 5);
-               return dev;
-       }
-
-       if (!strncasecmp(dev_str, "label=", 6)) {
-               enc = encode_label(dev_str + 6);
-               asprintf(&dev, "/dev/disk/by-label/%s", enc);
-               free(enc);
-               return dev;
-       }
-
-       /* normalise '/dev/foo' to 'foo' for easy comparisons, we'll expand
-        * back before returning.
-        */
-       if (!strncmp(dev_str, "/dev/", 5))
-               dev_str += 5;
-
-       /* PS3 hack: if we're reading from a ps3dx device, and we refer to
-        * a sdx device, remap to ps3dx */
-       if (cur_dev && !strncmp(cur_dev, "/dev/ps3d", 9)
-                       && !strncmp(dev_str, "sd", 2)) {
-               snprintf(tmp, 255, "ps3d%s", dev_str + 2);
-               dev_str = tmp;
-       }
-
-       return join_paths("/dev", dev_str);
-}
-
-const char *mountpoint_for_device(const char *dev)
-{
-       int i;
-
-       if (!strncmp(dev, "/dev/", 5))
-               dev += 5;
-
-       /* check existing entries in the map */
-       for (i = 0; (i < DEVICE_MAP_SIZE) && device_map[i].dev; i++)
-               if (!strcmp(device_map[i].dev, dev))
-                       return device_map[i].mnt;
-
-       if (i == DEVICE_MAP_SIZE)
-               return NULL;
-
-       device_map[i].dev = strdup(dev);
-       device_map[i].mnt = join_paths(mount_base, dev);
-       return device_map[i].mnt;
-}
-
-char *resolve_path(const char *path, const char *current_dev)
-{
-       char *ret;
-       const char *devpath, *sep;
-
-       sep = strchr(path, ':');
-       if (!sep) {
-               devpath = mountpoint_for_device(current_dev);
-               ret = join_paths(devpath, path);
-       } else {
-               /* parse just the device name into dev */
-               char *tmp, *dev;
-               tmp = strndup(path, sep - path);
-               dev = parse_device_path(tmp, current_dev);
-
-               devpath = mountpoint_for_device(dev);
-               ret = join_paths(devpath, sep + 1);
-
-               free(dev);
-               free(tmp);
-       }
-
-       return ret;
-}
-
-void set_mount_base(const char *path)
-{
-       if (mount_base)
-               free(mount_base);
-       mount_base = strdup(path);
-}
-
-char *join_paths(const char *a, const char *b)
-{
-       char *full_path;
-
-       full_path = malloc(strlen(a) + strlen(b) + 2);
-
-       strcpy(full_path, a);
-       if (b[0] != '/' && a[strlen(a) - 1] != '/')
-               strcat(full_path, "/");
-       strcat(full_path, b);
-
-       return full_path;
-}
-
diff --git a/devices/paths.h b/devices/paths.h
deleted file mode 100644 (file)
index 26d4ce4..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef PATHS_H
-#define PATHS_H
-
-/**
- * Given a string (eg /dev/sda1, sda1 or UUID=B8E53381CA9EA0E3), parse the
- * device path (eg /dev/sda1). Any device descriptions read from config files
- * should be parsed into the path first.
- *
- * The cur_dev is provided for some remapping situations. If NULL is provided,
- * no remapping will be done.
- *
- * Returns a newly-allocated string.
- */
-char *parse_device_path(const char *dev_str, const char *current_device);
-
-/**
- * Get the mountpoint for a device.
- */
-const char *mountpoint_for_device(const char *dev);
-
-/**
- * Resolve a path given in a config file, to a path in the local filesystem.
- * Paths may be of the form:
- *  device:path (eg /dev/sda:/boot/vmlinux)
- *
- * or just a path:
- *  /boot/vmlinux
- * - in this case, the current mountpoint is used.
- *
- * Returns a newly-allocated string containing a full path to the file in path
- */
-char *resolve_path(const char *path, const char *current_device);
-
-
-/**
- * Set the base directory for newly-created mountpoints
- */
-void set_mount_base(const char *path);
-
-/**
- * Utility function for joining two paths. Adds a / between a and b if
- * required.
- *
- * Returns a newly-allocated string.
- */
-char *join_paths(const char *a, const char *b);
-
-/**
- * encode a disk label (or uuid) for use in a symlink.
- */
-char *encode_label(const char *label);
-
-#endif /* PATHS_H */
diff --git a/devices/petitboot-udev-helper.c b/devices/petitboot-udev-helper.c
deleted file mode 100644 (file)
index f2f15b1..0000000
+++ /dev/null
@@ -1,636 +0,0 @@
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <asm/byteorder.h>
-#include <linux/cdrom.h>
-#include <sys/ioctl.h>
-
-#include "parser.h"
-#include "paths.h"
-#include "petitboot-paths.h"
-
-/* Define below to operate without the frontend */
-#undef USE_FAKE_SOCKET
-
-/* Delay in seconds between polling of removable devices */
-#define REMOVABLE_SLEEP_DELAY  2
-
-static FILE *logf;
-static int sock;
-
-void pb_log(const char *fmt, ...)
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       vfprintf(logf, fmt, ap);
-       va_end(ap);
-}
-
-static void print_boot_option(const struct boot_option *opt)
-{
-       pb_log("\tname: %s\n", opt->name);
-       pb_log("\tdescription: %s\n", opt->description);
-       pb_log("\tboot_image: %s\n", opt->boot_image_file);
-       pb_log("\tinitrd: %s\n", opt->initrd_file);
-       pb_log("\tboot_args: %s\n", opt->boot_args);
-
-}
-
-static void print_device(const struct device *dev)
-{
-       pb_log("\tid: %s\n", dev->id);
-       pb_log("\tname: %s\n", dev->name);
-       pb_log("\tdescription: %s\n", dev->description);
-       pb_log("\tboot_image: %s\n", dev->icon_file);
-}
-
-static int write_action(int fd, enum device_action action)
-{
-       uint8_t action_buf = action;
-       return write(fd, &action_buf, sizeof(action_buf)) != sizeof(action_buf);
-}
-
-static int write_string(int fd, const char *str)
-{
-       int len, pos = 0;
-       uint32_t len_buf;
-
-       if (!str) {
-               len_buf = 0;
-               if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
-                       pb_log("write failed: %s\n", strerror(errno));
-                       return -1;
-               }
-               return 0;
-       }
-
-       len = strlen(str);
-       if (len > (1ull << (sizeof(len_buf) * 8 - 1))) {
-               pb_log("string too large\n");
-               return -1;
-       }
-
-       len_buf = __cpu_to_be32(len);
-       if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
-               pb_log("write failed: %s\n", strerror(errno));
-               return -1;
-       }
-
-       while (pos < len) {
-               int rc = write(fd, str, len - pos);
-               if (rc <= 0) {
-                       pb_log("write failed: %s\n", strerror(errno));
-                       return -1;
-               }
-               pos += rc;
-               str += rc;
-       }
-
-       return 0;
-}
-
-int add_device(const struct device *dev)
-{
-       int rc;
-
-       pb_log("device added:\n");
-       print_device(dev);
-       rc = write_action(sock, DEV_ACTION_ADD_DEVICE) ||
-               write_string(sock, dev->id) ||
-               write_string(sock, dev->name) ||
-               write_string(sock, dev->description) ||
-               write_string(sock, dev->icon_file);
-
-       if (rc)
-               pb_log("error writing device %s to socket\n", dev->name);
-
-       return rc;
-}
-
-int add_boot_option(const struct boot_option *opt)
-{
-       int rc;
-
-       pb_log("boot option added:\n");
-       print_boot_option(opt);
-
-       rc = write_action(sock, DEV_ACTION_ADD_OPTION) ||
-               write_string(sock, opt->id) ||
-               write_string(sock, opt->name) ||
-               write_string(sock, opt->description) ||
-               write_string(sock, opt->icon_file) ||
-               write_string(sock, opt->boot_image_file) ||
-               write_string(sock, opt->initrd_file) ||
-               write_string(sock, opt->boot_args);
-
-       if (rc)
-               pb_log("error writing boot option %s to socket\n", opt->name);
-
-       return rc;
-}
-
-int remove_device(const char *dev_path)
-{
-       return write_action(sock, DEV_ACTION_REMOVE_DEVICE) ||
-               write_string(sock, dev_path);
-}
-
-int connect_to_socket()
-{
-#ifndef USE_FAKE_SOCKET
-       int fd;
-       struct sockaddr_un addr;
-
-       fd = socket(PF_UNIX, SOCK_STREAM, 0);
-       if (fd == -1) {
-               pb_log("can't create socket: %s\n", strerror(errno));
-               return -1;
-       }
-
-       addr.sun_family = AF_UNIX;
-       strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
-
-       if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
-               pb_log("can't connect to %s: %s\n",
-                               addr.sun_path, strerror(errno));
-               return -1;
-       }
-       sock = fd;
-
-       return 0;
-#else
-       int fd;
-       fd = open("./debug_socket", O_WRONLY | O_CREAT, 0640);
-       if (fd < 0) {
-               pb_log("can't create output file: %s\n", strerror(errno));
-               return -1;
-       }
-       sock = fd;
-       return 0;
-#endif
-}
-
-static int mkdir_recursive(const char *dir)
-{
-       char *str, *sep;
-       int mode = 0755;
-       struct stat statbuf;
-
-       pb_log("mkdir_recursive(%s)\n", dir);
-
-       if (!*dir)
-               return 0;
-
-       if (!stat(dir, &statbuf)) {
-               if (!S_ISDIR(statbuf.st_mode)) {
-                       pb_log("%s: %s exists, but isn't a directory\n",
-                                       __func__, dir);
-                       return -1;
-               }
-               return 0;
-       }
-
-       str = strdup(dir);
-       sep = strchr(*str == '/' ? str + 1 : str, '/');
-
-       while (1) {
-
-               /* terminate the path at sep */
-               if (sep)
-                       *sep = '\0';
-               pb_log("mkdir(%s)\n", str);
-
-               if (mkdir(str, mode) && errno != EEXIST) {
-                       pb_log("mkdir(%s): %s\n", str, strerror(errno));
-                       return -1;
-               }
-
-               if (!sep)
-                       break;
-
-               /* reset dir to the full path */
-               strcpy(str, dir);
-               sep = strchr(sep + 1, '/');
-       }
-
-       free(str);
-
-       return 0;
-}
-
-static void setup_device_links(const char *device)
-{
-       struct link {
-               char *env, *dir;
-       } *link, links[] = {
-               {
-                       .env = "ID_FS_UUID",
-                       .dir = "disk/by-uuid"
-               },
-               {
-                       .env = "ID_FS_LABEL",
-                       .dir = "disk/by-label"
-               },
-               {
-                       .env = NULL
-               }
-       };
-
-       for (link = links; link->env; link++) {
-               char *value, *dir, *path;
-
-               value = getenv(link->env);
-               if (!value)
-                       continue;
-
-               value = encode_label(value);
-               dir = join_paths(TMP_DIR, link->dir);
-               path = join_paths(dir, value);
-
-               if (!mkdir_recursive(dir)) {
-                       unlink(path);
-                       if (symlink(mountpoint_for_device(device), path)) {
-                               pb_log("symlink(%s): %s\n",
-                                               path, strerror(errno));
-                       }
-               }
-
-               free(path);
-               free(dir);
-               free(value);
-       }
-}
-
-int mount_device(const char *dev_path)
-{
-       const char *dir;
-       int pid, status, rc = -1;
-       struct stat statbuf;
-
-       dir = mountpoint_for_device(dev_path);
-
-       if (stat(dir, &statbuf)) {
-               if (mkdir(dir, 0755)) {
-                       pb_log("couldn't create directory %s: %s\n",
-                                       dir, strerror(errno));
-                       goto out;
-               }
-       } else {
-               if (!S_ISDIR(statbuf.st_mode)) {
-                       pb_log("mountpoint %s exists, "
-                                       "but isn't a directory\n", dir);
-                       goto out;
-               }
-       }
-
-
-       pid = fork();
-       if (pid == -1) {
-               pb_log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno));
-               goto out;
-       }
-
-       if (pid == 0) {
-               execl(MOUNT_BIN, MOUNT_BIN, dev_path, dir, "-o", "ro", NULL);
-               exit(EXIT_FAILURE);
-       }
-
-       if (waitpid(pid, &status, 0) == -1) {
-               pb_log("%s: waitpid failed: %s\n", __FUNCTION__,
-                               strerror(errno));
-               goto out;
-       }
-
-       if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-               setup_device_links(dev_path);
-               rc = 0;
-       }
-
-out:
-       return rc;
-}
-
-static int unmount_device(const char *dev_path)
-{
-       int pid, status, rc;
-
-       pid = fork();
-
-       if (pid == -1) {
-               pb_log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno));
-               return -1;
-       }
-
-       if (pid == 0) {
-               execl(UMOUNT_BIN, UMOUNT_BIN, dev_path, NULL);
-               exit(EXIT_FAILURE);
-       }
-
-       if (waitpid(pid, &status, 0) == -1) {
-               pb_log("%s: waitpid failed: %s\n", __FUNCTION__,
-                               strerror(errno));
-               return -1;
-       }
-
-       rc = !WIFEXITED(status) || WEXITSTATUS(status) != 0;
-
-       return rc;
-}
-
-static const struct device fake_boot_devices[] =
-{
-       {
-               .id             = "fakeDisk0",
-               .name           = "Hard Disk",
-               .icon_file      = artwork_pathname("hdd.png"),
-       },
-       {
-               .id             = "fakeDisk1",
-               .name           = "PinkCat Linux CD",
-               .icon_file      = artwork_pathname("cdrom.png"),
-       }
-};
-
-static const struct boot_option fake_boot_options[] =
-{
-       {
-               .id             = "fakeBoot0",
-               .name           = "Bloobuntu Linux",
-               .description    = "Boot Bloobuntu Linux",
-               .icon_file      = artwork_pathname("hdd.png"),
-       },
-       {
-               .id             = "fakeBoot1",
-               .name           = "Pendora Gore 6",
-               .description    = "Boot Pendora Gora 6",
-               .icon_file      = artwork_pathname("hdd.png"),
-       },
-       {
-               .id             = "fakeBoot2",
-               .name           = "Genfoo Minux",
-               .description    = "Boot Genfoo Minux",
-               .icon_file      = artwork_pathname("hdd.png"),
-       },
-       {
-               .id             = "fakeBoot3",
-               .name           = "PinkCat Linux",
-               .description    = "Install PinkCat Linux - Graphical install",
-               .icon_file      = artwork_pathname("cdrom.png"),
-       },
-};
-
-enum generic_icon_type guess_device_type(void)
-{
-       const char *type = getenv("ID_TYPE");
-       const char *bus = getenv("ID_BUS");
-       if (type && streq(type, "cd"))
-               return ICON_TYPE_OPTICAL;
-       if (!bus)
-               return ICON_TYPE_UNKNOWN;
-       if (streq(bus, "usb"))
-               return ICON_TYPE_USB;
-       if (streq(bus, "ata") || streq(bus, "scsi"))
-               return ICON_TYPE_DISK;
-       return ICON_TYPE_UNKNOWN;
-}
-
-
-static int is_removable_device(const char *sysfs_path) 
-{
-       char full_path[PATH_MAX];
-       char buf[80];
-       int fd, buf_len;
-
-       sprintf(full_path, "/sys/%s/removable", sysfs_path);    
-       fd = open(full_path, O_RDONLY);
-       pb_log(" -> removable check on %s, fd=%d\n", full_path, fd);
-       if (fd < 0)
-               return 0;
-       buf_len = read(fd, buf, 79);
-       close(fd);
-       if (buf_len < 0)
-               return 0;
-       buf[buf_len] = 0;
-       return strtol(buf, NULL, 10);
-}
-
-static int is_ignored_device(const char *devname)
-{
-       static const char *ignored_devices[] =
-               { "/dev/ram", "/dev/loop", NULL };
-       const char **dev;
-
-       for (dev = ignored_devices; *dev; dev++)
-               if (!strncmp(devname, *dev, strlen(*dev)))
-                       return 1;
-
-       return 0;
-}
-
-static int found_new_device(const char *dev_path)
-{
-       const char *mountpoint = mountpoint_for_device(dev_path);
-
-       if (mount_device(dev_path)) {
-               pb_log("failed to mount %s\n", dev_path);
-               return EXIT_FAILURE;
-       }
-
-       pb_log("mounted %s at %s\n", dev_path, mountpoint);
-
-       iterate_parsers(dev_path, mountpoint);
-
-       return EXIT_SUCCESS;
-}
-
-static void detach_and_sleep(int sec)
-{
-       static int forked = 0;
-       int rc = 0;
-
-       if (sec <= 0)
-               return;
-
-       if (!forked) {
-               pb_log("running in background...");
-               rc = fork();
-               forked = 1;
-       }
-
-       if (rc == 0) {
-               sleep(sec);
-
-       } else if (rc == -1) {
-               perror("fork()");
-               exit(EXIT_FAILURE);
-       } else {
-               exit(EXIT_SUCCESS);
-       }
-}
-
-static int poll_device_plug(const char *dev_path,
-                           int *optical)
-{
-       int rc, fd;
-
-       /* Polling loop for optical drive */
-       for (; (*optical) != 0; ) {
-               fd = open(dev_path, O_RDONLY|O_NONBLOCK);
-               if (fd < 0)
-                       return EXIT_FAILURE;
-               rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
-               close(fd);
-               if (rc == -1)
-                       break;
-
-               *optical = 1;
-               if (rc == CDS_DISC_OK)
-                       return EXIT_SUCCESS;
-
-               detach_and_sleep(REMOVABLE_SLEEP_DELAY);
-       }
-
-       /* Fall back to bare open() */
-       *optical = 0;
-       for (;;) {
-               fd = open(dev_path, O_RDONLY);
-               if (fd < 0 && errno != ENOMEDIUM)
-                       return EXIT_FAILURE;
-               close(fd);
-               if (fd >= 0)
-                       return EXIT_SUCCESS;
-               detach_and_sleep(REMOVABLE_SLEEP_DELAY);
-       }
-}
-
-static int poll_device_unplug(const char *dev_path, int optical)
-{
-       int rc, fd;
-
-       for (;optical;) {
-               fd = open(dev_path, O_RDONLY|O_NONBLOCK);
-               if (fd < 0)
-                       return EXIT_FAILURE;
-               rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
-               close(fd);
-               if (rc != CDS_DISC_OK)
-                       return EXIT_SUCCESS;
-               detach_and_sleep(REMOVABLE_SLEEP_DELAY);
-       }
-
-       /* Fall back to bare open() */
-       for (;;) {
-               fd = open(dev_path, O_RDONLY);
-               if (fd < 0 && errno != ENOMEDIUM)
-                       return EXIT_FAILURE;
-               close(fd);
-               if (fd < 0)
-                       return EXIT_SUCCESS;
-               detach_and_sleep(REMOVABLE_SLEEP_DELAY);
-       }
-}
-
-static int poll_removable_device(const char *sysfs_path,
-                                const char *dev_path)
-{
-       int rc, mounted, optical = -1;
-       
-       for (;;) {
-               rc = poll_device_plug(dev_path, &optical);
-               if (rc == EXIT_FAILURE)
-                       return rc;
-               rc = found_new_device(dev_path);
-               mounted = (rc == EXIT_SUCCESS);
-
-               poll_device_unplug(dev_path, optical);
-
-               remove_device(dev_path);
-
-               /* Unmount it repeatedly, if needs be */
-               while (mounted && !unmount_device(dev_path))
-                       ;
-               detach_and_sleep(1);
-       }
-}
-
-int main(int argc, char **argv)
-{
-       char *dev_path, *action;
-       int rc;
-
-       action = getenv("ACTION");
-
-       logf = fopen("/var/log/petitboot-udev-helpers.log", "a");
-       if (!logf)
-               logf = stdout;
-       pb_log("%d started\n", getpid());
-       rc = EXIT_SUCCESS;
-
-       if (!action) {
-               pb_log("missing environment?\n");
-               return EXIT_FAILURE;
-       }
-
-       set_mount_base(TMP_DIR);
-
-       if (connect_to_socket())
-               return EXIT_FAILURE;
-
-       if (streq(action, "fake")) {
-               pb_log("fake mode");
-
-               add_device(&fake_boot_devices[0]);
-               add_boot_option(&fake_boot_options[0]);
-               add_boot_option(&fake_boot_options[1]);
-               add_boot_option(&fake_boot_options[2]);
-               add_device(&fake_boot_devices[1]);
-               add_boot_option(&fake_boot_options[3]);
-
-               return EXIT_SUCCESS;
-       }
-
-       dev_path = getenv("DEVNAME");
-       if (!dev_path) {
-               pb_log("missing environment?\n");
-               return EXIT_FAILURE;
-       }
-
-       if (is_ignored_device(dev_path))
-               return EXIT_SUCCESS;
-
-       if (streq(action, "add")) {
-               char *sysfs_path = getenv("DEVPATH");
-               if (sysfs_path && is_removable_device(sysfs_path))
-                       rc = poll_removable_device(sysfs_path, dev_path);
-               else
-                       rc = found_new_device(dev_path);
-       } else if (streq(action, "remove")) {
-               pb_log("%s removed\n", dev_path);
-
-               remove_device(dev_path);
-
-               /* Unmount it repeatedly, if needs be */
-               while (!unmount_device(dev_path))
-                       ;
-
-       } else {
-               pb_log("invalid action '%s'\n", action);
-               rc = EXIT_FAILURE;
-       }
-       return rc;
-}
diff --git a/devices/yaboot-cfg.c b/devices/yaboot-cfg.c
deleted file mode 100644 (file)
index 6b007e4..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- *  cfg.c - Handling and parsing of yaboot.conf
- *
- *  Copyright (C) 1995 Werner Almesberger
- *                1996 Jakub Jelinek
- *
- *  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; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#define prom_printf printf
-#define prom_putchar putchar
-#define prom_vprintf vprintf
-
-/* Imported functions */
-extern int strcasecmp(const char *s1, const char *s2);
-
-typedef enum {
-     cft_strg, cft_flag, cft_end
-} CONFIG_TYPE;
-
-typedef struct {
-     CONFIG_TYPE type;
-     char *name;
-     void *data;
-} CONFIG;
-
-#define MAX_TOKEN 200
-#define MAX_VAR_NAME MAX_TOKEN
-char *cfg_get_default (void);
-
-CONFIG cf_options[] =
-{
-     {cft_strg, "device", NULL},
-     {cft_strg, "partition", NULL},
-     {cft_strg, "default", NULL},
-     {cft_strg, "timeout", NULL},
-     {cft_strg, "password", NULL},
-     {cft_flag, "restricted", NULL},
-     {cft_strg, "message", NULL},
-     {cft_strg, "root", NULL},
-     {cft_strg, "ramdisk", NULL},
-     {cft_flag, "read-only", NULL},
-     {cft_flag, "read-write", NULL},
-     {cft_strg, "append", NULL},
-     {cft_strg, "initrd", NULL},
-     {cft_flag, "initrd-prompt", NULL},
-     {cft_strg, "initrd-size", NULL},
-     {cft_flag, "pause-after", NULL},
-     {cft_strg, "pause-message", NULL},
-     {cft_strg, "init-code", NULL},
-     {cft_strg, "init-message", NULL},
-     {cft_strg, "fgcolor", NULL},
-     {cft_strg, "bgcolor", NULL},
-     {cft_strg, "ptypewarning", NULL},
-     {cft_end, NULL, NULL}};
-
-CONFIG cf_image[] =
-{
-     {cft_strg, "image", NULL},
-     {cft_strg, "label", NULL},
-     {cft_strg, "alias", NULL},
-     {cft_flag, "single-key", NULL},
-     {cft_flag, "restricted", NULL},
-     {cft_strg, "device", NULL},
-     {cft_strg, "partition", NULL},
-     {cft_strg, "root", NULL},
-     {cft_strg, "ramdisk", NULL},
-     {cft_flag, "read-only", NULL},
-     {cft_flag, "read-write", NULL},
-     {cft_strg, "append", NULL},
-     {cft_strg, "literal", NULL},
-     {cft_strg, "initrd", NULL},
-     {cft_flag, "initrd-prompt", NULL},
-     {cft_strg, "initrd-size", NULL},
-     {cft_flag, "pause-after", NULL},
-     {cft_strg, "pause-message", NULL},
-     {cft_flag, "novideo", NULL},
-     {cft_strg, "sysmap", NULL},
-     {cft_end, NULL, NULL}};
-
-static char flag_set;
-static char *last_token = NULL, *last_item = NULL, *last_value = NULL;
-static int line_num;
-static int back = 0;           /* can go back by one char */
-static char *currp = NULL;
-static char *endp = NULL;
-static char *file_name = NULL;
-static CONFIG *curr_table = cf_options;
-static jmp_buf env;
-
-static struct IMAGES {
-     CONFIG table[sizeof (cf_image) / sizeof (cf_image[0])];
-     struct IMAGES *next;
-} *images = NULL;
-
-void cfg_error (char *msg,...)
-{
-     va_list ap;
-
-     va_start (ap, msg);
-     prom_printf ("Config file error: ");
-     prom_vprintf (msg, ap);
-     va_end (ap);
-     prom_printf (" near line %d in file %s\n", line_num, file_name);
-     longjmp (env, 1);
-}
-
-void cfg_warn (char *msg,...)
-{
-     va_list ap;
-
-     va_start (ap, msg);
-     prom_printf ("Config file warning: ");
-     prom_vprintf (msg, ap);
-     va_end (ap);
-     prom_printf (" near line %d in file %s\n", line_num, file_name);
-}
-
-int cfg_getc ()
-{
-     if (currp == endp)
-         return EOF;
-     return *currp++;
-}
-
-#define next_raw next
-static int next (void)
-{
-     int ch;
-
-     if (!back)
-         return cfg_getc ();
-     ch = back;
-     back = 0;
-     return ch;
-}
-
-static void again (int ch)
-{
-     back = ch;
-}
-
-static char *cfg_get_token (void)
-{
-     char buf[MAX_TOKEN + 1];
-     char *here;
-     int ch, escaped;
-
-     if (last_token) {
-         here = last_token;
-         last_token = NULL;
-         return here;
-     }
-     while (1) {
-         while (ch = next (), ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
-              if (ch == '\n' || ch == '\r')
-                   line_num++;
-         if (ch == EOF || ch == (int)NULL)
-              return NULL;
-         if (ch != '#')
-              break;
-         while (ch = next_raw (), (ch != '\n' && ch != '\r'))
-              if (ch == EOF)
-                   return NULL;
-         line_num++;
-     }
-     if (ch == '=')
-         return strdup ("=");
-     if (ch == '"') {
-         here = buf;
-         while (here - buf < MAX_TOKEN) {
-              if ((ch = next ()) == EOF)
-                   cfg_error ("EOF in quoted string");
-              if (ch == '"') {
-                   *here = 0;
-                   return strdup (buf);
-              }
-              if (ch == '\\') {
-                   ch = next ();
-                   switch (ch) {
-                   case '"':
-                   case '\\':
-                        break;
-                   case '\n':
-                   case '\r':
-                        while ((ch = next ()), ch == ' ' || ch == '\t');
-                        if (!ch)
-                             continue;
-                        again (ch);
-                        ch = ' ';
-                        break;
-                   case 'n':
-                        ch = '\n';
-                        break;
-                   default:
-                        cfg_error ("Bad use of \\ in quoted string");
-                   }
-              } else if ((ch == '\n') || (ch == '\r'))
-                   cfg_error ("newline is not allowed in quoted strings");
-              *here++ = ch;
-         }
-         cfg_error ("Quoted string is too long");
-         return 0;             /* not reached */
-     }
-     here = buf;
-     escaped = 0;
-     while (here - buf < MAX_TOKEN) {
-         if (escaped) {
-              if (ch == EOF)
-                   cfg_error ("\\ precedes EOF");
-              if (ch == '\n')
-                   line_num++;
-              else
-                   *here++ = ch == '\t' ? ' ' : ch;
-              escaped = 0;
-         } else {
-              if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '#' ||
-                  ch == '=' || ch == EOF) {
-                   again (ch);
-                   *here = 0;
-                   return strdup (buf);
-              }
-              if (!(escaped = (ch == '\\')))
-                   *here++ = ch;
-         }
-         ch = next ();
-     }
-     cfg_error ("Token is too long");
-     return 0;                 /* not reached */
-}
-
-static void cfg_return_token (char *token)
-{
-     last_token = token;
-}
-
-static int cfg_next (char **item, char **value)
-{
-     char *this;
-
-     if (last_item) {
-         *item = last_item;
-         *value = last_value;
-         last_item = NULL;
-         return 1;
-     }
-     *value = NULL;
-     if (!(*item = cfg_get_token ()))
-         return 0;
-     if (!strcmp (*item, "="))
-         cfg_error ("Syntax error");
-     if (!(this = cfg_get_token ()))
-         return 1;
-     if (strcmp (this, "=")) {
-         cfg_return_token (this);
-         return 1;
-     }
-     if (!(*value = cfg_get_token ()))
-         cfg_error ("Value expected at EOF");
-     if (!strcmp (*value, "="))
-         cfg_error ("Syntax error after %s", *item);
-     return 1;
-}
-
-#if 0
-// The one and only call to this procedure is commented out
-// below, so we don't need this unless we decide to use it again.
-static void cfg_return (char *item, char *value)
-{
-     last_item = item;
-     last_value = value;
-}
-#endif
-
-static int cfg_set (char *item, char *value)
-{
-     CONFIG *walk;
-
-     if (!strcasecmp (item, "image")) {
-         struct IMAGES **p = &images;
-
-         while (*p)
-              p = &((*p)->next);
-         *p = (struct IMAGES *)malloc (sizeof (struct IMAGES));
-         if (*p == NULL) {
-              prom_printf("malloc error in cfg_set\n");
-              return -1;
-         }
-         (*p)->next = 0;
-         curr_table = ((*p)->table);
-         memcpy (curr_table, cf_image, sizeof (cf_image));
-     }
-     for (walk = curr_table; walk->type != cft_end; walk++) {
-         if (walk->name && !strcasecmp (walk->name, item)) {
-              if (value && walk->type != cft_strg)
-                   cfg_warn ("'%s' doesn't have a value", walk->name);
-              else if (!value && walk->type == cft_strg)
-                   cfg_warn ("Value expected for '%s'", walk->name);
-              else {
-                   if (walk->data)
-                        cfg_warn ("Duplicate entry '%s'", walk->name);
-                   if (walk->type == cft_flag)
-                        walk->data = &flag_set;
-                   else if (walk->type == cft_strg)
-                        walk->data = value;
-              }
-              break;
-         }
-     }
-     if (walk->type != cft_end)
-         return 1;
-//    cfg_return (item, value);
-     return 0;
-}
-
-int cfg_parse (char *cfg_file, char *buff, int len)
-{
-     char *item, *value;
-
-     file_name = cfg_file;
-     currp = buff;
-     endp = currp + len;
-
-     if (setjmp (env))
-         return -1;
-     while (1) {
-         if (!cfg_next (&item, &value))
-              return 0;
-         if (!cfg_set (item, value)) {
-#if DEBUG
-              prom_printf("Can't set item %s to value %s\n", item, value);
-#endif     
-         }
-         free (item);
-     }
-}
-
-static char *cfg_get_strg_i (CONFIG * table, char *item)
-{
-     CONFIG *walk;
-
-     for (walk = table; walk->type != cft_end; walk++)
-         if (walk->name && !strcasecmp (walk->name, item))
-              return walk->data;
-     return 0;
-}
-
-char *cfg_get_strg (char *image, char *item)
-{
-     struct IMAGES *p;
-     char *label, *alias;
-     char *ret;
-
-     if (!image)
-         return cfg_get_strg_i (cf_options, item);
-     for (p = images; p; p = p->next) {
-         label = cfg_get_strg_i (p->table, "label");
-         if (!label) {
-              label = cfg_get_strg_i (p->table, "image");
-              alias = strrchr (label, '/');
-              if (alias)
-                   label = alias + 1;
-         }
-         alias = cfg_get_strg_i (p->table, "alias");
-         if (!strcmp (label, image) || (alias && !strcmp (alias, image))) {
-              ret = cfg_get_strg_i (p->table, item);
-              if (!ret)
-                   ret = cfg_get_strg_i (cf_options, item);
-              return ret;
-         }
-     }
-     return 0;
-}
-
-int cfg_get_flag (char *image, char *item)
-{
-     return !!cfg_get_strg (image, item);
-}
-
-static int printl_count = 0;
-static void printlabel (char *label, int defflag)
-{
-     int len = strlen (label);
-
-     if (!printl_count)
-         prom_printf ("\n");
-     prom_printf ("%s %s",defflag?"*":" ", label);
-     while (len++ < 25)
-         prom_putchar (' ');
-     printl_count++;
-     if (printl_count == 3)
-         printl_count = 0;
-}
-
-void cfg_print_images (void)
-{
-     struct IMAGES *p;
-     char *label, *alias;
-
-     char *ret = cfg_get_default();//strg_i (cf_options, "default");
-     int defflag=0;
-
-     printl_count = 0;
-     for (p = images; p; p = p->next) {
-         label = cfg_get_strg_i (p->table, "label");
-         if (!label) {
-              label = cfg_get_strg_i (p->table, "image");
-              alias = strrchr (label, '/');
-              if (alias)
-                   label = alias + 1;
-         }
-         if(!strcmp(ret,label))
-              defflag=1;
-         else
-              defflag=0;
-         alias = cfg_get_strg_i (p->table, "alias");
-         printlabel (label, defflag);
-         if (alias)
-              printlabel (alias, 0);
-     }
-     prom_printf("\n");
-}
-
-char *cfg_get_default (void)
-{
-     char *label;
-     char *ret = cfg_get_strg_i (cf_options, "default");
-
-     if (ret)
-         return ret;
-     if (!images)
-         return 0;
-     ret = cfg_get_strg_i (images->table, "label");
-     if (!ret) {
-         ret = cfg_get_strg_i (images->table, "image");
-         label = strrchr (ret, '/');
-         if (label)
-              ret = label + 1;
-     }
-     return ret;
-}
-
-char *cfg_next_image(char *prev)
-{
-     struct IMAGES *p;
-     char *label, *alias;
-     int wantnext = 0;
-
-     if (!prev)
-         wantnext = 1;
-
-     for (p = images; p; p = p->next) {
-         label = cfg_get_strg_i (p->table, "label");
-         if (!label) {
-              label = cfg_get_strg_i (p->table, "image");
-              alias = strrchr (label, '/');
-              if (alias)
-                   label = alias + 1;
-         }
-         if (wantnext)
-              return label;
-         if (!strcmp(prev, label))
-              wantnext = 1;
-     }
-     return NULL;
-}
-/* 
- * Local variables:
- * c-file-style: "k&r"
- * c-basic-offset: 5
- * End:
- */
diff --git a/devices/yaboot-cfg.h b/devices/yaboot-cfg.h
deleted file mode 100644 (file)
index 2ab4fec..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  cfg.h - config file parsing definitions
- *
- *  Copyright (C) 1999 Benjamin Herrenschmidt
- *
- *  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; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#ifndef CFG_H
-#define CFG_H
-
-extern int     cfg_parse(char *cfg_file, char *buff, int len);
-extern char*   cfg_get_strg(char *image, char *item);
-extern int     cfg_get_flag(char *image, char *item);
-extern void    cfg_print_images(void);
-extern char*   cfg_get_default(void);
-extern char*   cfg_next_image(char *);
-#endif
diff --git a/devices/yaboot-parser.c b/devices/yaboot-parser.c
deleted file mode 100644 (file)
index 27b4b78..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-
-#include "parser.h"
-#include "params.h"
-#include "paths.h"
-#include "yaboot-cfg.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <sys/param.h>
-
-static struct device *dev;
-static char *devpath;
-static char *defimage;
-
-char *
-make_params(char *label, char *params)
-{
-     char *p, *q;
-     static char buffer[2048];
-
-     q = buffer;
-     *q = 0;
-
-     p = cfg_get_strg(label, "literal");
-     if (p) {
-          strcpy(q, p);
-          q = strchr(q, 0);
-          if (params) {
-               if (*p)
-                    *q++ = ' ';
-               strcpy(q, params);
-          }
-          return buffer;
-     }
-
-     p = cfg_get_strg(label, "root");
-     if (p) {
-          strcpy (q, "root=");
-          strcpy (q + 5, p);
-          q = strchr (q, 0);
-          *q++ = ' ';
-     }
-     if (cfg_get_flag(label, "read-only")) {
-          strcpy (q, "ro ");
-          q += 3;
-     }
-     if (cfg_get_flag(label, "read-write")) {
-          strcpy (q, "rw ");
-          q += 3;
-     }
-     p = cfg_get_strg(label, "ramdisk");
-     if (p) {
-          strcpy (q, "ramdisk=");
-          strcpy (q + 8, p);
-          q = strchr (q, 0);
-          *q++ = ' ';
-     }
-     p = cfg_get_strg(label, "initrd-size");
-     if (p) {
-          strcpy (q, "ramdisk_size=");
-          strcpy (q + 13, p);
-          q = strchr (q, 0);
-          *q++ = ' ';
-     }
-     if (cfg_get_flag(label, "novideo")) {
-          strcpy (q, "video=ofonly");
-          q = strchr (q, 0);
-          *q++ = ' ';
-     }
-     p = cfg_get_strg (label, "append");
-     if (p) {
-          strcpy (q, p);
-          q = strchr (q, 0);
-          *q++ = ' ';
-     }
-     *q = 0;
-     if (params)
-          strcpy(q, params);
-
-     return buffer;
-}
-
-static int check_and_add_device(struct device *dev)
-{
-       if (!dev->icon_file)
-               dev->icon_file = strdup(generic_icon_file(guess_device_type()));
-
-       return !add_device(dev);
-}
-
-void process_image(char *label)
-{
-       struct boot_option opt;
-       char *cfgopt;
-
-       memset(&opt, 0, sizeof(opt));
-
-       opt.name = label;
-       cfgopt = cfg_get_strg(label, "image");
-       opt.boot_image_file = resolve_path(cfgopt, devpath);
-       if (cfgopt == defimage)
-               pb_log("This one is default. What do we do about it?\n");
-
-       cfgopt = cfg_get_strg(label, "initrd");
-       if (cfgopt)
-               opt.initrd_file = resolve_path(cfgopt, devpath);
-
-       opt.boot_args = make_params(label, NULL);
-
-       add_boot_option(&opt);
-
-       if (opt.initrd_file)
-               free(opt.initrd_file);
-}
-
-static int yaboot_parse(const char *device)
-{
-       char *filepath;
-       char *conf_file;
-       char *tmpstr;
-       ssize_t conf_len;
-       int fd;
-       struct stat st;
-       char *label;
-
-       devpath = strdup(device);
-
-       filepath = resolve_path("/etc/yaboot.conf", devpath);
-
-       fd = open(filepath, O_RDONLY);
-       if (fd < 0) {
-               free(filepath);
-               filepath = resolve_path("/yaboot.conf", devpath);
-               fd = open(filepath, O_RDONLY);
-               
-               if (fd < 0)
-                       return 0;
-       }
-
-       if (fstat(fd, &st)) {
-               close(fd);
-               return 0;
-       }
-
-       conf_file = malloc(st.st_size+1);
-       if (!conf_file) {
-               close(fd);
-               return 0;
-       }
-       
-       conf_len = read(fd, conf_file, st.st_size);
-       if (conf_len < 0) {
-               close(fd);
-               return 0;
-       }
-       conf_file[conf_len] = 0;
-
-       close(fd);
-       
-       if (cfg_parse(filepath, conf_file, conf_len)) {
-               pb_log("Error parsing yaboot.conf\n");
-               return 0;
-       }
-
-       free(filepath);
-
-       dev = malloc(sizeof(*dev));
-       memset(dev, 0, sizeof(*dev));
-       dev->id = strdup(devpath);
-       if (cfg_get_strg(0, "init-message")) {
-               char *newline;
-               dev->description = strdup(cfg_get_strg(0, "init-message"));
-               newline = strchr(dev->description, '\n');
-               if (newline)
-                       *newline = 0;
-       }
-       dev->icon_file = strdup(generic_icon_file(guess_device_type()));
-
-       /* If we have a 'partiton=' directive, update the default devpath
-        * to use that instead of the current device */
-       tmpstr = cfg_get_strg(0, "partition");
-       if (tmpstr) {
-               char *endp;
-               int partnr = strtol(tmpstr, &endp, 10);
-               if (endp != tmpstr && !*endp) {
-                       char *new_dev, *tmp;
-
-                       new_dev = malloc(strlen(devpath) + strlen(tmpstr) + 1);
-                       if (!new_dev)
-                               return 0;
-
-                       strcpy(new_dev, devpath);
-
-                       /* Strip digits (partition number) from string */
-                       endp = new_dev + strlen(devpath) - 1;
-                       while (isdigit(*endp))
-                               *(endp--) = 0;
-
-                       /* and add our own... */
-                       sprintf(endp + 1, "%d", partnr);
-
-                       tmp = devpath;
-                       devpath = parse_device_path(new_dev, devpath);
-                       free(tmp);
-                       free(new_dev);
-               }
-       }
-
-       defimage = cfg_get_default();
-       if (!defimage)
-               return 0;
-       defimage = cfg_get_strg(defimage, "image");
-
-       label = cfg_next_image(NULL);
-       if (!label || !check_and_add_device(dev))
-               return 0;
-
-       do {
-               process_image(label);
-       } while ((label = cfg_next_image(label)));
-
-       return 1;
-}
-
-struct parser yaboot_parser = {
-       .name = "yaboot.conf parser",
-       .priority = 99,
-       .parse    = yaboot_parse
-};
diff --git a/discover/discover-server.c b/discover/discover-server.c
new file mode 100644 (file)
index 0000000..8358f06
--- /dev/null
@@ -0,0 +1,227 @@
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <asm/byteorder.h>
+
+#include <talloc/talloc.h>
+
+#include "ui/common/device.h"
+#include "pb-protocol/pb-protocol.h"
+#include "list/list.h"
+
+#include "log.h"
+#include "waiter.h"
+
+struct discover_server {
+       int socket;
+       struct waiter *waiter;
+       struct list clients;
+};
+
+struct client {
+       struct list_item list;
+       int fd;
+};
+
+
+static int server_destructor(void *arg)
+{
+       struct discover_server *server = arg;
+
+       if (server->waiter)
+               waiter_unregister(server->waiter);
+
+       if (server->socket >= 0)
+               close(server->socket);
+
+       return 0;
+}
+
+static int client_destructor(void *arg)
+{
+       struct client *client = arg;
+
+       if (client->fd >= 0)
+               close(client->fd);
+
+       list_remove(&client->list);
+
+       return 0;
+
+}
+
+static void print_clients(struct discover_server *server)
+       __attribute__((unused));
+
+static void print_clients(struct discover_server *server)
+{
+       struct client *client;
+
+       printf("current clients [%p,%p,%p]:\n",
+                       &server->clients.head,
+                       server->clients.head.prev,
+                       server->clients.head.next);
+       list_for_each_entry(&server->clients, client, list)
+               printf("\t[%p,%p,%p] client: %d\n", &client->list,
+                               client->list.prev, client->list.next,
+                               client->fd);
+}
+
+static struct boot_option options[] = {
+       {
+               .id = "1.1",
+               .name = "meep one",
+               .description = "meep description one",
+               .icon_file = "meep.one.png",
+               .boot_args = "root=/dev/sda1",
+       },
+};
+
+static struct device device = {
+       .id = "1",
+       .name = "meep",
+       .description = "meep description",
+       .icon_file = "meep.png",
+       .n_options = 1,
+       .options = options,
+};
+
+static int client_write_message(struct discover_server *server,
+               struct client *client, struct pb_protocol_message *message)
+{
+       int rc;
+
+       rc = pb_protocol_write_message(client->fd, message);
+       if (rc)
+               talloc_free(client);
+
+       return rc;
+}
+
+static int write_add_message(struct discover_server *server,
+               struct client *client, struct device *dev)
+{
+       struct pb_protocol_message *message;
+       int len;
+
+       len = pb_protocol_device_len(dev);
+
+       message = pb_protocol_create_message(client,
+                       PB_PROTOCOL_ACTION_ADD, len);
+       if (!message)
+               return -1;
+
+       pb_protocol_serialise_device(dev, message->payload, len);
+
+       return client_write_message(server, client, message);
+}
+
+static int write_remove_message(struct discover_server *server,
+               struct client *client, char *dev_id)
+{
+       struct pb_protocol_message *message;
+       int len;
+
+       len = strlen(dev_id) + sizeof(uint32_t);
+
+       message = pb_protocol_create_message(client,
+                       PB_PROTOCOL_ACTION_REMOVE, len);
+       if (!message)
+               return -1;
+
+       pb_protocol_serialise_string(message->payload, dev_id);
+
+       return client_write_message(server, client, message);
+}
+
+static int discover_server_process(void *arg)
+{
+       struct discover_server *server = arg;
+       struct client *client;
+       int fd;
+
+
+       len = sizeof(addr);
+
+       /* accept the incoming connection */
+       fd = accept(server->socket, NULL, 0);
+       if (!fd) {
+               pb_log("accept: %s\n", strerror(errno));
+               return 0;
+       }
+
+       /* add to our list of clients */
+       client = talloc(server, struct client);
+       list_add(&server->clients, &client->list);
+
+       talloc_set_destructor(client, client_destructor);
+
+       client->fd = fd;
+
+       /* send existing devices to client */
+       write_add_message(server, client, &device);
+
+       sleep(2);
+
+       write_remove_message(server, client, "1");
+
+       return 0;
+}
+
+struct discover_server *discover_server_init(void)
+{
+       struct discover_server *server;
+       struct sockaddr_un addr;
+
+       server = talloc(NULL, struct discover_server);
+       if (!server)
+               return NULL;
+
+       server->waiter = NULL;
+       list_init(&server->clients);
+
+       unlink(PB_SOCKET_PATH);
+
+       server->socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (server->socket < 0) {
+               pb_log("error creating server socket: %s\n", strerror(errno));
+               goto out_err;
+       }
+
+       talloc_set_destructor(server, server_destructor);
+
+       addr.sun_family = AF_UNIX;
+       strcpy(addr.sun_path, PB_SOCKET_PATH);
+
+       if (bind(server->socket, (struct sockaddr *)&addr, sizeof(addr))) {
+               pb_log("error binding server socket: %s\n", strerror(errno));
+               goto out_err;
+       }
+
+       if (listen(server->socket, 8)) {
+               pb_log("server socket listen: %s\n", strerror(errno));
+               goto out_err;
+       }
+
+       server->waiter = waiter_register(server->socket, WAIT_IN,
+                       discover_server_process, server);
+
+       return server;
+
+out_err:
+       talloc_free(server);
+       return NULL;
+}
+
+void discover_server_destroy(struct discover_server *server)
+{
+       talloc_free(server);
+}
+
diff --git a/discover/discover-server.h b/discover/discover-server.h
new file mode 100644 (file)
index 0000000..ff27f15
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _DISCOVER_SERVER_H
+#define _DISCOVER_SERVER_H
+
+struct discover_server;
+
+struct discover_server *discover_server_init(void);
+
+void discover_server_destroy(struct discover_server *server);
+
+#endif /* _DISCOVER_SERVER_H */
diff --git a/discover/kboot-parser.c b/discover/kboot-parser.c
new file mode 100644 (file)
index 0000000..df2e762
--- /dev/null
@@ -0,0 +1,288 @@
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "parser.h"
+#include "params.h"
+
+#define buf_size 1024
+
+static const char *devpath;
+
+static int param_is_ignored(const char *param)
+{
+       static const char *ignored_options[] =
+               { "message", "timeout", "default", NULL };
+       const char **str;
+
+       for (str = ignored_options; *str; str++)
+               if (streq(*str, param))
+                       return 1;
+       return 0;
+}
+
+/**
+ * Splits a name=value pair, with value terminated by @term (or nul). if there
+ * is no '=', then only the value is populated, and *name is set to NULL. The
+ * string is modified in place.
+ *
+ * Returns the next byte to process, or null if we've hit the end of the
+ * string.
+ *
+ * */
+static char *get_param_pair(char *str, char **name_out, char **value_out,
+               char terminator)
+{
+       char *sep, *tmp, *name, *value;
+
+       /* terminate the value */
+       tmp = strchr(str, terminator);
+       if (tmp)
+               *tmp = 0;
+       else
+               tmp = NULL;
+
+       sep = strchr(str, '=');
+       if (!sep) {
+               *name_out = NULL;
+               *value_out = str;
+               return tmp ? tmp + 1 : NULL;
+       }
+
+       /* terminate the name */
+       *sep = 0;
+
+       /* remove leading spaces */
+       for (name = str; isspace(*name); name++);
+       for (value = sep + 1; isspace(*value); value++);
+
+       /* .. and trailing ones.. */
+       for (sep--; isspace(*sep); sep--)
+               *sep = 0;
+       for (sep = value + strlen(value) - 1; isspace(*sep); sep--)
+               *sep = 0;
+
+       *name_out = name;
+       *value_out = value;
+
+       return tmp ? tmp + 1 : NULL;
+}
+
+struct global_option {
+       char *name;
+       char *value;
+};
+
+
+static struct global_option global_options[] = {
+       { .name = "root" },
+       { .name = "initrd" },
+       { .name = "video" },
+       { .name = NULL }
+};
+
+/*
+ * Check if an option (name=value) is a global option. If so, store it in
+ * the global options table, and return 1. Otherwise, return 0.
+ */
+static int check_for_global_option(const char *name, const char *value)
+{
+       int i;
+
+       for (i = 0; global_options[i].name ;i++) {
+               if (!strcmp(name, global_options[i].name)) {
+                       global_options[i].value = strdup(value);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static char *get_global_option(const char *name)
+{
+       int i;
+
+       for (i = 0; global_options[i].name ;i++)
+               if (!strcmp(name, global_options[i].name))
+                       return global_options[i].value;
+
+       return NULL;
+}
+
+static int parse_option(struct boot_option *opt, char *config)
+{
+       char *pos, *name, *value, *root, *initrd, *cmdline, *tmp;
+
+       root = initrd = cmdline = NULL;
+
+       /* remove quotes around the value */
+       while (*config == '"' || *config == '\'')
+               config++;
+
+       pos = config + strlen(config) - 1;
+       while (*pos == '"' || *pos == '\'')
+               *(pos--) = 0;
+
+       if (!strlen(pos))
+               return 0;
+
+       pos = strchr(config, ' ');
+
+       /* if there's no space, it's only a kernel image with no params */
+       if (!pos) {
+               opt->boot_image_file = resolve_path(config, devpath);
+               opt->description = strdup(config);
+               return 1;
+       }
+
+       *pos = 0;
+       opt->boot_image_file = resolve_path(config, devpath);
+
+       cmdline = malloc(buf_size);
+       *cmdline = 0;
+
+       for (pos++; pos;) {
+               pos = get_param_pair(pos, &name, &value, ' ');
+
+               if (!name) {
+                       strcat(cmdline, " ");
+                       strcat(cmdline, value);
+
+               } else if (streq(name, "initrd")) {
+                       initrd = value;
+
+               } else if (streq(name, "root")) {
+                       root = value;
+
+               } else {
+                       strcat(cmdline, " ");
+                       *(value - 1) = '=';
+                       strcat(cmdline, name);
+               }
+       }
+
+       if (!root)
+               root = get_global_option("root");
+       if (!initrd)
+               initrd = get_global_option("initrd");
+
+       if (initrd) {
+               asprintf(&tmp, "initrd=%s %s", initrd, cmdline);
+               free(cmdline);
+               cmdline = tmp;
+
+               opt->initrd_file = resolve_path(initrd, devpath);
+       }
+
+       if (root) {
+               asprintf(&tmp, "root=%s %s", root, cmdline);
+               free(cmdline);
+               cmdline = tmp;
+
+       } else if (initrd) {
+               /* if there's an initrd but no root, fake up /dev/ram0 */
+               asprintf(&tmp, "root=/dev/ram0 %s", cmdline);
+               free(cmdline);
+               cmdline = tmp;
+       }
+
+       pb_log("kboot cmdline: %s\n", cmdline);
+       opt->boot_args = cmdline;
+
+       asprintf(&opt->description, "%s %s",
+                       config, opt->boot_args);
+
+       return 1;
+}
+
+static void parse_buf(struct device *dev, char *buf)
+{
+       char *pos, *name, *value;
+       int sent_device = 0;
+
+       for (pos = buf; pos;) {
+               struct boot_option opt;
+
+               pos = get_param_pair(pos, &name, &value, '\n');
+
+               pb_log("kboot param: '%s' = '%s'\n", name, value);
+
+               if (name == NULL || param_is_ignored(name))
+                       continue;
+
+               if (*name == '#')
+                       continue;
+
+               if (check_for_global_option(name, value))
+                       continue;
+
+               memset(&opt, 0, sizeof(opt));
+               opt.name = strdup(name);
+
+               if (parse_option(&opt, value))
+                       if (!sent_device++)
+                               add_device(dev);
+                       add_boot_option(&opt);
+
+               free(opt.name);
+       }
+}
+
+static int parse(const char *device)
+{
+       char *filepath, *buf;
+       int fd, len, rc = 0;
+       struct stat stat;
+       struct device *dev;
+
+       devpath = device;
+
+       filepath = resolve_path("/etc/kboot.conf", devpath);
+
+       fd = open(filepath, O_RDONLY);
+       if (fd < 0)
+               goto out_free_path;
+
+       if (fstat(fd, &stat))
+               goto out_close;
+
+       buf = malloc(stat.st_size + 1);
+       if (!buf)
+               goto out_close;;
+
+       len = read(fd, buf, stat.st_size);
+       if (len < 0)
+               goto out_free_buf;
+       buf[len] = 0;
+
+       dev = malloc(sizeof(*dev));
+       memset(dev, 0, sizeof(*dev));
+       dev->id = strdup(device);
+       dev->icon_file = strdup(generic_icon_file(guess_device_type()));
+
+       parse_buf(dev, buf);
+
+       rc = 1;
+
+out_free_buf:
+       free(buf);
+out_close:
+       close(fd);
+out_free_path:
+       free(filepath);
+       return rc;
+}
+
+struct parser kboot_parser = {
+       .name = "kboot.conf parser",
+       .priority = 98,
+       .parse    = parse
+};
diff --git a/discover/log.c b/discover/log.c
new file mode 100644 (file)
index 0000000..189f31e
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "log.h"
+
+static FILE *logf;
+
+void pb_log(const char *fmt, ...)
+{
+       va_list ap;
+       FILE *stream;
+
+       stream = logf ? logf : stdout;
+
+       va_start(ap, fmt);
+       vfprintf(stream, fmt, ap);
+       va_end(ap);
+}
+
+void pb_log_set_stream(FILE *stream)
+{
+       logf = stream;
+}
diff --git a/discover/log.h b/discover/log.h
new file mode 100644 (file)
index 0000000..7f9b01f
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _LOG_H
+#define _LOG_H
+
+void pb_log(const char *fmt, ...);
+
+#endif /* _LOG_H */
diff --git a/discover/message.h b/discover/message.h
new file mode 100644 (file)
index 0000000..d0b0e34
--- /dev/null
@@ -0,0 +1,31 @@
+
+#ifndef _MESSAGE_H
+#define _MESSAGE_H
+
+enum device_action {
+       DEV_ACTION_ADD_DEVICE = 0,
+       DEV_ACTION_ADD_OPTION = 1,
+       DEV_ACTION_REMOVE_DEVICE = 2,
+       DEV_ACTION_REMOVE_OPTION = 3
+};
+
+struct device {
+       char *id;
+       char *name;
+       char *description;
+       char *icon_file;
+
+       struct boot_option {
+               char *id;
+               char *name;
+               char *description;
+               char *icon_file;
+               char *boot_image_file;
+               char *initrd_file;
+               char *boot_args;
+       } *options;
+       int n_options;
+};
+
+
+#endif /* _MESSAGE_H */
diff --git a/discover/native-parser.c b/discover/native-parser.c
new file mode 100644 (file)
index 0000000..24713b1
--- /dev/null
@@ -0,0 +1,124 @@
+
+#include "parser.h"
+#include "params.h"
+#include "paths.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *conf_filename = "/boot/petitboot.conf";
+
+static struct boot_option *cur_opt;
+static struct device *dev;
+static const char *devpath;
+int device_added;
+
+int check_and_add_device(struct device *dev)
+{
+       if (!dev->icon_file)
+               dev->icon_file = strdup(generic_icon_file(guess_device_type()));
+
+       return !add_device(dev);
+}
+
+static int section(char *section_name)
+{
+       if (!device_added++ && !check_and_add_device(dev))
+               return 0;
+
+       if (cur_opt) {
+               add_boot_option(cur_opt);
+               free_boot_option(cur_opt);
+       }
+
+       cur_opt = malloc(sizeof(*cur_opt));
+       memset(cur_opt, 0, sizeof(*cur_opt));
+       return 1;
+}
+
+
+static void set_boot_option_parameter(struct boot_option *opt,
+               const char *name, const char *value)
+{
+       if (streq(name, "name"))
+               opt->name = strdup(value);
+
+       else if (streq(name, "description"))
+               opt->description = strdup(value);
+
+       else if (streq(name, "image"))
+               opt->boot_image_file = resolve_path(value, devpath);
+
+       else if (streq(name, "icon"))
+               opt->icon_file = resolve_path(value, devpath);
+
+       else if (streq(name, "initrd"))
+               opt->initrd_file =resolve_path(value, devpath);
+
+       else if (streq(name, "args"))
+               opt->boot_args = strdup(value);
+
+       else
+               fprintf(stderr, "Unknown parameter %s\n", name);
+}
+
+static void set_device_parameter(struct device *dev,
+               const char *name, const char *value)
+{
+       if (streq(name, "name"))
+               dev->name = strdup(value);
+
+       else if (streq(name, "description"))
+               dev->description = strdup(value);
+
+       else if (streq(name, "icon"))
+               dev->icon_file = resolve_path(value, devpath);
+}
+
+static int parameter(char *param_name, char *param_value)
+{
+       if (cur_opt)
+               set_boot_option_parameter(cur_opt, param_name, param_value);
+       else
+               set_device_parameter(dev, param_name, param_value);
+       return 1;
+}
+
+
+int parse(const char *device)
+{
+       char *filepath;
+       int rc;
+
+       filepath = resolve_path(conf_filename, device);
+
+       cur_opt = NULL;
+       dev = malloc(sizeof(*dev));
+       memset(dev, 0, sizeof(*dev));
+       dev->id = strdup(device);
+
+       rc = pm_process(filepath, section, parameter);
+       if (!rc)
+               return 0;
+
+       if (cur_opt) {
+               add_boot_option(cur_opt);
+               free_boot_option(cur_opt);
+       }
+
+       cur_opt = NULL;
+
+       free(filepath);
+
+       return 1;
+}
+
+struct parser native_parser = {
+       .name = "native petitboot parser",
+       .priority = 100,
+       .parse    = parse
+};
+
+
+
diff --git a/discover/params.c b/discover/params.c
new file mode 100644 (file)
index 0000000..76a1451
--- /dev/null
@@ -0,0 +1,595 @@
+/* This modules is based on the params.c module from Samba, written by Karl Auer
+   and much modifed by Christopher Hertel. */
+
+/*
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "params.h"
+
+#define new_array(type, num) ((type *)_new_array(sizeof(type), (num)))
+#define realloc_array(ptr, type, num) \
+       ((type *)_realloc_array((ptr), sizeof(type), (num)))
+
+#define rprintf(x, ...) do { fprintf(stderr, ##__VA_ARGS__);   \
+                               fprintf(stderr, "\n"); } while (0)
+#define rsyserr(x, y, ...) do { fprintf(stderr, ##__VA_ARGS__);        \
+                               fprintf(stderr, "\n"); } while (0)
+
+#define MALLOC_MAX 0x40000000
+#define False 0
+#define True 1
+
+void *_new_array(unsigned int size, unsigned long num)
+{
+       if (num >= MALLOC_MAX/size)
+               return NULL;
+       return malloc(size * num);
+}
+
+void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
+{
+       if (num >= MALLOC_MAX/size)
+               return NULL;
+       /* No realloc should need this, but just in case... */
+       if (!ptr)
+               return malloc(size * num);
+       return realloc(ptr, size * num);
+}
+
+
+/* -------------------------------------------------------------------------- **
+ *
+ * Module name: params
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ *  This module performs lexical analysis and initial parsing of a
+ *  Windows-like parameter file.  It recognizes and handles four token
+ *  types:  section-name, parameter-name, parameter-value, and
+ *  end-of-file.  Comments and line continuation are handled
+ *  internally.
+ *
+ *  The entry point to the module is function pm_process().  This
+ *  function opens the source file, calls the Parse() function to parse
+ *  the input, and then closes the file when either the EOF is reached
+ *  or a fatal error is encountered.
+ *
+ *  A sample parameter file might look like this:
+ *
+ *  [section one]
+ *  parameter one = value string
+ *  parameter two = another value
+ *  [section two]
+ *  new parameter = some value or t'other
+ *
+ *  The parameter file is divided into sections by section headers:
+ *  section names enclosed in square brackets (eg. [section one]).
+ *  Each section contains parameter lines, each of which consist of a
+ *  parameter name and value delimited by an equal sign.  Roughly, the
+ *  syntax is:
+ *
+ *    <file>            :==  { <section> } EOF
+ *
+ *    <section>         :==  <section header> { <parameter line> }
+ *
+ *    <section header>  :==  '[' NAME ']'
+ *
+ *    <parameter line>  :==  NAME '=' VALUE '\n'
+ *
+ *  Blank lines and comment lines are ignored.  Comment lines are lines
+ *  beginning with either a semicolon (';') or a pound sign ('#').
+ *
+ *  All whitespace in section names and parameter names is compressed
+ *  to single spaces.  Leading and trailing whitespace is stipped from
+ *  both names and values.
+ *
+ *  Only the first equals sign in a parameter line is significant.
+ *  Parameter values may contain equals signs, square brackets and
+ *  semicolons.  Internal whitespace is retained in parameter values,
+ *  with the exception of the '\r' character, which is stripped for
+ *  historic reasons.  Parameter names may not start with a left square
+ *  bracket, an equal sign, a pound sign, or a semicolon, because these
+ *  are used to identify other tokens.
+ *
+ * -------------------------------------------------------------------------- **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Constants...
+ */
+
+#define BUFR_INC 1024
+
+
+/* -------------------------------------------------------------------------- **
+ * Variables...
+ *
+ *  bufr        - pointer to a global buffer.  This is probably a kludge,
+ *                but it was the nicest kludge I could think of (for now).
+ *  bSize       - The size of the global buffer <bufr>.
+ */
+
+static char *bufr  = NULL;
+static int   bSize = 0;
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+static int EatWhitespace( FILE *InFile )
+  /* ------------------------------------------------------------------------ **
+   * Scan past whitespace (see ctype(3C)) and return the first non-whitespace
+   * character, or newline, or EOF.
+   *
+   *  Input:  InFile  - Input source.
+   *
+   *  Output: The next non-whitespace character in the input stream.
+   *
+   *  Notes:  Because the config files use a line-oriented grammar, we
+   *          explicitly exclude the newline character from the list of
+   *          whitespace characters.
+   *        - Note that both EOF (-1) and the nul character ('\0') are
+   *          considered end-of-file markers.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  int c;
+
+  for( c = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) )
+    ;
+  return( c );
+  } /* EatWhitespace */
+
+static int EatComment( FILE *InFile )
+  /* ------------------------------------------------------------------------ **
+   * Scan to the end of a comment.
+   *
+   *  Input:  InFile  - Input source.
+   *
+   *  Output: The character that marks the end of the comment.  Normally,
+   *          this will be a newline, but it *might* be an EOF.
+   *
+   *  Notes:  Because the config files use a line-oriented grammar, we
+   *          explicitly exclude the newline character from the list of
+   *          whitespace characters.
+   *        - Note that both EOF (-1) and the nul character ('\0') are
+   *          considered end-of-file markers.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  int c;
+
+  for( c = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) )
+    ;
+  return( c );
+  } /* EatComment */
+
+static int Continuation( char *line, int pos )
+  /* ------------------------------------------------------------------------ **
+   * Scan backards within a string to discover if the last non-whitespace
+   * character is a line-continuation character ('\\').
+   *
+   *  Input:  line  - A pointer to a buffer containing the string to be
+   *                  scanned.
+   *          pos   - This is taken to be the offset of the end of the
+   *                  string.  This position is *not* scanned.
+   *
+   *  Output: The offset of the '\\' character if it was found, or -1 to
+   *          indicate that it was not.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  pos--;
+  while( (pos >= 0) && isspace(((unsigned char *)line)[pos]) )
+     pos--;
+
+  return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
+  } /* Continuation */
+
+
+static BOOL Section( FILE *InFile, BOOL (*sfunc)(char *) )
+  /* ------------------------------------------------------------------------ **
+   * Scan a section name, and pass the name to function sfunc().
+   *
+   *  Input:  InFile  - Input source.
+   *          sfunc   - Pointer to the function to be called if the section
+   *                    name is successfully read.
+   *
+   *  Output: True if the section name was read and True was returned from
+   *          <sfunc>.  False if <sfunc> failed or if a lexical error was
+   *          encountered.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  int   c;
+  int   i;
+  int   end;
+  char *func  = "params.c:Section() -";
+
+  i = 0;      /* <i> is the offset of the next free byte in bufr[] and  */
+  end = 0;    /* <end> is the current "end of string" offset.  In most  */
+              /* cases these will be the same, but if the last          */
+              /* character written to bufr[] is a space, then <end>     */
+              /* will be one less than <i>.                             */
+
+  c = EatWhitespace( InFile );    /* We've already got the '['.  Scan */
+                                  /* past initial white space.        */
+
+  while( (EOF != c) && (c > 0) )
+    {
+
+    /* Check that the buffer is big enough for the next character. */
+    if( i > (bSize - 2) )
+      {
+      bSize += BUFR_INC;
+      bufr   = realloc_array( bufr, char, bSize );
+      if( NULL == bufr )
+        {
+        rprintf(FERROR, "%s Memory re-allocation failure.", func);
+        return( False );
+        }
+      }
+
+    /* Handle a single character. */
+    switch( c )
+      {
+      case ']':                       /* Found the closing bracket.         */
+        bufr[end] = '\0';
+        if( 0 == end )                  /* Don't allow an empty name.       */
+          {
+          rprintf(FERROR, "%s Empty section name in configuration file.\n", func );
+          return( False );
+          }
+        if( !sfunc( bufr ) )            /* Got a valid name.  Deal with it. */
+          return( False );
+        (void)EatComment( InFile );     /* Finish off the line.             */
+        return( True );
+
+      case '\n':                      /* Got newline before closing ']'.    */
+        i = Continuation( bufr, i );    /* Check for line continuation.     */
+        if( i < 0 )
+          {
+          bufr[end] = '\0';
+          rprintf(FERROR, "%s Badly formed line in configuration file: %s\n",
+                   func, bufr );
+          return( False );
+          }
+        end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
+        c = getc( InFile );             /* Continue with next line.         */
+        break;
+
+      default:                        /* All else are a valid name chars.   */
+        if( isspace( c ) )              /* One space per whitespace region. */
+          {
+          bufr[end] = ' ';
+          i = end + 1;
+          c = EatWhitespace( InFile );
+          }
+        else                            /* All others copy verbatim.        */
+          {
+          bufr[i++] = c;
+          end = i;
+          c = getc( InFile );
+          }
+      }
+    }
+
+  /* We arrive here if we've met the EOF before the closing bracket. */
+  rprintf(FERROR, "%s Unexpected EOF in the configuration file: %s\n", func, bufr );
+  return( False );
+  } /* Section */
+
+static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
+  /* ------------------------------------------------------------------------ **
+   * Scan a parameter name and value, and pass these two fields to pfunc().
+   *
+   *  Input:  InFile  - The input source.
+   *          pfunc   - A pointer to the function that will be called to
+   *                    process the parameter, once it has been scanned.
+   *          c       - The first character of the parameter name, which
+   *                    would have been read by Parse().  Unlike a comment
+   *                    line or a section header, there is no lead-in
+   *                    character that can be discarded.
+   *
+   *  Output: True if the parameter name and value were scanned and processed
+   *          successfully, else False.
+   *
+   *  Notes:  This function is in two parts.  The first loop scans the
+   *          parameter name.  Internal whitespace is compressed, and an
+   *          equal sign (=) terminates the token.  Leading and trailing
+   *          whitespace is discarded.  The second loop scans the parameter
+   *          value.  When both have been successfully identified, they are
+   *          passed to pfunc() for processing.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  int   i       = 0;    /* Position within bufr. */
+  int   end     = 0;    /* bufr[end] is current end-of-string. */
+  int   vstart  = 0;    /* Starting position of the parameter value. */
+  char *func    = "params.c:Parameter() -";
+
+  /* Read the parameter name. */
+  while( 0 == vstart )  /* Loop until we've found the start of the value. */
+    {
+
+    if( i > (bSize - 2) )       /* Ensure there's space for next char.    */
+      {
+      bSize += BUFR_INC;
+      bufr   = realloc_array( bufr, char, bSize );
+      if( NULL == bufr )
+        {
+        rprintf(FERROR, "%s Memory re-allocation failure.", func) ;
+        return( False );
+        }
+      }
+
+    switch( c )
+      {
+      case '=':                 /* Equal sign marks end of param name. */
+        if( 0 == end )              /* Don't allow an empty name.      */
+          {
+          rprintf(FERROR, "%s Invalid parameter name in config. file.\n", func );
+          return( False );
+          }
+        bufr[end++] = '\0';         /* Mark end of string & advance.   */
+        i       = end;              /* New string starts here.         */
+        vstart  = end;              /* New string is parameter value.  */
+        bufr[i] = '\0';             /* New string is nul, for now.     */
+        break;
+
+      case '\n':                /* Find continuation char, else error. */
+        i = Continuation( bufr, i );
+        if( i < 0 )
+          {
+          bufr[end] = '\0';
+          rprintf(FERROR, "%s Ignoring badly formed line in configuration file: %s\n",
+                   func, bufr );
+          return( True );
+          }
+        end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
+        c = getc( InFile );       /* Read past eoln.                   */
+        break;
+
+      case '\0':                /* Shouldn't have EOF within param name. */
+      case EOF:
+        bufr[i] = '\0';
+        rprintf(FERROR, "%s Unexpected end-of-file at: %s\n", func, bufr );
+        return( True );
+
+      default:
+        if( isspace( c ) )     /* One ' ' per whitespace region.       */
+          {
+          bufr[end] = ' ';
+          i = end + 1;
+          c = EatWhitespace( InFile );
+          }
+        else                   /* All others verbatim.                 */
+          {
+          bufr[i++] = c;
+          end = i;
+          c = getc( InFile );
+          }
+      }
+    }
+
+  /* Now parse the value. */
+  c = EatWhitespace( InFile );  /* Again, trim leading whitespace. */
+  while( (EOF !=c) && (c > 0) )
+    {
+
+    if( i > (bSize - 2) )       /* Make sure there's enough room. */
+      {
+      bSize += BUFR_INC;
+      bufr   = realloc_array( bufr, char, bSize );
+      if( NULL == bufr )
+        {
+        rprintf(FERROR, "%s Memory re-allocation failure.", func) ;
+        return( False );
+        }
+      }
+
+    switch( c )
+      {
+      case '\r':              /* Explicitly remove '\r' because the older */
+        c = getc( InFile );   /* version called fgets_slash() which also  */
+        break;                /* removes them.                            */
+
+      case '\n':              /* Marks end of value unless there's a '\'. */
+        i = Continuation( bufr, i );
+        if( i < 0 )
+          c = 0;
+        else
+          {
+          for( end = i; (end >= 0) && isspace(((unsigned char *) bufr)[end]); end-- )
+            ;
+          c = getc( InFile );
+          }
+        break;
+
+      default:               /* All others verbatim.  Note that spaces do */
+        bufr[i++] = c;       /* not advance <end>.  This allows trimming  */
+        if( !isspace( c ) )  /* of whitespace at the end of the line.     */
+          end = i;
+        c = getc( InFile );
+        break;
+      }
+    }
+  bufr[end] = '\0';          /* End of value. */
+
+  return( pfunc( bufr, &bufr[vstart] ) );   /* Pass name & value to pfunc().  */
+  } /* Parameter */
+
+static BOOL Parse( FILE *InFile,
+                   BOOL (*sfunc)(char *),
+                   BOOL (*pfunc)(char *, char *) )
+  /* ------------------------------------------------------------------------ **
+   * Scan & parse the input.
+   *
+   *  Input:  InFile  - Input source.
+   *          sfunc   - Function to be called when a section name is scanned.
+   *                    See Section().
+   *          pfunc   - Function to be called when a parameter is scanned.
+   *                    See Parameter().
+   *
+   *  Output: True if the file was successfully scanned, else False.
+   *
+   *  Notes:  The input can be viewed in terms of 'lines'.  There are four
+   *          types of lines:
+   *            Blank      - May contain whitespace, otherwise empty.
+   *            Comment    - First non-whitespace character is a ';' or '#'.
+   *                         The remainder of the line is ignored.
+   *            Section    - First non-whitespace character is a '['.
+   *            Parameter  - The default case.
+   * 
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  int    c;
+
+  c = EatWhitespace( InFile );
+  while( (EOF != c) && (c > 0) )
+    {
+    switch( c )
+      {
+      case '\n':                        /* Blank line. */
+        c = EatWhitespace( InFile );
+        break;
+
+      case ';':                         /* Comment line. */
+      case '#':
+        c = EatComment( InFile );
+        break;
+
+      case '[':                         /* Section Header. */
+             if (!sfunc) return True;
+             if( !Section( InFile, sfunc ) )
+                     return( False );
+             c = EatWhitespace( InFile );
+             break;
+
+      case '\\':                        /* Bogus backslash. */
+        c = EatWhitespace( InFile );
+        break;
+
+      default:                          /* Parameter line. */
+        if( !Parameter( InFile, pfunc, c ) )
+          return( False );
+        c = EatWhitespace( InFile );
+        break;
+      }
+    }
+  return( True );
+  } /* Parse */
+
+static FILE *OpenConfFile( char *FileName )
+  /* ------------------------------------------------------------------------ **
+   * Open a configuration file.
+   *
+   *  Input:  FileName  - The pathname of the config file to be opened.
+   *
+   *  Output: A pointer of type (FILE *) to the opened file, or NULL if the
+   *          file could not be opened.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  FILE *OpenedFile;
+  char *func = "params.c:OpenConfFile() -";
+
+  if( NULL == FileName || 0 == *FileName )
+    {
+    rprintf(FERROR,"%s No configuration filename specified.\n", func);
+    return( NULL );
+    }
+
+  OpenedFile = fopen( FileName, "r" );
+  if( NULL == OpenedFile )
+    {
+    rsyserr(FERROR, errno, "unable to open configuration file \"%s\"",
+           FileName);
+    }
+
+  return( OpenedFile );
+  } /* OpenConfFile */
+
+BOOL pm_process( char *FileName,
+                 BOOL (*sfunc)(char *),
+                 BOOL (*pfunc)(char *, char *) )
+  /* ------------------------------------------------------------------------ **
+   * Process the named parameter file.
+   *
+   *  Input:  FileName  - The pathname of the parameter file to be opened.
+   *          sfunc     - A pointer to a function that will be called when
+   *                      a section name is discovered.
+   *          pfunc     - A pointer to a function that will be called when
+   *                      a parameter name and value are discovered.
+   *
+   *  Output: TRUE if the file was successfully parsed, else FALSE.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  int   result;
+  FILE *InFile;
+  char *func = "params.c:pm_process() -";
+
+  InFile = OpenConfFile( FileName );          /* Open the config file. */
+  if( NULL == InFile )
+    return( False );
+
+  if( NULL != bufr )                          /* If we already have a buffer */
+    result = Parse( InFile, sfunc, pfunc );   /* (recursive call), then just */
+                                              /* use it.                     */
+
+  else                                        /* If we don't have a buffer   */
+    {                                         /* allocate one, then parse,   */
+    bSize = BUFR_INC;                         /* then free.                  */
+    bufr = new_array( char, bSize );
+    if( NULL == bufr )
+      {
+      rprintf(FERROR,"%s memory allocation failure.\n", func);
+      fclose(InFile);
+      return( False );
+      }
+    result = Parse( InFile, sfunc, pfunc );
+    free( bufr );
+    bufr  = NULL;
+    bSize = 0;
+    }
+
+  fclose(InFile);
+
+  if( !result )                               /* Generic failure. */
+    {
+    rprintf(FERROR,"%s Failed.  Error returned from params.c:parse().\n", func);
+    return( False );
+    }
+
+  return( True );                             /* Generic success. */
+  } /* pm_process */
+
+/* -------------------------------------------------------------------------- */
+
diff --git a/discover/params.h b/discover/params.h
new file mode 100644 (file)
index 0000000..02a39c9
--- /dev/null
@@ -0,0 +1,6 @@
+
+#define BOOL int
+
+BOOL pm_process( char *FileName,
+                 BOOL (*sfunc)(char *),
+                 BOOL (*pfunc)(char *, char *) );
diff --git a/discover/parser.c b/discover/parser.c
new file mode 100644 (file)
index 0000000..5e50dcb
--- /dev/null
@@ -0,0 +1,85 @@
+
+#include <petitboot-paths.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+extern struct parser native_parser;
+extern struct parser yaboot_parser;
+extern struct parser kboot_parser;
+
+/* array of parsers, ordered by priority */
+static struct parser *parsers[] = {
+       &native_parser,
+       &yaboot_parser,
+       &kboot_parser,
+       NULL
+};
+
+void iterate_parsers(const char *devpath, const char *mountpoint)
+{
+       int i;
+
+       pb_log("trying parsers for %s\n", devpath);
+
+       for (i = 0; parsers[i]; i++) {
+               pb_log("\ttrying parser '%s'\n", parsers[i]->name);
+               /* just use a dummy device path for now */
+               if (parsers[i]->parse(devpath))
+                       return;
+       }
+       pb_log("\tno boot_options found\n");
+}
+
+/* convenience functions for parsers */
+void free_device(struct device *dev)
+{
+       if (!dev)
+               return;
+       if (dev->id)
+               free(dev->id);
+       if (dev->name)
+               free(dev->name);
+       if (dev->description)
+               free(dev->description);
+       if (dev->icon_file)
+               free(dev->icon_file);
+       free(dev);
+}
+
+void free_boot_option(struct boot_option *opt)
+{
+       if (!opt)
+               return;
+       if (opt->name)
+               free(opt->name);
+       if (opt->description)
+               free(opt->description);
+       if (opt->icon_file)
+               free(opt->icon_file);
+       if (opt->boot_image_file)
+               free(opt->boot_image_file);
+       if (opt->initrd_file)
+               free(opt->initrd_file);
+       if (opt->boot_args)
+               free(opt->boot_args);
+       free(opt);
+}
+
+const char *generic_icon_file(enum generic_icon_type type)
+{
+       switch (type) {
+       case ICON_TYPE_DISK:
+               return artwork_pathname("hdd.png");
+       case ICON_TYPE_USB:
+               return artwork_pathname("usbpen.png");
+       case ICON_TYPE_OPTICAL:
+               return artwork_pathname("cdrom.png");
+       case ICON_TYPE_NETWORK:
+       case ICON_TYPE_UNKNOWN:
+               break;
+       }
+       return artwork_pathname("hdd.png");
+}
+
diff --git a/discover/parser.h b/discover/parser.h
new file mode 100644 (file)
index 0000000..9c6fb35
--- /dev/null
@@ -0,0 +1,46 @@
+
+#ifndef _PARSERS_H
+#define _PARSERS_H
+
+#include <stdarg.h>
+#include "message.h"
+
+struct parser {
+       char *name;
+       int priority;
+       int (*parse)(const char *device);
+       struct parser *next;
+};
+
+enum generic_icon_type {
+       ICON_TYPE_DISK,
+       ICON_TYPE_USB,
+       ICON_TYPE_OPTICAL,
+       ICON_TYPE_NETWORK,
+       ICON_TYPE_UNKNOWN
+};
+
+#define streq(a,b) (!strcasecmp((a),(b)))
+
+/* general functions provided by parsers.c */
+void iterate_parsers(const char *devpath, const char *mountpoint);
+
+void free_device(struct device *dev);
+void free_boot_option(struct boot_option *opt);
+
+const char *generic_icon_file(enum generic_icon_type type);
+
+/* functions provided by udev-helper or the test wrapper */
+void pb_log(const char *fmt, ...);
+
+int mount_device(const char *dev_path);
+
+char *resolve_path(const char *path, const char *current_dev);
+const char *mountpoint_for_device(const char *dev_path);
+
+enum generic_icon_type guess_device_type(void);
+
+int add_device(const struct device *dev);
+int add_boot_option(const struct boot_option *opt);
+
+#endif /* _PARSERS_H */
diff --git a/discover/paths.c b/discover/paths.c
new file mode 100644 (file)
index 0000000..2373c28
--- /dev/null
@@ -0,0 +1,141 @@
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "paths.h"
+
+static char *mount_base;
+
+struct device_map {
+       char *dev, *mnt;
+};
+
+#define DEVICE_MAP_SIZE 32
+static struct device_map device_map[DEVICE_MAP_SIZE];
+
+char *encode_label(const char *label)
+{
+       char *str, *c;
+       int i;
+
+       /* the label can be expanded by up to four times */
+       str = malloc(strlen(label) * 4 + 1);
+       c = str;
+
+       for (i = 0; i < strlen(label); i++) {
+
+               if (label[i] == '/' || label[i] == '\\') {
+                       sprintf(c, "\\x%02x", label[i]);
+                       c += 4;
+                       continue;
+               }
+
+               *(c++) = label[i];
+       }
+
+       *c = '\0';
+
+       return str;
+}
+
+char *parse_device_path(const char *dev_str, const char *cur_dev)
+{
+       char *dev, tmp[256], *enc;
+
+       if (!strncasecmp(dev_str, "uuid=", 5)) {
+               asprintf(&dev, "/dev/disk/by-uuid/%s", dev_str + 5);
+               return dev;
+       }
+
+       if (!strncasecmp(dev_str, "label=", 6)) {
+               enc = encode_label(dev_str + 6);
+               asprintf(&dev, "/dev/disk/by-label/%s", enc);
+               free(enc);
+               return dev;
+       }
+
+       /* normalise '/dev/foo' to 'foo' for easy comparisons, we'll expand
+        * back before returning.
+        */
+       if (!strncmp(dev_str, "/dev/", 5))
+               dev_str += 5;
+
+       /* PS3 hack: if we're reading from a ps3dx device, and we refer to
+        * a sdx device, remap to ps3dx */
+       if (cur_dev && !strncmp(cur_dev, "/dev/ps3d", 9)
+                       && !strncmp(dev_str, "sd", 2)) {
+               snprintf(tmp, 255, "ps3d%s", dev_str + 2);
+               dev_str = tmp;
+       }
+
+       return join_paths("/dev", dev_str);
+}
+
+const char *mountpoint_for_device(const char *dev)
+{
+       int i;
+
+       if (!strncmp(dev, "/dev/", 5))
+               dev += 5;
+
+       /* check existing entries in the map */
+       for (i = 0; (i < DEVICE_MAP_SIZE) && device_map[i].dev; i++)
+               if (!strcmp(device_map[i].dev, dev))
+                       return device_map[i].mnt;
+
+       if (i == DEVICE_MAP_SIZE)
+               return NULL;
+
+       device_map[i].dev = strdup(dev);
+       device_map[i].mnt = join_paths(mount_base, dev);
+       return device_map[i].mnt;
+}
+
+char *resolve_path(const char *path, const char *current_dev)
+{
+       char *ret;
+       const char *devpath, *sep;
+
+       sep = strchr(path, ':');
+       if (!sep) {
+               devpath = mountpoint_for_device(current_dev);
+               ret = join_paths(devpath, path);
+       } else {
+               /* parse just the device name into dev */
+               char *tmp, *dev;
+               tmp = strndup(path, sep - path);
+               dev = parse_device_path(tmp, current_dev);
+
+               devpath = mountpoint_for_device(dev);
+               ret = join_paths(devpath, sep + 1);
+
+               free(dev);
+               free(tmp);
+       }
+
+       return ret;
+}
+
+void set_mount_base(const char *path)
+{
+       if (mount_base)
+               free(mount_base);
+       mount_base = strdup(path);
+}
+
+char *join_paths(const char *a, const char *b)
+{
+       char *full_path;
+
+       full_path = malloc(strlen(a) + strlen(b) + 2);
+
+       strcpy(full_path, a);
+       if (b[0] != '/' && a[strlen(a) - 1] != '/')
+               strcat(full_path, "/");
+       strcat(full_path, b);
+
+       return full_path;
+}
+
diff --git a/discover/paths.h b/discover/paths.h
new file mode 100644 (file)
index 0000000..26d4ce4
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef PATHS_H
+#define PATHS_H
+
+/**
+ * Given a string (eg /dev/sda1, sda1 or UUID=B8E53381CA9EA0E3), parse the
+ * device path (eg /dev/sda1). Any device descriptions read from config files
+ * should be parsed into the path first.
+ *
+ * The cur_dev is provided for some remapping situations. If NULL is provided,
+ * no remapping will be done.
+ *
+ * Returns a newly-allocated string.
+ */
+char *parse_device_path(const char *dev_str, const char *current_device);
+
+/**
+ * Get the mountpoint for a device.
+ */
+const char *mountpoint_for_device(const char *dev);
+
+/**
+ * Resolve a path given in a config file, to a path in the local filesystem.
+ * Paths may be of the form:
+ *  device:path (eg /dev/sda:/boot/vmlinux)
+ *
+ * or just a path:
+ *  /boot/vmlinux
+ * - in this case, the current mountpoint is used.
+ *
+ * Returns a newly-allocated string containing a full path to the file in path
+ */
+char *resolve_path(const char *path, const char *current_device);
+
+
+/**
+ * Set the base directory for newly-created mountpoints
+ */
+void set_mount_base(const char *path);
+
+/**
+ * Utility function for joining two paths. Adds a / between a and b if
+ * required.
+ *
+ * Returns a newly-allocated string.
+ */
+char *join_paths(const char *a, const char *b);
+
+/**
+ * encode a disk label (or uuid) for use in a symlink.
+ */
+char *encode_label(const char *label);
+
+#endif /* PATHS_H */
diff --git a/discover/pb-discover.c b/discover/pb-discover.c
new file mode 100644 (file)
index 0000000..45b6ba1
--- /dev/null
@@ -0,0 +1,34 @@
+
+#include <stdlib.h>
+#include <signal.h>
+
+#include "udev.h"
+#include "discover-server.h"
+#include "waiter.h"
+#include "log.h"
+
+
+int main(void)
+{
+       struct discover_server *server;
+       struct udev *udev;
+
+       /* we look for closed sockets when we write, so ignore SIGPIPE */
+       signal(SIGPIPE, SIG_IGN);
+
+       udev = udev_init();
+       if (!udev)
+               return EXIT_FAILURE;
+
+       server = discover_server_init();
+       if (!server)
+               return EXIT_FAILURE;
+
+       for (;;) {
+               if (waiter_poll())
+                       return EXIT_FAILURE;
+       }
+
+
+       return EXIT_SUCCESS;
+}
diff --git a/discover/pb-discover.h b/discover/pb-discover.h
new file mode 100644 (file)
index 0000000..a48557c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _PB_DISCOVER_H
+#define _PB_DISCOVER_H
+
+int register_waiter(int fd, int *callback(void *), void *arg);
+
+#endif /* _PB_DISCOVER_H */
diff --git a/discover/udev.c b/discover/udev.c
new file mode 100644 (file)
index 0000000..9c1b399
--- /dev/null
@@ -0,0 +1,208 @@
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <talloc/talloc.h>
+
+#include "udev.h"
+#include "log.h"
+#include "waiter.h"
+#include "pb-discover.h"
+
+#define PBOOT_DEVICE_SOCKET "/tmp/petitboot.udev"
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+struct udev {
+       int socket;
+};
+
+static void parse_event_params(struct udev_event *event, char *buf, int len)
+{
+       int param_len, name_len, value_len;
+       struct param *param;
+       char *sep;
+
+       for (; len > 0; len -= param_len + 1, buf += param_len + 1) {
+
+               /* find the length of the whole parameter */
+               param_len = strnlen(buf, len);
+               if (!param_len) {
+                       /* multiple NULs? skip over */
+                       param_len = 1;
+                       continue;
+               }
+
+               /* find the separator */
+               sep = memchr(buf, '=', param_len);
+               if (!sep)
+                       continue;
+
+               name_len = sep - buf;
+               value_len = param_len - name_len - 1;
+
+               /* update the params array */
+               event->params = talloc_realloc(event, event->params,
+                                       struct param, ++event->n_params);
+               param = &event->params[event->n_params - 1];
+
+               param->name = talloc_strndup(event, buf, name_len);
+               param->value = talloc_strndup(event, sep + 1, value_len);
+       }
+}
+
+static const char *event_param(struct udev_event *event, const char *name)
+{
+       int i;
+
+       for (i = 0; i < event->n_params; i++)
+               if (!strcasecmp(event->params[i].name, name))
+                       return event->params[i].value;
+
+       return NULL;
+}
+
+static void print_event(struct udev_event *event)
+{
+       const char *action, *params[] = {
+               "DEVNAME", "ID_TYPE", "ID_BUS", "ID_FS_UUID", "ID_FS_LABEL",
+               NULL,
+       };
+       int i;
+
+       action = event->action == UDEV_ACTION_ADD ? "add" : "remove";
+
+       pb_log("udev %s event:\n", action);
+       printf("\tdevice: %s\n", event->device);
+
+       for (i = 0; params[i]; i++)
+               printf("\t%-12s => %s\n",
+                               params[i], event_param(event, params[i]));
+
+}
+
+static void handle_udev_message(struct udev *udev, char *buf, int len)
+{
+       char *sep, *device;
+       enum udev_action action;
+       struct udev_event *event;
+       int device_len;
+
+       /* we should see an <action>@<device>\0 at the head of the buffer */
+       sep = strchr(buf, '@');
+       if (!sep)
+               return;
+
+       /* terminate the action string */
+       *sep = '\0';
+       len -= sep - buf + 1;
+
+       if (!strcmp(buf, "add")) {
+               action = UDEV_ACTION_ADD;
+
+       } else if (!strcmp(buf, "remove")) {
+               action = UDEV_ACTION_REMOVE;
+
+       } else {
+               return;
+       }
+
+       /* initialise the device string */
+       device = sep + 1;
+       device_len = strnlen(device, len);
+       if (!device_len)
+               return;
+
+       /* now we have an action and a device, we can construct an event */
+       event = talloc(udev, struct udev_event);
+       event->action = action;
+       event->device = talloc_strndup(event, device, device_len);
+       event->n_params = 0;
+       event->params = NULL;
+
+       len -= device_len + 1;
+       parse_event_params(event, device + device_len + 1, len);
+
+       print_event(event);
+
+       talloc_free(event);
+
+       return;
+}
+
+static int udev_process(void *arg)
+{
+       struct udev *udev = arg;
+       char buf[4096];
+       int len;
+
+       len = recvfrom(udev->socket, buf, sizeof(buf), 0, NULL, NULL);
+
+       if (len < 0) {
+               pb_log("udev socket read failed: %s", strerror(errno));
+               return -1;
+       }
+
+       if (len == 0)
+               return 0;
+
+       handle_udev_message(udev, buf, len);
+
+       return 0;
+}
+
+static int udev_destructor(void *p)
+{
+       struct udev *udev = p;
+
+       if (udev->socket >= 0)
+               close(udev->socket);
+
+       return 0;
+}
+
+struct udev *udev_init(void)
+{
+       struct sockaddr_un addr;
+       struct udev *udev;
+
+       unlink(PBOOT_DEVICE_SOCKET);
+
+       udev = talloc(NULL, struct udev);
+
+       udev->socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (udev->socket < 0) {
+               pb_log("Error creating udev socket: %s\n", strerror(errno));
+               goto out_err;
+       }
+
+       talloc_set_destructor(udev, udev_destructor);
+
+       addr.sun_family = AF_UNIX;
+       strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
+
+       if (bind(udev->socket, (struct sockaddr *)&addr, sizeof(addr))) {
+               pb_log("Error binding udev socket: %s\n", strerror(errno));
+               goto out_err;
+       }
+
+       waiter_register(udev->socket, WAIT_IN, udev_process, udev);
+
+       return udev;
+
+out_err:
+       talloc_free(udev);
+       return NULL;
+}
+
+void udev_destroy(struct udev *udev)
+{
+       talloc_free(udev);
+}
diff --git a/discover/udev.h b/discover/udev.h
new file mode 100644 (file)
index 0000000..c30adc9
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _UDEV_H
+#define _UDEV_H
+
+enum udev_action {
+       UDEV_ACTION_ADD,
+       UDEV_ACTION_REMOVE,
+};
+
+struct udev_event {
+       enum udev_action action;
+       char *device;
+
+       struct param {
+               char *name;
+               char *value;
+       } *params;
+       int n_params;
+};
+
+struct udev;
+
+struct udev *udev_init(void);
+
+void udev_destroy(struct udev *udev);
+
+#endif /* _UDEV_H */
diff --git a/discover/waiter.c b/discover/waiter.c
new file mode 100644 (file)
index 0000000..21dd4a5
--- /dev/null
@@ -0,0 +1,83 @@
+
+#include <poll.h>
+#include <string.h>
+#include <assert.h>
+
+#include <talloc/talloc.h>
+
+#include "waiter.h"
+
+struct waiter {
+       int             fd;
+       int             events;
+       waiter_cb       callback;
+       void            *arg;
+};
+
+static struct waiter *waiters;
+static int n_waiters;
+
+struct waiter *waiter_register(int fd, int events,
+               waiter_cb callback, void *arg)
+{
+       struct waiter *waiter;
+
+       n_waiters++;
+
+       waiters = talloc_realloc(NULL, waiters, struct waiter, n_waiters);
+       waiter = &waiters[n_waiters - 1];
+
+       waiter->fd = fd;
+       waiter->events = events;
+       waiter->callback = callback;
+       waiter->arg = arg;
+
+       return 0;
+}
+
+void waiter_remove(struct waiter *waiter)
+{
+       int i;
+
+       i = waiter - waiters;
+       assert(i >= 0 && i < n_waiters);
+
+       n_waiters--;
+       memmove(&waiters[i], &waiters[i+1], n_waiters - i);
+
+       waiters = talloc_realloc(NULL, waiters, struct waiter, n_waiters);
+}
+
+int waiter_poll(void)
+{
+       static struct pollfd *pollfds;
+       static int n_pollfds;
+       int i, rc;
+
+       if (n_waiters > n_pollfds) {
+               pollfds = talloc_realloc(NULL, pollfds,
+                               struct pollfd, n_waiters);
+       }
+
+       for (i = 0; i < n_waiters; i++) {
+               pollfds[i].fd = waiters[i].fd;
+               pollfds[i].events = waiters[i].events;
+               pollfds[i].revents = 0;
+       }
+
+       rc = poll(pollfds, n_waiters, -1);
+
+       if (rc <= 0)
+               return rc;
+
+       for (i = 0; i < n_waiters; i++) {
+               if (pollfds[i].revents) {
+                       rc = waiters[i].callback(waiters[i].arg);
+
+                       if (rc)
+                               waiter_remove(&waiters[i]);
+               }
+       }
+
+       return 0;
+}
diff --git a/discover/waiter.h b/discover/waiter.h
new file mode 100644 (file)
index 0000000..ff8a5ff
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _WAITER_H
+#define _WAITER_H
+
+#include <poll.h>
+
+struct waiter;
+
+enum events {
+       WAIT_IN  = POLLIN,
+       WAIT_OUT = POLLOUT,
+};
+
+typedef int (*waiter_cb)(void *);
+
+struct waiter *waiter_register(int fd, int events,
+               waiter_cb callback, void *arg);
+
+void waiter_remove(struct waiter *waiter);
+
+int waiter_poll(void);
+#endif /* _WAITER_H */
+
+
diff --git a/discover/yaboot-cfg.c b/discover/yaboot-cfg.c
new file mode 100644 (file)
index 0000000..6b007e4
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ *  cfg.c - Handling and parsing of yaboot.conf
+ *
+ *  Copyright (C) 1995 Werner Almesberger
+ *                1996 Jakub Jelinek
+ *
+ *  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; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#define prom_printf printf
+#define prom_putchar putchar
+#define prom_vprintf vprintf
+
+/* Imported functions */
+extern int strcasecmp(const char *s1, const char *s2);
+
+typedef enum {
+     cft_strg, cft_flag, cft_end
+} CONFIG_TYPE;
+
+typedef struct {
+     CONFIG_TYPE type;
+     char *name;
+     void *data;
+} CONFIG;
+
+#define MAX_TOKEN 200
+#define MAX_VAR_NAME MAX_TOKEN
+char *cfg_get_default (void);
+
+CONFIG cf_options[] =
+{
+     {cft_strg, "device", NULL},
+     {cft_strg, "partition", NULL},
+     {cft_strg, "default", NULL},
+     {cft_strg, "timeout", NULL},
+     {cft_strg, "password", NULL},
+     {cft_flag, "restricted", NULL},
+     {cft_strg, "message", NULL},
+     {cft_strg, "root", NULL},
+     {cft_strg, "ramdisk", NULL},
+     {cft_flag, "read-only", NULL},
+     {cft_flag, "read-write", NULL},
+     {cft_strg, "append", NULL},
+     {cft_strg, "initrd", NULL},
+     {cft_flag, "initrd-prompt", NULL},
+     {cft_strg, "initrd-size", NULL},
+     {cft_flag, "pause-after", NULL},
+     {cft_strg, "pause-message", NULL},
+     {cft_strg, "init-code", NULL},
+     {cft_strg, "init-message", NULL},
+     {cft_strg, "fgcolor", NULL},
+     {cft_strg, "bgcolor", NULL},
+     {cft_strg, "ptypewarning", NULL},
+     {cft_end, NULL, NULL}};
+
+CONFIG cf_image[] =
+{
+     {cft_strg, "image", NULL},
+     {cft_strg, "label", NULL},
+     {cft_strg, "alias", NULL},
+     {cft_flag, "single-key", NULL},
+     {cft_flag, "restricted", NULL},
+     {cft_strg, "device", NULL},
+     {cft_strg, "partition", NULL},
+     {cft_strg, "root", NULL},
+     {cft_strg, "ramdisk", NULL},
+     {cft_flag, "read-only", NULL},
+     {cft_flag, "read-write", NULL},
+     {cft_strg, "append", NULL},
+     {cft_strg, "literal", NULL},
+     {cft_strg, "initrd", NULL},
+     {cft_flag, "initrd-prompt", NULL},
+     {cft_strg, "initrd-size", NULL},
+     {cft_flag, "pause-after", NULL},
+     {cft_strg, "pause-message", NULL},
+     {cft_flag, "novideo", NULL},
+     {cft_strg, "sysmap", NULL},
+     {cft_end, NULL, NULL}};
+
+static char flag_set;
+static char *last_token = NULL, *last_item = NULL, *last_value = NULL;
+static int line_num;
+static int back = 0;           /* can go back by one char */
+static char *currp = NULL;
+static char *endp = NULL;
+static char *file_name = NULL;
+static CONFIG *curr_table = cf_options;
+static jmp_buf env;
+
+static struct IMAGES {
+     CONFIG table[sizeof (cf_image) / sizeof (cf_image[0])];
+     struct IMAGES *next;
+} *images = NULL;
+
+void cfg_error (char *msg,...)
+{
+     va_list ap;
+
+     va_start (ap, msg);
+     prom_printf ("Config file error: ");
+     prom_vprintf (msg, ap);
+     va_end (ap);
+     prom_printf (" near line %d in file %s\n", line_num, file_name);
+     longjmp (env, 1);
+}
+
+void cfg_warn (char *msg,...)
+{
+     va_list ap;
+
+     va_start (ap, msg);
+     prom_printf ("Config file warning: ");
+     prom_vprintf (msg, ap);
+     va_end (ap);
+     prom_printf (" near line %d in file %s\n", line_num, file_name);
+}
+
+int cfg_getc ()
+{
+     if (currp == endp)
+         return EOF;
+     return *currp++;
+}
+
+#define next_raw next
+static int next (void)
+{
+     int ch;
+
+     if (!back)
+         return cfg_getc ();
+     ch = back;
+     back = 0;
+     return ch;
+}
+
+static void again (int ch)
+{
+     back = ch;
+}
+
+static char *cfg_get_token (void)
+{
+     char buf[MAX_TOKEN + 1];
+     char *here;
+     int ch, escaped;
+
+     if (last_token) {
+         here = last_token;
+         last_token = NULL;
+         return here;
+     }
+     while (1) {
+         while (ch = next (), ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
+              if (ch == '\n' || ch == '\r')
+                   line_num++;
+         if (ch == EOF || ch == (int)NULL)
+              return NULL;
+         if (ch != '#')
+              break;
+         while (ch = next_raw (), (ch != '\n' && ch != '\r'))
+              if (ch == EOF)
+                   return NULL;
+         line_num++;
+     }
+     if (ch == '=')
+         return strdup ("=");
+     if (ch == '"') {
+         here = buf;
+         while (here - buf < MAX_TOKEN) {
+              if ((ch = next ()) == EOF)
+                   cfg_error ("EOF in quoted string");
+              if (ch == '"') {
+                   *here = 0;
+                   return strdup (buf);
+              }
+              if (ch == '\\') {
+                   ch = next ();
+                   switch (ch) {
+                   case '"':
+                   case '\\':
+                        break;
+                   case '\n':
+                   case '\r':
+                        while ((ch = next ()), ch == ' ' || ch == '\t');
+                        if (!ch)
+                             continue;
+                        again (ch);
+                        ch = ' ';
+                        break;
+                   case 'n':
+                        ch = '\n';
+                        break;
+                   default:
+                        cfg_error ("Bad use of \\ in quoted string");
+                   }
+              } else if ((ch == '\n') || (ch == '\r'))
+                   cfg_error ("newline is not allowed in quoted strings");
+              *here++ = ch;
+         }
+         cfg_error ("Quoted string is too long");
+         return 0;             /* not reached */
+     }
+     here = buf;
+     escaped = 0;
+     while (here - buf < MAX_TOKEN) {
+         if (escaped) {
+              if (ch == EOF)
+                   cfg_error ("\\ precedes EOF");
+              if (ch == '\n')
+                   line_num++;
+              else
+                   *here++ = ch == '\t' ? ' ' : ch;
+              escaped = 0;
+         } else {
+              if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '#' ||
+                  ch == '=' || ch == EOF) {
+                   again (ch);
+                   *here = 0;
+                   return strdup (buf);
+              }
+              if (!(escaped = (ch == '\\')))
+                   *here++ = ch;
+         }
+         ch = next ();
+     }
+     cfg_error ("Token is too long");
+     return 0;                 /* not reached */
+}
+
+static void cfg_return_token (char *token)
+{
+     last_token = token;
+}
+
+static int cfg_next (char **item, char **value)
+{
+     char *this;
+
+     if (last_item) {
+         *item = last_item;
+         *value = last_value;
+         last_item = NULL;
+         return 1;
+     }
+     *value = NULL;
+     if (!(*item = cfg_get_token ()))
+         return 0;
+     if (!strcmp (*item, "="))
+         cfg_error ("Syntax error");
+     if (!(this = cfg_get_token ()))
+         return 1;
+     if (strcmp (this, "=")) {
+         cfg_return_token (this);
+         return 1;
+     }
+     if (!(*value = cfg_get_token ()))
+         cfg_error ("Value expected at EOF");
+     if (!strcmp (*value, "="))
+         cfg_error ("Syntax error after %s", *item);
+     return 1;
+}
+
+#if 0
+// The one and only call to this procedure is commented out
+// below, so we don't need this unless we decide to use it again.
+static void cfg_return (char *item, char *value)
+{
+     last_item = item;
+     last_value = value;
+}
+#endif
+
+static int cfg_set (char *item, char *value)
+{
+     CONFIG *walk;
+
+     if (!strcasecmp (item, "image")) {
+         struct IMAGES **p = &images;
+
+         while (*p)
+              p = &((*p)->next);
+         *p = (struct IMAGES *)malloc (sizeof (struct IMAGES));
+         if (*p == NULL) {
+              prom_printf("malloc error in cfg_set\n");
+              return -1;
+         }
+         (*p)->next = 0;
+         curr_table = ((*p)->table);
+         memcpy (curr_table, cf_image, sizeof (cf_image));
+     }
+     for (walk = curr_table; walk->type != cft_end; walk++) {
+         if (walk->name && !strcasecmp (walk->name, item)) {
+              if (value && walk->type != cft_strg)
+                   cfg_warn ("'%s' doesn't have a value", walk->name);
+              else if (!value && walk->type == cft_strg)
+                   cfg_warn ("Value expected for '%s'", walk->name);
+              else {
+                   if (walk->data)
+                        cfg_warn ("Duplicate entry '%s'", walk->name);
+                   if (walk->type == cft_flag)
+                        walk->data = &flag_set;
+                   else if (walk->type == cft_strg)
+                        walk->data = value;
+              }
+              break;
+         }
+     }
+     if (walk->type != cft_end)
+         return 1;
+//    cfg_return (item, value);
+     return 0;
+}
+
+int cfg_parse (char *cfg_file, char *buff, int len)
+{
+     char *item, *value;
+
+     file_name = cfg_file;
+     currp = buff;
+     endp = currp + len;
+
+     if (setjmp (env))
+         return -1;
+     while (1) {
+         if (!cfg_next (&item, &value))
+              return 0;
+         if (!cfg_set (item, value)) {
+#if DEBUG
+              prom_printf("Can't set item %s to value %s\n", item, value);
+#endif     
+         }
+         free (item);
+     }
+}
+
+static char *cfg_get_strg_i (CONFIG * table, char *item)
+{
+     CONFIG *walk;
+
+     for (walk = table; walk->type != cft_end; walk++)
+         if (walk->name && !strcasecmp (walk->name, item))
+              return walk->data;
+     return 0;
+}
+
+char *cfg_get_strg (char *image, char *item)
+{
+     struct IMAGES *p;
+     char *label, *alias;
+     char *ret;
+
+     if (!image)
+         return cfg_get_strg_i (cf_options, item);
+     for (p = images; p; p = p->next) {
+         label = cfg_get_strg_i (p->table, "label");
+         if (!label) {
+              label = cfg_get_strg_i (p->table, "image");
+              alias = strrchr (label, '/');
+              if (alias)
+                   label = alias + 1;
+         }
+         alias = cfg_get_strg_i (p->table, "alias");
+         if (!strcmp (label, image) || (alias && !strcmp (alias, image))) {
+              ret = cfg_get_strg_i (p->table, item);
+              if (!ret)
+                   ret = cfg_get_strg_i (cf_options, item);
+              return ret;
+         }
+     }
+     return 0;
+}
+
+int cfg_get_flag (char *image, char *item)
+{
+     return !!cfg_get_strg (image, item);
+}
+
+static int printl_count = 0;
+static void printlabel (char *label, int defflag)
+{
+     int len = strlen (label);
+
+     if (!printl_count)
+         prom_printf ("\n");
+     prom_printf ("%s %s",defflag?"*":" ", label);
+     while (len++ < 25)
+         prom_putchar (' ');
+     printl_count++;
+     if (printl_count == 3)
+         printl_count = 0;
+}
+
+void cfg_print_images (void)
+{
+     struct IMAGES *p;
+     char *label, *alias;
+
+     char *ret = cfg_get_default();//strg_i (cf_options, "default");
+     int defflag=0;
+
+     printl_count = 0;
+     for (p = images; p; p = p->next) {
+         label = cfg_get_strg_i (p->table, "label");
+         if (!label) {
+              label = cfg_get_strg_i (p->table, "image");
+              alias = strrchr (label, '/');
+              if (alias)
+                   label = alias + 1;
+         }
+         if(!strcmp(ret,label))
+              defflag=1;
+         else
+              defflag=0;
+         alias = cfg_get_strg_i (p->table, "alias");
+         printlabel (label, defflag);
+         if (alias)
+              printlabel (alias, 0);
+     }
+     prom_printf("\n");
+}
+
+char *cfg_get_default (void)
+{
+     char *label;
+     char *ret = cfg_get_strg_i (cf_options, "default");
+
+     if (ret)
+         return ret;
+     if (!images)
+         return 0;
+     ret = cfg_get_strg_i (images->table, "label");
+     if (!ret) {
+         ret = cfg_get_strg_i (images->table, "image");
+         label = strrchr (ret, '/');
+         if (label)
+              ret = label + 1;
+     }
+     return ret;
+}
+
+char *cfg_next_image(char *prev)
+{
+     struct IMAGES *p;
+     char *label, *alias;
+     int wantnext = 0;
+
+     if (!prev)
+         wantnext = 1;
+
+     for (p = images; p; p = p->next) {
+         label = cfg_get_strg_i (p->table, "label");
+         if (!label) {
+              label = cfg_get_strg_i (p->table, "image");
+              alias = strrchr (label, '/');
+              if (alias)
+                   label = alias + 1;
+         }
+         if (wantnext)
+              return label;
+         if (!strcmp(prev, label))
+              wantnext = 1;
+     }
+     return NULL;
+}
+/* 
+ * Local variables:
+ * c-file-style: "k&r"
+ * c-basic-offset: 5
+ * End:
+ */
diff --git a/discover/yaboot-cfg.h b/discover/yaboot-cfg.h
new file mode 100644 (file)
index 0000000..2ab4fec
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  cfg.h - config file parsing definitions
+ *
+ *  Copyright (C) 1999 Benjamin Herrenschmidt
+ *
+ *  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; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef CFG_H
+#define CFG_H
+
+extern int     cfg_parse(char *cfg_file, char *buff, int len);
+extern char*   cfg_get_strg(char *image, char *item);
+extern int     cfg_get_flag(char *image, char *item);
+extern void    cfg_print_images(void);
+extern char*   cfg_get_default(void);
+extern char*   cfg_next_image(char *);
+#endif
diff --git a/discover/yaboot-parser.c b/discover/yaboot-parser.c
new file mode 100644 (file)
index 0000000..27b4b78
--- /dev/null
@@ -0,0 +1,235 @@
+
+#include "parser.h"
+#include "params.h"
+#include "paths.h"
+#include "yaboot-cfg.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+static struct device *dev;
+static char *devpath;
+static char *defimage;
+
+char *
+make_params(char *label, char *params)
+{
+     char *p, *q;
+     static char buffer[2048];
+
+     q = buffer;
+     *q = 0;
+
+     p = cfg_get_strg(label, "literal");
+     if (p) {
+          strcpy(q, p);
+          q = strchr(q, 0);
+          if (params) {
+               if (*p)
+                    *q++ = ' ';
+               strcpy(q, params);
+          }
+          return buffer;
+     }
+
+     p = cfg_get_strg(label, "root");
+     if (p) {
+          strcpy (q, "root=");
+          strcpy (q + 5, p);
+          q = strchr (q, 0);
+          *q++ = ' ';
+     }
+     if (cfg_get_flag(label, "read-only")) {
+          strcpy (q, "ro ");
+          q += 3;
+     }
+     if (cfg_get_flag(label, "read-write")) {
+          strcpy (q, "rw ");
+          q += 3;
+     }
+     p = cfg_get_strg(label, "ramdisk");
+     if (p) {
+          strcpy (q, "ramdisk=");
+          strcpy (q + 8, p);
+          q = strchr (q, 0);
+          *q++ = ' ';
+     }
+     p = cfg_get_strg(label, "initrd-size");
+     if (p) {
+          strcpy (q, "ramdisk_size=");
+          strcpy (q + 13, p);
+          q = strchr (q, 0);
+          *q++ = ' ';
+     }
+     if (cfg_get_flag(label, "novideo")) {
+          strcpy (q, "video=ofonly");
+          q = strchr (q, 0);
+          *q++ = ' ';
+     }
+     p = cfg_get_strg (label, "append");
+     if (p) {
+          strcpy (q, p);
+          q = strchr (q, 0);
+          *q++ = ' ';
+     }
+     *q = 0;
+     if (params)
+          strcpy(q, params);
+
+     return buffer;
+}
+
+static int check_and_add_device(struct device *dev)
+{
+       if (!dev->icon_file)
+               dev->icon_file = strdup(generic_icon_file(guess_device_type()));
+
+       return !add_device(dev);
+}
+
+void process_image(char *label)
+{
+       struct boot_option opt;
+       char *cfgopt;
+
+       memset(&opt, 0, sizeof(opt));
+
+       opt.name = label;
+       cfgopt = cfg_get_strg(label, "image");
+       opt.boot_image_file = resolve_path(cfgopt, devpath);
+       if (cfgopt == defimage)
+               pb_log("This one is default. What do we do about it?\n");
+
+       cfgopt = cfg_get_strg(label, "initrd");
+       if (cfgopt)
+               opt.initrd_file = resolve_path(cfgopt, devpath);
+
+       opt.boot_args = make_params(label, NULL);
+
+       add_boot_option(&opt);
+
+       if (opt.initrd_file)
+               free(opt.initrd_file);
+}
+
+static int yaboot_parse(const char *device)
+{
+       char *filepath;
+       char *conf_file;
+       char *tmpstr;
+       ssize_t conf_len;
+       int fd;
+       struct stat st;
+       char *label;
+
+       devpath = strdup(device);
+
+       filepath = resolve_path("/etc/yaboot.conf", devpath);
+
+       fd = open(filepath, O_RDONLY);
+       if (fd < 0) {
+               free(filepath);
+               filepath = resolve_path("/yaboot.conf", devpath);
+               fd = open(filepath, O_RDONLY);
+               
+               if (fd < 0)
+                       return 0;
+       }
+
+       if (fstat(fd, &st)) {
+               close(fd);
+               return 0;
+       }
+
+       conf_file = malloc(st.st_size+1);
+       if (!conf_file) {
+               close(fd);
+               return 0;
+       }
+       
+       conf_len = read(fd, conf_file, st.st_size);
+       if (conf_len < 0) {
+               close(fd);
+               return 0;
+       }
+       conf_file[conf_len] = 0;
+
+       close(fd);
+       
+       if (cfg_parse(filepath, conf_file, conf_len)) {
+               pb_log("Error parsing yaboot.conf\n");
+               return 0;
+       }
+
+       free(filepath);
+
+       dev = malloc(sizeof(*dev));
+       memset(dev, 0, sizeof(*dev));
+       dev->id = strdup(devpath);
+       if (cfg_get_strg(0, "init-message")) {
+               char *newline;
+               dev->description = strdup(cfg_get_strg(0, "init-message"));
+               newline = strchr(dev->description, '\n');
+               if (newline)
+                       *newline = 0;
+       }
+       dev->icon_file = strdup(generic_icon_file(guess_device_type()));
+
+       /* If we have a 'partiton=' directive, update the default devpath
+        * to use that instead of the current device */
+       tmpstr = cfg_get_strg(0, "partition");
+       if (tmpstr) {
+               char *endp;
+               int partnr = strtol(tmpstr, &endp, 10);
+               if (endp != tmpstr && !*endp) {
+                       char *new_dev, *tmp;
+
+                       new_dev = malloc(strlen(devpath) + strlen(tmpstr) + 1);
+                       if (!new_dev)
+                               return 0;
+
+                       strcpy(new_dev, devpath);
+
+                       /* Strip digits (partition number) from string */
+                       endp = new_dev + strlen(devpath) - 1;
+                       while (isdigit(*endp))
+                               *(endp--) = 0;
+
+                       /* and add our own... */
+                       sprintf(endp + 1, "%d", partnr);
+
+                       tmp = devpath;
+                       devpath = parse_device_path(new_dev, devpath);
+                       free(tmp);
+                       free(new_dev);
+               }
+       }
+
+       defimage = cfg_get_default();
+       if (!defimage)
+               return 0;
+       defimage = cfg_get_strg(defimage, "image");
+
+       label = cfg_next_image(NULL);
+       if (!label || !check_and_add_device(dev))
+               return 0;
+
+       do {
+               process_image(label);
+       } while ((label = cfg_next_image(label)));
+
+       return 1;
+}
+
+struct parser yaboot_parser = {
+       .name = "yaboot.conf parser",
+       .priority = 99,
+       .parse    = yaboot_parse
+};
diff --git a/lib/list/list.c b/lib/list/list.c
new file mode 100644 (file)
index 0000000..d9bc532
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include "list/list.h"
+
+void list_init(struct list *list)
+{
+       list->head.next = &list->head;
+       list->head.prev = &list->head;
+}
+
+void list_add(struct list *list, struct list_item *new)
+{
+       new->next = list->head.next;
+       new->prev = &list->head;
+
+       list->head.next->prev = new;
+       list->head.next = new;
+}
+
+void list_remove(struct list_item *item)
+{
+       item->next->prev = item->prev;
+       item->prev->next = item->next;
+}
+
diff --git a/lib/list/list.h b/lib/list/list.h
new file mode 100644 (file)
index 0000000..3858cf6
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+struct list_item {
+       struct list_item *prev, *next;
+};
+
+struct list {
+       struct list_item head;
+};
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                     \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define list_for_each(list, pos) \
+       for (pos = (list)->head.next; pos != ((list)->head); pos = pos->next)
+
+#define list_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+
+#define list_for_each_entry(list, pos, member)                         \
+       for (pos = list_entry((list)->head.next, typeof(*pos), member); \
+            &pos->member != &(list)->head;     \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+void list_init(struct list *list);
+
+void list_add(struct list *list, struct list_item *item);
+
+void list_remove(struct list_item *item);
+
+#endif /* _LIST_H */
diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
new file mode 100644 (file)
index 0000000..2fd76c5
--- /dev/null
@@ -0,0 +1,307 @@
+
+#include <string.h>
+#include <stdint.h>
+#include <asm/byteorder.h>
+
+#include <talloc/talloc.h>
+
+#include "pb-protocol.h"
+
+
+/* Message format:
+ *
+ * 4-byte action, determines the remaining message content
+ * 4-byte total payload len
+ *   - not including action and payload len header
+ *
+ * action = 0x1: device add message
+ *  payload:
+ *   4-byte len, id
+ *   4-byte len, name
+ *   4-byte len, description
+ *   4-byte len, icon_file
+ *
+ *   4-byte option count
+ *   for each option:
+ *    4-byte len, id
+ *    4-byte len, name
+ *    4-byte len, description
+ *    4-byte len, icon_file
+ *    4-byte len, boot_image_file
+ *    4-byte len, initrd_file
+ *    4-byte len, boot_args
+ *
+ * action = 0x2: device remove message
+ *  payload:
+ *   4-byte len, id
+ */
+
+
+/* Write a string into the buffer, starting at pos.
+ *
+ * Returns the total length used for the write, including length header.
+ */
+int pb_protocol_serialise_string(char *pos, const char *str)
+{
+       int len = 0;
+
+       if (str)
+               len = strlen(str);
+
+       *(uint32_t *)pos = __cpu_to_be32(len);
+       pos += sizeof(uint32_t);
+
+       memcpy(pos, str, len);
+
+       return len + sizeof(uint32_t);
+}
+
+/* Read a string from a buffer, allocating the new string as necessary.
+ *
+ * @param[in] ctx      The talloc context to base the allocation on
+ * @param[in,out] pos  Where to start reading
+ * @param[in,out] len  The amount of data remaining in the buffer
+ * @param[out] str     Pointer to resuling string
+ * @return             zero on success, non-zero on failure
+ */
+static int read_string(void *ctx, char **pos, int *len, char **str)
+{
+       uint32_t str_len, read_len;
+
+       if (*len < sizeof(uint32_t))
+               return -1;
+
+       str_len = __be32_to_cpu(*(uint32_t *)(*pos));
+       read_len = sizeof(uint32_t);
+
+       if (read_len + str_len > *len)
+               return -1;
+
+       if (str_len == 0)
+               *str = NULL;
+       else
+               *str = talloc_strndup(ctx, *pos + read_len, str_len);
+
+       read_len += str_len;
+
+       /* all ok, update the caller's pointers */
+       *pos += read_len;
+       *len -= read_len;
+
+       return 0;
+}
+
+char *pb_protocol_deserialise_string(void *ctx,
+               struct pb_protocol_message *message)
+{
+       char *buf, *str;
+       int len;
+
+       len = message->payload_len;
+       buf = message->payload;
+
+       if (read_string(ctx, &buf, &len, &str))
+               return NULL;
+
+       return str;
+}
+
+static int optional_strlen(const char *str)
+{
+       if (!str)
+               return 0;
+       return strlen(str);
+}
+
+int pb_protocol_device_len(struct device *dev)
+{
+       int len, i;
+
+       len =   4 + optional_strlen(dev->id) +
+               4 + optional_strlen(dev->name) +
+               4 + optional_strlen(dev->description) +
+               4 + optional_strlen(dev->icon_file) +
+               4;
+
+       for (i = 0; i < dev->n_options; i++) {
+               struct boot_option *opt = &dev->options[i];
+               len +=  4 + optional_strlen(opt->id) +
+                       4 + optional_strlen(opt->name) +
+                       4 + optional_strlen(opt->description) +
+                       4 + optional_strlen(opt->icon_file) +
+                       4 + optional_strlen(opt->boot_image_file) +
+                       4 + optional_strlen(opt->initrd_file) +
+                       4 + optional_strlen(opt->boot_args);
+       }
+
+       return len;
+}
+
+int pb_protocol_serialise_device(struct device *dev, char *buf, int buf_len)
+{
+       char *pos;
+       int i;
+
+       pos = buf;
+
+       /* construct payload into buffer */
+       pos += pb_protocol_serialise_string(pos, dev->id);
+       pos += pb_protocol_serialise_string(pos, dev->name);
+       pos += pb_protocol_serialise_string(pos, dev->description);
+       pos += pb_protocol_serialise_string(pos, dev->icon_file);
+
+       /* write option count */
+       *(uint32_t *)pos = __cpu_to_be32(dev->n_options);
+       pos += sizeof(uint32_t);
+
+       /* write each option */
+       for (i = 0; i < dev->n_options; i++) {
+               struct boot_option *opt = &dev->options[i];
+               pos += pb_protocol_serialise_string(pos, opt->id);
+               pos += pb_protocol_serialise_string(pos, opt->name);
+               pos += pb_protocol_serialise_string(pos, opt->description);
+               pos += pb_protocol_serialise_string(pos, opt->icon_file);
+               pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
+               pos += pb_protocol_serialise_string(pos, opt->initrd_file);
+               pos += pb_protocol_serialise_string(pos, opt->boot_args);
+       }
+
+       return 0;
+}
+
+int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
+{
+       int total_len, rc;
+       char *pos;
+
+       total_len = sizeof(*message) + message->payload_len;
+
+       message->payload_len = __cpu_to_be32(message->payload_len);
+       message->action = __cpu_to_be32(message->action);
+
+       for (pos = (void *)message; total_len;) {
+               rc = write(fd, pos, total_len);
+
+               if (rc <= 0)
+                       break;
+
+               total_len -= rc;
+               pos += rc;
+       }
+
+       talloc_free(message);
+
+       return total_len ? -1 : 0;
+}
+
+struct pb_protocol_message *pb_protocol_create_message(void *ctx,
+               int action, int payload_len)
+{
+       struct pb_protocol_message *message;
+
+       if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
+               return NULL;
+
+       message = talloc_size(ctx, sizeof(*message) + payload_len);
+
+       /* we convert these to big-endian in write_message() */
+       message->action = action;
+       message->payload_len = payload_len;
+
+       return message;
+
+}
+
+struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
+{
+       struct pb_protocol_message *message, m;
+       int rc, len;
+
+       /* use the stack for the initial 8-byte read */
+
+       rc = read(fd, &m, sizeof(m));
+       if (rc != sizeof(m))
+               return NULL;
+
+       m.payload_len = __be32_to_cpu(m.payload_len);
+       m.action = __be32_to_cpu(m.action);
+
+       if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
+               return NULL;
+
+       message = talloc_size(ctx, sizeof(m) + m.payload_len);
+       memcpy(message, &m, sizeof(m));
+
+       for (len = 0; len < m.payload_len;) {
+               rc = read(fd, message->payload + len, m.payload_len - len);
+
+               if (rc <= 0) {
+                       talloc_free(message);
+                       return NULL;
+               }
+
+               len += rc;
+       }
+
+       return message;
+}
+
+
+struct device *pb_protocol_deserialise_device(void *ctx,
+               struct pb_protocol_message *message)
+{
+       struct device *dev;
+       char *pos;
+       int i, len;
+
+       len = message->payload_len;
+       pos = message->payload;
+
+       dev = talloc(ctx, struct device);
+
+       if (read_string(dev, &pos, &len, &dev->id))
+               goto out_err;
+
+       if (read_string(dev, &pos, &len, &dev->name))
+               goto out_err;
+
+       if (read_string(dev, &pos, &len, &dev->description))
+               goto out_err;
+
+       if (read_string(dev, &pos, &len, &dev->icon_file))
+               goto out_err;
+
+       dev->n_options = __be32_to_cpu(*(uint32_t *)pos);
+       dev->options = talloc_array(dev, struct boot_option, dev->n_options);
+       pos += sizeof(uint32_t);
+
+       for (i = 0; i < dev->n_options; i++) {
+               struct boot_option *opt = &dev->options[i];
+
+               if (read_string(opt, &pos, &len, &opt->id))
+                       goto out_err;
+               if (read_string(opt, &pos, &len, &opt->name))
+                       goto out_err;
+               if (read_string(opt, &pos, &len,
+                                       &opt->description))
+                       goto out_err;
+               if (read_string(opt, &pos, &len,
+                                       &opt->icon_file))
+                       goto out_err;
+               if (read_string(opt, &pos, &len,
+                                       &opt->boot_image_file))
+                       goto out_err;
+               if (read_string(opt, &pos, &len,
+                                       &opt->initrd_file))
+                       goto out_err;
+               if (read_string(opt, &pos, &len,
+                                       &opt->boot_args))
+                       goto out_err;
+       }
+
+       return dev;
+
+out_err:
+       talloc_free(dev);
+       return NULL;
+}
diff --git a/lib/pb-protocol/pb-protocol.h b/lib/pb-protocol/pb-protocol.h
new file mode 100644 (file)
index 0000000..7b557d6
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _PB_PROTOCOL_H
+#define _PB_PROTOCOL_H
+
+#include <stdint.h>
+
+#define PB_SOCKET_PATH "/tmp/petitboot.ui"
+
+#define PB_PROTOCOL_MAX_PAYLOAD_SIZE 4096
+
+enum pb_protocol_action {
+       PB_PROTOCOL_ACTION_ADD          = 0x1,
+       PB_PROTOCOL_ACTION_REMOVE       = 0x2,
+};
+
+struct pb_protocol_message {
+       uint32_t action;
+       uint32_t payload_len;
+       char     payload[];
+};
+
+struct device {
+       char *id;
+       char *name;
+       char *description;
+       char *icon_file;
+
+       struct boot_option {
+               char *id;
+               char *name;
+               char *description;
+               char *icon_file;
+               char *boot_image_file;
+               char *initrd_file;
+               char *boot_args;
+       } *options;
+       int n_options;
+};
+
+int pb_protocol_device_len(struct device *dev);
+
+int pb_protocol_serialise_string(char *pos, const char *str);
+char *pb_protocol_deserialise_string(void *ctx,
+               struct pb_protocol_message *message);
+
+int pb_protocol_serialise_device(struct device *dev, char *buf, int buf_len);
+
+int pb_protocol_write_message(int fd, struct pb_protocol_message *message);
+
+struct pb_protocol_message *pb_protocol_create_message(void *ctx,
+               int action, int payload_len);
+
+struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd);
+
+struct device *pb_protocol_deserialise_device(void *ctx,
+               struct pb_protocol_message *message);
+
+#endif /* _PB_PROTOCOL_H */
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
new file mode 100644 (file)
index 0000000..c660870
--- /dev/null
@@ -0,0 +1,1130 @@
+/*
+   Samba Unix SMB/CIFS implementation.
+
+   Samba trivial allocation library - new interface
+
+   NOTE: Please read talloc_guide.txt for full documentation
+
+   Copyright (C) Andrew Tridgell 2004
+
+   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; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+  inspired by http://swapped.cc/halloc/
+*/
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* nfsim additions */
+#define HAVE_SYS_TYPES_H
+#define HAVE_UNISTD_H
+#define HAVE_STDARG_H
+#define HAVE_STDINT_H
+#define HAVE_VA_COPY
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "talloc.h"
+
+/* use this to force every realloc to change the pointer, to stress test
+   code that might not cope */
+#define ALWAYS_REALLOC 0
+
+
+#define MAX_TALLOC_SIZE 0x10000000
+#define TALLOC_MAGIC 0xe814ec4f
+#define TALLOC_MAGIC_FREE 0x7faebef3
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
+
+/* by default we abort when given a bad pointer (such as when talloc_free() is
+ * called on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+   talloc_enable_leak_report_full() is called, otherwise it remains
+   NULL
+*/
+static const void *null_context;
+static void *cleanup_context;
+
+
+struct talloc_reference_handle {
+       struct talloc_reference_handle *next, *prev;
+       void *ptr;
+};
+
+typedef int (*talloc_destructor_t)(void *);
+
+struct talloc_chunk {
+       struct talloc_chunk *next, *prev;
+       struct talloc_chunk *parent, *child;
+       struct talloc_reference_handle *refs;
+       size_t size;
+       talloc_destructor_t destructor;
+       const char *name;
+       union {
+               unsigned magic;
+               double align_dummy;
+       } u;
+};
+
+/* panic if we get a bad magic value */
+static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
+{
+       struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1;
+       if (tc->u.magic != TALLOC_MAGIC) {
+               if (tc->u.magic == TALLOC_MAGIC_FREE) {
+                       TALLOC_ABORT("Bad talloc magic value - double free");
+               } else {
+                       TALLOC_ABORT("Bad talloc magic value - unknown value");
+               }
+       }
+
+       return tc;
+}
+
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+        if (!(list)) { \
+               (list) = (p); \
+               (p)->next = (p)->prev = NULL; \
+       } else { \
+               (list)->prev = (p); \
+               (p)->next = (list); \
+               (p)->prev = NULL; \
+               (list) = (p); \
+       }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+       if ((p) == (list)) { \
+               (list) = (p)->next; \
+               if (list) (list)->prev = NULL; \
+       } else { \
+               if ((p)->prev) (p)->prev->next = (p)->next; \
+               if ((p)->next) (p)->next->prev = (p)->prev; \
+       } \
+       if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+
+/*
+  return the parent chunk of a pointer
+*/
+static struct talloc_chunk *talloc_parent_chunk(const void *ptr)
+{
+       struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       while (tc->prev) tc=tc->prev;
+       return tc->parent;
+}
+
+void *talloc_parent(const void *ptr)
+{
+       struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+       return (void *)(tc+1);
+}
+
+/*
+   Allocate a bit of memory as a child of an existing pointer
+*/
+void *_talloc(const void *context, size_t size)
+{
+       struct talloc_chunk *tc;
+
+       if (context == NULL) {
+               context = null_context;
+       }
+
+       if (size >= MAX_TALLOC_SIZE) {
+               return NULL;
+       }
+
+       tc = malloc(sizeof(*tc)+size);
+       if (tc == NULL) return NULL;
+
+       tc->size = size;
+       tc->u.magic = TALLOC_MAGIC;
+       tc->destructor = NULL;
+       tc->child = NULL;
+       tc->name = NULL;
+       tc->refs = NULL;
+
+       if (context) {
+               struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
+
+               tc->parent = parent;
+
+               if (parent->child) {
+                       parent->child->parent = NULL;
+               }
+
+               _TLIST_ADD(parent->child, tc);
+       } else {
+               tc->next = tc->prev = tc->parent = NULL;
+       }
+
+       return (void *)(tc+1);
+}
+
+
+/*
+  setup a destructor to be called on free of a pointer
+  the destructor should return 0 on success, or -1 on failure.
+  if the destructor fails then the free is failed, and the memory can
+  be continued to be used
+*/
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *))
+{
+       struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       tc->destructor = destructor;
+}
+
+/*
+  increase the reference count on a piece of memory.
+*/
+void talloc_increase_ref_count(const void *ptr)
+{
+       talloc_reference(null_context, ptr);
+}
+
+/*
+  helper for talloc_reference()
+*/
+static int talloc_reference_destructor(void *ptr)
+{
+       struct talloc_reference_handle *handle = ptr;
+       struct talloc_chunk *tc1 = talloc_chunk_from_ptr(ptr);
+       struct talloc_chunk *tc2 = talloc_chunk_from_ptr(handle->ptr);
+       if (tc1->destructor != (talloc_destructor_t)-1) {
+               tc1->destructor = NULL;
+       }
+       _TLIST_REMOVE(tc2->refs, handle);
+       talloc_free(handle);
+       return 0;
+}
+
+/*
+  make a secondary reference to a pointer, hanging off the given context.
+  the pointer remains valid until both the original caller and this given
+  context are freed.
+
+  the major use for this is when two different structures need to reference the
+  same underlying data, and you want to be able to free the two instances
+  separately, and in either order
+*/
+void *talloc_reference(const void *context, const void *ptr)
+{
+       struct talloc_chunk *tc;
+       struct talloc_reference_handle *handle;
+       if (ptr == NULL) return NULL;
+
+       tc = talloc_chunk_from_ptr(ptr);
+       handle = talloc_named_const(context, sizeof(*handle),
+                       TALLOC_MAGIC_REFERENCE);
+
+       if (handle == NULL) return NULL;
+
+       /* note that we hang the destructor off the handle, not the
+          main context as that allows the caller to still setup their
+          own destructor on the context if they want to */
+       talloc_set_destructor(handle, talloc_reference_destructor);
+       handle->ptr = discard_const_p(void, ptr);
+       _TLIST_ADD(tc->refs, handle);
+       return handle->ptr;
+}
+
+/*
+  remove a secondary reference to a pointer. This undo's what
+  talloc_reference() has done. The context and pointer arguments
+  must match those given to a talloc_reference()
+*/
+static int talloc_unreference(const void *context, const void *ptr)
+{
+       struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       struct talloc_reference_handle *h;
+
+       if (context == NULL) {
+               context = null_context;
+       }
+
+       for (h=tc->refs;h;h=h->next) {
+               struct talloc_chunk *p = talloc_parent_chunk(h);
+               if ((p==NULL && context==NULL) || p+1 == context) break;
+       }
+       if (h == NULL) {
+               return -1;
+       }
+
+       talloc_set_destructor(h, NULL);
+       _TLIST_REMOVE(tc->refs, h);
+       talloc_free(h);
+       return 0;
+}
+
+/*
+  remove a specific parent context from a pointer. This is a more
+  controlled varient of talloc_free()
+*/
+int talloc_unlink(const void *context, void *ptr)
+{
+       struct talloc_chunk *tc_p, *new_p;
+       void *new_parent;
+
+       if (ptr == NULL) {
+               return -1;
+       }
+
+       if (context == NULL) {
+               context = null_context;
+       }
+
+       if (talloc_unreference(context, ptr) == 0) {
+               return 0;
+       }
+
+       if (context == NULL) {
+               if (talloc_parent_chunk(ptr) != NULL) {
+                       return -1;
+               }
+       } else {
+               if (talloc_chunk_from_ptr(context)
+                               != talloc_parent_chunk(ptr)) {
+                       return -1;
+               }
+       }
+
+       tc_p = talloc_chunk_from_ptr(ptr);
+
+       if (tc_p->refs == NULL) {
+               return talloc_free(ptr);
+       }
+
+       new_p = talloc_parent_chunk(tc_p->refs);
+       if (new_p) {
+               new_parent = new_p+1;
+       } else {
+               new_parent = NULL;
+       }
+
+       if (talloc_unreference(new_parent, ptr) != 0) {
+               return -1;
+       }
+
+       talloc_steal(new_parent, ptr);
+
+       return 0;
+}
+
+/*
+  add a name to an existing pointer - va_list version
+*/
+static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+       PRINTF_ATTRIBUTE(2,0);
+
+static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+{
+       struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       tc->name = talloc_vasprintf(ptr, fmt, ap);
+       if (tc->name) {
+               talloc_set_name_const(tc->name, ".name");
+       }
+}
+
+/*
+  add a name to an existing pointer
+*/
+void talloc_set_name(const void *ptr, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       talloc_set_name_v(ptr, fmt, ap);
+       va_end(ap);
+}
+
+/*
+   more efficient way to add a name to a pointer - the name must point to a
+   true string constant
+*/
+void talloc_set_name_const(const void *ptr, const char *name)
+{
+       struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       tc->name = name;
+}
+
+/*
+  create a named talloc pointer. Any talloc pointer can be named, and
+  talloc_named() operates just like talloc() except that it allows you
+  to name the pointer.
+*/
+void *talloc_named(const void *context, size_t size, const char *fmt, ...)
+{
+       va_list ap;
+       void *ptr;
+
+       ptr = _talloc(context, size);
+       if (ptr == NULL) return NULL;
+
+       va_start(ap, fmt);
+       talloc_set_name_v(ptr, fmt, ap);
+       va_end(ap);
+
+       return ptr;
+}
+
+/*
+  create a named talloc pointer. Any talloc pointer can be named, and
+  talloc_named() operates just like talloc() except that it allows you
+  to name the pointer.
+*/
+void *talloc_named_const(const void *context, size_t size, const char *name)
+{
+       void *ptr;
+
+       ptr = _talloc(context, size);
+       if (ptr == NULL) {
+               return NULL;
+       }
+
+       talloc_set_name_const(ptr, name);
+
+       return ptr;
+}
+
+/*
+  return the name of a talloc ptr, or "UNNAMED"
+*/
+const char *talloc_get_name(const void *ptr)
+{
+       struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       if (tc->name == TALLOC_MAGIC_REFERENCE) {
+               return ".reference";
+       }
+       if (tc->name) {
+               return tc->name;
+       }
+       return "UNNAMED";
+}
+
+
+/*
+  check if a pointer has the given name. If it does, return the pointer,
+  otherwise return NULL
+*/
+void *talloc_check_name(const void *ptr, const char *name)
+{
+       const char *pname;
+       if (ptr == NULL) return NULL;
+       pname = talloc_get_name(ptr);
+       if (pname == name || strcmp(pname, name) == 0) {
+               return discard_const_p(void, ptr);
+       }
+       return NULL;
+}
+
+
+/*
+  this is for compatibility with older versions of talloc
+*/
+void *talloc_init(const char *fmt, ...)
+{
+       va_list ap;
+       void *ptr;
+
+       ptr = _talloc(NULL, 0);
+       if (ptr == NULL) return NULL;
+
+       va_start(ap, fmt);
+       talloc_set_name_v(ptr, fmt, ap);
+       va_end(ap);
+
+       return ptr;
+}
+
+/*
+  this is a replacement for the Samba3 talloc_destroy_pool functionality. It
+  should probably not be used in new code. It's in here to keep the talloc
+  code consistent across Samba 3 and 4.
+*/
+static void talloc_free_children(void *ptr)
+{
+       struct talloc_chunk *tc;
+
+       if (ptr == NULL) {
+               return;
+       }
+
+       tc = talloc_chunk_from_ptr(ptr);
+
+       while (tc->child) {
+               /* we need to work out who will own an abandoned child
+                  if it cannot be freed. In priority order, the first
+                  choice is owner of any remaining reference to this
+                  pointer, the second choice is our parent, and the
+                  final choice is the null context. */
+               void *child = tc->child+1;
+               const void *new_parent = null_context;
+               if (tc->child->refs) {
+                       struct talloc_chunk *p =
+                               talloc_parent_chunk(tc->child->refs);
+                       if (p) new_parent = p+1;
+               }
+               if (talloc_free(child) == -1) {
+                       if (new_parent == null_context) {
+                               struct talloc_chunk *p =
+                                       talloc_parent_chunk(ptr);
+                               if (p) new_parent = p+1;
+                       }
+                       talloc_steal(new_parent, child);
+               }
+       }
+}
+
+/*
+   free a talloc pointer. This also frees all child pointers of this
+   pointer recursively
+
+   return 0 if the memory is actually freed, otherwise -1. The memory
+   will not be freed if the ref_count is > 1 or the destructor (if
+   any) returns non-zero
+*/
+int talloc_free(void *ptr)
+{
+       struct talloc_chunk *tc;
+
+       if (ptr == NULL) {
+               return -1;
+       }
+
+       tc = talloc_chunk_from_ptr(ptr);
+
+       if (tc->refs) {
+               talloc_reference_destructor(tc->refs);
+               return -1;
+       }
+
+       if (tc->destructor) {
+               talloc_destructor_t d = tc->destructor;
+               if (d == (talloc_destructor_t)-1) {
+                       return -1;
+               }
+               tc->destructor = (talloc_destructor_t)-1;
+               if (d(ptr) == -1) {
+                       tc->destructor = d;
+                       return -1;
+               }
+               tc->destructor = NULL;
+       }
+
+       talloc_free_children(ptr);
+
+       if (tc->parent) {
+               _TLIST_REMOVE(tc->parent->child, tc);
+               if (tc->parent->child) {
+                       tc->parent->child->parent = tc->parent;
+               }
+       } else {
+               if (tc->prev) tc->prev->next = tc->next;
+               if (tc->next) tc->next->prev = tc->prev;
+       }
+
+       tc->u.magic = TALLOC_MAGIC_FREE;
+
+       free(tc);
+       return 0;
+}
+
+
+
+/*
+  A talloc version of realloc. The context argument is only used if
+  ptr is NULL
+*/
+void *_talloc_realloc(const void *context, void *ptr, size_t size,
+               const char *name)
+{
+       struct talloc_chunk *tc;
+       void *new_ptr;
+
+       /* size zero is equivalent to free() */
+       if (size == 0) {
+               talloc_free(ptr);
+               return NULL;
+       }
+
+       if (size >= MAX_TALLOC_SIZE) {
+               return NULL;
+       }
+
+       /* realloc(NULL) is equavalent to malloc() */
+       if (ptr == NULL) {
+               return talloc_named_const(context, size, name);
+       }
+
+       tc = talloc_chunk_from_ptr(ptr);
+
+       /* don't allow realloc on referenced pointers */
+       if (tc->refs) {
+               return NULL;
+       }
+
+       /* by resetting magic we catch users of the old memory */
+       tc->u.magic = TALLOC_MAGIC_FREE;
+
+#if ALWAYS_REALLOC
+       new_ptr = malloc(size + sizeof(*tc));
+       if (new_ptr) {
+               memcpy(new_ptr, tc, tc->size + sizeof(*tc));
+               free(tc);
+       }
+#else
+       new_ptr = realloc(tc, size + sizeof(*tc));
+#endif
+       if (!new_ptr) {
+               tc->u.magic = TALLOC_MAGIC;
+               return NULL;
+       }
+
+       tc = new_ptr;
+       tc->u.magic = TALLOC_MAGIC;
+       if (tc->parent) {
+               tc->parent->child = new_ptr;
+       }
+       if (tc->child) {
+               tc->child->parent = new_ptr;
+       }
+
+       if (tc->prev) {
+               tc->prev->next = tc;
+       }
+       if (tc->next) {
+               tc->next->prev = tc;
+       }
+
+       tc->size = size;
+       talloc_set_name_const(tc+1, name);
+
+       return (void *)(tc+1);
+}
+
+/*
+   move a lump of memory from one talloc context to another return the
+   ptr on success, or NULL if it could not be transferred.
+   passing NULL as ptr will always return NULL with no side effects.
+*/
+void *talloc_steal(const void *new_ctx, const void *ptr)
+{
+       struct talloc_chunk *tc, *new_tc;
+
+       if (!ptr) {
+               return NULL;
+       }
+
+       if (new_ctx == NULL) {
+               new_ctx = null_context;
+       }
+
+       tc = talloc_chunk_from_ptr(ptr);
+
+       if (new_ctx == NULL) {
+               if (tc->parent) {
+                       _TLIST_REMOVE(tc->parent->child, tc);
+                       if (tc->parent->child) {
+                               tc->parent->child->parent = tc->parent;
+                       }
+               } else {
+                       if (tc->prev) tc->prev->next = tc->next;
+                       if (tc->next) tc->next->prev = tc->prev;
+               }
+
+               tc->parent = tc->next = tc->prev = NULL;
+               return discard_const_p(void, ptr);
+       }
+
+       new_tc = talloc_chunk_from_ptr(new_ctx);
+
+       if (tc == new_tc) {
+               return discard_const_p(void, ptr);
+       }
+
+       if (tc->parent) {
+               _TLIST_REMOVE(tc->parent->child, tc);
+               if (tc->parent->child) {
+                       tc->parent->child->parent = tc->parent;
+               }
+       } else {
+               if (tc->prev) tc->prev->next = tc->next;
+               if (tc->next) tc->next->prev = tc->prev;
+       }
+
+       tc->parent = new_tc;
+       if (new_tc->child) new_tc->child->parent = NULL;
+       _TLIST_ADD(new_tc->child, tc);
+
+       return discard_const_p(void, ptr);
+}
+
+/*
+  return the total size of a talloc pool (subtree)
+*/
+off_t talloc_total_size(const void *ptr)
+{
+       off_t total = 0;
+       struct talloc_chunk *c, *tc;
+
+       if (ptr == NULL) {
+               ptr = null_context;
+       }
+       if (ptr == NULL) {
+               return 0;
+       }
+
+       tc = talloc_chunk_from_ptr(ptr);
+
+       total = tc->size;
+       for (c=tc->child;c;c=c->next) {
+               total += talloc_total_size(c+1);
+       }
+       return total;
+}
+
+/*
+  return the total number of blocks in a talloc pool (subtree)
+*/
+off_t talloc_total_blocks(const void *ptr)
+{
+       off_t total = 0;
+       struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+       total++;
+       for (c=tc->child;c;c=c->next) {
+               total += talloc_total_blocks(c+1);
+       }
+       return total;
+}
+
+/*
+  return the number of external references to a pointer
+*/
+static int talloc_reference_count(const void *ptr)
+{
+       struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       struct talloc_reference_handle *h;
+       int ret = 0;
+
+       for (h=tc->refs;h;h=h->next) {
+               ret++;
+       }
+       return ret;
+}
+
+/*
+  report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth(const void *ptr, FILE *f, int depth)
+{
+       struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+       for (c=tc->child;c;c=c->next) {
+               if (c->name == TALLOC_MAGIC_REFERENCE) {
+                       struct talloc_reference_handle *handle = (void *)(c+1);
+                       const char *name2 = talloc_get_name(handle->ptr);
+                       fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
+               } else {
+                       const char *name = talloc_get_name(c+1);
+                       fprintf(f, "%*s%-30s contains %6lu bytes "
+                                       "in %3lu blocks (ref %d)\n",
+                               depth * 4, "", name,
+                               (unsigned long)talloc_total_size(c+1),
+                               (unsigned long)talloc_total_blocks(c+1),
+                               talloc_reference_count(c+1));
+                       talloc_report_depth(c+1, f, depth+1);
+               }
+       }
+
+}
+
+/*
+  report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_full(const void *ptr, FILE *f)
+{
+       if (ptr == NULL) {
+               ptr = null_context;
+       }
+       if (ptr == NULL) return;
+
+       fprintf(f, "full talloc report on '%s' "
+                       "(total %lu bytes in %lu blocks)\n",
+               talloc_get_name(ptr),
+               (unsigned long)talloc_total_size(ptr),
+               (unsigned long)talloc_total_blocks(ptr));
+
+       talloc_report_depth(ptr, f, 1);
+       fflush(f);
+}
+
+/*
+  report on memory usage by all children of a pointer
+*/
+void talloc_report(const void *ptr, FILE *f)
+{
+       struct talloc_chunk *c, *tc;
+
+       if (ptr == NULL) {
+               ptr = null_context;
+       }
+       if (ptr == NULL) return;
+
+       fprintf(f, "talloc report on '%s' (total %lu bytes in %lu blocks)\n",
+               talloc_get_name(ptr),
+               (unsigned long)talloc_total_size(ptr),
+               (unsigned long)talloc_total_blocks(ptr));
+
+       tc = talloc_chunk_from_ptr(ptr);
+
+       for (c=tc->child;c;c=c->next) {
+               fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n",
+                       talloc_get_name(c+1),
+                       (unsigned long)talloc_total_size(c+1),
+                       (unsigned long)talloc_total_blocks(c+1));
+       }
+       fflush(f);
+}
+
+/*
+  report on any memory hanging off the null context
+*/
+static void talloc_report_null(void)
+{
+       if (talloc_total_size(null_context) != 0) {
+               talloc_report(null_context, stderr);
+       }
+}
+
+/*
+  report on any memory hanging off the null context
+*/
+static void talloc_report_null_full(void)
+{
+       if (talloc_total_size(null_context) != 0) {
+               talloc_report_full(null_context, stderr);
+       }
+}
+
+/*
+  enable tracking of the NULL context
+*/
+void talloc_enable_null_tracking(void)
+{
+       if (null_context == NULL) {
+               null_context = talloc_named_const(NULL, 0, "null_context");
+       }
+}
+
+/*
+  enable leak reporting on exit
+*/
+void talloc_enable_leak_report(void)
+{
+       talloc_enable_null_tracking();
+       atexit(talloc_report_null);
+}
+
+/*
+  enable full leak reporting on exit
+*/
+void talloc_enable_leak_report_full(void)
+{
+       talloc_enable_null_tracking();
+       atexit(talloc_report_null_full);
+}
+
+/*
+   talloc and zero memory.
+*/
+void *_talloc_zero(const void *ctx, size_t size, const char *name)
+{
+       void *p = talloc_named_const(ctx, size, name);
+
+       if (p) {
+               memset(p, '\0', size);
+       }
+
+       return p;
+}
+
+
+/*
+  memdup with a talloc.
+*/
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
+{
+       void *newp = talloc_named_const(t, size, name);
+
+       if (newp) {
+               memcpy(newp, p, size);
+       }
+
+       return newp;
+}
+
+/*
+  strdup with a talloc
+*/
+char *talloc_strdup(const void *t, const char *p)
+{
+       char *ret;
+       if (!p) {
+               return NULL;
+       }
+       ret = talloc_memdup(t, p, strlen(p) + 1);
+       if (ret) {
+               talloc_set_name_const(ret, ret);
+       }
+       return ret;
+}
+
+/*
+  strndup with a talloc
+*/
+char *talloc_strndup(const void *t, const char *p, size_t n)
+{
+       size_t len;
+       char *ret;
+
+       for (len=0; len<n && p[len]; len++) ;
+
+       ret = _talloc(t, len + 1);
+       if (!ret) { return NULL; }
+       memcpy(ret, p, len);
+       ret[len] = 0;
+       talloc_set_name_const(ret, ret);
+       return ret;
+}
+
+#ifndef VA_COPY
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#elif defined(HAVE___VA_COPY)
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
+{
+       int len;
+       char *ret;
+       va_list ap2;
+
+       VA_COPY(ap2, ap);
+
+       len = vsnprintf(NULL, 0, fmt, ap2);
+
+       ret = _talloc(t, len+1);
+       if (ret) {
+               VA_COPY(ap2, ap);
+               vsnprintf(ret, len+1, fmt, ap2);
+               talloc_set_name_const(ret, ret);
+       }
+
+       return ret;
+}
+
+
+/*
+  Perform string formatting, and return a pointer to newly allocated
+  memory holding the result, inside a memory pool.
+ */
+char *talloc_asprintf(const void *t, const char *fmt, ...)
+{
+       va_list ap;
+       char *ret;
+
+       va_start(ap, fmt);
+       ret = talloc_vasprintf(t, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved.  Good for gradually
+ * accumulating output into a string buffer.
+ **/
+
+static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+       PRINTF_ATTRIBUTE(2,0);
+
+static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+       struct talloc_chunk *tc;
+       int len, s_len;
+       va_list ap2;
+
+       if (s == NULL) {
+               return talloc_vasprintf(NULL, fmt, ap);
+       }
+
+       tc = talloc_chunk_from_ptr(s);
+
+       VA_COPY(ap2, ap);
+
+       s_len = tc->size - 1;
+       len = vsnprintf(NULL, 0, fmt, ap2);
+
+       s = talloc_realloc(NULL, s, char, s_len + len+1);
+       if (!s) return NULL;
+
+       VA_COPY(ap2, ap);
+
+       vsnprintf(s+s_len, len+1, fmt, ap2);
+       talloc_set_name_const(s, s);
+
+       return s;
+}
+
+/*
+  Realloc @p s to append the formatted result of @p fmt and return @p
+  s, which may have moved.  Good for gradually accumulating output
+  into a string buffer.
+ */
+char *talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       s = talloc_vasprintf_append(s, fmt, ap);
+       va_end(ap);
+       return s;
+}
+
+/*
+  alloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count,
+               const char *name)
+{
+       if (count >= MAX_TALLOC_SIZE/el_size) {
+               return NULL;
+       }
+       return talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+  alloc an zero array, checking for integer overflow in the array size
+*/
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count,
+               const char *name)
+{
+       if (count >= MAX_TALLOC_SIZE/el_size) {
+               return NULL;
+       }
+       return _talloc_zero(ctx, el_size * count, name);
+}
+
+
+/*
+  realloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size,
+               unsigned count, const char *name)
+{
+       if (count >= MAX_TALLOC_SIZE/el_size) {
+               return NULL;
+       }
+       return _talloc_realloc(ctx, ptr, el_size * count, name);
+}
+
+/*
+  a function version of talloc_realloc(), so it can be passed as a function
+  pointer to libraries that want a realloc function (a realloc function
+  encapsulates all the basic capabilities of an allocation library, which is
+  why this is useful)
+*/
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
+{
+       return _talloc_realloc(context, ptr, size, NULL);
+}
+
+
+static void talloc_autofree(void)
+{
+       talloc_free(cleanup_context);
+       cleanup_context = NULL;
+}
+
+/*
+  return a context which will be auto-freed on exit
+  this is useful for reducing the noise in leak reports
+*/
+void *talloc_autofree_context(void)
+{
+       if (cleanup_context == NULL) {
+               cleanup_context = talloc_named_const(NULL, 0,
+                               "autofree_context");
+               atexit(talloc_autofree);
+       }
+       return cleanup_context;
+}
+
+size_t talloc_get_size(const void *context)
+{
+       struct talloc_chunk *tc;
+
+       if (context == NULL)
+               return 0;
+
+       tc = talloc_chunk_from_ptr(context);
+
+       return tc->size;
+}
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
new file mode 100644 (file)
index 0000000..15a1eb6
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef _TALLOC_H_
+#define _TALLOC_H_
+/*
+   Unix SMB/CIFS implementation.
+   Samba temporary memory allocation functions
+
+   Copyright (C) Andrew Tridgell 2004-2005
+
+   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; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* petitboot additions */
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* this is only needed for compatibility with the old talloc */
+typedef void TALLOC_CTX;
+
+/*
+  this uses a little trick to allow __LINE__ to be stringified
+*/
+#define _STRING_LINE_(s)    #s
+#define _STRING_LINE2_(s)   _STRING_LINE_(s)
+#define __LINESTR__       _STRING_LINE2_(__LINE__)
+#define __location__ __FILE__ ":" __LINESTR__
+
+#ifndef TALLOC_DEPRECATED
+#define TALLOC_DEPRECATED 0
+#endif
+
+/* useful macros for creating type checked pointers */
+#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
+
+#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
+
+#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
+
+#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
+
+#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
+#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
+
+#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
+
+#define malloc_p(type) (type *)malloc(sizeof(type))
+#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count)
+#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count)
+
+#define data_blob(ptr, size) data_blob_named(ptr, size, "DATA_BLOB: "__location__)
+#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, "DATA_BLOB: "__location__)
+#define data_blob_dup_talloc(ctx, blob) data_blob_talloc_named(ctx, (blob)->data, (blob)->length, "DATA_BLOB: "__location__)
+
+#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
+#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+
+
+#if TALLOC_DEPRECATED
+#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
+#define talloc_p(ctx, type) talloc(ctx, type)
+#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
+#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns.  a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+
+/* The following definitions come from talloc.c  */
+void *_talloc(const void *context, size_t size);
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+void talloc_increase_ref_count(const void *ptr);
+void *talloc_reference(const void *context, const void *ptr);
+int talloc_unlink(const void *context, void *ptr);
+void talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void talloc_set_name_const(const void *ptr, const char *name);
+void *talloc_named(const void *context, size_t size,
+                  const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+void *talloc_named_const(const void *context, size_t size, const char *name);
+const char *talloc_get_name(const void *ptr);
+void *talloc_check_name(const void *ptr, const char *name);
+void talloc_report_depth(const void *ptr, FILE *f, int depth);
+void *talloc_parent(const void *ptr);
+void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+int talloc_free(void *ptr);
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+void *talloc_steal(const void *new_ctx, const void *ptr);
+off_t talloc_total_size(const void *ptr);
+off_t talloc_total_blocks(const void *ptr);
+void talloc_report_full(const void *ptr, FILE *f);
+void talloc_report(const void *ptr, FILE *f);
+void talloc_enable_null_tracking(void);
+void talloc_enable_leak_report(void);
+void talloc_enable_leak_report_full(void);
+void *_talloc_zero(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+char *talloc_strdup(const void *t, const char *p);
+char *talloc_strndup(const void *t, const char *p, size_t n);
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_append(char *s,
+                            const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
+void *talloc_autofree_context(void);
+size_t talloc_get_size(const void *ctx);
+
+#endif
+
diff --git a/petitboot-paths.h b/petitboot-paths.h
deleted file mode 100644 (file)
index 40ce557..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _PATHS_H
-#define _PATHS_H
-
-#ifndef PREFIX
-#define PREFIX "/usr"
-#endif
-
-#ifndef PKG_SHARE_DIR
-#define PKG_SHARE_DIR PREFIX "/share/petitboot"
-#endif
-
-#ifndef TMP_DIR
-#define TMP_DIR "/var/tmp/mnt/"
-#endif
-
-#define PBOOT_DEVICE_SOCKET "/var/tmp/petitboot-dev"
-#define MOUNT_BIN "/bin/mount"
-#define UMOUNT_BIN "/bin/umount"
-#define BOOT_GAMEOS_BIN "/usr/bin/ps3-boot-game-os"
-
-/* at present, all default artwork strings are const. */
-#define artwork_pathname(s) (PKG_SHARE_DIR "/artwork/" s)
-
-#endif /* _PATHS_H */
diff --git a/petitboot.c b/petitboot.c
deleted file mode 100644 (file)
index ee68930..0000000
+++ /dev/null
@@ -1,1194 +0,0 @@
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-#include <syscall.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <linux/input.h>
-
-#undef _USE_X11
-
-#include <libtwin/twin.h>
-#include <libtwin/twin_linux_mouse.h>
-#include <libtwin/twin_linux_js.h>
-#include <libtwin/twin_png.h>
-#include <libtwin/twin_jpeg.h>
-
-#include "petitboot.h"
-#include "petitboot-paths.h"
-
-#ifdef _USE_X11
-#include <libtwin/twin_x11.h>
-static twin_x11_t *pboot_x11;
-#else
-#include <libtwin/twin_fbdev.h>
-static twin_fbdev_t *pboot_fbdev;
-#endif
-
-static twin_screen_t *pboot_screen;
-
-#define PBOOT_INITIAL_MESSAGE          \
-       "keys: 0=safe 1=720p 2=1080i 3=1080p del=GameOS"
-
-#define PBOOT_LEFT_PANE_SIZE           160
-#define PBOOT_LEFT_PANE_COLOR          0x80000000
-#define PBOOT_LEFT_LINE_COLOR          0xff000000
-
-#define PBOOT_LEFT_FOCUS_WIDTH         80
-#define PBOOT_LEFT_FOCUS_HEIGHT                80
-#define PBOOT_LEFT_FOCUS_XOFF          40
-#define PBOOT_LEFT_FOCUS_YOFF          40
-#define PBOOT_LEFT_FOCUS_XRAD          (6 * TWIN_FIXED_ONE)
-#define PBOOT_LEFT_FOCUS_YRAD          (6 * TWIN_FIXED_ONE)
-
-#define PBOOT_RIGHT_FOCUS_XOFF         20
-#define PBOOT_RIGHT_FOCUS_YOFF         60
-#define PBOOT_RIGHT_FOCUS_HEIGHT       80
-#define PBOOT_RIGHT_FOCUS_XRAD         (6 * TWIN_FIXED_ONE)
-#define PBOOT_RIGHT_FOCUS_YRAD         (6 * TWIN_FIXED_ONE)
-
-#define PBOOT_LEFT_ICON_WIDTH          64
-#define PBOOT_LEFT_ICON_HEIGHT         64
-#define PBOOT_LEFT_ICON_XOFF           50
-#define PBOOT_LEFT_ICON_YOFF           50
-#define PBOOT_LEFT_ICON_STRIDE         100
-
-#define PBOOT_RIGHT_OPTION_LMARGIN     30
-#define PBOOT_RIGHT_OPTION_RMARGIN     30
-#define PBOOT_RIGHT_OPTION_TMARGIN     70
-#define PBOOT_RIGHT_OPTION_HEIGHT      64
-#define PBOOT_RIGHT_OPTION_STRIDE      100
-#define PBOOT_RIGHT_TITLE_TEXT_SIZE    (30 * TWIN_FIXED_ONE)
-#define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
-#define PBOOT_RIGHT_TITLE_XOFFSET      80
-#define PBOOT_RIGHT_TITLE_YOFFSET      30
-#define PBOOT_RIGHT_SUBTITLE_XOFFSET   100
-#define PBOOT_RIGHT_SUBTITLE_YOFFSET   50
-#define PBOOT_RIGHT_BADGE_XOFFSET      2
-#define PBOOT_RIGHT_BADGE_YOFFSET      0
-
-
-#define PBOOT_RIGHT_TITLE_COLOR                0xff000000
-#define PBOOT_RIGHT_SUBTITLE_COLOR     0xff400000
-
-#define PBOOT_FOCUS_COLOR              0x10404040
-
-#define PBOOT_STATUS_PANE_COLOR                0x60606060
-#define PBOOT_STATUS_PANE_HEIGHT       20
-#define PBOOT_STATUS_PANE_XYMARGIN     20
-#define PBOOT_STATUS_TEXT_MARGIN       10
-#define PBOOT_STATUS_TEXT_SIZE         (16 * TWIN_FIXED_ONE)
-#define PBOOT_STATUS_TEXT_COLOR                0xff000000
-
-typedef struct _pboot_option pboot_option_t;
-typedef struct _pboot_device pboot_device_t;
-
-struct _pboot_option
-{
-       char            *title;
-       char            *subtitle;
-       twin_pixmap_t   *badge;
-       twin_pixmap_t   *cache;
-       twin_rect_t     box;
-       void            *data;
-};
-
-struct _pboot_device
-{
-       char                    *id;
-       twin_pixmap_t           *badge;
-       twin_rect_t             box;
-       int                     option_count;
-       pboot_option_t          options[PBOOT_MAX_OPTION];
-};
-
-static twin_pixmap_t   *pboot_cursor;
-static int             pboot_cursor_hx;
-static int             pboot_cursor_hy;
-
-static pboot_device_t  *pboot_devices[PBOOT_MAX_DEV];
-static int             pboot_dev_count;
-static int             pboot_dev_sel = -1;
-static int             pboot_focus_lpane = 1;
-
-typedef struct _pboot_lpane {
-       twin_window_t   *window;
-       twin_rect_t     focus_box;
-       int             focus_start;
-       int             focus_target;
-       int             focus_curindex;
-       int             mouse_target;
-} pboot_lpane_t;
-
-typedef struct _pboot_rpane {
-       twin_window_t   *window;
-       twin_rect_t     focus_box;
-       int             focus_start;
-       int             focus_target;
-       int             focus_curindex;
-       int             mouse_target;
-} pboot_rpane_t;
-
-typedef struct _pboot_spane {
-       twin_window_t   *window;
-       char            *text;
-} pboot_spane_t;
-
-static pboot_lpane_t   *pboot_lpane;
-static pboot_rpane_t   *pboot_rpane;
-static pboot_spane_t   *pboot_spane;
-
-/* control to keyboard mappings for the sixaxis controller */
-uint8_t sixaxis_map[] = {
-       0,              /*   0  Select          */
-       0,              /*   1  L3              */
-       0,              /*   2  R3              */
-       0,              /*   3  Start           */
-       KEY_UP,         /*   4  Dpad Up         */
-       KEY_RIGHT,      /*   5  Dpad Right      */
-       KEY_DOWN,       /*   6  Dpad Down       */
-       KEY_LEFT,       /*   7  Dpad Left       */
-       0,              /*   8  L2              */
-       0,              /*   9  R2              */
-       0,              /*  10  L1              */
-       0,              /*  11  R1              */
-       0,              /*  12  Triangle        */
-       KEY_ENTER,      /*  13  Circle          */
-       0,              /*  14  Cross           */
-       KEY_DELETE,     /*  15  Square          */
-       0,              /*  16  PS Button       */
-       0,              /*  17  nothing      */
-       0,              /*  18  nothing      */
-};
-
-
-static int pboot_vmode_change = -1;
-
-/* XXX move to twin */
-static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
-                                             twin_rect_t r2)
-{
-       return !(r1.left > r2.right ||
-                r1.right < r2.left ||
-                r1.top > r2.bottom ||
-                r1.bottom < r2.top);
-}
-
-static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
-                                   int index)
-{
-       twin_pixmap_t   *px;
-       twin_path_t     *path;
-       twin_fixed_t    tx, ty;
-
-       /* Create pixmap */
-       px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
-                                opt->box.bottom - opt->box.top);
-       assert(px);
-       opt->cache = px;
-
-       /* Fill background */
-       twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
-
-       /* Allocate a path for drawing */
-       path = twin_path_create();
-       assert(path);
-
-#if 0
-       /* TEST - Bounding rectangle */
-       twin_path_rectangle(path, 0, 0,
-                           twin_int_to_fixed(px->width),
-                           twin_int_to_fixed(px->height));
-       twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
-       twin_path_empty(path);
-       twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
-                 px->width - 3, px->height - 3);
-#endif
-
-       /* Draw texts */
-       twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
-       twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
-       tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
-       ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
-       twin_path_move (path, tx, ty);
-       twin_path_utf8 (path, opt->title);
-       twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
-       twin_path_empty (path);
-
-       if (opt->subtitle) {
-               twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
-               twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
-               tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
-               ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
-               twin_path_move (path, tx, ty);
-               twin_path_utf8 (path, opt->subtitle);
-               twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
-               twin_path_empty (path);
-       }
-
-       if (opt->badge) {
-               twin_operand_t  src;
-
-               src.source_kind = TWIN_PIXMAP;
-               src.u.pixmap = opt->badge;
-
-               twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
-                              PBOOT_RIGHT_BADGE_YOFFSET,
-                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
-                              opt->badge->width, opt->badge->height);
-       }
-
-
-       /* Destroy path */
-       twin_path_destroy(path);
-}
-
-static void pboot_rpane_draw(twin_window_t *window)
-{
-       twin_pixmap_t   *px = window->pixmap;
-       pboot_rpane_t   *rpane = window->client_data;
-       pboot_device_t  *dev;
-       twin_path_t     *path;
-       twin_fixed_t    x, y, w, h;
-       int             i;
-
-       /* Fill background */
-       twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
-
-       /* Nothing to draw, return */
-       if (pboot_dev_sel < 0)
-               return;
-
-       /* Create a path for use later */
-       path = twin_path_create();
-       assert(path);
-
-       /* Draw focus box */
-       if (rpane->focus_curindex >= 0 &&
-           twin_rect_intersect(rpane->focus_box, px->clip)) {
-               x = twin_int_to_fixed(rpane->focus_box.left + 2);
-               y = twin_int_to_fixed(rpane->focus_box.top + 2);
-               w = twin_int_to_fixed(rpane->focus_box.right -
-                                     rpane->focus_box.left - 4);
-               h = twin_int_to_fixed(rpane->focus_box.bottom -
-                                     rpane->focus_box.top - 4);
-               twin_path_rounded_rectangle(path, x, y, w, h,
-                                           PBOOT_RIGHT_FOCUS_XRAD,
-                                           PBOOT_RIGHT_FOCUS_YRAD);
-               if (!pboot_focus_lpane)
-                       twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
-               else
-                       twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
-                                         4 * TWIN_FIXED_ONE);
-       }
-
-       /* Get device and iterate through options */
-       dev = pboot_devices[pboot_dev_sel];
-       for (i = 0; i < dev->option_count; i++) {
-               pboot_option_t  *opt = &dev->options[i];
-               twin_operand_t  src;
-
-               if (opt->title == NULL)
-                       continue;
-               if (!twin_rect_intersect(opt->box, px->clip))
-                       continue;
-               if (opt->cache == NULL)
-                       pboot_draw_option_cache(dev, opt, i);
-
-               src.source_kind = TWIN_PIXMAP;
-               src.u.pixmap = opt->cache;
-
-               twin_composite(px, opt->box.left, opt->box.top,
-                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
-                              opt->box.right - opt->box.left,
-                              opt->box.bottom - opt->box.top);
-       }
-
-       /* Destroy path */
-       twin_path_destroy(path);
-}
-
-static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
-{
-       int dir = 1, dist, pos;
-       const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
-
-       dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
-       dir = dist > 5 ? 5 : dist;
-       pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
-       if (pos == 0) {
-               return -1;
-       }
-       if (pos < 0) {
-               dir = -dir;
-               pos = -pos;
-       }
-       twin_window_damage(pboot_rpane->window,
-                          pboot_rpane->focus_box.left,
-                          pboot_rpane->focus_box.top,
-                          pboot_rpane->focus_box.right,
-                          pboot_rpane->focus_box.bottom);
-
-       pboot_rpane->focus_box.top += dir;
-       pboot_rpane->focus_box.bottom += dir;
-
-       twin_window_damage(pboot_rpane->window,
-                          pboot_rpane->focus_box.left,
-                          pboot_rpane->focus_box.top,
-                          pboot_rpane->focus_box.right,
-                          pboot_rpane->focus_box.bottom);
-
-       twin_window_queue_paint(pboot_rpane->window);
-
-       return accel[(pos * 10) / dist];
-}
-
-static void pboot_set_rfocus(int index)
-{
-       pboot_device_t  *dev;
-
-       if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
-               return;
-       dev = pboot_devices[pboot_dev_sel];
-       if (index < 0 || index >= dev->option_count)
-               return;
-
-       pboot_rpane->focus_start = pboot_rpane->focus_box.top;
-       pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
-               PBOOT_RIGHT_OPTION_STRIDE * index;
-       pboot_rpane->focus_curindex = index;
-
-       twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
-}
-
-static void pboot_select_rpane(void)
-{
-       if (pboot_focus_lpane == 0)
-               return;
-       pboot_focus_lpane = 0;
-
-       twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
-
-       twin_window_damage(pboot_lpane->window,
-                          pboot_lpane->focus_box.left,
-                          pboot_lpane->focus_box.top,
-                          pboot_lpane->focus_box.right,
-                          pboot_lpane->focus_box.bottom);
-
-       twin_window_damage(pboot_rpane->window,
-                          pboot_rpane->focus_box.left,
-                          pboot_rpane->focus_box.top,
-                          pboot_rpane->focus_box.right,
-                          pboot_rpane->focus_box.bottom);
-
-       twin_window_queue_paint(pboot_lpane->window);
-       twin_window_queue_paint(pboot_rpane->window);
-
-       pboot_set_rfocus(0);
-}
-
-static void pboot_select_lpane(void)
-{
-       if (pboot_focus_lpane == 1)
-               return;
-       pboot_focus_lpane = 1;
-
-       twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
-
-       twin_window_damage(pboot_lpane->window,
-                          pboot_lpane->focus_box.left,
-                          pboot_lpane->focus_box.top,
-                          pboot_lpane->focus_box.right,
-                          pboot_lpane->focus_box.bottom);
-
-       twin_window_damage(pboot_rpane->window,
-                          pboot_rpane->focus_box.left,
-                          pboot_rpane->focus_box.top,
-                          pboot_rpane->focus_box.right,
-                          pboot_rpane->focus_box.bottom);
-
-       twin_window_queue_paint(pboot_lpane->window);
-       twin_window_queue_paint(pboot_rpane->window);
-}
-
-static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
-{
-       pboot_device_t  *dev;
-       pboot_option_t  *opt;
-       int             candidate = -1;
-
-       if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
-               return;
-       dev = pboot_devices[pboot_dev_sel];
-
-       if (y < PBOOT_RIGHT_OPTION_TMARGIN)
-               goto miss;
-       candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
-               PBOOT_RIGHT_OPTION_STRIDE;
-       if (candidate >= dev->option_count) {
-               candidate = -1;
-               goto miss;
-       }
-       if (candidate == pboot_rpane->mouse_target)
-               return;
-       opt = &dev->options[candidate];
-       if (x < opt->box.left || x > opt->box.right ||
-           y < opt->box.top || y > opt->box.bottom) {
-               candidate = -1;
-               goto miss;
-       }
-
-       /* Ok, so now, we know the mouse hit an icon that wasn't the same
-        * as the previous one, we trigger a focus change
-        */
-       pboot_set_rfocus(candidate);
-
- miss:
-       pboot_rpane->mouse_target = candidate;
-}
-
-static void pboot_choose_option(void)
-{
-       pboot_device_t *dev = pboot_devices[pboot_dev_sel];
-       pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
-
-       LOG("Selected device %s\n", opt->title);
-       pboot_message("booting %s...", opt->title);
-
-       /* Give user feedback, make sure errors and panics will be seen */
-       pboot_exec_option(opt->data);
-}
-
-static twin_bool_t pboot_rpane_event (twin_window_t        *window,
-                                     twin_event_t          *event)
-{
-       /* filter out all mouse events */
-       switch(event->kind) {
-       case TwinEventEnter:
-       case TwinEventMotion:
-       case TwinEventLeave:
-               pboot_select_rpane();
-               pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
-               return TWIN_TRUE;
-       case TwinEventButtonDown:
-               pboot_select_rpane();
-               pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
-               pboot_choose_option();
-       case TwinEventButtonUp:
-               return TWIN_TRUE;
-       case TwinEventKeyDown:
-               switch(event->u.key.key) {
-               case KEY_UP:
-                       pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
-                       return TWIN_TRUE;
-               case KEY_DOWN:
-                       pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
-                       return TWIN_TRUE;
-               case KEY_LEFT:
-                       pboot_select_lpane();
-                       return TWIN_TRUE;
-               case KEY_ENTER:
-                       pboot_choose_option();
-               default:
-                       break;
-               }
-               break;
-       default:
-               break;
-       }
-       return TWIN_FALSE;
-}
-
-
-int pboot_add_option(int devindex, const char *title,
-                    const char *subtitle, twin_pixmap_t *badge, void *data)
-{
-       pboot_device_t  *dev;
-       pboot_option_t  *opt;
-       twin_coord_t    width;
-       int             index;
-
-       if (devindex < 0 || devindex >= pboot_dev_count)
-               return -1;
-       dev = pboot_devices[devindex];
-
-       if (dev->option_count >= PBOOT_MAX_OPTION)
-               return -1;
-       index = dev->option_count++;
-       opt = &dev->options[index];
-
-       opt->title = malloc(strlen(title) + 1);
-       strcpy(opt->title, title);
-
-       if (subtitle) {
-               opt->subtitle = malloc(strlen(subtitle) + 1);
-               strcpy(opt->subtitle, subtitle);
-       } else
-               opt->subtitle = NULL;
-
-       opt->badge = badge;
-       opt->cache = NULL;
-
-       width = pboot_rpane->window->pixmap->width -
-               (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
-
-       opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
-       opt->box.right = opt->box.left + width;
-       opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
-               index * PBOOT_RIGHT_OPTION_STRIDE;
-       opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
-
-       opt->data = data;
-       return index;
-}
-
-
-static void pboot_set_device_select(int sel, int force)
-{
-       LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
-       if (!force && sel == pboot_dev_sel)
-               return;
-       if (sel >= pboot_dev_count)
-               return;
-       pboot_dev_sel = sel;
-       if (force) {
-               pboot_lpane->focus_curindex = sel;
-               if (sel < 0)
-                       pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
-               else
-                       pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
-                               PBOOT_LEFT_ICON_STRIDE * sel;
-               pboot_rpane->focus_box.bottom = pboot_lpane->focus_target;
-               pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
-                       PBOOT_RIGHT_FOCUS_HEIGHT;
-               twin_window_damage(pboot_lpane->window,
-                                  0, 0,
-                                  pboot_lpane->window->pixmap->width,
-                                  pboot_lpane->window->pixmap->height);
-               twin_window_queue_paint(pboot_lpane->window);
-       }
-       pboot_rpane->focus_curindex = -1;
-       pboot_rpane->mouse_target = -1;
-       pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
-       pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
-               PBOOT_RIGHT_FOCUS_HEIGHT;
-       twin_window_damage(pboot_rpane->window, 0, 0,
-                          pboot_rpane->window->pixmap->width,
-                          pboot_rpane->window->pixmap->height);
-       twin_window_queue_paint(pboot_rpane->window);
-}
-
-static void pboot_create_rpane(void)
-{
-       pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
-       assert(pboot_rpane);
-
-       pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
-                                                TwinWindowPlain,
-                                                PBOOT_LEFT_PANE_SIZE, 0,
-                                                pboot_screen->width -
-                                                  PBOOT_LEFT_PANE_SIZE,
-                                                pboot_screen->height);
-       assert(pboot_rpane->window);
-
-       pboot_rpane->window->draw = pboot_rpane_draw;
-       pboot_rpane->window->event = pboot_rpane_event;
-       pboot_rpane->window->client_data = pboot_rpane;
-
-       pboot_rpane->focus_curindex = -1;
-       pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
-       pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
-       pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
-               2 * PBOOT_RIGHT_FOCUS_XOFF;
-       pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
-               PBOOT_RIGHT_FOCUS_HEIGHT;
-       pboot_rpane->mouse_target = -1;
-       twin_window_show(pboot_rpane->window);
-       twin_window_queue_paint(pboot_rpane->window);
-}
-
-
-static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
-{
-       int dir = 1, dist, pos;
-       const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
-
-       dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
-       dir = dist > 2 ? 2 : dist;
-       pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
-       if (pos == 0) {
-               pboot_set_device_select(pboot_lpane->focus_curindex, 0);
-               return -1;
-       }
-       if (pos < 0) {
-               dir = -1;
-               pos = -pos;
-       }
-       twin_window_damage(pboot_lpane->window,
-                          pboot_lpane->focus_box.left,
-                          pboot_lpane->focus_box.top,
-                          pboot_lpane->focus_box.right,
-                          pboot_lpane->focus_box.bottom);
-
-       pboot_lpane->focus_box.top += dir;
-       pboot_lpane->focus_box.bottom += dir;
-
-       twin_window_damage(pboot_lpane->window,
-                          pboot_lpane->focus_box.left,
-                          pboot_lpane->focus_box.top,
-                          pboot_lpane->focus_box.right,
-                          pboot_lpane->focus_box.bottom);
-
-       twin_window_queue_paint(pboot_lpane->window);
-
-       return accel[(pos * 10) / dist];
-}
-
-static void pboot_set_lfocus(int index)
-{
-       if (index >= pboot_dev_count)
-               return;
-
-       pboot_lpane->focus_start = pboot_lpane->focus_box.top;
-
-       if (index < 0)
-               pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
-       else
-               pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
-                       PBOOT_LEFT_ICON_STRIDE * index;
-
-       pboot_lpane->focus_curindex = index;
-
-       twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
-}
-
-static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
-{
-       int candidate = -1;
-       twin_coord_t icon_top;
-
-       if (x < PBOOT_LEFT_ICON_XOFF ||
-           x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
-               goto miss;
-       if (y < PBOOT_LEFT_ICON_YOFF)
-               goto miss;
-       candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
-       if (candidate >= pboot_dev_count) {
-               candidate = -1;
-               goto miss;
-       }
-       if (candidate == pboot_lpane->mouse_target)
-               return;
-       icon_top = PBOOT_LEFT_ICON_YOFF +
-               candidate * PBOOT_LEFT_ICON_STRIDE;
-       if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
-               candidate = -1;
-               goto miss;
-       }
-
-       /* Ok, so now, we know the mouse hit an icon that wasn't the same
-        * as the previous one, we trigger a focus change
-        */
-       pboot_set_lfocus(candidate);
-
- miss:
-       pboot_lpane->mouse_target = candidate;
-}
-
-static twin_bool_t pboot_lpane_event (twin_window_t        *window,
-                                     twin_event_t          *event)
-{
-       /* filter out all mouse events */
-       switch(event->kind) {
-       case TwinEventEnter:
-       case TwinEventMotion:
-       case TwinEventLeave:
-               pboot_select_lpane();
-               pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
-               return TWIN_TRUE;
-       case TwinEventButtonDown:
-       case TwinEventButtonUp:
-               return TWIN_TRUE;
-       case TwinEventKeyDown:
-               switch(event->u.key.key) {
-               case KEY_UP:
-                       if (pboot_lpane->focus_curindex > 0)
-                               pboot_set_lfocus(
-                                       pboot_lpane->focus_curindex - 1);
-                       return TWIN_TRUE;
-               case KEY_DOWN:
-                       pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
-                       return TWIN_TRUE;
-               case KEY_RIGHT:
-                       pboot_select_rpane();
-                       return TWIN_TRUE;
-               default:
-                       break;
-               }
-               break;
-       default:
-               break;
-       }
-       return TWIN_FALSE;
-}
-
-static void pboot_quit(void)
-{
-       kill(0, SIGINT);
-}
-
-twin_bool_t pboot_event_filter(twin_screen_t       *screen,
-                              twin_event_t         *event)
-{
-       switch(event->kind) {
-       case TwinEventEnter:
-       case TwinEventMotion:
-       case TwinEventLeave:
-       case TwinEventButtonDown:
-       case TwinEventButtonUp:
-               if (pboot_cursor != NULL)
-                       twin_screen_set_cursor(pboot_screen, pboot_cursor,
-                                              pboot_cursor_hx,
-                                              pboot_cursor_hy);
-               break;
-       case TwinEventJoyButton:
-               /* map joystick events into key events */
-               if (event->u.js.control >= sizeof(sixaxis_map))
-                       break;
-
-               event->u.key.key = sixaxis_map[event->u.js.control];
-               if (event->u.js.value == 0) {
-                       event->kind = TwinEventKeyUp;
-                       break;
-               } else {
-                       event->kind = TwinEventKeyDown;
-               }
-
-               /* fall through.. */
-       case TwinEventKeyDown:
-               switch(event->u.key.key) {
-               /* Gross hack for video modes, need something better ! */
-               case KEY_0:
-                       pboot_vmode_change = 0; /* auto */
-                       pboot_quit();
-                       return TWIN_TRUE;
-               case KEY_1:
-                       pboot_vmode_change = 3; /* 720p */
-                       pboot_quit();
-                       return TWIN_TRUE;
-               case KEY_2:
-                       pboot_vmode_change = 4; /* 1080i */
-                       pboot_quit();
-                       return TWIN_TRUE;
-               case KEY_3:
-                       pboot_vmode_change = 5; /* 1080p */
-                       pboot_quit();
-                       return TWIN_TRUE;
-
-               /* Another gross hack for booting back to gameos */
-               case KEY_BACKSPACE:
-               case KEY_DELETE:
-                       pboot_message("booting to GameOS...");
-                       system(BOOT_GAMEOS_BIN);
-               }
-       case TwinEventKeyUp:
-               twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
-               break;
-       default:
-               break;
-       }
-       return TWIN_FALSE;
-}
-
-static void pboot_lpane_draw(twin_window_t *window)
-{
-       twin_pixmap_t   *px = window->pixmap;
-       pboot_lpane_t   *lpane = window->client_data;
-       twin_path_t     *path;
-       twin_fixed_t    x, y, w, h;
-       int             i;
-
-       /* Fill background */
-       twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
-                 0, 0, px->width, px->height);
-
-       /* Create a path for use later */
-       path = twin_path_create();
-       assert(path);
-
-       /* Draw right line if needed */
-       if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
-               x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
-               y = twin_int_to_fixed(px->height);
-               twin_path_rectangle(path, x, 0, 0x40000, y);
-               twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
-               twin_path_empty(path);
-       }
-
-       /* Draw focus box */
-       if (lpane->focus_curindex >= 0 &&
-           twin_rect_intersect(lpane->focus_box, px->clip)) {
-               x = twin_int_to_fixed(lpane->focus_box.left + 2);
-               y = twin_int_to_fixed(lpane->focus_box.top + 2);
-               w = twin_int_to_fixed(lpane->focus_box.right -
-                                     lpane->focus_box.left - 4);
-               h = twin_int_to_fixed(lpane->focus_box.bottom -
-                                     lpane->focus_box.top - 4);
-               twin_path_rounded_rectangle(path, x, y, w, h,
-                                           PBOOT_LEFT_FOCUS_XRAD,
-                                           PBOOT_LEFT_FOCUS_YRAD);
-               if (pboot_focus_lpane)
-                       twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
-               else
-                       twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
-                                         4 * TWIN_FIXED_ONE);
-       }
-
-       /* Draw icons */
-       for (i = 0; i < pboot_dev_count; i++) {
-               pboot_device_t  *dev = pboot_devices[i];
-               twin_operand_t  src;
-
-               if (!twin_rect_intersect(dev->box, px->clip))
-                       continue;
-
-               src.source_kind = TWIN_PIXMAP;
-               src.u.pixmap = dev->badge;
-
-               twin_composite(px, dev->box.left, dev->box.top,
-                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
-                              dev->box.right - dev->box.left,
-                              dev->box.bottom - dev->box.top);
-
-       }
-
-       /* Destroy path */
-       twin_path_destroy(path);
-}
-
-static void pboot_create_lpane(void)
-{
-       pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
-       assert(pboot_lpane);
-
-       pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
-                                                TwinWindowPlain,
-                                                0, 0, PBOOT_LEFT_PANE_SIZE,
-                                                pboot_screen->height);
-       assert(pboot_lpane->window);
-
-       pboot_lpane->window->draw = pboot_lpane_draw;
-       pboot_lpane->window->event = pboot_lpane_event;
-       pboot_lpane->window->client_data = pboot_lpane;
-       pboot_lpane->focus_curindex = -1;
-       pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
-       pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
-       pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
-               PBOOT_LEFT_FOCUS_WIDTH;
-       pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
-               PBOOT_LEFT_FOCUS_HEIGHT;
-       pboot_lpane->mouse_target = -1;
-       twin_window_show(pboot_lpane->window);
-       twin_window_queue_paint(pboot_lpane->window);
-}
-
-static void pboot_spane_draw(twin_window_t *window)
-{
-       twin_pixmap_t   *px = window->pixmap;
-       pboot_spane_t   *spane = window->client_data;
-       twin_path_t     *path;
-       twin_fixed_t    tx, ty;
-
-       /* Fill background */
-       twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
-                 0, 0, px->width, px->height);
-
-       path = twin_path_create();
-       assert(path);
-
-       twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
-       twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
-       tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
-       ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
-       twin_path_move (path, tx, ty);
-       twin_path_utf8 (path, spane->text);
-       twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
-
-       twin_path_destroy(path);
-}
-
-void pboot_message(const char *fmt, ...)
-{
-       va_list ap;
-       char *msg;
-
-       if (pboot_spane->text)
-               free(pboot_spane->text);
-
-       va_start(ap, fmt);
-       vasprintf(&msg, fmt, ap);
-       va_end(ap);
-
-       pboot_spane->text = msg;
-       twin_window_damage(pboot_spane->window,
-                          0, 0,
-                          pboot_spane->window->pixmap->width,
-                          pboot_spane->window->pixmap->height);
-       twin_window_draw(pboot_spane->window);
-}
-
-static void pboot_create_spane(void)
-{
-       pboot_spane = calloc(1, sizeof(pboot_spane_t));
-       assert(pboot_spane);
-
-       pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
-                                                TwinWindowPlain,
-                                                PBOOT_LEFT_PANE_SIZE +
-                                                 PBOOT_STATUS_PANE_XYMARGIN,
-                                                pboot_screen->height - 
-                                                 PBOOT_STATUS_PANE_HEIGHT,
-                                                pboot_screen->width -
-                                                 PBOOT_LEFT_PANE_SIZE -
-                                                 2*PBOOT_STATUS_PANE_XYMARGIN,
-                                                PBOOT_STATUS_PANE_HEIGHT);
-       assert(pboot_spane->window);
-
-       pboot_spane->window->draw = pboot_spane_draw;
-       pboot_spane->window->client_data = pboot_spane;
-       pboot_spane->text = strdup(PBOOT_INITIAL_MESSAGE);
-       twin_window_show(pboot_spane->window);
-       twin_window_queue_paint(pboot_spane->window);
-}
-
-int pboot_add_device(const char *dev_id, const char *name,
-               twin_pixmap_t *pixmap)
-{
-       int             index;
-       pboot_device_t  *dev;
-
-       if (pboot_dev_count >= PBOOT_MAX_DEV)
-               return -1;
-
-       index = pboot_dev_count++;
-
-       dev = malloc(sizeof(*dev));
-       memset(dev, 0, sizeof(*dev));
-       dev->id = malloc(strlen(dev_id) + 1);
-       strcpy(dev->id, dev_id);
-       dev->badge = pixmap;
-       dev->box.left = PBOOT_LEFT_ICON_XOFF;
-       dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
-       dev->box.top = PBOOT_LEFT_ICON_YOFF +
-               PBOOT_LEFT_ICON_STRIDE * index;
-       dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
-
-       pboot_devices[index] = dev;
-
-       twin_window_damage(pboot_lpane->window,
-                          dev->box.left, dev->box.top,
-                          dev->box.right, dev->box.bottom);
-       twin_window_queue_paint(pboot_lpane->window);
-
-       return index;
-}
-
-int pboot_remove_device(const char *dev_id)
-{
-       pboot_device_t  *dev = NULL;
-       int             i, newsel = pboot_dev_sel;
-
-       /* find the matching device */
-       for (i = 0; i < pboot_dev_count; i++) {
-               if (!strcmp(pboot_devices[i]->id, dev_id)) {
-                       dev = pboot_devices[i];
-                       break;
-               }
-       }
-
-       if (!dev)
-               return TWIN_FALSE;
-
-       memmove(pboot_devices + i, pboot_devices + i + 1,
-                       sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
-       pboot_devices[--pboot_dev_count] = NULL;
-
-       /* select the newly-focussed device */
-       if (pboot_dev_sel > i)
-               newsel = pboot_dev_sel - 1;
-       else if (pboot_dev_sel == i && i >= pboot_dev_count)
-                       newsel = pboot_dev_count - 1;
-       pboot_set_device_select(newsel, 1);
-
-       /* todo: free device & options */
-
-       return TWIN_TRUE;
-}
-
-static void pboot_make_background(void)
-{
-       twin_pixmap_t   *filepic, *scaledpic;
-       const char      *background_path;
-
-       /* Set background pixmap */
-       LOG("loading background...");
-       background_path = artwork_pathname("background.jpg");
-       filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
-       LOG("%s\n", filepic ? "ok" : "failed");
-
-       if (filepic == NULL)
-               return;
-
-       if (pboot_screen->height == filepic->height &&
-           pboot_screen->width == filepic->width)
-               scaledpic = filepic;
-       else {
-               twin_fixed_t    sx, sy;
-               twin_operand_t  srcop;
-
-               scaledpic = twin_pixmap_create(TWIN_ARGB32,
-                                              pboot_screen->width,
-                                              pboot_screen->height);
-               if (scaledpic == NULL) {
-                       twin_pixmap_destroy(filepic);
-                       return;
-               }
-               sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
-                                   twin_int_to_fixed(pboot_screen->width));
-               sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
-                                   twin_int_to_fixed(pboot_screen->height));
-               
-               twin_matrix_scale(&filepic->transform, sx, sy);
-               srcop.source_kind = TWIN_PIXMAP;
-               srcop.u.pixmap = filepic;
-               twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
-                              NULL, 0, 0, TWIN_SOURCE,
-                              pboot_screen->width, pboot_screen->height);
-               twin_pixmap_destroy(filepic);
-                              
-       }
-       twin_screen_set_background(pboot_screen, scaledpic);
-}
-
-#define PS3FB_IOCTL_SETMODE          _IOW('r',  1, int)
-#define PS3FB_IOCTL_GETMODE          _IOR('r',  2, int)
-
-static void exitfunc(void)
-{
-#ifndef _USE_X11
-       if (pboot_fbdev)
-               twin_fbdev_destroy(pboot_fbdev);
-       pboot_fbdev = NULL;
-       if (pboot_vmode_change != -1) {
-               int fd = open("/dev/fb0", O_RDWR);
-               if (fd >= 0)
-                       ioctl(fd, PS3FB_IOCTL_SETMODE,
-                             (unsigned long)&pboot_vmode_change);
-               close(fd);
-       }
-#endif
-}
-
-static void sigint(int sig)
-{
-       exitfunc();
-       syscall(__NR_exit);
-}
-
-static void usage(const char *progname)
-{
-       fprintf(stderr, "Usage: %s [-u] [-h]\n", progname);
-}
-
-int main(int argc, char **argv)
-{
-       int c;
-       int udev_trigger = 0;
-
-       for (;;) {
-               c = getopt(argc, argv, "u::h");
-               if (c == -1)
-                       break;
-
-               switch (c) {
-               case 'u':
-                       udev_trigger = 1;
-                       break;
-               case 'h':
-                       usage(argv[0]);
-                       return EXIT_SUCCESS;
-               default:
-                       fprintf(stderr, "Unknown option '%c'\n", c);
-                       usage(argv[0]);
-                       return EXIT_FAILURE;
-               }
-       }
-
-       atexit(exitfunc);
-       signal(SIGINT, sigint);
-
-#ifdef _USE_X11
-       pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
-       if (pboot_x11 == NULL) {
-               perror("failed to create x11 screen !\n");
-               return 1;
-       }
-       pboot_screen = pboot_x11->screen;
-#else
-       /* Create screen and mouse drivers */
-       pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
-       if (pboot_fbdev == NULL) {
-               perror("failed to create fbdev screen !\n");
-               return 1;
-       }
-       pboot_screen = pboot_fbdev->screen;
-       twin_linux_mouse_create(NULL, pboot_screen);
-       twin_linux_js_create(pboot_screen);
-
-       if (pboot_fbdev != NULL) {
-               char *cursor_path = artwork_pathname("cursor.gz");
-               pboot_cursor = twin_load_X_cursor(cursor_path, 2,
-                                                 &pboot_cursor_hx,
-                                                 &pboot_cursor_hy);
-               if (pboot_cursor == NULL)
-                       pboot_cursor =
-                               twin_get_default_cursor(&pboot_cursor_hx,
-                                                       &pboot_cursor_hy);
-       }
-#endif
-
-       /* Set background pixmap */
-       pboot_make_background();
-
-       /* Init more stuffs */
-       pboot_create_lpane();
-       pboot_create_rpane();
-       pboot_create_spane();
-
-       if (!pboot_start_device_discovery(udev_trigger)) {
-               LOG("Couldn't start device discovery!\n");
-               return 1;
-       }
-
-       pboot_set_lfocus(0);
-       twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
-       pboot_screen->event_filter = pboot_event_filter;
-
-       /* Console switch */
-#ifndef _USE_X11
-       if (pboot_fbdev)
-               twin_fbdev_activate(pboot_fbdev);
-#endif
-
-       /* Process events */
-       twin_dispatch ();
-
-       return 0;
-}
diff --git a/petitboot.h b/petitboot.h
deleted file mode 100644 (file)
index 893be04..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-
-#include <libtwin/twin.h>
-#include <stdarg.h>
-
-#define LOG(fmt...)    printf(fmt)
-
-#define PBOOT_MAX_DEV          16
-#define PBOOT_MAX_OPTION       16
-
-int pboot_add_device(const char *dev_id, const char *name,
-               twin_pixmap_t *pixmap);
-int pboot_add_option(int devindex, const char *title,
-                    const char *subtitle, twin_pixmap_t *badge, void *data);
-int pboot_remove_device(const char *dev_id);
-
-int pboot_start_device_discovery(int udev_trigger);
-void pboot_exec_option(void *data);
-void pboot_message(const char *fmt, ...);
index 9239d29248cd23947df44a0d0f41f724049c7389..f8d64c61752b3d0c505740c33dea4e8d5850a50f 100644 (file)
--- a/rules.mk
+++ b/rules.mk
@@ -1,36 +1,56 @@
 
 VPATH = $(srcdir)
 
+CFLAGS += -I$(top_srcdir) -I$(top_srcdir)/lib -I$(builddir)
+
 # we need paths to be overridable at build-time
 DEFS += '-DPREFIX="$(prefix)"' '-DPKG_SHARE_DIR="$(pkgdatadir)"'
 
+#uis = ui/twin/pb-twin
+uis = ui/test/pb-test
 parsers = native yaboot kboot
 artwork = background.jpg cdrom.png hdd.png usbpen.png tux.png cursor.gz
 
-petitboot_objs = petitboot.o devices.o
 
-parser_objs = devices/params.o devices/parser.o devices/paths.o \
-             devices/yaboot-cfg.o \
-             $(foreach p,$(parsers),devices/$(p)-parser.o)
+talloc_objs = lib/talloc/talloc.o
+list_objs = lib/list/list.o
+server_objs = lib/pb-protocol/pb-protocol.o
 
-petitboot_udev_helper_objs = devices/petitboot-udev-helper.o $(parser_objs)
 parser_test_objs = parser-test.o $(parser_objs)
 
-all: petitboot petitboot-udev-helper
+all: $(uis) discover/pb-discover
+
+# twin gui
+ui/twin/pb-twin: LDFLAGS+=$(twin_LDFLAGS)
+ui/twin/pb-twin: CFLAGS+=$(twin_CFLAGS)
 
-petitboot: LDFLAGS+=$(twin_LDFLAGS)
-petitboot: CFLAGS+=$(twin_CFLAGS)
+pb_twin_objs = ui/twin/pb-twin.o ui/common/devices.o
 
-petitboot: $(petitboot_objs)
+ui/twin/pb-twin: $(pb_twin_objs)
        $(LINK.o) -o $@ $^
 
-petitboot-udev-helper: $(petitboot_udev_helper_objs)
+# test ui
+pb_test_objs = ui/test/pb-test.o ui/common/discover-client.o \
+       $(talloc_objs) $(server_objs)
+
+ui/test/pb-test: $(pb_test_objs)
        $(LINK.o) -o $@ $^
 
-parser-test: $(parser_test_objs)
+# discovery daemon
+#pb_discover_objs = discover/params.o discover/parser.o discover/paths.o \
+#            discover/yaboot-cfg.o \
+#            $(foreach p,$(parsers),discover/$(p)-parser.o)
+
+pb_discover_objs = discover/pb-discover.o discover/udev.o discover/log.o \
+                  discover/waiter.o discover/discover-server.o \
+                  $(talloc_objs) $(server_objs) $(list_objs)
+
+discover/pb-discover: $(pb_discover_objs)
        $(LINK.o) -o $@ $^
 
-petitboot-udev-helper: CFLAGS+=-I$(top_srcdir)
+
+parser-test: $(parser_test_objs)
+       $(LINK.o) -o $@ $^
 
 install: all
        $(INSTALL) -D petitboot $(DESTDIR)$(sbindir)/petitboot
@@ -60,6 +80,9 @@ $(PACKAGE)-$(VERSION): clean
        done
 clean:
        rm -rf $(PACKAGE)-$(VERSION)
-       rm -f petitboot
-       rm -f petitboot-udev-helper
-       rm -f *.o devices/*.o
+       rm -f $(uis)
+       rm -f $(pb_twin_objs) $(pb_test_objs)
+       rm -f $(pb_discover_objs)
+       rm -f discover/pb-discover
+       rm -f ui/test/pb-test
+
diff --git a/test/parser-test.c b/test/parser-test.c
new file mode 100644 (file)
index 0000000..8c94d3f
--- /dev/null
@@ -0,0 +1,85 @@
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "parser.h"
+#include "paths.h"
+
+void pb_log(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+}
+
+int mount_device(const char *dev_path)
+{
+       printf("[mount] %s\n", dev_path);
+       return 0;
+}
+
+static int device_idx;
+static int option_idx;
+
+int add_device(const struct device *dev)
+{
+       printf("[dev %2d] id: %s\n", device_idx, dev->id);
+       printf("[dev %2d] name: %s\n", device_idx, dev->name);
+       printf("[dev %2d] description: %s\n", device_idx, dev->description);
+       printf("[dev %2d] boot_image: %s\n", device_idx, dev->icon_file);
+
+       device_idx++;
+       option_idx = 0;
+       return 0;
+}
+
+
+int add_boot_option(const struct boot_option *opt)
+{
+       if (!device_idx) {
+               fprintf(stderr, "Option (%s) added before device\n",
+                               opt->name);
+               exit(EXIT_FAILURE);
+       }
+
+       printf("[opt %2d] name: %s\n", option_idx, opt->name);
+       printf("[opt %2d] description: %s\n", option_idx, opt->description);
+       printf("[opt %2d] boot_image: %s\n", option_idx, opt->boot_image_file);
+       printf("[opt %2d] initrd: %s\n", option_idx, opt->initrd_file);
+       printf("[opt %2d] boot_args: %s\n", option_idx, opt->boot_args);
+
+       option_idx++;
+
+       return 0;
+}
+
+enum generic_icon_type guess_device_type(void)
+{
+       return ICON_TYPE_UNKNOWN;
+}
+
+int main(int argc, char **argv)
+{
+       char *mountpoint, *dev;
+
+       if (argc != 3) {
+               fprintf(stderr, "usage: %s <basedir> <devname>\n", argv[0]);
+               return EXIT_FAILURE;
+       }
+
+       mountpoint = argv[1];
+       dev = argv[2];
+
+       set_mount_base(mountpoint);
+
+       iterate_parsers(dev, mountpoint);
+
+
+       return EXIT_SUCCESS;
+}
diff --git a/test/parser-test.sh b/test/parser-test.sh
new file mode 100755 (executable)
index 0000000..140601e
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+testdir=devices/parser-tests
+default_rootdev=ps3da1
+
+function test_dir()
+{
+       dir="$1"
+       rootdev=$default_rootdev
+       if [ -e "$dir/rootdev" ]
+       then
+               rootdev=$(cat "$dir/rootdev")
+       fi
+       ./parser-test "$dir" /dev/$rootdev 2>/dev/null |
+               diff -u "$dir/expected-output" -
+}
+
+set -ex
+
+for test in $testdir/*
+do
+       echo $test
+       test_dir "$test"
+done
+
+echo "All tests passed"
diff --git a/test/parser/001/expected-output b/test/parser/001/expected-output
new file mode 100644 (file)
index 0000000..bace9f7
--- /dev/null
@@ -0,0 +1,24 @@
+[dev  0] id: /dev/ps3da1
+[dev  0] name: (null)
+[dev  0] description: (null)
+[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
+[opt  0] name: live
+[opt  0] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
+[opt  0] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
+[opt  0] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
+[opt  0] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
+[opt  1] name: live_nosplash
+[opt  1] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
+[opt  1] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
+[opt  1] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
+[opt  1] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
+[opt  2] name: driverupdates
+[opt  2] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
+[opt  2] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
+[opt  2] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
+[opt  2] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
+[opt  3] name: check
+[opt  3] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
+[opt  3] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux
+[opt  3] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz
+[opt  3] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
diff --git a/test/parser/001/ps3da1/etc/kboot.conf b/test/parser/001/ps3da1/etc/kboot.conf
new file mode 100644 (file)
index 0000000..591c51b
--- /dev/null
@@ -0,0 +1,9 @@
+# Ubuntu feisty kboot.conf
+message=/etc/kboot.msg
+timeout=300
+default=live
+live='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --'
+live_nosplash='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet --'
+driverupdates='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --'
+check='/casper/vmlinux initrd=/casper/initrd.gz  boot=casper integrity-check quiet splash --'
+
diff --git a/test/parser/002/expected-output b/test/parser/002/expected-output
new file mode 100644 (file)
index 0000000..304f15c
--- /dev/null
@@ -0,0 +1,9 @@
+[dev  0] id: /dev/ps3da1
+[dev  0] name: (null)
+[dev  0] description: 
+[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
+[opt  0] name: linux
+[opt  0] description: (null)
+[opt  0] boot_image: devices/parser-tests/002/ps3da1/ppc/ppc64/vmlinux
+[opt  0] initrd: devices/parser-tests/002/ps3da1/ppc/ppc64/ramdisk.image.gz
+[opt  0] boot_args: ro 
diff --git a/test/parser/002/ps3da1/etc/yaboot.conf b/test/parser/002/ps3da1/etc/yaboot.conf
new file mode 100644 (file)
index 0000000..f13b1b3
--- /dev/null
@@ -0,0 +1,8 @@
+init-message = "\nWelcome to the 64-bit Yellow Dog Linux 5.0 installer!\nHit <TAB> for boot options.\n\n"
+timeout=6000
+default=linux
+
+image=/ppc/ppc64/vmlinux
+       label=linux
+       initrd=/ppc/ppc64/ramdisk.image.gz
+       read-only
diff --git a/test/parser/003/expected-output b/test/parser/003/expected-output
new file mode 100644 (file)
index 0000000..4f60310
--- /dev/null
@@ -0,0 +1,9 @@
+[dev  0] id: /dev/ps3da1
+[dev  0] name: (null)
+[dev  0] description: (null)
+[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
+[opt  0] name: test
+[opt  0] description: /dev/sda1:/vmlinux
+[opt  0] boot_image: devices/parser-tests/003/ps3da1/vmlinux
+[opt  0] initrd: (null)
+[opt  0] boot_args: (null)
diff --git a/test/parser/003/ps3da1/etc/kboot.conf b/test/parser/003/ps3da1/etc/kboot.conf
new file mode 100644 (file)
index 0000000..a7bb199
--- /dev/null
@@ -0,0 +1,4 @@
+# test remapping sda to ps3da, when mounted from a ps3da device
+
+test='/dev/sda1:/vmlinux'
+
diff --git a/test/parser/004/expected-output b/test/parser/004/expected-output
new file mode 100644 (file)
index 0000000..76a90a2
--- /dev/null
@@ -0,0 +1,9 @@
+[dev  0] id: /dev/sda1
+[dev  0] name: (null)
+[dev  0] description: (null)
+[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
+[opt  0] name: test
+[opt  0] description: /dev/sda1:/vmlinux
+[opt  0] boot_image: devices/parser-tests/004/sda1/vmlinux
+[opt  0] initrd: (null)
+[opt  0] boot_args: (null)
diff --git a/test/parser/004/rootdev b/test/parser/004/rootdev
new file mode 100644 (file)
index 0000000..36cfa0d
--- /dev/null
@@ -0,0 +1 @@
+sda1
diff --git a/test/parser/004/sda1/etc/kboot.conf b/test/parser/004/sda1/etc/kboot.conf
new file mode 100644 (file)
index 0000000..9755f77
--- /dev/null
@@ -0,0 +1,4 @@
+# test remapping sda to ps3da, when mounted from a plain sd device
+
+test='/dev/sda1:/vmlinux'
+
diff --git a/test/parser/005/expected-output b/test/parser/005/expected-output
new file mode 100644 (file)
index 0000000..bfaccc8
--- /dev/null
@@ -0,0 +1,14 @@
+[dev  0] id: /dev/ps3da1
+[dev  0] name: (null)
+[dev  0] description: (null)
+[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
+[opt  0] name: test_uuid
+[opt  0] description: UUID=meep:/vmlinux
+[opt  0] boot_image: devices/parser-tests/005/disk/by-uuid/meep/vmlinux
+[opt  0] initrd: (null)
+[opt  0] boot_args: (null)
+[opt  1] name: test_label
+[opt  1] description: LABEL=meep:/vmlinux
+[opt  1] boot_image: devices/parser-tests/005/disk/by-label/meep/vmlinux
+[opt  1] initrd: (null)
+[opt  1] boot_args: (null)
diff --git a/test/parser/005/ps3da1/etc/kboot.conf b/test/parser/005/ps3da1/etc/kboot.conf
new file mode 100644 (file)
index 0000000..72b7db8
--- /dev/null
@@ -0,0 +1,6 @@
+
+# test for LABEL= and UUID= lookups
+
+test_uuid='UUID=meep:/vmlinux'
+test_label='LABEL=meep:/vmlinux'
+
diff --git a/test/parser/101/expected-output b/test/parser/101/expected-output
new file mode 100644 (file)
index 0000000..45d99a1
--- /dev/null
@@ -0,0 +1,24 @@
+[dev  0] id: /dev/ps3da1
+[dev  0] name: (null)
+[dev  0] description: (null)
+[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
+[opt  0] name: ydl
+[opt  0] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:3 rhgb
+[opt  0] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
+[opt  0] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
+[opt  0] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:3 rhgb
+[opt  1] name: ydl480i
+[opt  1] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:1 rhgb
+[opt  1] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
+[opt  1] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
+[opt  1] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:1 rhgb
+[opt  2] name: ydl1080i
+[opt  2] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:4 rhgb
+[opt  2] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
+[opt  2] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
+[opt  2] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init video=ps3fb:mode:4 rhgb
+[opt  3] name: ydltext
+[opt  3] description: /dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init 3
+[opt  3] boot_image: devices/parser-tests/101/ps3da1/vmlinux-2.6.22-0.ydl.rc4
+[opt  3] initrd: devices/parser-tests/101/ps3da1/initrd-2.6.22-0.ydl.rc4.img
+[opt  3] boot_args: root=LABEL=/ initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img  init=/sbin/init 3
diff --git a/test/parser/101/ps3da1/etc/kboot.conf b/test/parser/101/ps3da1/etc/kboot.conf
new file mode 100644 (file)
index 0000000..4a986c0
--- /dev/null
@@ -0,0 +1,12 @@
+# kboot.conf for ydl
+
+default=ydl
+timeout=10
+root=/dev/sda1
+ydl='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init video=ps3fb:mode:3 rhgb'
+ydl480i='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init video=ps3fb:mode:1 rhgb'
+ydl1080i='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init video=ps3fb:mode:4 rhgb'
+ydltext='/dev/sda1:/vmlinux-2.6.22-0.ydl.rc4 initrd=/dev/sda1:/initrd-2.6.22-0.ydl.rc4.img root=LABEL=/ init=/sbin/init 3'
+
+
+
diff --git a/test/parser/102/expected-output b/test/parser/102/expected-output
new file mode 100644 (file)
index 0000000..cc0d096
--- /dev/null
@@ -0,0 +1,24 @@
+[dev  0] id: /dev/ps3da1
+[dev  0] name: (null)
+[dev  0] description: (null)
+[dev  0] boot_image: /usr/share/petitboot/artwork/hdd.png
+[opt  0] name: live
+[opt  0] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
+[opt  0] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
+[opt  0] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
+[opt  0] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --
+[opt  1] name: live_nosplash
+[opt  1] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
+[opt  1] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
+[opt  1] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
+[opt  1] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper quiet --
+[opt  2] name: driverupdates
+[opt  2] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
+[opt  2] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
+[opt  2] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
+[opt  2] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --
+[opt  3] name: check
+[opt  3] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
+[opt  3] boot_image: devices/parser-tests/102/ps3da1/casper/vmlinux
+[opt  3] initrd: devices/parser-tests/102/ps3da1/casper/initrd.gz
+[opt  3] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz   boot=casper integrity-check quiet splash --
diff --git a/test/parser/102/ps3da1/etc/kboot.conf b/test/parser/102/ps3da1/etc/kboot.conf
new file mode 100644 (file)
index 0000000..591c51b
--- /dev/null
@@ -0,0 +1,9 @@
+# Ubuntu feisty kboot.conf
+message=/etc/kboot.msg
+timeout=300
+default=live
+live='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --'
+live_nosplash='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet --'
+driverupdates='/casper/vmlinux initrd=/casper/initrd.gz  file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash --'
+check='/casper/vmlinux initrd=/casper/initrd.gz  boot=casper integrity-check quiet splash --'
+
diff --git a/ui/common/discover-client.c b/ui/common/discover-client.c
new file mode 100644 (file)
index 0000000..bc5a4fa
--- /dev/null
@@ -0,0 +1,111 @@
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <asm/byteorder.h>
+
+#include <talloc/talloc.h>
+
+#include "ui/common/discover-client.h"
+#include "ui/common/device.h"
+#include "pb-protocol/pb-protocol.h"
+
+struct discover_client {
+       int fd;
+       struct discover_client_ops ops;
+};
+
+static int discover_client_destructor(void *arg)
+{
+       struct discover_client *client = arg;
+
+       if (client->fd >= 0)
+               close(client->fd);
+
+       return 0;
+}
+
+struct discover_client* discover_client_init(struct discover_client_ops *ops)
+{
+       struct discover_client *client;
+       struct sockaddr_un addr;
+
+       client = talloc(NULL, struct discover_client);
+       if (!client)
+               return NULL;
+
+       memcpy(&client->ops, ops, sizeof(client->ops));
+
+       client->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (!client->fd < 0) {
+               perror("socket");
+               goto out_err;
+       }
+
+       talloc_set_destructor(client, discover_client_destructor);
+
+       addr.sun_family = AF_UNIX;
+       strcpy(addr.sun_path, PB_SOCKET_PATH);
+
+       if (connect(client->fd, (struct sockaddr *)&addr, sizeof(addr))) {
+               perror("connect");
+               goto out_err;
+       }
+
+       return client;
+
+out_err:
+       talloc_free(client);
+       return NULL;
+}
+
+int discover_client_get_fd(struct discover_client *client)
+{
+       return client->fd;
+}
+
+void discover_client_destroy(struct discover_client *client)
+{
+       talloc_free(client);
+}
+
+int discover_client_process(struct discover_client *client)
+{
+       struct pb_protocol_message *message;
+       struct device *dev;
+       char *dev_id;
+
+       message = pb_protocol_read_message(client, client->fd);
+
+       if (!message)
+               return 0;
+
+       switch (message->action) {
+       case PB_PROTOCOL_ACTION_ADD:
+               dev = pb_protocol_deserialise_device(client, message);
+               if (!dev) {
+                       printf("no device?\n");
+                       return 0;
+               }
+               client->ops.add_device(dev);
+               talloc_free(dev);
+               break;
+       case PB_PROTOCOL_ACTION_REMOVE:
+               dev_id = pb_protocol_deserialise_string(client, message);
+               if (!dev_id) {
+                       printf("no device id?\n");
+                       return 0;
+               }
+               client->ops.remove_device(dev_id);
+               break;
+       default:
+               printf("unknown action %d\n", message->action);
+       }
+
+
+       return 0;
+}
diff --git a/ui/common/discover-client.h b/ui/common/discover-client.h
new file mode 100644 (file)
index 0000000..3ce745b
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _DISCOVER_CLIENT_H
+#define _DISCOVER_CLIENT_H
+
+#include <pb-protocol/pb-protocol.h>
+#include "ui/common/device.h"
+
+struct discover_client;
+
+struct discover_client_ops {
+       int     (*add_device)(struct device *);
+       void    (*remove_device)(char *);
+};
+
+struct discover_client *discover_client_init(struct discover_client_ops *ops);
+
+int discover_client_get_fd(struct discover_client *client);
+
+void discover_client_destroy(struct discover_client *client);
+
+/**
+ * Process data from the server.
+ *
+ * Will read from the client socket, and call add_device on any discovered
+ * devices.
+ * 
+ */
+int discover_client_process(struct discover_client *client);
+
+#endif
diff --git a/ui/test/pb-test.c b/ui/test/pb-test.c
new file mode 100644 (file)
index 0000000..a36e991
--- /dev/null
@@ -0,0 +1,62 @@
+
+#include <stdio.h>
+
+#include "ui/common/discover-client.h"
+#include "ui/common/device.h"
+
+static int print_device_add(struct device *device)
+{
+       int i;
+
+       printf("new device:\n");
+       printf("\tid:   %s\n", device->id);
+       printf("\tname: %s\n", device->name);
+       printf("\tdesc: %s\n", device->description);
+       printf("\ticon: %s\n", device->icon_file);
+
+       printf("\t%d boot options:\n", device->n_options);
+       for (i = 0; i < device->n_options; i++) {
+               struct boot_option *opt = &device->options[i];
+               printf("\t\tid:   %s\n", opt->id);
+               printf("\t\tname: %s\n", opt->name);
+               printf("\t\tdesc: %s\n", opt->description);
+               printf("\t\ticon: %s\n", opt->icon_file);
+               printf("\t\tboot: %s\n", opt->boot_image_file);
+               printf("\t\tinit: %s\n", opt->initrd_file);
+               printf("\t\targs: %s\n", opt->boot_args);
+       }
+
+       return 0;
+}
+
+static void print_device_remove(const char *dev_id)
+{
+       printf("removed device:\n");
+       printf("\tid:   %s\n", dev_id);
+}
+
+struct discover_client_ops client_ops = {
+       .add_device = print_device_add,
+       .remove_device = print_device_remove,
+};
+
+int main(void)
+{
+       struct discover_client *client;
+
+       printf("pid: %d\n", getpid());
+
+       client = discover_client_init(&client_ops);
+       if (!client)
+               return -1;
+
+       for (;;) {
+               int rc;
+
+               rc = discover_client_process(client);
+               if (rc)
+                       break;
+       }
+
+       return 0;
+}
diff --git a/ui/twin/artwork/background.jpg b/ui/twin/artwork/background.jpg
new file mode 100644 (file)
index 0000000..9d54d31
Binary files /dev/null and b/ui/twin/artwork/background.jpg differ
diff --git a/ui/twin/artwork/cdrom.png b/ui/twin/artwork/cdrom.png
new file mode 100644 (file)
index 0000000..8b3eeb6
Binary files /dev/null and b/ui/twin/artwork/cdrom.png differ
diff --git a/ui/twin/artwork/cursor.gz b/ui/twin/artwork/cursor.gz
new file mode 100644 (file)
index 0000000..b73b72f
Binary files /dev/null and b/ui/twin/artwork/cursor.gz differ
diff --git a/ui/twin/artwork/hdd.png b/ui/twin/artwork/hdd.png
new file mode 100644 (file)
index 0000000..2b1594c
Binary files /dev/null and b/ui/twin/artwork/hdd.png differ
diff --git a/ui/twin/artwork/tux.png b/ui/twin/artwork/tux.png
new file mode 100644 (file)
index 0000000..99f3465
Binary files /dev/null and b/ui/twin/artwork/tux.png differ
diff --git a/ui/twin/artwork/usbpen.png b/ui/twin/artwork/usbpen.png
new file mode 100644 (file)
index 0000000..53a365e
Binary files /dev/null and b/ui/twin/artwork/usbpen.png differ
diff --git a/ui/twin/pb-twin.c b/ui/twin/pb-twin.c
new file mode 100644 (file)
index 0000000..ee68930
--- /dev/null
@@ -0,0 +1,1194 @@
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <syscall.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/input.h>
+
+#undef _USE_X11
+
+#include <libtwin/twin.h>
+#include <libtwin/twin_linux_mouse.h>
+#include <libtwin/twin_linux_js.h>
+#include <libtwin/twin_png.h>
+#include <libtwin/twin_jpeg.h>
+
+#include "petitboot.h"
+#include "petitboot-paths.h"
+
+#ifdef _USE_X11
+#include <libtwin/twin_x11.h>
+static twin_x11_t *pboot_x11;
+#else
+#include <libtwin/twin_fbdev.h>
+static twin_fbdev_t *pboot_fbdev;
+#endif
+
+static twin_screen_t *pboot_screen;
+
+#define PBOOT_INITIAL_MESSAGE          \
+       "keys: 0=safe 1=720p 2=1080i 3=1080p del=GameOS"
+
+#define PBOOT_LEFT_PANE_SIZE           160
+#define PBOOT_LEFT_PANE_COLOR          0x80000000
+#define PBOOT_LEFT_LINE_COLOR          0xff000000
+
+#define PBOOT_LEFT_FOCUS_WIDTH         80
+#define PBOOT_LEFT_FOCUS_HEIGHT                80
+#define PBOOT_LEFT_FOCUS_XOFF          40
+#define PBOOT_LEFT_FOCUS_YOFF          40
+#define PBOOT_LEFT_FOCUS_XRAD          (6 * TWIN_FIXED_ONE)
+#define PBOOT_LEFT_FOCUS_YRAD          (6 * TWIN_FIXED_ONE)
+
+#define PBOOT_RIGHT_FOCUS_XOFF         20
+#define PBOOT_RIGHT_FOCUS_YOFF         60
+#define PBOOT_RIGHT_FOCUS_HEIGHT       80
+#define PBOOT_RIGHT_FOCUS_XRAD         (6 * TWIN_FIXED_ONE)
+#define PBOOT_RIGHT_FOCUS_YRAD         (6 * TWIN_FIXED_ONE)
+
+#define PBOOT_LEFT_ICON_WIDTH          64
+#define PBOOT_LEFT_ICON_HEIGHT         64
+#define PBOOT_LEFT_ICON_XOFF           50
+#define PBOOT_LEFT_ICON_YOFF           50
+#define PBOOT_LEFT_ICON_STRIDE         100
+
+#define PBOOT_RIGHT_OPTION_LMARGIN     30
+#define PBOOT_RIGHT_OPTION_RMARGIN     30
+#define PBOOT_RIGHT_OPTION_TMARGIN     70
+#define PBOOT_RIGHT_OPTION_HEIGHT      64
+#define PBOOT_RIGHT_OPTION_STRIDE      100
+#define PBOOT_RIGHT_TITLE_TEXT_SIZE    (30 * TWIN_FIXED_ONE)
+#define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
+#define PBOOT_RIGHT_TITLE_XOFFSET      80
+#define PBOOT_RIGHT_TITLE_YOFFSET      30
+#define PBOOT_RIGHT_SUBTITLE_XOFFSET   100
+#define PBOOT_RIGHT_SUBTITLE_YOFFSET   50
+#define PBOOT_RIGHT_BADGE_XOFFSET      2
+#define PBOOT_RIGHT_BADGE_YOFFSET      0
+
+
+#define PBOOT_RIGHT_TITLE_COLOR                0xff000000
+#define PBOOT_RIGHT_SUBTITLE_COLOR     0xff400000
+
+#define PBOOT_FOCUS_COLOR              0x10404040
+
+#define PBOOT_STATUS_PANE_COLOR                0x60606060
+#define PBOOT_STATUS_PANE_HEIGHT       20
+#define PBOOT_STATUS_PANE_XYMARGIN     20
+#define PBOOT_STATUS_TEXT_MARGIN       10
+#define PBOOT_STATUS_TEXT_SIZE         (16 * TWIN_FIXED_ONE)
+#define PBOOT_STATUS_TEXT_COLOR                0xff000000
+
+typedef struct _pboot_option pboot_option_t;
+typedef struct _pboot_device pboot_device_t;
+
+struct _pboot_option
+{
+       char            *title;
+       char            *subtitle;
+       twin_pixmap_t   *badge;
+       twin_pixmap_t   *cache;
+       twin_rect_t     box;
+       void            *data;
+};
+
+struct _pboot_device
+{
+       char                    *id;
+       twin_pixmap_t           *badge;
+       twin_rect_t             box;
+       int                     option_count;
+       pboot_option_t          options[PBOOT_MAX_OPTION];
+};
+
+static twin_pixmap_t   *pboot_cursor;
+static int             pboot_cursor_hx;
+static int             pboot_cursor_hy;
+
+static pboot_device_t  *pboot_devices[PBOOT_MAX_DEV];
+static int             pboot_dev_count;
+static int             pboot_dev_sel = -1;
+static int             pboot_focus_lpane = 1;
+
+typedef struct _pboot_lpane {
+       twin_window_t   *window;
+       twin_rect_t     focus_box;
+       int             focus_start;
+       int             focus_target;
+       int             focus_curindex;
+       int             mouse_target;
+} pboot_lpane_t;
+
+typedef struct _pboot_rpane {
+       twin_window_t   *window;
+       twin_rect_t     focus_box;
+       int             focus_start;
+       int             focus_target;
+       int             focus_curindex;
+       int             mouse_target;
+} pboot_rpane_t;
+
+typedef struct _pboot_spane {
+       twin_window_t   *window;
+       char            *text;
+} pboot_spane_t;
+
+static pboot_lpane_t   *pboot_lpane;
+static pboot_rpane_t   *pboot_rpane;
+static pboot_spane_t   *pboot_spane;
+
+/* control to keyboard mappings for the sixaxis controller */
+uint8_t sixaxis_map[] = {
+       0,              /*   0  Select          */
+       0,              /*   1  L3              */
+       0,              /*   2  R3              */
+       0,              /*   3  Start           */
+       KEY_UP,         /*   4  Dpad Up         */
+       KEY_RIGHT,      /*   5  Dpad Right      */
+       KEY_DOWN,       /*   6  Dpad Down       */
+       KEY_LEFT,       /*   7  Dpad Left       */
+       0,              /*   8  L2              */
+       0,              /*   9  R2              */
+       0,              /*  10  L1              */
+       0,              /*  11  R1              */
+       0,              /*  12  Triangle        */
+       KEY_ENTER,      /*  13  Circle          */
+       0,              /*  14  Cross           */
+       KEY_DELETE,     /*  15  Square          */
+       0,              /*  16  PS Button       */
+       0,              /*  17  nothing      */
+       0,              /*  18  nothing      */
+};
+
+
+static int pboot_vmode_change = -1;
+
+/* XXX move to twin */
+static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
+                                             twin_rect_t r2)
+{
+       return !(r1.left > r2.right ||
+                r1.right < r2.left ||
+                r1.top > r2.bottom ||
+                r1.bottom < r2.top);
+}
+
+static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
+                                   int index)
+{
+       twin_pixmap_t   *px;
+       twin_path_t     *path;
+       twin_fixed_t    tx, ty;
+
+       /* Create pixmap */
+       px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
+                                opt->box.bottom - opt->box.top);
+       assert(px);
+       opt->cache = px;
+
+       /* Fill background */
+       twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
+
+       /* Allocate a path for drawing */
+       path = twin_path_create();
+       assert(path);
+
+#if 0
+       /* TEST - Bounding rectangle */
+       twin_path_rectangle(path, 0, 0,
+                           twin_int_to_fixed(px->width),
+                           twin_int_to_fixed(px->height));
+       twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
+       twin_path_empty(path);
+       twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
+                 px->width - 3, px->height - 3);
+#endif
+
+       /* Draw texts */
+       twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
+       twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
+       tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
+       ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
+       twin_path_move (path, tx, ty);
+       twin_path_utf8 (path, opt->title);
+       twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
+       twin_path_empty (path);
+
+       if (opt->subtitle) {
+               twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
+               twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
+               tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
+               ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
+               twin_path_move (path, tx, ty);
+               twin_path_utf8 (path, opt->subtitle);
+               twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
+               twin_path_empty (path);
+       }
+
+       if (opt->badge) {
+               twin_operand_t  src;
+
+               src.source_kind = TWIN_PIXMAP;
+               src.u.pixmap = opt->badge;
+
+               twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
+                              PBOOT_RIGHT_BADGE_YOFFSET,
+                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
+                              opt->badge->width, opt->badge->height);
+       }
+
+
+       /* Destroy path */
+       twin_path_destroy(path);
+}
+
+static void pboot_rpane_draw(twin_window_t *window)
+{
+       twin_pixmap_t   *px = window->pixmap;
+       pboot_rpane_t   *rpane = window->client_data;
+       pboot_device_t  *dev;
+       twin_path_t     *path;
+       twin_fixed_t    x, y, w, h;
+       int             i;
+
+       /* Fill background */
+       twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
+
+       /* Nothing to draw, return */
+       if (pboot_dev_sel < 0)
+               return;
+
+       /* Create a path for use later */
+       path = twin_path_create();
+       assert(path);
+
+       /* Draw focus box */
+       if (rpane->focus_curindex >= 0 &&
+           twin_rect_intersect(rpane->focus_box, px->clip)) {
+               x = twin_int_to_fixed(rpane->focus_box.left + 2);
+               y = twin_int_to_fixed(rpane->focus_box.top + 2);
+               w = twin_int_to_fixed(rpane->focus_box.right -
+                                     rpane->focus_box.left - 4);
+               h = twin_int_to_fixed(rpane->focus_box.bottom -
+                                     rpane->focus_box.top - 4);
+               twin_path_rounded_rectangle(path, x, y, w, h,
+                                           PBOOT_RIGHT_FOCUS_XRAD,
+                                           PBOOT_RIGHT_FOCUS_YRAD);
+               if (!pboot_focus_lpane)
+                       twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
+               else
+                       twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
+                                         4 * TWIN_FIXED_ONE);
+       }
+
+       /* Get device and iterate through options */
+       dev = pboot_devices[pboot_dev_sel];
+       for (i = 0; i < dev->option_count; i++) {
+               pboot_option_t  *opt = &dev->options[i];
+               twin_operand_t  src;
+
+               if (opt->title == NULL)
+                       continue;
+               if (!twin_rect_intersect(opt->box, px->clip))
+                       continue;
+               if (opt->cache == NULL)
+                       pboot_draw_option_cache(dev, opt, i);
+
+               src.source_kind = TWIN_PIXMAP;
+               src.u.pixmap = opt->cache;
+
+               twin_composite(px, opt->box.left, opt->box.top,
+                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
+                              opt->box.right - opt->box.left,
+                              opt->box.bottom - opt->box.top);
+       }
+
+       /* Destroy path */
+       twin_path_destroy(path);
+}
+
+static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
+{
+       int dir = 1, dist, pos;
+       const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
+
+       dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
+       dir = dist > 5 ? 5 : dist;
+       pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
+       if (pos == 0) {
+               return -1;
+       }
+       if (pos < 0) {
+               dir = -dir;
+               pos = -pos;
+       }
+       twin_window_damage(pboot_rpane->window,
+                          pboot_rpane->focus_box.left,
+                          pboot_rpane->focus_box.top,
+                          pboot_rpane->focus_box.right,
+                          pboot_rpane->focus_box.bottom);
+
+       pboot_rpane->focus_box.top += dir;
+       pboot_rpane->focus_box.bottom += dir;
+
+       twin_window_damage(pboot_rpane->window,
+                          pboot_rpane->focus_box.left,
+                          pboot_rpane->focus_box.top,
+                          pboot_rpane->focus_box.right,
+                          pboot_rpane->focus_box.bottom);
+
+       twin_window_queue_paint(pboot_rpane->window);
+
+       return accel[(pos * 10) / dist];
+}
+
+static void pboot_set_rfocus(int index)
+{
+       pboot_device_t  *dev;
+
+       if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
+               return;
+       dev = pboot_devices[pboot_dev_sel];
+       if (index < 0 || index >= dev->option_count)
+               return;
+
+       pboot_rpane->focus_start = pboot_rpane->focus_box.top;
+       pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
+               PBOOT_RIGHT_OPTION_STRIDE * index;
+       pboot_rpane->focus_curindex = index;
+
+       twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
+}
+
+static void pboot_select_rpane(void)
+{
+       if (pboot_focus_lpane == 0)
+               return;
+       pboot_focus_lpane = 0;
+
+       twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
+
+       twin_window_damage(pboot_lpane->window,
+                          pboot_lpane->focus_box.left,
+                          pboot_lpane->focus_box.top,
+                          pboot_lpane->focus_box.right,
+                          pboot_lpane->focus_box.bottom);
+
+       twin_window_damage(pboot_rpane->window,
+                          pboot_rpane->focus_box.left,
+                          pboot_rpane->focus_box.top,
+                          pboot_rpane->focus_box.right,
+                          pboot_rpane->focus_box.bottom);
+
+       twin_window_queue_paint(pboot_lpane->window);
+       twin_window_queue_paint(pboot_rpane->window);
+
+       pboot_set_rfocus(0);
+}
+
+static void pboot_select_lpane(void)
+{
+       if (pboot_focus_lpane == 1)
+               return;
+       pboot_focus_lpane = 1;
+
+       twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
+
+       twin_window_damage(pboot_lpane->window,
+                          pboot_lpane->focus_box.left,
+                          pboot_lpane->focus_box.top,
+                          pboot_lpane->focus_box.right,
+                          pboot_lpane->focus_box.bottom);
+
+       twin_window_damage(pboot_rpane->window,
+                          pboot_rpane->focus_box.left,
+                          pboot_rpane->focus_box.top,
+                          pboot_rpane->focus_box.right,
+                          pboot_rpane->focus_box.bottom);
+
+       twin_window_queue_paint(pboot_lpane->window);
+       twin_window_queue_paint(pboot_rpane->window);
+}
+
+static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
+{
+       pboot_device_t  *dev;
+       pboot_option_t  *opt;
+       int             candidate = -1;
+
+       if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
+               return;
+       dev = pboot_devices[pboot_dev_sel];
+
+       if (y < PBOOT_RIGHT_OPTION_TMARGIN)
+               goto miss;
+       candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
+               PBOOT_RIGHT_OPTION_STRIDE;
+       if (candidate >= dev->option_count) {
+               candidate = -1;
+               goto miss;
+       }
+       if (candidate == pboot_rpane->mouse_target)
+               return;
+       opt = &dev->options[candidate];
+       if (x < opt->box.left || x > opt->box.right ||
+           y < opt->box.top || y > opt->box.bottom) {
+               candidate = -1;
+               goto miss;
+       }
+
+       /* Ok, so now, we know the mouse hit an icon that wasn't the same
+        * as the previous one, we trigger a focus change
+        */
+       pboot_set_rfocus(candidate);
+
+ miss:
+       pboot_rpane->mouse_target = candidate;
+}
+
+static void pboot_choose_option(void)
+{
+       pboot_device_t *dev = pboot_devices[pboot_dev_sel];
+       pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
+
+       LOG("Selected device %s\n", opt->title);
+       pboot_message("booting %s...", opt->title);
+
+       /* Give user feedback, make sure errors and panics will be seen */
+       pboot_exec_option(opt->data);
+}
+
+static twin_bool_t pboot_rpane_event (twin_window_t        *window,
+                                     twin_event_t          *event)
+{
+       /* filter out all mouse events */
+       switch(event->kind) {
+       case TwinEventEnter:
+       case TwinEventMotion:
+       case TwinEventLeave:
+               pboot_select_rpane();
+               pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
+               return TWIN_TRUE;
+       case TwinEventButtonDown:
+               pboot_select_rpane();
+               pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
+               pboot_choose_option();
+       case TwinEventButtonUp:
+               return TWIN_TRUE;
+       case TwinEventKeyDown:
+               switch(event->u.key.key) {
+               case KEY_UP:
+                       pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
+                       return TWIN_TRUE;
+               case KEY_DOWN:
+                       pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
+                       return TWIN_TRUE;
+               case KEY_LEFT:
+                       pboot_select_lpane();
+                       return TWIN_TRUE;
+               case KEY_ENTER:
+                       pboot_choose_option();
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       return TWIN_FALSE;
+}
+
+
+int pboot_add_option(int devindex, const char *title,
+                    const char *subtitle, twin_pixmap_t *badge, void *data)
+{
+       pboot_device_t  *dev;
+       pboot_option_t  *opt;
+       twin_coord_t    width;
+       int             index;
+
+       if (devindex < 0 || devindex >= pboot_dev_count)
+               return -1;
+       dev = pboot_devices[devindex];
+
+       if (dev->option_count >= PBOOT_MAX_OPTION)
+               return -1;
+       index = dev->option_count++;
+       opt = &dev->options[index];
+
+       opt->title = malloc(strlen(title) + 1);
+       strcpy(opt->title, title);
+
+       if (subtitle) {
+               opt->subtitle = malloc(strlen(subtitle) + 1);
+               strcpy(opt->subtitle, subtitle);
+       } else
+               opt->subtitle = NULL;
+
+       opt->badge = badge;
+       opt->cache = NULL;
+
+       width = pboot_rpane->window->pixmap->width -
+               (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
+
+       opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
+       opt->box.right = opt->box.left + width;
+       opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
+               index * PBOOT_RIGHT_OPTION_STRIDE;
+       opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
+
+       opt->data = data;
+       return index;
+}
+
+
+static void pboot_set_device_select(int sel, int force)
+{
+       LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
+       if (!force && sel == pboot_dev_sel)
+               return;
+       if (sel >= pboot_dev_count)
+               return;
+       pboot_dev_sel = sel;
+       if (force) {
+               pboot_lpane->focus_curindex = sel;
+               if (sel < 0)
+                       pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
+               else
+                       pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
+                               PBOOT_LEFT_ICON_STRIDE * sel;
+               pboot_rpane->focus_box.bottom = pboot_lpane->focus_target;
+               pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
+                       PBOOT_RIGHT_FOCUS_HEIGHT;
+               twin_window_damage(pboot_lpane->window,
+                                  0, 0,
+                                  pboot_lpane->window->pixmap->width,
+                                  pboot_lpane->window->pixmap->height);
+               twin_window_queue_paint(pboot_lpane->window);
+       }
+       pboot_rpane->focus_curindex = -1;
+       pboot_rpane->mouse_target = -1;
+       pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
+       pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
+               PBOOT_RIGHT_FOCUS_HEIGHT;
+       twin_window_damage(pboot_rpane->window, 0, 0,
+                          pboot_rpane->window->pixmap->width,
+                          pboot_rpane->window->pixmap->height);
+       twin_window_queue_paint(pboot_rpane->window);
+}
+
+static void pboot_create_rpane(void)
+{
+       pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
+       assert(pboot_rpane);
+
+       pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
+                                                TwinWindowPlain,
+                                                PBOOT_LEFT_PANE_SIZE, 0,
+                                                pboot_screen->width -
+                                                  PBOOT_LEFT_PANE_SIZE,
+                                                pboot_screen->height);
+       assert(pboot_rpane->window);
+
+       pboot_rpane->window->draw = pboot_rpane_draw;
+       pboot_rpane->window->event = pboot_rpane_event;
+       pboot_rpane->window->client_data = pboot_rpane;
+
+       pboot_rpane->focus_curindex = -1;
+       pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
+       pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
+       pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
+               2 * PBOOT_RIGHT_FOCUS_XOFF;
+       pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
+               PBOOT_RIGHT_FOCUS_HEIGHT;
+       pboot_rpane->mouse_target = -1;
+       twin_window_show(pboot_rpane->window);
+       twin_window_queue_paint(pboot_rpane->window);
+}
+
+
+static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
+{
+       int dir = 1, dist, pos;
+       const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
+
+       dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
+       dir = dist > 2 ? 2 : dist;
+       pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
+       if (pos == 0) {
+               pboot_set_device_select(pboot_lpane->focus_curindex, 0);
+               return -1;
+       }
+       if (pos < 0) {
+               dir = -1;
+               pos = -pos;
+       }
+       twin_window_damage(pboot_lpane->window,
+                          pboot_lpane->focus_box.left,
+                          pboot_lpane->focus_box.top,
+                          pboot_lpane->focus_box.right,
+                          pboot_lpane->focus_box.bottom);
+
+       pboot_lpane->focus_box.top += dir;
+       pboot_lpane->focus_box.bottom += dir;
+
+       twin_window_damage(pboot_lpane->window,
+                          pboot_lpane->focus_box.left,
+                          pboot_lpane->focus_box.top,
+                          pboot_lpane->focus_box.right,
+                          pboot_lpane->focus_box.bottom);
+
+       twin_window_queue_paint(pboot_lpane->window);
+
+       return accel[(pos * 10) / dist];
+}
+
+static void pboot_set_lfocus(int index)
+{
+       if (index >= pboot_dev_count)
+               return;
+
+       pboot_lpane->focus_start = pboot_lpane->focus_box.top;
+
+       if (index < 0)
+               pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
+       else
+               pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
+                       PBOOT_LEFT_ICON_STRIDE * index;
+
+       pboot_lpane->focus_curindex = index;
+
+       twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
+}
+
+static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
+{
+       int candidate = -1;
+       twin_coord_t icon_top;
+
+       if (x < PBOOT_LEFT_ICON_XOFF ||
+           x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
+               goto miss;
+       if (y < PBOOT_LEFT_ICON_YOFF)
+               goto miss;
+       candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
+       if (candidate >= pboot_dev_count) {
+               candidate = -1;
+               goto miss;
+       }
+       if (candidate == pboot_lpane->mouse_target)
+               return;
+       icon_top = PBOOT_LEFT_ICON_YOFF +
+               candidate * PBOOT_LEFT_ICON_STRIDE;
+       if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
+               candidate = -1;
+               goto miss;
+       }
+
+       /* Ok, so now, we know the mouse hit an icon that wasn't the same
+        * as the previous one, we trigger a focus change
+        */
+       pboot_set_lfocus(candidate);
+
+ miss:
+       pboot_lpane->mouse_target = candidate;
+}
+
+static twin_bool_t pboot_lpane_event (twin_window_t        *window,
+                                     twin_event_t          *event)
+{
+       /* filter out all mouse events */
+       switch(event->kind) {
+       case TwinEventEnter:
+       case TwinEventMotion:
+       case TwinEventLeave:
+               pboot_select_lpane();
+               pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
+               return TWIN_TRUE;
+       case TwinEventButtonDown:
+       case TwinEventButtonUp:
+               return TWIN_TRUE;
+       case TwinEventKeyDown:
+               switch(event->u.key.key) {
+               case KEY_UP:
+                       if (pboot_lpane->focus_curindex > 0)
+                               pboot_set_lfocus(
+                                       pboot_lpane->focus_curindex - 1);
+                       return TWIN_TRUE;
+               case KEY_DOWN:
+                       pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
+                       return TWIN_TRUE;
+               case KEY_RIGHT:
+                       pboot_select_rpane();
+                       return TWIN_TRUE;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       return TWIN_FALSE;
+}
+
+static void pboot_quit(void)
+{
+       kill(0, SIGINT);
+}
+
+twin_bool_t pboot_event_filter(twin_screen_t       *screen,
+                              twin_event_t         *event)
+{
+       switch(event->kind) {
+       case TwinEventEnter:
+       case TwinEventMotion:
+       case TwinEventLeave:
+       case TwinEventButtonDown:
+       case TwinEventButtonUp:
+               if (pboot_cursor != NULL)
+                       twin_screen_set_cursor(pboot_screen, pboot_cursor,
+                                              pboot_cursor_hx,
+                                              pboot_cursor_hy);
+               break;
+       case TwinEventJoyButton:
+               /* map joystick events into key events */
+               if (event->u.js.control >= sizeof(sixaxis_map))
+                       break;
+
+               event->u.key.key = sixaxis_map[event->u.js.control];
+               if (event->u.js.value == 0) {
+                       event->kind = TwinEventKeyUp;
+                       break;
+               } else {
+                       event->kind = TwinEventKeyDown;
+               }
+
+               /* fall through.. */
+       case TwinEventKeyDown:
+               switch(event->u.key.key) {
+               /* Gross hack for video modes, need something better ! */
+               case KEY_0:
+                       pboot_vmode_change = 0; /* auto */
+                       pboot_quit();
+                       return TWIN_TRUE;
+               case KEY_1:
+                       pboot_vmode_change = 3; /* 720p */
+                       pboot_quit();
+                       return TWIN_TRUE;
+               case KEY_2:
+                       pboot_vmode_change = 4; /* 1080i */
+                       pboot_quit();
+                       return TWIN_TRUE;
+               case KEY_3:
+                       pboot_vmode_change = 5; /* 1080p */
+                       pboot_quit();
+                       return TWIN_TRUE;
+
+               /* Another gross hack for booting back to gameos */
+               case KEY_BACKSPACE:
+               case KEY_DELETE:
+                       pboot_message("booting to GameOS...");
+                       system(BOOT_GAMEOS_BIN);
+               }
+       case TwinEventKeyUp:
+               twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
+               break;
+       default:
+               break;
+       }
+       return TWIN_FALSE;
+}
+
+static void pboot_lpane_draw(twin_window_t *window)
+{
+       twin_pixmap_t   *px = window->pixmap;
+       pboot_lpane_t   *lpane = window->client_data;
+       twin_path_t     *path;
+       twin_fixed_t    x, y, w, h;
+       int             i;
+
+       /* Fill background */
+       twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
+                 0, 0, px->width, px->height);
+
+       /* Create a path for use later */
+       path = twin_path_create();
+       assert(path);
+
+       /* Draw right line if needed */
+       if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
+               x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
+               y = twin_int_to_fixed(px->height);
+               twin_path_rectangle(path, x, 0, 0x40000, y);
+               twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
+               twin_path_empty(path);
+       }
+
+       /* Draw focus box */
+       if (lpane->focus_curindex >= 0 &&
+           twin_rect_intersect(lpane->focus_box, px->clip)) {
+               x = twin_int_to_fixed(lpane->focus_box.left + 2);
+               y = twin_int_to_fixed(lpane->focus_box.top + 2);
+               w = twin_int_to_fixed(lpane->focus_box.right -
+                                     lpane->focus_box.left - 4);
+               h = twin_int_to_fixed(lpane->focus_box.bottom -
+                                     lpane->focus_box.top - 4);
+               twin_path_rounded_rectangle(path, x, y, w, h,
+                                           PBOOT_LEFT_FOCUS_XRAD,
+                                           PBOOT_LEFT_FOCUS_YRAD);
+               if (pboot_focus_lpane)
+                       twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
+               else
+                       twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
+                                         4 * TWIN_FIXED_ONE);
+       }
+
+       /* Draw icons */
+       for (i = 0; i < pboot_dev_count; i++) {
+               pboot_device_t  *dev = pboot_devices[i];
+               twin_operand_t  src;
+
+               if (!twin_rect_intersect(dev->box, px->clip))
+                       continue;
+
+               src.source_kind = TWIN_PIXMAP;
+               src.u.pixmap = dev->badge;
+
+               twin_composite(px, dev->box.left, dev->box.top,
+                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
+                              dev->box.right - dev->box.left,
+                              dev->box.bottom - dev->box.top);
+
+       }
+
+       /* Destroy path */
+       twin_path_destroy(path);
+}
+
+static void pboot_create_lpane(void)
+{
+       pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
+       assert(pboot_lpane);
+
+       pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
+                                                TwinWindowPlain,
+                                                0, 0, PBOOT_LEFT_PANE_SIZE,
+                                                pboot_screen->height);
+       assert(pboot_lpane->window);
+
+       pboot_lpane->window->draw = pboot_lpane_draw;
+       pboot_lpane->window->event = pboot_lpane_event;
+       pboot_lpane->window->client_data = pboot_lpane;
+       pboot_lpane->focus_curindex = -1;
+       pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
+       pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
+       pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
+               PBOOT_LEFT_FOCUS_WIDTH;
+       pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
+               PBOOT_LEFT_FOCUS_HEIGHT;
+       pboot_lpane->mouse_target = -1;
+       twin_window_show(pboot_lpane->window);
+       twin_window_queue_paint(pboot_lpane->window);
+}
+
+static void pboot_spane_draw(twin_window_t *window)
+{
+       twin_pixmap_t   *px = window->pixmap;
+       pboot_spane_t   *spane = window->client_data;
+       twin_path_t     *path;
+       twin_fixed_t    tx, ty;
+
+       /* Fill background */
+       twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
+                 0, 0, px->width, px->height);
+
+       path = twin_path_create();
+       assert(path);
+
+       twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
+       twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
+       tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
+       ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
+       twin_path_move (path, tx, ty);
+       twin_path_utf8 (path, spane->text);
+       twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
+
+       twin_path_destroy(path);
+}
+
+void pboot_message(const char *fmt, ...)
+{
+       va_list ap;
+       char *msg;
+
+       if (pboot_spane->text)
+               free(pboot_spane->text);
+
+       va_start(ap, fmt);
+       vasprintf(&msg, fmt, ap);
+       va_end(ap);
+
+       pboot_spane->text = msg;
+       twin_window_damage(pboot_spane->window,
+                          0, 0,
+                          pboot_spane->window->pixmap->width,
+                          pboot_spane->window->pixmap->height);
+       twin_window_draw(pboot_spane->window);
+}
+
+static void pboot_create_spane(void)
+{
+       pboot_spane = calloc(1, sizeof(pboot_spane_t));
+       assert(pboot_spane);
+
+       pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
+                                                TwinWindowPlain,
+                                                PBOOT_LEFT_PANE_SIZE +
+                                                 PBOOT_STATUS_PANE_XYMARGIN,
+                                                pboot_screen->height - 
+                                                 PBOOT_STATUS_PANE_HEIGHT,
+                                                pboot_screen->width -
+                                                 PBOOT_LEFT_PANE_SIZE -
+                                                 2*PBOOT_STATUS_PANE_XYMARGIN,
+                                                PBOOT_STATUS_PANE_HEIGHT);
+       assert(pboot_spane->window);
+
+       pboot_spane->window->draw = pboot_spane_draw;
+       pboot_spane->window->client_data = pboot_spane;
+       pboot_spane->text = strdup(PBOOT_INITIAL_MESSAGE);
+       twin_window_show(pboot_spane->window);
+       twin_window_queue_paint(pboot_spane->window);
+}
+
+int pboot_add_device(const char *dev_id, const char *name,
+               twin_pixmap_t *pixmap)
+{
+       int             index;
+       pboot_device_t  *dev;
+
+       if (pboot_dev_count >= PBOOT_MAX_DEV)
+               return -1;
+
+       index = pboot_dev_count++;
+
+       dev = malloc(sizeof(*dev));
+       memset(dev, 0, sizeof(*dev));
+       dev->id = malloc(strlen(dev_id) + 1);
+       strcpy(dev->id, dev_id);
+       dev->badge = pixmap;
+       dev->box.left = PBOOT_LEFT_ICON_XOFF;
+       dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
+       dev->box.top = PBOOT_LEFT_ICON_YOFF +
+               PBOOT_LEFT_ICON_STRIDE * index;
+       dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
+
+       pboot_devices[index] = dev;
+
+       twin_window_damage(pboot_lpane->window,
+                          dev->box.left, dev->box.top,
+                          dev->box.right, dev->box.bottom);
+       twin_window_queue_paint(pboot_lpane->window);
+
+       return index;
+}
+
+int pboot_remove_device(const char *dev_id)
+{
+       pboot_device_t  *dev = NULL;
+       int             i, newsel = pboot_dev_sel;
+
+       /* find the matching device */
+       for (i = 0; i < pboot_dev_count; i++) {
+               if (!strcmp(pboot_devices[i]->id, dev_id)) {
+                       dev = pboot_devices[i];
+                       break;
+               }
+       }
+
+       if (!dev)
+               return TWIN_FALSE;
+
+       memmove(pboot_devices + i, pboot_devices + i + 1,
+                       sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
+       pboot_devices[--pboot_dev_count] = NULL;
+
+       /* select the newly-focussed device */
+       if (pboot_dev_sel > i)
+               newsel = pboot_dev_sel - 1;
+       else if (pboot_dev_sel == i && i >= pboot_dev_count)
+                       newsel = pboot_dev_count - 1;
+       pboot_set_device_select(newsel, 1);
+
+       /* todo: free device & options */
+
+       return TWIN_TRUE;
+}
+
+static void pboot_make_background(void)
+{
+       twin_pixmap_t   *filepic, *scaledpic;
+       const char      *background_path;
+
+       /* Set background pixmap */
+       LOG("loading background...");
+       background_path = artwork_pathname("background.jpg");
+       filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
+       LOG("%s\n", filepic ? "ok" : "failed");
+
+       if (filepic == NULL)
+               return;
+
+       if (pboot_screen->height == filepic->height &&
+           pboot_screen->width == filepic->width)
+               scaledpic = filepic;
+       else {
+               twin_fixed_t    sx, sy;
+               twin_operand_t  srcop;
+
+               scaledpic = twin_pixmap_create(TWIN_ARGB32,
+                                              pboot_screen->width,
+                                              pboot_screen->height);
+               if (scaledpic == NULL) {
+                       twin_pixmap_destroy(filepic);
+                       return;
+               }
+               sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
+                                   twin_int_to_fixed(pboot_screen->width));
+               sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
+                                   twin_int_to_fixed(pboot_screen->height));
+               
+               twin_matrix_scale(&filepic->transform, sx, sy);
+               srcop.source_kind = TWIN_PIXMAP;
+               srcop.u.pixmap = filepic;
+               twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
+                              NULL, 0, 0, TWIN_SOURCE,
+                              pboot_screen->width, pboot_screen->height);
+               twin_pixmap_destroy(filepic);
+                              
+       }
+       twin_screen_set_background(pboot_screen, scaledpic);
+}
+
+#define PS3FB_IOCTL_SETMODE          _IOW('r',  1, int)
+#define PS3FB_IOCTL_GETMODE          _IOR('r',  2, int)
+
+static void exitfunc(void)
+{
+#ifndef _USE_X11
+       if (pboot_fbdev)
+               twin_fbdev_destroy(pboot_fbdev);
+       pboot_fbdev = NULL;
+       if (pboot_vmode_change != -1) {
+               int fd = open("/dev/fb0", O_RDWR);
+               if (fd >= 0)
+                       ioctl(fd, PS3FB_IOCTL_SETMODE,
+                             (unsigned long)&pboot_vmode_change);
+               close(fd);
+       }
+#endif
+}
+
+static void sigint(int sig)
+{
+       exitfunc();
+       syscall(__NR_exit);
+}
+
+static void usage(const char *progname)
+{
+       fprintf(stderr, "Usage: %s [-u] [-h]\n", progname);
+}
+
+int main(int argc, char **argv)
+{
+       int c;
+       int udev_trigger = 0;
+
+       for (;;) {
+               c = getopt(argc, argv, "u::h");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'u':
+                       udev_trigger = 1;
+                       break;
+               case 'h':
+                       usage(argv[0]);
+                       return EXIT_SUCCESS;
+               default:
+                       fprintf(stderr, "Unknown option '%c'\n", c);
+                       usage(argv[0]);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       atexit(exitfunc);
+       signal(SIGINT, sigint);
+
+#ifdef _USE_X11
+       pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
+       if (pboot_x11 == NULL) {
+               perror("failed to create x11 screen !\n");
+               return 1;
+       }
+       pboot_screen = pboot_x11->screen;
+#else
+       /* Create screen and mouse drivers */
+       pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
+       if (pboot_fbdev == NULL) {
+               perror("failed to create fbdev screen !\n");
+               return 1;
+       }
+       pboot_screen = pboot_fbdev->screen;
+       twin_linux_mouse_create(NULL, pboot_screen);
+       twin_linux_js_create(pboot_screen);
+
+       if (pboot_fbdev != NULL) {
+               char *cursor_path = artwork_pathname("cursor.gz");
+               pboot_cursor = twin_load_X_cursor(cursor_path, 2,
+                                                 &pboot_cursor_hx,
+                                                 &pboot_cursor_hy);
+               if (pboot_cursor == NULL)
+                       pboot_cursor =
+                               twin_get_default_cursor(&pboot_cursor_hx,
+                                                       &pboot_cursor_hy);
+       }
+#endif
+
+       /* Set background pixmap */
+       pboot_make_background();
+
+       /* Init more stuffs */
+       pboot_create_lpane();
+       pboot_create_rpane();
+       pboot_create_spane();
+
+       if (!pboot_start_device_discovery(udev_trigger)) {
+               LOG("Couldn't start device discovery!\n");
+               return 1;
+       }
+
+       pboot_set_lfocus(0);
+       twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
+       pboot_screen->event_filter = pboot_event_filter;
+
+       /* Console switch */
+#ifndef _USE_X11
+       if (pboot_fbdev)
+               twin_fbdev_activate(pboot_fbdev);
+#endif
+
+       /* Process events */
+       twin_dispatch ();
+
+       return 0;
+}