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