--- a/Makefile.am
+++ b/Makefile.am
@@ -14,9 +14,9 @@
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
-SUBDIRS = artwork devices utils test
+SUBDIRS = artwork lib utils test
 
-AM_CPPFLAGS = -I$(includedir) \
+AM_CPPFLAGS = -I$(srcdir)/lib -I$(includedir) \
  -DPKG_SHARE_DIR="\"$(datadir)/petitboot\""
 
 AM_CFLAGS = \
@@ -37,22 +37,22 @@ sbin_PROGRAMS = petitboot-udev-helper pe
 petitboot_headers = \
 	petitboot.h \
 	petitboot-paths.h \
-	devices/params.h \
-	devices/yaboot-cfg.h \
-	devices/parser.h \
-	devices/paths.h \
-	devices/message.h
+	lib/params.h \
+	lib/yaboot-cfg.h \
+	lib/parser.h \
+	lib/paths.h \
+	lib/message.h
 
 petitboot_udev_helper_SOURCES = \
 	$(petitboot_headers) \
-	devices/petitboot-udev-helper.c \
-	devices/params.c \
-	devices/parser.c \
-	devices/paths.c \
-	devices/yaboot-cfg.c \
-	devices/native-parser.c \
-	devices/yaboot-parser.c \
-	devices/kboot-parser.c
+	lib/petitboot-udev-helper.c \
+	lib/params.c \
+	lib/parser.c \
+	lib/paths.c \
+	lib/yaboot-cfg.c \
+	lib/native-parser.c \
+	lib/yaboot-parser.c \
+	lib/kboot-parser.c
 
 petitboot_SOURCES = \
 	$(petitboot_headers) \
--- a/configure.ac
+++ b/configure.ac
@@ -22,7 +22,7 @@ AC_PROG_LIBTOOL
 AM_INIT_AUTOMAKE
 AC_SUBST([DESTDIR])
 AC_CONFIG_HEADERS([config.h])
-AC_CONFIG_FILES([Makefile artwork/Makefile devices/Makefile test/Makefile \
+AC_CONFIG_FILES([Makefile artwork/Makefile lib/Makefile test/Makefile \
 	utils/Makefile])
 
 AC_OUTPUT
--- a/devices.c
+++ b/devices.c
@@ -11,7 +11,7 @@
 #include <libtwin/twin_png.h>
 #include "petitboot.h"
 #include "petitboot-paths.h"
-#include "devices/message.h"
+#include "message.h"
 
 #define PBOOT_DEFAULT_ICON	"tux.png"
 
--- a/devices/Makefile.am
+++ /dev/null
@@ -1,17 +0,0 @@
-## Makefile.am -- Process this file with automake to produce Makefile.in
-#
-#  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; version 2 of the License.
-#
-#  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
-#
-
-MAINTAINERCLEANFILES = Makefile.in
--- a/devices/kboot-parser.c
+++ /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
-};
--- a/devices/message.h
+++ /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 */
--- a/devices/native-parser.c
+++ /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
-};
-
-
-
--- a/devices/params.c
+++ /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 */
-
-/* -------------------------------------------------------------------------- */
-
--- a/devices/params.h
+++ /dev/null
@@ -1,6 +0,0 @@
-
-#define BOOL int
-
-BOOL pm_process( char *FileName,
-                 BOOL (*sfunc)(char *),
-                 BOOL (*pfunc)(char *, char *) );
--- a/devices/parser.c
+++ /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");
-}
-
--- a/devices/parser.h
+++ /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 */
--- a/devices/paths.c
+++ /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;
-}
-
--- a/devices/paths.h
+++ /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 */
--- a/devices/petitboot-udev-helper.c
+++ /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;
-}
--- a/devices/yaboot-cfg.c
+++ /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);
-}
-
-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:
- */
--- a/devices/yaboot-cfg.h
+++ /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
--- a/devices/yaboot-parser.c
+++ /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
-};
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,17 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+#
+#  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; version 2 of the License.
+#
+#  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
+#
+
+MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+++ b/lib/kboot-parser.c
@@ -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
+};
--- /dev/null
+++ b/lib/message.h
@@ -0,0 +1,30 @@
+
+#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 */
--- /dev/null
+++ b/lib/native-parser.c
@@ -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
+};
+
+
+
--- /dev/null
+++ b/lib/params.c
@@ -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 */
+
+/* -------------------------------------------------------------------------- */
+
--- /dev/null
+++ b/lib/params.h
@@ -0,0 +1,6 @@
+
+#define BOOL int
+
+BOOL pm_process( char *FileName,
+                 BOOL (*sfunc)(char *),
+                 BOOL (*pfunc)(char *, char *) );
--- /dev/null
+++ b/lib/parser.c
@@ -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");
+}
+
--- /dev/null
+++ b/lib/parser.h
@@ -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 */
--- /dev/null
+++ b/lib/paths.c
@@ -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;
+}
+
--- /dev/null
+++ b/lib/paths.h
@@ -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 */
--- /dev/null
+++ b/lib/petitboot-udev-helper.c
@@ -0,0 +1,636 @@
+
+#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;
+}
--- /dev/null
+++ b/lib/yaboot-cfg.c
@@ -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);
+}
+
+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:
+ */
--- /dev/null
+++ b/lib/yaboot-cfg.h
@@ -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
--- /dev/null
+++ b/lib/yaboot-parser.c
@@ -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
+};
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -14,7 +14,7 @@
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
-AM_CPPFLAGS = -I$(srcdir)/.. -I$(srcdir)/../devices -I$(includedir)
+AM_CPPFLAGS = -I$(srcdir)/.. -I$(srcdir)/../lib -I$(includedir)
 
 AM_CFLAGS = \
 	-g \
@@ -35,13 +35,13 @@ check_SCRIPTS = parser-test.sh
 
 parser_test_SOURCES = \
 	parser-test.c \
-	../devices/params.c \
-	../devices/parser.c \
-	../devices/paths.c \
-	../devices/yaboot-cfg.c \
-	../devices/native-parser.c \
-	../devices/yaboot-parser.c \
-	../devices/kboot-parser.c
+	../lib/params.c \
+	../lib/parser.c \
+	../lib/paths.c \
+	../lib/yaboot-cfg.c \
+	../lib/native-parser.c \
+	../lib/yaboot-parser.c \
+	../lib/kboot-parser.c
 
 composed_scripts = parser-test.sh
 
