From 32e6a41f33e5576716b351bd473a27939fe94fa1 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 15 Dec 2008 15:22:34 +1100 Subject: [PATCH] Initial support for multiple UIs Move the device discovery code from separate udev helpers to a single process to listen on two sockets: one SOCK_DGRAM for incoming udev events, and one SOCK_STREAM for UIs to connect. Initial support for client/server infrastructure, still need to wire-up the udev messages. Signed-off-by: Jeremy Kerr --- Makefile.in | 1 + configure.ac | 2 +- devices.c | 313 ----- devices/petitboot-udev-helper.c | 636 ---------- discover/discover-server.c | 227 ++++ discover/discover-server.h | 10 + {devices => discover}/kboot-parser.c | 0 discover/log.c | 24 + discover/log.h | 6 + {devices => discover}/message.h | 19 +- {devices => discover}/native-parser.c | 0 {devices => discover}/params.c | 0 {devices => discover}/params.h | 0 {devices => discover}/parser.c | 0 {devices => discover}/parser.h | 0 {devices => discover}/paths.c | 0 {devices => discover}/paths.h | 0 discover/pb-discover.c | 34 + discover/pb-discover.h | 6 + discover/udev.c | 208 +++ discover/udev.h | 26 + discover/waiter.c | 83 ++ discover/waiter.h | 23 + {devices => discover}/yaboot-cfg.c | 0 {devices => discover}/yaboot-cfg.h | 0 {devices => discover}/yaboot-parser.c | 0 lib/list/list.c | 24 + lib/list/list.h | 39 + lib/pb-protocol/pb-protocol.c | 307 +++++ lib/pb-protocol/pb-protocol.h | 57 + lib/talloc/talloc.c | 1130 +++++++++++++++++ lib/talloc/talloc.h | 137 ++ petitboot-paths.h | 24 - petitboot.h | 18 - rules.mk | 53 +- {devices => test}/parser-test.c | 0 {devices => test}/parser-test.sh | 0 .../parser}/001/expected-output | 0 .../parser}/001/ps3da1/etc/kboot.conf | 0 .../parser}/002/expected-output | 0 .../parser}/002/ps3da1/etc/yaboot.conf | 0 .../parser}/003/expected-output | 0 .../parser}/003/ps3da1/etc/kboot.conf | 0 .../parser}/004/expected-output | 0 .../parser-tests => test/parser}/004/rootdev | 0 .../parser}/004/sda1/etc/kboot.conf | 0 .../parser}/005/expected-output | 0 .../parser}/005/ps3da1/etc/kboot.conf | 0 .../parser}/101/expected-output | 0 .../parser}/101/ps3da1/etc/kboot.conf | 0 .../parser}/102/expected-output | 0 .../parser}/102/ps3da1/etc/kboot.conf | 0 ui/common/discover-client.c | 111 ++ ui/common/discover-client.h | 29 + ui/test/pb-test.c | 62 + {artwork => ui/twin/artwork}/background.jpg | Bin {artwork => ui/twin/artwork}/cdrom.png | Bin {artwork => ui/twin/artwork}/cursor.gz | Bin {artwork => ui/twin/artwork}/hdd.png | Bin {artwork => ui/twin/artwork}/tux.png | Bin {artwork => ui/twin/artwork}/usbpen.png | Bin petitboot.c => ui/twin/pb-twin.c | 0 62 files changed, 2593 insertions(+), 1016 deletions(-) delete mode 100644 devices.c delete mode 100644 devices/petitboot-udev-helper.c create mode 100644 discover/discover-server.c create mode 100644 discover/discover-server.h rename {devices => discover}/kboot-parser.c (100%) create mode 100644 discover/log.c create mode 100644 discover/log.h rename {devices => discover}/message.h (61%) rename {devices => discover}/native-parser.c (100%) rename {devices => discover}/params.c (100%) rename {devices => discover}/params.h (100%) rename {devices => discover}/parser.c (100%) rename {devices => discover}/parser.h (100%) rename {devices => discover}/paths.c (100%) rename {devices => discover}/paths.h (100%) create mode 100644 discover/pb-discover.c create mode 100644 discover/pb-discover.h create mode 100644 discover/udev.c create mode 100644 discover/udev.h create mode 100644 discover/waiter.c create mode 100644 discover/waiter.h rename {devices => discover}/yaboot-cfg.c (100%) rename {devices => discover}/yaboot-cfg.h (100%) rename {devices => discover}/yaboot-parser.c (100%) create mode 100644 lib/list/list.c create mode 100644 lib/list/list.h create mode 100644 lib/pb-protocol/pb-protocol.c create mode 100644 lib/pb-protocol/pb-protocol.h create mode 100644 lib/talloc/talloc.c create mode 100644 lib/talloc/talloc.h delete mode 100644 petitboot-paths.h delete mode 100644 petitboot.h rename {devices => test}/parser-test.c (100%) rename {devices => test}/parser-test.sh (100%) rename {devices/parser-tests => test/parser}/001/expected-output (100%) rename {devices/parser-tests => test/parser}/001/ps3da1/etc/kboot.conf (100%) rename {devices/parser-tests => test/parser}/002/expected-output (100%) rename {devices/parser-tests => test/parser}/002/ps3da1/etc/yaboot.conf (100%) rename {devices/parser-tests => test/parser}/003/expected-output (100%) rename {devices/parser-tests => test/parser}/003/ps3da1/etc/kboot.conf (100%) rename {devices/parser-tests => test/parser}/004/expected-output (100%) rename {devices/parser-tests => test/parser}/004/rootdev (100%) rename {devices/parser-tests => test/parser}/004/sda1/etc/kboot.conf (100%) rename {devices/parser-tests => test/parser}/005/expected-output (100%) rename {devices/parser-tests => test/parser}/005/ps3da1/etc/kboot.conf (100%) rename {devices/parser-tests => test/parser}/101/expected-output (100%) rename {devices/parser-tests => test/parser}/101/ps3da1/etc/kboot.conf (100%) rename {devices/parser-tests => test/parser}/102/expected-output (100%) rename {devices/parser-tests => test/parser}/102/ps3da1/etc/kboot.conf (100%) create mode 100644 ui/common/discover-client.c create mode 100644 ui/common/discover-client.h create mode 100644 ui/test/pb-test.c rename {artwork => ui/twin/artwork}/background.jpg (100%) rename {artwork => ui/twin/artwork}/cdrom.png (100%) rename {artwork => ui/twin/artwork}/cursor.gz (100%) rename {artwork => ui/twin/artwork}/hdd.png (100%) rename {artwork => ui/twin/artwork}/tux.png (100%) rename {artwork => ui/twin/artwork}/usbpen.png (100%) rename petitboot.c => ui/twin/pb-twin.c (100%) 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "parser.h" -#include "paths.h" -#include "petitboot-paths.h" - -/* Define below to operate without the frontend */ -#undef USE_FAKE_SOCKET - -/* Delay in seconds between polling of removable devices */ -#define REMOVABLE_SLEEP_DELAY 2 - -static FILE *logf; -static int sock; - -void pb_log(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(logf, fmt, ap); - va_end(ap); -} - -static void print_boot_option(const struct boot_option *opt) -{ - pb_log("\tname: %s\n", opt->name); - pb_log("\tdescription: %s\n", opt->description); - pb_log("\tboot_image: %s\n", opt->boot_image_file); - pb_log("\tinitrd: %s\n", opt->initrd_file); - pb_log("\tboot_args: %s\n", opt->boot_args); - -} - -static void print_device(const struct device *dev) -{ - pb_log("\tid: %s\n", dev->id); - pb_log("\tname: %s\n", dev->name); - pb_log("\tdescription: %s\n", dev->description); - pb_log("\tboot_image: %s\n", dev->icon_file); -} - -static int write_action(int fd, enum device_action action) -{ - uint8_t action_buf = action; - return write(fd, &action_buf, sizeof(action_buf)) != sizeof(action_buf); -} - -static int write_string(int fd, const char *str) -{ - int len, pos = 0; - uint32_t len_buf; - - if (!str) { - len_buf = 0; - if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) { - pb_log("write failed: %s\n", strerror(errno)); - return -1; - } - return 0; - } - - len = strlen(str); - if (len > (1ull << (sizeof(len_buf) * 8 - 1))) { - pb_log("string too large\n"); - return -1; - } - - len_buf = __cpu_to_be32(len); - if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) { - pb_log("write failed: %s\n", strerror(errno)); - return -1; - } - - while (pos < len) { - int rc = write(fd, str, len - pos); - if (rc <= 0) { - pb_log("write failed: %s\n", strerror(errno)); - return -1; - } - pos += rc; - str += rc; - } - - return 0; -} - -int add_device(const struct device *dev) -{ - int rc; - - pb_log("device added:\n"); - print_device(dev); - rc = write_action(sock, DEV_ACTION_ADD_DEVICE) || - write_string(sock, dev->id) || - write_string(sock, dev->name) || - write_string(sock, dev->description) || - write_string(sock, dev->icon_file); - - if (rc) - pb_log("error writing device %s to socket\n", dev->name); - - return rc; -} - -int add_boot_option(const struct boot_option *opt) -{ - int rc; - - pb_log("boot option added:\n"); - print_boot_option(opt); - - rc = write_action(sock, DEV_ACTION_ADD_OPTION) || - write_string(sock, opt->id) || - write_string(sock, opt->name) || - write_string(sock, opt->description) || - write_string(sock, opt->icon_file) || - write_string(sock, opt->boot_image_file) || - write_string(sock, opt->initrd_file) || - write_string(sock, opt->boot_args); - - if (rc) - pb_log("error writing boot option %s to socket\n", opt->name); - - return rc; -} - -int remove_device(const char *dev_path) -{ - return write_action(sock, DEV_ACTION_REMOVE_DEVICE) || - write_string(sock, dev_path); -} - -int connect_to_socket() -{ -#ifndef USE_FAKE_SOCKET - int fd; - struct sockaddr_un addr; - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - pb_log("can't create socket: %s\n", strerror(errno)); - return -1; - } - - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET); - - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) { - pb_log("can't connect to %s: %s\n", - addr.sun_path, strerror(errno)); - return -1; - } - sock = fd; - - return 0; -#else - int fd; - fd = open("./debug_socket", O_WRONLY | O_CREAT, 0640); - if (fd < 0) { - pb_log("can't create output file: %s\n", strerror(errno)); - return -1; - } - sock = fd; - return 0; -#endif -} - -static int mkdir_recursive(const char *dir) -{ - char *str, *sep; - int mode = 0755; - struct stat statbuf; - - pb_log("mkdir_recursive(%s)\n", dir); - - if (!*dir) - return 0; - - if (!stat(dir, &statbuf)) { - if (!S_ISDIR(statbuf.st_mode)) { - pb_log("%s: %s exists, but isn't a directory\n", - __func__, dir); - return -1; - } - return 0; - } - - str = strdup(dir); - sep = strchr(*str == '/' ? str + 1 : str, '/'); - - while (1) { - - /* terminate the path at sep */ - if (sep) - *sep = '\0'; - pb_log("mkdir(%s)\n", str); - - if (mkdir(str, mode) && errno != EEXIST) { - pb_log("mkdir(%s): %s\n", str, strerror(errno)); - return -1; - } - - if (!sep) - break; - - /* reset dir to the full path */ - strcpy(str, dir); - sep = strchr(sep + 1, '/'); - } - - free(str); - - return 0; -} - -static void setup_device_links(const char *device) -{ - struct link { - char *env, *dir; - } *link, links[] = { - { - .env = "ID_FS_UUID", - .dir = "disk/by-uuid" - }, - { - .env = "ID_FS_LABEL", - .dir = "disk/by-label" - }, - { - .env = NULL - } - }; - - for (link = links; link->env; link++) { - char *value, *dir, *path; - - value = getenv(link->env); - if (!value) - continue; - - value = encode_label(value); - dir = join_paths(TMP_DIR, link->dir); - path = join_paths(dir, value); - - if (!mkdir_recursive(dir)) { - unlink(path); - if (symlink(mountpoint_for_device(device), path)) { - pb_log("symlink(%s): %s\n", - path, strerror(errno)); - } - } - - free(path); - free(dir); - free(value); - } -} - -int mount_device(const char *dev_path) -{ - const char *dir; - int pid, status, rc = -1; - struct stat statbuf; - - dir = mountpoint_for_device(dev_path); - - if (stat(dir, &statbuf)) { - if (mkdir(dir, 0755)) { - pb_log("couldn't create directory %s: %s\n", - dir, strerror(errno)); - goto out; - } - } else { - if (!S_ISDIR(statbuf.st_mode)) { - pb_log("mountpoint %s exists, " - "but isn't a directory\n", dir); - goto out; - } - } - - - pid = fork(); - if (pid == -1) { - pb_log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno)); - goto out; - } - - if (pid == 0) { - execl(MOUNT_BIN, MOUNT_BIN, dev_path, dir, "-o", "ro", NULL); - exit(EXIT_FAILURE); - } - - if (waitpid(pid, &status, 0) == -1) { - pb_log("%s: waitpid failed: %s\n", __FUNCTION__, - strerror(errno)); - goto out; - } - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - setup_device_links(dev_path); - rc = 0; - } - -out: - return rc; -} - -static int unmount_device(const char *dev_path) -{ - int pid, status, rc; - - pid = fork(); - - if (pid == -1) { - pb_log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno)); - return -1; - } - - if (pid == 0) { - execl(UMOUNT_BIN, UMOUNT_BIN, dev_path, NULL); - exit(EXIT_FAILURE); - } - - if (waitpid(pid, &status, 0) == -1) { - pb_log("%s: waitpid failed: %s\n", __FUNCTION__, - strerror(errno)); - return -1; - } - - rc = !WIFEXITED(status) || WEXITSTATUS(status) != 0; - - return rc; -} - -static const struct device fake_boot_devices[] = -{ - { - .id = "fakeDisk0", - .name = "Hard Disk", - .icon_file = artwork_pathname("hdd.png"), - }, - { - .id = "fakeDisk1", - .name = "PinkCat Linux CD", - .icon_file = artwork_pathname("cdrom.png"), - } -}; - -static const struct boot_option fake_boot_options[] = -{ - { - .id = "fakeBoot0", - .name = "Bloobuntu Linux", - .description = "Boot Bloobuntu Linux", - .icon_file = artwork_pathname("hdd.png"), - }, - { - .id = "fakeBoot1", - .name = "Pendora Gore 6", - .description = "Boot Pendora Gora 6", - .icon_file = artwork_pathname("hdd.png"), - }, - { - .id = "fakeBoot2", - .name = "Genfoo Minux", - .description = "Boot Genfoo Minux", - .icon_file = artwork_pathname("hdd.png"), - }, - { - .id = "fakeBoot3", - .name = "PinkCat Linux", - .description = "Install PinkCat Linux - Graphical install", - .icon_file = artwork_pathname("cdrom.png"), - }, -}; - -enum generic_icon_type guess_device_type(void) -{ - const char *type = getenv("ID_TYPE"); - const char *bus = getenv("ID_BUS"); - if (type && streq(type, "cd")) - return ICON_TYPE_OPTICAL; - if (!bus) - return ICON_TYPE_UNKNOWN; - if (streq(bus, "usb")) - return ICON_TYPE_USB; - if (streq(bus, "ata") || streq(bus, "scsi")) - return ICON_TYPE_DISK; - return ICON_TYPE_UNKNOWN; -} - - -static int is_removable_device(const char *sysfs_path) -{ - char full_path[PATH_MAX]; - char buf[80]; - int fd, buf_len; - - sprintf(full_path, "/sys/%s/removable", sysfs_path); - fd = open(full_path, O_RDONLY); - pb_log(" -> removable check on %s, fd=%d\n", full_path, fd); - if (fd < 0) - return 0; - buf_len = read(fd, buf, 79); - close(fd); - if (buf_len < 0) - return 0; - buf[buf_len] = 0; - return strtol(buf, NULL, 10); -} - -static int is_ignored_device(const char *devname) -{ - static const char *ignored_devices[] = - { "/dev/ram", "/dev/loop", NULL }; - const char **dev; - - for (dev = ignored_devices; *dev; dev++) - if (!strncmp(devname, *dev, strlen(*dev))) - return 1; - - return 0; -} - -static int found_new_device(const char *dev_path) -{ - const char *mountpoint = mountpoint_for_device(dev_path); - - if (mount_device(dev_path)) { - pb_log("failed to mount %s\n", dev_path); - return EXIT_FAILURE; - } - - pb_log("mounted %s at %s\n", dev_path, mountpoint); - - iterate_parsers(dev_path, mountpoint); - - return EXIT_SUCCESS; -} - -static void detach_and_sleep(int sec) -{ - static int forked = 0; - int rc = 0; - - if (sec <= 0) - return; - - if (!forked) { - pb_log("running in background..."); - rc = fork(); - forked = 1; - } - - if (rc == 0) { - sleep(sec); - - } else if (rc == -1) { - perror("fork()"); - exit(EXIT_FAILURE); - } else { - exit(EXIT_SUCCESS); - } -} - -static int poll_device_plug(const char *dev_path, - int *optical) -{ - int rc, fd; - - /* Polling loop for optical drive */ - for (; (*optical) != 0; ) { - fd = open(dev_path, O_RDONLY|O_NONBLOCK); - if (fd < 0) - return EXIT_FAILURE; - rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); - close(fd); - if (rc == -1) - break; - - *optical = 1; - if (rc == CDS_DISC_OK) - return EXIT_SUCCESS; - - detach_and_sleep(REMOVABLE_SLEEP_DELAY); - } - - /* Fall back to bare open() */ - *optical = 0; - for (;;) { - fd = open(dev_path, O_RDONLY); - if (fd < 0 && errno != ENOMEDIUM) - return EXIT_FAILURE; - close(fd); - if (fd >= 0) - return EXIT_SUCCESS; - detach_and_sleep(REMOVABLE_SLEEP_DELAY); - } -} - -static int poll_device_unplug(const char *dev_path, int optical) -{ - int rc, fd; - - for (;optical;) { - fd = open(dev_path, O_RDONLY|O_NONBLOCK); - if (fd < 0) - return EXIT_FAILURE; - rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); - close(fd); - if (rc != CDS_DISC_OK) - return EXIT_SUCCESS; - detach_and_sleep(REMOVABLE_SLEEP_DELAY); - } - - /* Fall back to bare open() */ - for (;;) { - fd = open(dev_path, O_RDONLY); - if (fd < 0 && errno != ENOMEDIUM) - return EXIT_FAILURE; - close(fd); - if (fd < 0) - return EXIT_SUCCESS; - detach_and_sleep(REMOVABLE_SLEEP_DELAY); - } -} - -static int poll_removable_device(const char *sysfs_path, - const char *dev_path) -{ - int rc, mounted, optical = -1; - - for (;;) { - rc = poll_device_plug(dev_path, &optical); - if (rc == EXIT_FAILURE) - return rc; - rc = found_new_device(dev_path); - mounted = (rc == EXIT_SUCCESS); - - poll_device_unplug(dev_path, optical); - - remove_device(dev_path); - - /* Unmount it repeatedly, if needs be */ - while (mounted && !unmount_device(dev_path)) - ; - detach_and_sleep(1); - } -} - -int main(int argc, char **argv) -{ - char *dev_path, *action; - int rc; - - action = getenv("ACTION"); - - logf = fopen("/var/log/petitboot-udev-helpers.log", "a"); - if (!logf) - logf = stdout; - pb_log("%d started\n", getpid()); - rc = EXIT_SUCCESS; - - if (!action) { - pb_log("missing environment?\n"); - return EXIT_FAILURE; - } - - set_mount_base(TMP_DIR); - - if (connect_to_socket()) - return EXIT_FAILURE; - - if (streq(action, "fake")) { - pb_log("fake mode"); - - add_device(&fake_boot_devices[0]); - add_boot_option(&fake_boot_options[0]); - add_boot_option(&fake_boot_options[1]); - add_boot_option(&fake_boot_options[2]); - add_device(&fake_boot_devices[1]); - add_boot_option(&fake_boot_options[3]); - - return EXIT_SUCCESS; - } - - dev_path = getenv("DEVNAME"); - if (!dev_path) { - pb_log("missing environment?\n"); - return EXIT_FAILURE; - } - - if (is_ignored_device(dev_path)) - return EXIT_SUCCESS; - - if (streq(action, "add")) { - char *sysfs_path = getenv("DEVPATH"); - if (sysfs_path && is_removable_device(sysfs_path)) - rc = poll_removable_device(sysfs_path, dev_path); - else - rc = found_new_device(dev_path); - } else if (streq(action, "remove")) { - pb_log("%s removed\n", dev_path); - - remove_device(dev_path); - - /* Unmount it repeatedly, if needs be */ - while (!unmount_device(dev_path)) - ; - - } else { - pb_log("invalid action '%s'\n", action); - rc = EXIT_FAILURE; - } - return rc; -} 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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 similarity index 100% rename from devices/kboot-parser.c rename to 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 +#include + +#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 similarity index 61% rename from devices/message.h rename to 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 similarity index 100% rename from devices/native-parser.c rename to discover/native-parser.c diff --git a/devices/params.c b/discover/params.c similarity index 100% rename from devices/params.c rename to discover/params.c diff --git a/devices/params.h b/discover/params.h similarity index 100% rename from devices/params.h rename to discover/params.h diff --git a/devices/parser.c b/discover/parser.c similarity index 100% rename from devices/parser.c rename to discover/parser.c diff --git a/devices/parser.h b/discover/parser.h similarity index 100% rename from devices/parser.h rename to discover/parser.h diff --git a/devices/paths.c b/discover/paths.c similarity index 100% rename from devices/paths.c rename to discover/paths.c diff --git a/devices/paths.h b/discover/paths.h similarity index 100% rename from devices/paths.h rename to 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 +#include + +#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 +#include +#include +#include +#include +#include +#include + +#include + +#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 @\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 +#include +#include + +#include + +#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 + +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 similarity index 100% rename from devices/yaboot-cfg.c rename to discover/yaboot-cfg.c diff --git a/devices/yaboot-cfg.h b/discover/yaboot-cfg.h similarity index 100% rename from devices/yaboot-cfg.h rename to discover/yaboot-cfg.h diff --git a/devices/yaboot-parser.c b/discover/yaboot-parser.c similarity index 100% rename from devices/yaboot-parser.c rename to 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 +#include +#include + +#include + +#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 + +#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 +#include +#include + +/* 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 +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#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; lensize - 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 +#include +#include + +/* 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 -#include - -#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 similarity index 100% rename from devices/parser-test.c rename to test/parser-test.c diff --git a/devices/parser-test.sh b/test/parser-test.sh similarity index 100% rename from devices/parser-test.sh rename to test/parser-test.sh diff --git a/devices/parser-tests/001/expected-output b/test/parser/001/expected-output similarity index 100% rename from devices/parser-tests/001/expected-output rename to test/parser/001/expected-output diff --git a/devices/parser-tests/001/ps3da1/etc/kboot.conf b/test/parser/001/ps3da1/etc/kboot.conf similarity index 100% rename from devices/parser-tests/001/ps3da1/etc/kboot.conf rename to test/parser/001/ps3da1/etc/kboot.conf diff --git a/devices/parser-tests/002/expected-output b/test/parser/002/expected-output similarity index 100% rename from devices/parser-tests/002/expected-output rename to test/parser/002/expected-output diff --git a/devices/parser-tests/002/ps3da1/etc/yaboot.conf b/test/parser/002/ps3da1/etc/yaboot.conf similarity index 100% rename from devices/parser-tests/002/ps3da1/etc/yaboot.conf rename to test/parser/002/ps3da1/etc/yaboot.conf diff --git a/devices/parser-tests/003/expected-output b/test/parser/003/expected-output similarity index 100% rename from devices/parser-tests/003/expected-output rename to test/parser/003/expected-output diff --git a/devices/parser-tests/003/ps3da1/etc/kboot.conf b/test/parser/003/ps3da1/etc/kboot.conf similarity index 100% rename from devices/parser-tests/003/ps3da1/etc/kboot.conf rename to test/parser/003/ps3da1/etc/kboot.conf diff --git a/devices/parser-tests/004/expected-output b/test/parser/004/expected-output similarity index 100% rename from devices/parser-tests/004/expected-output rename to test/parser/004/expected-output diff --git a/devices/parser-tests/004/rootdev b/test/parser/004/rootdev similarity index 100% rename from devices/parser-tests/004/rootdev rename to test/parser/004/rootdev diff --git a/devices/parser-tests/004/sda1/etc/kboot.conf b/test/parser/004/sda1/etc/kboot.conf similarity index 100% rename from devices/parser-tests/004/sda1/etc/kboot.conf rename to test/parser/004/sda1/etc/kboot.conf diff --git a/devices/parser-tests/005/expected-output b/test/parser/005/expected-output similarity index 100% rename from devices/parser-tests/005/expected-output rename to test/parser/005/expected-output diff --git a/devices/parser-tests/005/ps3da1/etc/kboot.conf b/test/parser/005/ps3da1/etc/kboot.conf similarity index 100% rename from devices/parser-tests/005/ps3da1/etc/kboot.conf rename to test/parser/005/ps3da1/etc/kboot.conf diff --git a/devices/parser-tests/101/expected-output b/test/parser/101/expected-output similarity index 100% rename from devices/parser-tests/101/expected-output rename to test/parser/101/expected-output diff --git a/devices/parser-tests/101/ps3da1/etc/kboot.conf b/test/parser/101/ps3da1/etc/kboot.conf similarity index 100% rename from devices/parser-tests/101/ps3da1/etc/kboot.conf rename to test/parser/101/ps3da1/etc/kboot.conf diff --git a/devices/parser-tests/102/expected-output b/test/parser/102/expected-output similarity index 100% rename from devices/parser-tests/102/expected-output rename to test/parser/102/expected-output diff --git a/devices/parser-tests/102/ps3da1/etc/kboot.conf b/test/parser/102/ps3da1/etc/kboot.conf similarity index 100% rename from devices/parser-tests/102/ps3da1/etc/kboot.conf rename to 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 +#include +#include +#include + +#include +#include +#include + +#include + +#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 +#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 + +#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 similarity index 100% rename from artwork/background.jpg rename to ui/twin/artwork/background.jpg diff --git a/artwork/cdrom.png b/ui/twin/artwork/cdrom.png similarity index 100% rename from artwork/cdrom.png rename to ui/twin/artwork/cdrom.png diff --git a/artwork/cursor.gz b/ui/twin/artwork/cursor.gz similarity index 100% rename from artwork/cursor.gz rename to ui/twin/artwork/cursor.gz diff --git a/artwork/hdd.png b/ui/twin/artwork/hdd.png similarity index 100% rename from artwork/hdd.png rename to ui/twin/artwork/hdd.png diff --git a/artwork/tux.png b/ui/twin/artwork/tux.png similarity index 100% rename from artwork/tux.png rename to ui/twin/artwork/tux.png diff --git a/artwork/usbpen.png b/ui/twin/artwork/usbpen.png similarity index 100% rename from artwork/usbpen.png rename to ui/twin/artwork/usbpen.png diff --git a/petitboot.c b/ui/twin/pb-twin.c similarity index 100% rename from petitboot.c rename to ui/twin/pb-twin.c -- 2.39.2