summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in1
-rw-r--r--configure.ac2
-rw-r--r--devices.c313
-rw-r--r--devices/petitboot-udev-helper.c636
-rw-r--r--discover/discover-server.c227
-rw-r--r--discover/discover-server.h10
-rw-r--r--discover/kboot-parser.c (renamed from devices/kboot-parser.c)0
-rw-r--r--discover/log.c24
-rw-r--r--discover/log.h6
-rw-r--r--discover/message.h (renamed from devices/message.h)19
-rw-r--r--discover/native-parser.c (renamed from devices/native-parser.c)0
-rw-r--r--discover/params.c (renamed from devices/params.c)0
-rw-r--r--discover/params.h (renamed from devices/params.h)0
-rw-r--r--discover/parser.c (renamed from devices/parser.c)0
-rw-r--r--discover/parser.h (renamed from devices/parser.h)0
-rw-r--r--discover/paths.c (renamed from devices/paths.c)0
-rw-r--r--discover/paths.h (renamed from devices/paths.h)0
-rw-r--r--discover/pb-discover.c34
-rw-r--r--discover/pb-discover.h6
-rw-r--r--discover/udev.c208
-rw-r--r--discover/udev.h26
-rw-r--r--discover/waiter.c83
-rw-r--r--discover/waiter.h23
-rw-r--r--discover/yaboot-cfg.c (renamed from devices/yaboot-cfg.c)0
-rw-r--r--discover/yaboot-cfg.h (renamed from devices/yaboot-cfg.h)0
-rw-r--r--discover/yaboot-parser.c (renamed from devices/yaboot-parser.c)0
-rw-r--r--lib/list/list.c24
-rw-r--r--lib/list/list.h39
-rw-r--r--lib/pb-protocol/pb-protocol.c307
-rw-r--r--lib/pb-protocol/pb-protocol.h57
-rw-r--r--lib/talloc/talloc.c1130
-rw-r--r--lib/talloc/talloc.h137
-rw-r--r--petitboot-paths.h24
-rw-r--r--petitboot.h18
-rw-r--r--rules.mk53
-rw-r--r--test/parser-test.c (renamed from devices/parser-test.c)0
-rwxr-xr-xtest/parser-test.sh (renamed from devices/parser-test.sh)0
-rw-r--r--test/parser/001/expected-output (renamed from devices/parser-tests/001/expected-output)0
-rw-r--r--test/parser/001/ps3da1/etc/kboot.conf (renamed from devices/parser-tests/001/ps3da1/etc/kboot.conf)0
-rw-r--r--test/parser/002/expected-output (renamed from devices/parser-tests/002/expected-output)0
-rw-r--r--test/parser/002/ps3da1/etc/yaboot.conf (renamed from devices/parser-tests/002/ps3da1/etc/yaboot.conf)0
-rw-r--r--test/parser/003/expected-output (renamed from devices/parser-tests/003/expected-output)0
-rw-r--r--test/parser/003/ps3da1/etc/kboot.conf (renamed from devices/parser-tests/003/ps3da1/etc/kboot.conf)0
-rw-r--r--test/parser/004/expected-output (renamed from devices/parser-tests/004/expected-output)0
-rw-r--r--test/parser/004/rootdev (renamed from devices/parser-tests/004/rootdev)0
-rw-r--r--test/parser/004/sda1/etc/kboot.conf (renamed from devices/parser-tests/004/sda1/etc/kboot.conf)0
-rw-r--r--test/parser/005/expected-output (renamed from devices/parser-tests/005/expected-output)0
-rw-r--r--test/parser/005/ps3da1/etc/kboot.conf (renamed from devices/parser-tests/005/ps3da1/etc/kboot.conf)0
-rw-r--r--test/parser/101/expected-output (renamed from devices/parser-tests/101/expected-output)0
-rw-r--r--test/parser/101/ps3da1/etc/kboot.conf (renamed from devices/parser-tests/101/ps3da1/etc/kboot.conf)0
-rw-r--r--test/parser/102/expected-output (renamed from devices/parser-tests/102/expected-output)0
-rw-r--r--test/parser/102/ps3da1/etc/kboot.conf (renamed from devices/parser-tests/102/ps3da1/etc/kboot.conf)0
-rw-r--r--ui/common/discover-client.c111
-rw-r--r--ui/common/discover-client.h29
-rw-r--r--ui/test/pb-test.c62
-rw-r--r--ui/twin/artwork/background.jpg (renamed from artwork/background.jpg)bin26285 -> 26285 bytes
-rw-r--r--ui/twin/artwork/cdrom.png (renamed from artwork/cdrom.png)bin4848 -> 4848 bytes
-rw-r--r--ui/twin/artwork/cursor.gz (renamed from artwork/cursor.gz)bin9167 -> 9167 bytes
-rw-r--r--ui/twin/artwork/hdd.png (renamed from artwork/hdd.png)bin4983 -> 4983 bytes
-rw-r--r--ui/twin/artwork/tux.png (renamed from artwork/tux.png)bin4382 -> 4382 bytes
-rw-r--r--ui/twin/artwork/usbpen.png (renamed from artwork/usbpen.png)bin5970 -> 5970 bytes
-rw-r--r--ui/twin/pb-twin.c (renamed from petitboot.c)0
62 files changed, 2593 insertions, 1016 deletions
diff --git a/Makefile.in b/Makefile.in
index 0da5a4e..e537e9d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -24,6 +24,7 @@ sbindir = @sbindir@
datarootdir = @datarootdir@
datadir = @datadir@
pkgdatadir = ${datadir}/${PACKAGE}
+builddir = @builddir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
diff --git a/configure.ac b/configure.ac
index 5ef5aa0..2e85b26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,6 +30,6 @@ AC_PROG_INSTALL
PKG_CHECK_MODULES([twin], [libtwin])
-mkdir devices
+mkdir -p discover ui/test ui/common lib/talloc lib/pb-protocol lib/list
AC_OUTPUT
diff --git a/devices.c b/devices.c
deleted file mode 100644
index 77860d0..0000000
--- a/devices.c
+++ /dev/null
@@ -1,313 +0,0 @@
-#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));
-}
diff --git a/devices/petitboot-udev-helper.c b/devices/petitboot-udev-helper.c
deleted file mode 100644
index f2f15b1..0000000
--- a/devices/petitboot-udev-helper.c
+++ /dev/null
@@ -1,636 +0,0 @@
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <asm/byteorder.h>
-#include <linux/cdrom.h>
-#include <sys/ioctl.h>
-
-#include "parser.h"
-#include "paths.h"
-#include "petitboot-paths.h"
-
-/* Define below to operate without the frontend */
-#undef USE_FAKE_SOCKET
-
-/* Delay in seconds between polling of removable devices */
-#define REMOVABLE_SLEEP_DELAY 2
-
-static FILE *logf;
-static int sock;
-
-void pb_log(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(logf, fmt, ap);
- va_end(ap);
-}
-
-static void print_boot_option(const struct boot_option *opt)
-{
- pb_log("\tname: %s\n", opt->name);
- pb_log("\tdescription: %s\n", opt->description);
- pb_log("\tboot_image: %s\n", opt->boot_image_file);
- pb_log("\tinitrd: %s\n", opt->initrd_file);
- pb_log("\tboot_args: %s\n", opt->boot_args);
-
-}
-
-static void print_device(const struct device *dev)
-{
- pb_log("\tid: %s\n", dev->id);
- pb_log("\tname: %s\n", dev->name);
- pb_log("\tdescription: %s\n", dev->description);
- pb_log("\tboot_image: %s\n", dev->icon_file);
-}
-
-static int write_action(int fd, enum device_action action)
-{
- uint8_t action_buf = action;
- return write(fd, &action_buf, sizeof(action_buf)) != sizeof(action_buf);
-}
-
-static int write_string(int fd, const char *str)
-{
- int len, pos = 0;
- uint32_t len_buf;
-
- if (!str) {
- len_buf = 0;
- if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
- pb_log("write failed: %s\n", strerror(errno));
- return -1;
- }
- return 0;
- }
-
- len = strlen(str);
- if (len > (1ull << (sizeof(len_buf) * 8 - 1))) {
- pb_log("string too large\n");
- return -1;
- }
-
- len_buf = __cpu_to_be32(len);
- if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
- pb_log("write failed: %s\n", strerror(errno));
- return -1;
- }
-
- while (pos < len) {
- int rc = write(fd, str, len - pos);
- if (rc <= 0) {
- pb_log("write failed: %s\n", strerror(errno));
- return -1;
- }
- pos += rc;
- str += rc;
- }
-
- return 0;
-}
-
-int add_device(const struct device *dev)
-{
- int rc;
-
- pb_log("device added:\n");
- print_device(dev);
- rc = write_action(sock, DEV_ACTION_ADD_DEVICE) ||
- write_string(sock, dev->id) ||
- write_string(sock, dev->name) ||
- write_string(sock, dev->description) ||
- write_string(sock, dev->icon_file);
-
- if (rc)
- pb_log("error writing device %s to socket\n", dev->name);
-
- return rc;
-}
-
-int add_boot_option(const struct boot_option *opt)
-{
- int rc;
-
- pb_log("boot option added:\n");
- print_boot_option(opt);
-
- rc = write_action(sock, DEV_ACTION_ADD_OPTION) ||
- write_string(sock, opt->id) ||
- write_string(sock, opt->name) ||
- write_string(sock, opt->description) ||
- write_string(sock, opt->icon_file) ||
- write_string(sock, opt->boot_image_file) ||
- write_string(sock, opt->initrd_file) ||
- write_string(sock, opt->boot_args);
-
- if (rc)
- pb_log("error writing boot option %s to socket\n", opt->name);
-
- return rc;
-}
-
-int remove_device(const char *dev_path)
-{
- return write_action(sock, DEV_ACTION_REMOVE_DEVICE) ||
- write_string(sock, dev_path);
-}
-
-int connect_to_socket()
-{
-#ifndef USE_FAKE_SOCKET
- int fd;
- struct sockaddr_un addr;
-
- fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (fd == -1) {
- pb_log("can't create socket: %s\n", strerror(errno));
- return -1;
- }
-
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
-
- if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
- pb_log("can't connect to %s: %s\n",
- addr.sun_path, strerror(errno));
- return -1;
- }
- sock = fd;
-
- return 0;
-#else
- int fd;
- fd = open("./debug_socket", O_WRONLY | O_CREAT, 0640);
- if (fd < 0) {
- pb_log("can't create output file: %s\n", strerror(errno));
- return -1;
- }
- sock = fd;
- return 0;
-#endif
-}
-
-static int mkdir_recursive(const char *dir)
-{
- char *str, *sep;
- int mode = 0755;
- struct stat statbuf;
-
- pb_log("mkdir_recursive(%s)\n", dir);
-
- if (!*dir)
- return 0;
-
- if (!stat(dir, &statbuf)) {
- if (!S_ISDIR(statbuf.st_mode)) {
- pb_log("%s: %s exists, but isn't a directory\n",
- __func__, dir);
- return -1;
- }
- return 0;
- }
-
- str = strdup(dir);
- sep = strchr(*str == '/' ? str + 1 : str, '/');
-
- while (1) {
-
- /* terminate the path at sep */
- if (sep)
- *sep = '\0';
- pb_log("mkdir(%s)\n", str);
-
- if (mkdir(str, mode) && errno != EEXIST) {
- pb_log("mkdir(%s): %s\n", str, strerror(errno));
- return -1;
- }
-
- if (!sep)
- break;
-
- /* reset dir to the full path */
- strcpy(str, dir);
- sep = strchr(sep + 1, '/');
- }
-
- free(str);
-
- return 0;
-}
-
-static void setup_device_links(const char *device)
-{
- struct link {
- char *env, *dir;
- } *link, links[] = {
- {
- .env = "ID_FS_UUID",
- .dir = "disk/by-uuid"
- },
- {
- .env = "ID_FS_LABEL",
- .dir = "disk/by-label"
- },
- {
- .env = NULL
- }
- };
-
- for (link = links; link->env; link++) {
- char *value, *dir, *path;
-
- value = getenv(link->env);
- if (!value)
- continue;
-
- value = encode_label(value);
- dir = join_paths(TMP_DIR, link->dir);
- path = join_paths(dir, value);
-
- if (!mkdir_recursive(dir)) {
- unlink(path);
- if (symlink(mountpoint_for_device(device), path)) {
- pb_log("symlink(%s): %s\n",
- path, strerror(errno));
- }
- }
-
- free(path);
- free(dir);
- free(value);
- }
-}
-
-int mount_device(const char *dev_path)
-{
- const char *dir;
- int pid, status, rc = -1;
- struct stat statbuf;
-
- dir = mountpoint_for_device(dev_path);
-
- if (stat(dir, &statbuf)) {
- if (mkdir(dir, 0755)) {
- pb_log("couldn't create directory %s: %s\n",
- dir, strerror(errno));
- goto out;
- }
- } else {
- if (!S_ISDIR(statbuf.st_mode)) {
- pb_log("mountpoint %s exists, "
- "but isn't a directory\n", dir);
- goto out;
- }
- }
-
-
- pid = fork();
- if (pid == -1) {
- pb_log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno));
- goto out;
- }
-
- if (pid == 0) {
- execl(MOUNT_BIN, MOUNT_BIN, dev_path, dir, "-o", "ro", NULL);
- exit(EXIT_FAILURE);
- }
-
- if (waitpid(pid, &status, 0) == -1) {
- pb_log("%s: waitpid failed: %s\n", __FUNCTION__,
- strerror(errno));
- goto out;
- }
-
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- setup_device_links(dev_path);
- rc = 0;
- }
-
-out:
- return rc;
-}
-
-static int unmount_device(const char *dev_path)
-{
- int pid, status, rc;
-
- pid = fork();
-
- if (pid == -1) {
- pb_log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno));
- return -1;
- }
-
- if (pid == 0) {
- execl(UMOUNT_BIN, UMOUNT_BIN, dev_path, NULL);
- exit(EXIT_FAILURE);
- }
-
- if (waitpid(pid, &status, 0) == -1) {
- pb_log("%s: waitpid failed: %s\n", __FUNCTION__,
- strerror(errno));
- return -1;
- }
-
- rc = !WIFEXITED(status) || WEXITSTATUS(status) != 0;
-
- return rc;
-}
-
-static const struct device fake_boot_devices[] =
-{
- {
- .id = "fakeDisk0",
- .name = "Hard Disk",
- .icon_file = artwork_pathname("hdd.png"),
- },
- {
- .id = "fakeDisk1",
- .name = "PinkCat Linux CD",
- .icon_file = artwork_pathname("cdrom.png"),
- }
-};
-
-static const struct boot_option fake_boot_options[] =
-{
- {
- .id = "fakeBoot0",
- .name = "Bloobuntu Linux",
- .description = "Boot Bloobuntu Linux",
- .icon_file = artwork_pathname("hdd.png"),
- },
- {
- .id = "fakeBoot1",
- .name = "Pendora Gore 6",
- .description = "Boot Pendora Gora 6",
- .icon_file = artwork_pathname("hdd.png"),
- },
- {
- .id = "fakeBoot2",
- .name = "Genfoo Minux",
- .description = "Boot Genfoo Minux",
- .icon_file = artwork_pathname("hdd.png"),
- },
- {
- .id = "fakeBoot3",
- .name = "PinkCat Linux",
- .description = "Install PinkCat Linux - Graphical install",
- .icon_file = artwork_pathname("cdrom.png"),
- },
-};
-
-enum generic_icon_type guess_device_type(void)
-{
- const char *type = getenv("ID_TYPE");
- const char *bus = getenv("ID_BUS");
- if (type && streq(type, "cd"))
- return ICON_TYPE_OPTICAL;
- if (!bus)
- return ICON_TYPE_UNKNOWN;
- if (streq(bus, "usb"))
- return ICON_TYPE_USB;
- if (streq(bus, "ata") || streq(bus, "scsi"))
- return ICON_TYPE_DISK;
- return ICON_TYPE_UNKNOWN;
-}
-
-
-static int is_removable_device(const char *sysfs_path)
-{
- char full_path[PATH_MAX];
- char buf[80];
- int fd, buf_len;
-
- sprintf(full_path, "/sys/%s/removable", sysfs_path);
- fd = open(full_path, O_RDONLY);
- pb_log(" -> removable check on %s, fd=%d\n", full_path, fd);
- if (fd < 0)
- return 0;
- buf_len = read(fd, buf, 79);
- close(fd);
- if (buf_len < 0)
- return 0;
- buf[buf_len] = 0;
- return strtol(buf, NULL, 10);
-}
-
-static int is_ignored_device(const char *devname)
-{
- static const char *ignored_devices[] =
- { "/dev/ram", "/dev/loop", NULL };
- const char **dev;
-
- for (dev = ignored_devices; *dev; dev++)
- if (!strncmp(devname, *dev, strlen(*dev)))
- return 1;
-
- return 0;
-}
-
-static int found_new_device(const char *dev_path)
-{
- const char *mountpoint = mountpoint_for_device(dev_path);
-
- if (mount_device(dev_path)) {
- pb_log("failed to mount %s\n", dev_path);
- return EXIT_FAILURE;
- }
-
- pb_log("mounted %s at %s\n", dev_path, mountpoint);
-
- iterate_parsers(dev_path, mountpoint);
-
- return EXIT_SUCCESS;
-}
-
-static void detach_and_sleep(int sec)
-{
- static int forked = 0;
- int rc = 0;
-
- if (sec <= 0)
- return;
-
- if (!forked) {
- pb_log("running in background...");
- rc = fork();
- forked = 1;
- }
-
- if (rc == 0) {
- sleep(sec);
-
- } else if (rc == -1) {
- perror("fork()");
- exit(EXIT_FAILURE);
- } else {
- exit(EXIT_SUCCESS);
- }
-}
-
-static int poll_device_plug(const char *dev_path,
- int *optical)
-{
- int rc, fd;
-
- /* Polling loop for optical drive */
- for (; (*optical) != 0; ) {
- fd = open(dev_path, O_RDONLY|O_NONBLOCK);
- if (fd < 0)
- return EXIT_FAILURE;
- rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
- close(fd);
- if (rc == -1)
- break;
-
- *optical = 1;
- if (rc == CDS_DISC_OK)
- return EXIT_SUCCESS;
-
- detach_and_sleep(REMOVABLE_SLEEP_DELAY);
- }
-
- /* Fall back to bare open() */
- *optical = 0;
- for (;;) {
- fd = open(dev_path, O_RDONLY);
- if (fd < 0 && errno != ENOMEDIUM)
- return EXIT_FAILURE;
- close(fd);
- if (fd >= 0)
- return EXIT_SUCCESS;
- detach_and_sleep(REMOVABLE_SLEEP_DELAY);
- }
-}
-
-static int poll_device_unplug(const char *dev_path, int optical)
-{
- int rc, fd;
-
- for (;optical;) {
- fd = open(dev_path, O_RDONLY|O_NONBLOCK);
- if (fd < 0)
- return EXIT_FAILURE;
- rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
- close(fd);
- if (rc != CDS_DISC_OK)
- return EXIT_SUCCESS;
- detach_and_sleep(REMOVABLE_SLEEP_DELAY);
- }
-
- /* Fall back to bare open() */
- for (;;) {
- fd = open(dev_path, O_RDONLY);
- if (fd < 0 && errno != ENOMEDIUM)
- return EXIT_FAILURE;
- close(fd);
- if (fd < 0)
- return EXIT_SUCCESS;
- detach_and_sleep(REMOVABLE_SLEEP_DELAY);
- }
-}
-
-static int poll_removable_device(const char *sysfs_path,
- const char *dev_path)
-{
- int rc, mounted, optical = -1;
-
- for (;;) {
- rc = poll_device_plug(dev_path, &optical);
- if (rc == EXIT_FAILURE)
- return rc;
- rc = found_new_device(dev_path);
- mounted = (rc == EXIT_SUCCESS);
-
- poll_device_unplug(dev_path, optical);
-
- remove_device(dev_path);
-
- /* Unmount it repeatedly, if needs be */
- while (mounted && !unmount_device(dev_path))
- ;
- detach_and_sleep(1);
- }
-}
-
-int main(int argc, char **argv)
-{
- char *dev_path, *action;
- int rc;
-
- action = getenv("ACTION");
-
- logf = fopen("/var/log/petitboot-udev-helpers.log", "a");
- if (!logf)
- logf = stdout;
- pb_log("%d started\n", getpid());
- rc = EXIT_SUCCESS;
-
- if (!action) {
- pb_log("missing environment?\n");
- return EXIT_FAILURE;
- }
-
- set_mount_base(TMP_DIR);
-
- if (connect_to_socket())
- return EXIT_FAILURE;
-
- if (streq(action, "fake")) {
- pb_log("fake mode");
-
- add_device(&fake_boot_devices[0]);
- add_boot_option(&fake_boot_options[0]);
- add_boot_option(&fake_boot_options[1]);
- add_boot_option(&fake_boot_options[2]);
- add_device(&fake_boot_devices[1]);
- add_boot_option(&fake_boot_options[3]);
-
- return EXIT_SUCCESS;
- }
-
- dev_path = getenv("DEVNAME");
- if (!dev_path) {
- pb_log("missing environment?\n");
- return EXIT_FAILURE;
- }
-
- if (is_ignored_device(dev_path))
- return EXIT_SUCCESS;
-
- if (streq(action, "add")) {
- char *sysfs_path = getenv("DEVPATH");
- if (sysfs_path && is_removable_device(sysfs_path))
- rc = poll_removable_device(sysfs_path, dev_path);
- else
- rc = found_new_device(dev_path);
- } else if (streq(action, "remove")) {
- pb_log("%s removed\n", dev_path);
-
- remove_device(dev_path);
-
- /* Unmount it repeatedly, if needs be */
- while (!unmount_device(dev_path))
- ;
-
- } else {
- pb_log("invalid action '%s'\n", action);
- rc = EXIT_FAILURE;
- }
- return rc;
-}
diff --git a/discover/discover-server.c b/discover/discover-server.c
new file mode 100644
index 0000000..8358f06
--- /dev/null
+++ b/discover/discover-server.c
@@ -0,0 +1,227 @@
+
+#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);
+}
+
diff --git a/discover/discover-server.h b/discover/discover-server.h
new file mode 100644
index 0000000..ff27f15
--- /dev/null
+++ b/discover/discover-server.h
@@ -0,0 +1,10 @@
+#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 */
diff --git a/devices/kboot-parser.c b/discover/kboot-parser.c
index df2e762..df2e762 100644
--- a/devices/kboot-parser.c
+++ b/discover/kboot-parser.c
diff --git a/discover/log.c b/discover/log.c
new file mode 100644
index 0000000..189f31e
--- /dev/null
+++ b/discover/log.c
@@ -0,0 +1,24 @@
+
+#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;
+}
diff --git a/discover/log.h b/discover/log.h
new file mode 100644
index 0000000..7f9b01f
--- /dev/null
+++ b/discover/log.h
@@ -0,0 +1,6 @@
+#ifndef _LOG_H
+#define _LOG_H
+
+void pb_log(const char *fmt, ...);
+
+#endif /* _LOG_H */
diff --git a/devices/message.h b/discover/message.h
index 7a5d4f2..d0b0e34 100644
--- a/devices/message.h
+++ b/discover/message.h
@@ -14,16 +14,17 @@ struct device {
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;
+ 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;
};
diff --git a/devices/native-parser.c b/discover/native-parser.c
index 24713b1..24713b1 100644
--- a/devices/native-parser.c
+++ b/discover/native-parser.c
diff --git a/devices/params.c b/discover/params.c
index 76a1451..76a1451 100644
--- a/devices/params.c
+++ b/discover/params.c
diff --git a/devices/params.h b/discover/params.h
index 02a39c9..02a39c9 100644
--- a/devices/params.h
+++ b/discover/params.h
diff --git a/devices/parser.c b/discover/parser.c
index 5e50dcb..5e50dcb 100644
--- a/devices/parser.c
+++ b/discover/parser.c
diff --git a/devices/parser.h b/discover/parser.h
index 9c6fb35..9c6fb35 100644
--- a/devices/parser.h
+++ b/discover/parser.h
diff --git a/devices/paths.c b/discover/paths.c
index 2373c28..2373c28 100644
--- a/devices/paths.c
+++ b/discover/paths.c
diff --git a/devices/paths.h b/discover/paths.h
index 26d4ce4..26d4ce4 100644
--- a/devices/paths.h
+++ b/discover/paths.h
diff --git a/discover/pb-discover.c b/discover/pb-discover.c
new file mode 100644
index 0000000..45b6ba1
--- /dev/null
+++ b/discover/pb-discover.c
@@ -0,0 +1,34 @@
+
+#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;
+}
diff --git a/discover/pb-discover.h b/discover/pb-discover.h
new file mode 100644
index 0000000..a48557c
--- /dev/null
+++ b/discover/pb-discover.h
@@ -0,0 +1,6 @@
+#ifndef _PB_DISCOVER_H
+#define _PB_DISCOVER_H
+
+int register_waiter(int fd, int *callback(void *), void *arg);
+
+#endif /* _PB_DISCOVER_H */
diff --git a/discover/udev.c b/discover/udev.c
new file mode 100644
index 0000000..9c1b399
--- /dev/null
+++ b/discover/udev.c
@@ -0,0 +1,208 @@
+
+#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);
+}
diff --git a/discover/udev.h b/discover/udev.h
new file mode 100644
index 0000000..c30adc9
--- /dev/null
+++ b/discover/udev.h
@@ -0,0 +1,26 @@
+#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 */
diff --git a/discover/waiter.c b/discover/waiter.c
new file mode 100644
index 0000000..21dd4a5
--- /dev/null
+++ b/discover/waiter.c
@@ -0,0 +1,83 @@
+
+#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;
+}
diff --git a/discover/waiter.h b/discover/waiter.h
new file mode 100644
index 0000000..ff8a5ff
--- /dev/null
+++ b/discover/waiter.h
@@ -0,0 +1,23 @@
+#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 */
+
+
diff --git a/devices/yaboot-cfg.c b/discover/yaboot-cfg.c
index 6b007e4..6b007e4 100644
--- a/devices/yaboot-cfg.c
+++ b/discover/yaboot-cfg.c
diff --git a/devices/yaboot-cfg.h b/discover/yaboot-cfg.h
index 2ab4fec..2ab4fec 100644
--- a/devices/yaboot-cfg.h
+++ b/discover/yaboot-cfg.h
diff --git a/devices/yaboot-parser.c b/discover/yaboot-parser.c
index 27b4b78..27b4b78 100644
--- a/devices/yaboot-parser.c
+++ b/discover/yaboot-parser.c
diff --git a/lib/list/list.c b/lib/list/list.c
new file mode 100644
index 0000000..d9bc532
--- /dev/null
+++ b/lib/list/list.c
@@ -0,0 +1,24 @@
+
+#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;
+}
+
diff --git a/lib/list/list.h b/lib/list/list.h
new file mode 100644
index 0000000..3858cf6
--- /dev/null
+++ b/lib/list/list.h
@@ -0,0 +1,39 @@
+#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 */
diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
new file mode 100644
index 0000000..2fd76c5
--- /dev/null
+++ b/lib/pb-protocol/pb-protocol.c
@@ -0,0 +1,307 @@
+
+#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;
+}
diff --git a/lib/pb-protocol/pb-protocol.h b/lib/pb-protocol/pb-protocol.h
new file mode 100644
index 0000000..7b557d6
--- /dev/null
+++ b/lib/pb-protocol/pb-protocol.h
@@ -0,0 +1,57 @@
+#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 */
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
new file mode 100644
index 0000000..c660870
--- /dev/null
+++ b/lib/talloc/talloc.c
@@ -0,0 +1,1130 @@
+/*
+ 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;
+}
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
new file mode 100644
index 0000000..15a1eb6
--- /dev/null
+++ b/lib/talloc/talloc.h
@@ -0,0 +1,137 @@
+#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
+
diff --git a/petitboot-paths.h b/petitboot-paths.h
deleted file mode 100644
index 40ce557..0000000
--- a/petitboot-paths.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#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 */
diff --git a/petitboot.h b/petitboot.h
deleted file mode 100644
index 893be04..0000000
--- a/petitboot.h
+++ /dev/null
@@ -1,18 +0,0 @@
-
-#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, ...);
diff --git a/rules.mk b/rules.mk
index 9239d29..f8d64c6 100644
--- a/rules.mk
+++ b/rules.mk
@@ -1,36 +1,56 @@
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
@@ -60,6 +80,9 @@ $(PACKAGE)-$(VERSION): clean
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
+
diff --git a/devices/parser-test.c b/test/parser-test.c
index 8c94d3f..8c94d3f 100644
--- a/devices/parser-test.c
+++ b/test/parser-test.c
diff --git a/devices/parser-test.sh b/test/parser-test.sh
index 140601e..140601e 100755
--- a/devices/parser-test.sh
+++ b/test/parser-test.sh
diff --git a/devices/parser-tests/001/expected-output b/test/parser/001/expected-output
index bace9f7..bace9f7 100644
--- a/devices/parser-tests/001/expected-output
+++ b/test/parser/001/expected-output
diff --git a/devices/parser-tests/001/ps3da1/etc/kboot.conf b/test/parser/001/ps3da1/etc/kboot.conf
index 591c51b..591c51b 100644
--- a/devices/parser-tests/001/ps3da1/etc/kboot.conf
+++ b/test/parser/001/ps3da1/etc/kboot.conf
diff --git a/devices/parser-tests/002/expected-output b/test/parser/002/expected-output
index 304f15c..304f15c 100644
--- a/devices/parser-tests/002/expected-output
+++ b/test/parser/002/expected-output
diff --git a/devices/parser-tests/002/ps3da1/etc/yaboot.conf b/test/parser/002/ps3da1/etc/yaboot.conf
index f13b1b3..f13b1b3 100644
--- a/devices/parser-tests/002/ps3da1/etc/yaboot.conf
+++ b/test/parser/002/ps3da1/etc/yaboot.conf
diff --git a/devices/parser-tests/003/expected-output b/test/parser/003/expected-output
index 4f60310..4f60310 100644
--- a/devices/parser-tests/003/expected-output
+++ b/test/parser/003/expected-output
diff --git a/devices/parser-tests/003/ps3da1/etc/kboot.conf b/test/parser/003/ps3da1/etc/kboot.conf
index a7bb199..a7bb199 100644
--- a/devices/parser-tests/003/ps3da1/etc/kboot.conf
+++ b/test/parser/003/ps3da1/etc/kboot.conf
diff --git a/devices/parser-tests/004/expected-output b/test/parser/004/expected-output
index 76a90a2..76a90a2 100644
--- a/devices/parser-tests/004/expected-output
+++ b/test/parser/004/expected-output
diff --git a/devices/parser-tests/004/rootdev b/test/parser/004/rootdev
index 36cfa0d..36cfa0d 100644
--- a/devices/parser-tests/004/rootdev
+++ b/test/parser/004/rootdev
diff --git a/devices/parser-tests/004/sda1/etc/kboot.conf b/test/parser/004/sda1/etc/kboot.conf
index 9755f77..9755f77 100644
--- a/devices/parser-tests/004/sda1/etc/kboot.conf
+++ b/test/parser/004/sda1/etc/kboot.conf
diff --git a/devices/parser-tests/005/expected-output b/test/parser/005/expected-output
index bfaccc8..bfaccc8 100644
--- a/devices/parser-tests/005/expected-output
+++ b/test/parser/005/expected-output
diff --git a/devices/parser-tests/005/ps3da1/etc/kboot.conf b/test/parser/005/ps3da1/etc/kboot.conf
index 72b7db8..72b7db8 100644
--- a/devices/parser-tests/005/ps3da1/etc/kboot.conf
+++ b/test/parser/005/ps3da1/etc/kboot.conf
diff --git a/devices/parser-tests/101/expected-output b/test/parser/101/expected-output
index 45d99a1..45d99a1 100644
--- a/devices/parser-tests/101/expected-output
+++ b/test/parser/101/expected-output
diff --git a/devices/parser-tests/101/ps3da1/etc/kboot.conf b/test/parser/101/ps3da1/etc/kboot.conf
index 4a986c0..4a986c0 100644
--- a/devices/parser-tests/101/ps3da1/etc/kboot.conf
+++ b/test/parser/101/ps3da1/etc/kboot.conf
diff --git a/devices/parser-tests/102/expected-output b/test/parser/102/expected-output
index cc0d096..cc0d096 100644
--- a/devices/parser-tests/102/expected-output
+++ b/test/parser/102/expected-output
diff --git a/devices/parser-tests/102/ps3da1/etc/kboot.conf b/test/parser/102/ps3da1/etc/kboot.conf
index 591c51b..591c51b 100644
--- a/devices/parser-tests/102/ps3da1/etc/kboot.conf
+++ b/test/parser/102/ps3da1/etc/kboot.conf
diff --git a/ui/common/discover-client.c b/ui/common/discover-client.c
new file mode 100644
index 0000000..bc5a4fa
--- /dev/null
+++ b/ui/common/discover-client.c
@@ -0,0 +1,111 @@
+
+#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;
+}
diff --git a/ui/common/discover-client.h b/ui/common/discover-client.h
new file mode 100644
index 0000000..3ce745b
--- /dev/null
+++ b/ui/common/discover-client.h
@@ -0,0 +1,29 @@
+#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
diff --git a/ui/test/pb-test.c b/ui/test/pb-test.c
new file mode 100644
index 0000000..a36e991
--- /dev/null
+++ b/ui/test/pb-test.c
@@ -0,0 +1,62 @@
+
+#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;
+}
diff --git a/artwork/background.jpg b/ui/twin/artwork/background.jpg
index 9d54d31..9d54d31 100644
--- a/artwork/background.jpg
+++ b/ui/twin/artwork/background.jpg
Binary files differ
diff --git a/artwork/cdrom.png b/ui/twin/artwork/cdrom.png
index 8b3eeb6..8b3eeb6 100644
--- a/artwork/cdrom.png
+++ b/ui/twin/artwork/cdrom.png
Binary files differ
diff --git a/artwork/cursor.gz b/ui/twin/artwork/cursor.gz
index b73b72f..b73b72f 100644
--- a/artwork/cursor.gz
+++ b/ui/twin/artwork/cursor.gz
Binary files differ
diff --git a/artwork/hdd.png b/ui/twin/artwork/hdd.png
index 2b1594c..2b1594c 100644
--- a/artwork/hdd.png
+++ b/ui/twin/artwork/hdd.png
Binary files differ
diff --git a/artwork/tux.png b/ui/twin/artwork/tux.png
index 99f3465..99f3465 100644
--- a/artwork/tux.png
+++ b/ui/twin/artwork/tux.png
Binary files differ
diff --git a/artwork/usbpen.png b/ui/twin/artwork/usbpen.png
index 53a365e..53a365e 100644
--- a/artwork/usbpen.png
+++ b/ui/twin/artwork/usbpen.png
Binary files differ
diff --git a/petitboot.c b/ui/twin/pb-twin.c
index ee68930..ee68930 100644
--- a/petitboot.c
+++ b/ui/twin/pb-twin.c
OpenPOWER on IntegriCloud