--- /dev/null
+
+#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
+};