Add some basic yaboot.conf parsing support
authorDavid Woodhouse <dwmw2@infradead.org>
Mon, 2 Apr 2007 06:30:49 +0000 (16:30 +1000)
committerJeremy Kerr <jk@ozlabs.org>
Tue, 3 Apr 2007 04:15:24 +0000 (14:15 +1000)
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Makefile
devices/native-parser.c
devices/udev-helper.c
devices/udev-helper.h
devices/yaboot-cfg.c [new file with mode: 0644]
devices/yaboot-cfg.h [new file with mode: 0644]
devices/yaboot-parser.c [new file with mode: 0644]

index 64a8c46e630bc8fbc759a20a3a30dfa2957d4089..642850d84ef578284644525bb71283d9e84c823a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ TWIN_LDFLAGS=$(shell pkg-config --libs libtwin)
 LDFLAGS = 
 CFLAGS = -O0 -ggdb -Wall '-DPREFIX="$(PREFIX)"'
 
-PARSERS = native
+PARSERS = native yaboot
 ARTWORK = background.png cdrom.png hdd.png usbpen.png cursor
 
 all: petitboot udev-helper
@@ -20,7 +20,7 @@ petitboot: petitboot.o devices.o
 petitboot: LDFLAGS+=$(TWIN_LDFLAGS)
 petitboot: CFLAGS+=$(TWIN_CFLAGS)
 
-udev-helper: devices/udev-helper.o devices/params.o \
+udev-helper: devices/udev-helper.o devices/params.o devices/yaboot-cfg.o \
                $(foreach p,$(PARSERS),devices/$(p)-parser.o)
        $(CC) $(LDFLAGS) -o $@ $^
 
index f47fdca0c3ac2871e7124b96847426962dc99a5b..bb1ca51e3e3e720bc9ab81588eb28dddd4d0e70a 100644 (file)
@@ -102,6 +102,7 @@ static int parameter(char *param_name, char *param_value)
 int parse(const char *devicepath, const char *_mountpoint)
 {
        char *filepath;
+       int rc;
 
        mountpoint = _mountpoint;
 
@@ -112,7 +113,9 @@ int parse(const char *devicepath, const char *_mountpoint)
        memset(dev, 0, sizeof(*dev));
        dev->id = strdup(devicepath);
 
-       pm_process(filepath, section, parameter);
+       rc = pm_process(filepath, section, parameter);
+       if (!rc)
+               return 0;
 
        if (cur_opt) {
                add_boot_option(cur_opt);
index ade97872e3b075f20419b5667ea9a733e61e37c1..a3f47a56c1229775b6b63a2a6f64193287f45817 100644 (file)
 #include "petitboot-paths.h"
 
 extern struct parser native_parser;
+extern struct parser yaboot_parser;
 static FILE *logf;
 static int sock;
 
 /* array of parsers, ordered by priority */
 static struct parser *parsers[] = {
        &native_parser,
+       &yaboot_parser,
        NULL
 };
 
@@ -48,13 +50,14 @@ static void print_boot_option(const struct boot_option *opt)
        log("\tname: %s\n", opt->name);
        log("\tdescription: %s\n", opt->description);
        log("\tboot_image: %s\n", opt->boot_image_file);
+       log("\tinitrd: %s\n", opt->initrd_file);
        log("\tboot_args: %s\n", opt->boot_args);
 
 }
 
 static void print_device(const struct device *dev)
 {
-       log("\tid: %s\n", dev->name);
+       log("\tid: %s\n", dev->id);
        log("\tname: %s\n", dev->name);
        log("\tdescription: %s\n", dev->description);
        log("\tboot_image: %s\n", dev->icon_file);
@@ -221,16 +224,21 @@ int connect_to_socket()
 #endif
 }
 
-#define template "mnt-XXXXXX"
-
-static int mount_device(const char *dev_path, char *mount_path)
+int mount_device(const char *dev_path, char *mount_path)
 {
        char *dir;
+       const char *basename;
        int pid, status, rc = -1;
 
-       /* create a unique mountpoint */
-       dir = malloc(strlen(TMP_DIR) + 2 + strlen(template));
-       sprintf(dir, "%s/%s", TMP_DIR, template);
+       basename = strrchr(dev_path, '/');
+       if (basename)
+               basename++;
+       else
+               basename = dev_path;
+       /* create a unique mountpoint */
+       dir = malloc(strlen(TMP_DIR) + 13 + strlen(basename));
+       sprintf(dir, "%s/mnt-%s-XXXXXX", TMP_DIR, basename);
 
        if (!mkdtemp(dir)) {
                log("failed to create temporary directory in %s: %s",
@@ -414,7 +422,9 @@ int main(int argc, char **argv)
 
                remove_device(dev_path);
 
-               unmount_device(dev_path);
+               /* Unmount it repeatedly, if needs be */
+               while (!unmount_device(dev_path))
+                       ;
 
        } else {
                log("invalid action '%s'\n", action);
index ea5400c58f28f1a25ab46611b97971742bd25d7b..10e5d2b032d28e39bc2953c32ea400f5c1885abd 100644 (file)
@@ -6,6 +6,8 @@ int add_device(const struct device *dev);
 int add_boot_option(const struct boot_option *opt);
 void free_boot_option(struct boot_option *opt);
 
+int mount_device(const char *dev_path, char *mount_path);
+
 struct parser {
        char *name;
        int priority;
diff --git a/devices/yaboot-cfg.c b/devices/yaboot-cfg.c
new file mode 100644 (file)
index 0000000..a252bdb
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ *  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>
+#include <libio.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);
+}
+
+inline 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
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/devices/yaboot-parser.c b/devices/yaboot-parser.c
new file mode 100644 (file)
index 0000000..ee1b992
--- /dev/null
@@ -0,0 +1,252 @@
+
+#include "udev-helper.h"
+#include "params.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 const char *mountpoint;
+static char partition_mntpoint[PATH_MAX];
+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 char *prepend_mountpoint(const char *path)
+{
+       char *full_path;
+
+       full_path = malloc(strlen(path) + strlen(mountpoint) + 2);
+
+       strcpy(full_path, mountpoint);
+       if (path[0] != '/')
+               strcat(full_path, "/");
+       strcat(full_path, path);
+
+       return full_path;
+}
+
+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 = prepend_mountpoint(cfgopt);
+       if (cfgopt == defimage)
+               printf("This one is default. What do we do about it?\n");
+
+       cfgopt = cfg_get_strg(label, "initrd");
+       if (cfgopt)
+               opt.initrd_file = prepend_mountpoint(cfgopt);
+
+       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 *devicepath, const char *_mountpoint)
+{
+       char *filepath;
+       char *conf_file;
+       char *tmpstr;
+       ssize_t conf_len;
+       int fd;
+       struct stat st;
+       char *label;
+
+       mountpoint = _mountpoint;
+
+       filepath = prepend_mountpoint("/etc/yaboot.conf");
+
+       fd = open(filepath, O_RDONLY);
+       if (fd < 0) {
+               free(filepath);
+               filepath = prepend_mountpoint("/yaboot.conf");
+               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)) {
+               printf("Error parsing yaboot.conf\n");
+               return 0;
+       }
+
+       free(filepath);
+
+       dev = malloc(sizeof(*dev));
+       memset(dev, 0, sizeof(*dev));
+       dev->id = strdup(devicepath);
+       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()));
+
+       /* Mount the 'partition' which is what all the image filenames
+          are relative to */
+       tmpstr = cfg_get_strg(0, "partition");
+       if (tmpstr) {
+               char *endp;
+               int partnr = strtol(tmpstr, &endp, 10);
+               if (endp != tmpstr && !*endp) {
+                       char *new_dev = malloc(strlen(devicepath) + strlen(tmpstr) + 1);
+                       if (!new_dev)
+                               return 0;
+
+                       strcpy(new_dev, devicepath);
+
+                       /* Strip digits (partition number) from string */
+                       endp = &new_dev[strlen(devicepath) - 1];
+                       while (isdigit(*endp))
+                               *(endp--) = 0;
+
+                       /* and add our own... */
+                       sprintf(endp+1, "%d", partnr);
+
+                       /* FIXME: udev may not have created the device node
+                          yet. And on removal, unmount_device() only unmounts
+                          it once, while in fact it may be mounted twice. */
+                       if (mount_device(new_dev, partition_mntpoint)) {
+                               printf("Error mounting image partition\n");
+                               return 0;
+                       }
+                       mountpoint = partition_mntpoint;
+                       dev->id = 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
+};