From patchwork Fri Nov 7 00:21:11 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geoff Levand X-Patchwork-Id: 7636 X-Patchwork-Delegate: jk@ozlabs.org Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id B5058DE126 for ; Fri, 7 Nov 2008 11:24:40 +1100 (EST) X-Original-To: cbe-oss-dev@ozlabs.org Delivered-To: cbe-oss-dev@ozlabs.org Received: from VA3EHSOBE005.bigfish.com (outbound-va3.frontbridge.com [216.32.180.16]) by ozlabs.org (Postfix) with ESMTP id 5CE0FDDFF7; Fri, 7 Nov 2008 11:22:40 +1100 (EST) Received: from mail134-va3-R.bigfish.com (10.7.14.253) by VA3EHSOBE005.bigfish.com (10.7.40.25) with Microsoft SMTP Server id 8.1.291.1; Fri, 7 Nov 2008 00:22:37 +0000 Received: from mail134-va3 (localhost.localdomain [127.0.0.1]) by mail134-va3-R.bigfish.com (Postfix) with ESMTP id 25BE9B081FC; Fri, 7 Nov 2008 00:22:37 +0000 (UTC) X-BigFish: VPS7(zz18c1K655O78fbpc8k19c2kzzzz2b68kz2fh6bh61h) X-Spam-TCS-SCL: 0:0 X-FB-SS: 5, Received: by mail134-va3 (MessageSwitch) id 12260173315041_32641; Fri, 7 Nov 2008 00:22:11 +0000 (UCT) Received: from mail8.fw-sd.sony.com (mail8.fw-sd.sony.com [160.33.66.75]) by mail134-va3.bigfish.com (Postfix) with ESMTP id 53DD61438064; Fri, 7 Nov 2008 00:22:10 +0000 (UTC) Received: from mail3.sjc.in.sel.sony.com (mail3.sjc.in.sel.sony.com [43.134.1.211]) by mail8.fw-sd.sony.com (8.14.2/8.14.2) with ESMTP id mA70M9hV017628; Fri, 7 Nov 2008 00:22:09 GMT Received: from ussdixhub21.spe.sony.com (ussdixhub21.spe.sony.com [43.130.141.76]) by mail3.sjc.in.sel.sony.com (8.12.11/8.12.11) with ESMTP id mA70M9bf000580; Fri, 7 Nov 2008 00:22:09 GMT Received: from USSDIXRG02.am.sony.com (43.130.140.32) by ussdixhub21.spe.sony.com (43.130.141.76) with Microsoft SMTP Server id 8.1.291.1; Thu, 6 Nov 2008 16:22:09 -0800 Received: from ussdixms03.am.sony.com ([43.130.140.23]) by USSDIXRG02.am.sony.com with Microsoft SMTPSVC(5.0.2195.6713); Thu, 6 Nov 2008 16:22:09 -0800 Received: from [192.168.1.10] ([43.135.148.226]) by ussdixms03.am.sony.com with Microsoft SMTPSVC(5.0.2195.6713); Thu, 6 Nov 2008 16:22:08 -0800 Message-ID: <491389F7.9070706@am.sony.com> Date: Thu, 6 Nov 2008 16:21:11 -0800 From: Geoff Levand User-Agent: Thunderbird 2.0.0.16 (X11/20080723) MIME-Version: 1.0 To: jk@ozlabs.org References: <491385D1.2070704@am.sony.com> In-Reply-To: <491385D1.2070704@am.sony.com> X-Enigmail-Version: 0.95.7 X-OriginalArrivalTime: 07 Nov 2008 00:22:08.0390 (UTC) FILETIME=[DEB73A60:01C9406E] X-SEL-encryption-scan: scanned Cc: cbe-oss-dev@ozlabs.org Subject: [Cbe-oss-dev] [patch 5/9] petitboot: Rename the devices directory to lib X-BeenThere: cbe-oss-dev@ozlabs.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Discussion about Open Source Software for the Cell Broadband Engine List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: cbe-oss-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org Errors-To: cbe-oss-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org From: Yuji Mano Rename the 'devices' directory to 'lib'. Most files in the devices directory are shared between the petitboot applications. This change simply renames the directory and makes minor fixups to the makefiles and removes an unneded relative path to the devices directory in devices.c Signed-off-by: Yuji Mano Signed-off-by: Geoff Levand --- This change is a step to convert petitboot into a collection of applications linking to a core petitboot library. Makefile.am | 30 - configure.ac | 2 devices.c | 2 devices/Makefile.am | 17 - devices/kboot-parser.c | 288 ------------------ devices/message.h | 30 - devices/native-parser.c | 124 ------- devices/params.c | 595 ------------------------------------- devices/params.h | 6 devices/parser.c | 85 ----- devices/parser.h | 46 -- devices/paths.c | 141 -------- devices/paths.h | 53 --- devices/petitboot-udev-helper.c | 636 ---------------------------------------- devices/yaboot-cfg.c | 491 ------------------------------ devices/yaboot-cfg.h | 30 - devices/yaboot-parser.c | 235 -------------- lib/Makefile.am | 17 + lib/kboot-parser.c | 288 ++++++++++++++++++ lib/message.h | 30 + lib/native-parser.c | 124 +++++++ lib/params.c | 595 +++++++++++++++++++++++++++++++++++++ lib/params.h | 6 lib/parser.c | 85 +++++ lib/parser.h | 46 ++ lib/paths.c | 141 ++++++++ lib/paths.h | 53 +++ lib/petitboot-udev-helper.c | 636 ++++++++++++++++++++++++++++++++++++++++ lib/yaboot-cfg.c | 491 ++++++++++++++++++++++++++++++ lib/yaboot-cfg.h | 30 + lib/yaboot-parser.c | 235 ++++++++++++++ test/Makefile.am | 16 - 32 files changed, 2802 insertions(+), 2802 deletions(-) --- 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 #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 -#include -#include -#include -#include - -#include -#include -#include - -#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 -#include -#include - -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 -#include -#include -#include - -#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: - * - * :== {
} EOF - * - *
:==
{ } - * - *
:== '[' NAME ']' - * - * :== 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 . - */ - -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 - * . False if failed or if a lexical error was - * encountered. - * - * ------------------------------------------------------------------------ ** - */ - { - int c; - int i; - int end; - char *func = "params.c:Section() -"; - - i = 0; /* is the offset of the next free byte in bufr[] and */ - end = 0; /* 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 */ - /* will be one less than . */ - - 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 . 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 -#include -#include - -#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 -#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 -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include - -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 +#include +#include +#include +#include + +#include +#include +#include + +#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 +#include +#include + +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 +#include +#include +#include + +#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: + * + * :== {
} EOF + * + *
:==
{ } + * + *
:== '[' NAME ']' + * + * :== 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 . + */ + +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 + * . False if failed or if a lexical error was + * encountered. + * + * ------------------------------------------------------------------------ ** + */ + { + int c; + int i; + int end; + char *func = "params.c:Section() -"; + + i = 0; /* is the offset of the next free byte in bufr[] and */ + end = 0; /* 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 */ + /* will be one less than . */ + + 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 . 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 +#include +#include + +#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 +#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 +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +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