@@ -43,7 +43,7 @@ discover_objs = discover/udev.o discove
discover/device-handler.o discover/paths.o discover/parser-utils.o
# client objs
-ui_common_objs = ui/common/discover-client.o
+ui_common_objs = ui/common/discover-client.o ui/common/pb-system.o
ncurses_objs =
twin_objs = ui/twin/pb-twin.o
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2009 Sony Computer Entertainment Inc.
+ * Copyright 2009 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log/log.h"
+#include "talloc/talloc.h"
+#include "pb-system.h"
+
+static const struct pb_system_apps pb_system_apps = {
+ .cp = "/bin/cp",
+ .kexec = "/usr/sbin/kexec",
+ .mkdir = "/bin/mkdir",
+ .mount = "/bin/mount",
+ .scp = "/usr/bin/scp",
+ .tftp = "/usr/bin/tftp",
+ .umount = "/bin/umount",
+ .wget = "/usr/bin/wget",
+};
+
+/**
+ * pb_run_system - Run system with the supplied command.
+ * @cmd: A command string.
+ */
+
+int pb_run_system(const char *cmd)
+{
+ int result;
+
+ pb_log("%s: '%s'\n", __func__, cmd);
+
+ result = system(cmd);
+
+ if (result == -1)
+ pb_log("%s: result failed: %s (%s)\n", __func__, cmd,
+ strerror(errno));
+
+ if (WEXITSTATUS(result))
+ pb_log("%s: WEXITSTATUS %d\n", __func__, WEXITSTATUS(result));
+
+ if (WIFSIGNALED(result) && WTERMSIG(result) == SIGINT)
+ pb_log("%s: signaled\n", __func__);
+
+ return WEXITSTATUS(result);
+}
+
+/**
+ * run_kexec_local - Final kexec helper.
+ * @l_image: The local image file for kexec to execute.
+ * @l_initrd: Optional local initrd file for kexec --initrd, can be NULL.
+ * @args: Optional command line args for kexec --append, can be NULL.
+ */
+
+static int run_kexec_local(const char *l_image, const char *l_initrd,
+ const char *args)
+{
+ int result;
+ char *cmd;
+
+ /* First try by telling kexec to run shutdown */
+
+ cmd = talloc_asprintf(NULL, "%s%s%s%s%s%s%s %s", pb_system_apps.kexec,
+ (l_initrd ? " --initrd='" : ""),
+ (l_initrd ? l_initrd : ""),
+ (l_initrd ? "'" : ""),
+ (args ? " --append='" : ""),
+ (args ? args : ""),
+ (args ? "'" : ""),
+ l_image);
+
+ pb_log("%s: '%s'\n", __func__, cmd);
+
+ result = pb_run_system(cmd);
+ talloc_free(cmd);
+
+ /* kexec will return zero on success */
+ /* On error force a kexec with the -f option */
+
+ if (result) {
+ cmd = talloc_asprintf(NULL, "%s -f%s%s%s%s%s%s %s",
+ pb_system_apps.kexec,
+ (l_initrd ? " --initrd='" : ""),
+ (l_initrd ? l_initrd : ""),
+ (l_initrd ? "'" : ""),
+ (args ? " --append='" : ""),
+ (args ? args : ""),
+ (args ? "'" : ""),
+ l_image);
+
+ pb_log("%s: '%s'\n", __func__, cmd);
+
+ result = pb_run_system(cmd);
+ talloc_free(cmd);
+ }
+
+ if (result)
+ pb_log("%s: failed: (%d)\n", __func__, result);
+
+ return result;
+}
+
+enum pb_url_scheme {
+ pb_url_unknown = 0,
+ pb_url_file,
+ pb_url_ftp,
+ pb_url_http,
+ pb_url_https,
+ pb_url_nfs,
+ pb_url_scp,
+ pb_url_tftp,
+};
+
+/**
+ * struct pb_url
+ *
+ * scheme://host:port/path
+ * http://www.ietf.org/rfc/rfc3986.txt
+ */
+
+struct pb_url {
+ enum pb_url_scheme scheme;
+ char *full;
+ char *host;
+ char *port;
+ char *path;
+ char *dir;
+ char *file;
+};
+
+/**
+ * pb_url_parse - Parse a remote file URL.
+ */
+
+static struct pb_url *pb_url_parse(const char *s_url)
+{
+ static const char s_file[] = "file://";
+ static const char s_ftp[] = "ftp://";
+ static const char s_http[] = "http://";
+ static const char s_https[] = "https://";
+ static const char s_nfs[] = "nfs://";
+ static const char s_scp[] = "scp://";
+ static const char s_tftp[] = "tftp://";
+ struct pb_url *url;
+ const char *p;
+
+ pb_log("%s: '%s'\n", __func__, s_url);
+
+ assert(s_url && *s_url);
+
+ url = talloc_zero(NULL, struct pb_url);
+
+ if (!url || !s_url || !*s_url) {
+ pb_log("%s: talloc failed\n", __func__);
+ return NULL;
+ }
+
+ if (!strncasecmp(s_url, s_file, sizeof(s_file) - 1)) {
+ url->scheme = pb_url_file;
+ p = s_url + sizeof(s_file) - 1;
+ goto got_scheme;
+ }
+
+ if (!strncasecmp(s_url, s_ftp, sizeof(s_ftp) - 1)) {
+ url->scheme = pb_url_ftp;
+ p = s_url + sizeof(s_ftp) - 1;
+ goto got_scheme;
+ }
+
+ if (!strncasecmp(s_url, s_http, sizeof(s_http) - 1)) {
+ url->scheme = pb_url_http;
+ p = s_url + sizeof(s_http) - 1;
+ goto got_scheme;
+ }
+
+ if (!strncasecmp(s_url, s_https, sizeof(s_https) - 1)) {
+ url->scheme = pb_url_https;
+ p = s_url + sizeof(s_https) - 1;
+ goto got_scheme;
+ }
+
+ if (!strncasecmp(s_url, s_nfs, sizeof(s_nfs) - 1)) {
+ url->scheme = pb_url_nfs;
+ p = s_url + sizeof(s_nfs) - 1;
+ goto got_scheme;
+ }
+
+ if (!strncasecmp(s_url, s_scp, sizeof(s_scp) - 1)) {
+ url->scheme = pb_url_scp;
+ p = s_url + sizeof(s_scp) - 1;
+ goto got_scheme;
+ }
+
+ if (!strncasecmp(s_url, s_tftp, sizeof(s_tftp) - 1)) {
+ url->scheme = pb_url_tftp;
+ p = s_url + sizeof(s_tftp) - 1;
+ goto got_scheme;
+ }
+
+ url->scheme = pb_url_file;
+ p = s_url;
+
+got_scheme:
+
+ url->full = talloc_strdup(url, s_url);
+
+ if (url->scheme == pb_url_file) {
+ url->port = NULL;
+ url->host = NULL;
+ url->path = talloc_strdup(url, p);
+ } else {
+ int len;
+ const char *col;
+ const char *path;
+
+ path = strchr(p, '/');
+
+ if (!path) {
+ pb_log("%s: parse path failed '%s'\n", p);
+ goto fail;
+ }
+
+ col = strchr(p, ':');
+
+ if (col) {
+ len = path - col - 1;
+ url->port = len ? talloc_strndup(url, col + 1, len)
+ : NULL;
+ len = col - p;
+ url->host = len ? talloc_strndup(url, p, len) : NULL;
+ } else {
+ url->port = NULL;
+ url->host = talloc_strndup(url, p, path - p);
+ }
+ url->path = talloc_strdup(url, path);
+ }
+
+ p = strrchr(url->path, '/');
+
+ if (p) {
+ p++;
+ url->dir = talloc_strndup(url, url->path, p - url->path);
+ url->file = talloc_strdup(url, p);
+ } else {
+ url->dir = NULL;
+ url->file = talloc_strdup(url, url->path);
+ }
+
+ pb_log(" scheme %d\n", url->scheme);
+ pb_log(" host '%s'\n", url->host);
+ pb_log(" port '%s'\n", url->port);
+ pb_log(" path '%s'\n", url->path);
+ pb_log(" dir '%s'\n", url->dir);
+ pb_log(" file '%s'\n", url->file);
+
+ return url;
+
+fail:
+ talloc_free(url);
+ return NULL;
+}
+
+/**
+ * pb_load_nfs - Mounts the NFS export and returns the local file path.
+ *
+ * The caller must free the returned string.
+ */
+
+static char *pb_load_nfs(struct pb_url *url)
+{
+ int result;
+ char *cmd;
+ char *local;
+ const char *mnt;
+
+ mnt = tempnam(NULL, "pb-");
+
+ if (mnt)
+ return NULL;
+
+ cmd = talloc_asprintf(NULL, "%s -p %s", pb_system_apps.mkdir, mnt);
+
+ result = pb_run_system(cmd);
+ talloc_free(cmd);
+
+ if (result)
+ goto fail;
+
+ cmd = talloc_asprintf(NULL,
+ "%s -t nfs %s%s -o ro,nolock,nodiratime %s:%s %s",
+ pb_system_apps.mount,
+ (url->port ? "-o port=" : ""),
+ (url->port ? url->port : ""),
+ url->host, url->dir, mnt);
+
+ pb_run_system(cmd);
+ talloc_free(cmd);
+
+ if (result)
+ goto fail;
+
+ asprintf(&local, "%s/%s", mnt, url->path);
+ pb_log("%s: local '%s'\n", __func__, local);
+
+ return local;
+
+fail:
+ cmd = talloc_asprintf(NULL, "%s %s", pb_system_apps.umount, mnt);
+ pb_run_system(cmd);
+ talloc_free(cmd);
+
+ return NULL;
+}
+
+/**
+ * pb_load_scp - Loads a remote file via scp and returns the local file path.
+ *
+ * The caller must free the returned string.
+ */
+
+static char *pb_load_scp(struct pb_url __attribute__((unused)) *url)
+{
+#if 0
+ int result;
+ char *cmd;
+
+ cmd = talloc_asprintf(NULL, "%s %s %s", pb_system_apps.scp, remote,
+ local);
+
+ result = pb_run_system(cmd);
+ talloc_free(cmd);
+
+ return result ? NULL : local;
+#endif
+ return NULL;
+}
+
+/**
+ * pb_load_tftp - Loads a remote file via tftp and returns the local file path.
+ *
+ * The caller must free the returned string.
+ */
+
+static char *pb_load_tftp(struct pb_url *url)
+{
+ int result;
+ char *cmd;
+ char *local;
+
+ local = tempnam(NULL, "pb-");
+
+ if (!local)
+ return NULL;
+
+ /* first try busybox tftp args */
+
+ cmd = talloc_asprintf(NULL, "%s -g -l %s -r %s %s %s >&- 2>&-",
+ pb_system_apps.tftp, local, url->path, url->host,
+ (url->port ? url->port : ""));
+
+ result = pb_run_system(cmd);
+ talloc_free(cmd);
+
+ if (!result)
+ return local;
+
+ /* next try tftp-hpa args */
+
+ cmd = talloc_asprintf(NULL,
+ "%s -v -m binary %s %s -c get %s %s >&- 2>&-",
+ pb_system_apps.tftp, url->host, (url->port ? url->port : ""),
+ url->path, local);
+
+ result = pb_run_system(cmd);
+ talloc_free(cmd);
+
+ return result ? NULL : local;
+}
+
+/**
+ * pb_load_wget - Loads a remote file via wget and returns the local file path.
+ *
+ * The caller must free the returned string.
+ */
+
+static char *pb_load_wget(struct pb_url *url)
+{
+ int result;
+ char *cmd;
+ char *local;
+
+ local = tempnam(NULL, "pb-");
+
+ if (!local)
+ return NULL;
+
+ cmd = talloc_asprintf(NULL, "%s -O %s %s", pb_system_apps.wget, local,
+ url->full);
+
+ result = pb_run_system(cmd);
+ talloc_free(cmd);
+
+ return result ? NULL : local;
+}
+
+/**
+ * pb_load_file - Loads a remote file and returns the local file path.
+ *
+ * The caller must free the returned string.
+ */
+
+static char *pb_load_file(const char *remote)
+{
+ char *local;
+ struct pb_url *url = pb_url_parse(remote);
+
+ if (!url)
+ return NULL;
+
+ switch(url->scheme) {
+ case pb_url_ftp:
+ case pb_url_http:
+ case pb_url_https:
+ local = pb_load_wget(url);
+ break;
+ case pb_url_nfs:
+ local = pb_load_nfs(url);
+ break;
+ case pb_url_scp:
+ local = pb_load_scp(url);
+ break;
+ case pb_url_tftp:
+ local = pb_load_tftp(url);
+ break;
+ default:
+ local = strdup(remote);
+ break;
+ }
+
+ talloc_free(url);
+ return local;
+}
+
+/**
+ * pb_run_kexec - Run kexec with the supplied boot options.
+ *
+ * For the convenience of the user, tries to load both files before
+ * returning error.
+ */
+
+int pb_run_kexec(const struct pb_kexec_data *kd)
+{
+ int result;
+ char *l_image;
+ char *l_initrd;
+
+ pb_log("%s: image: '%s'\n", __func__, kd->image);
+ pb_log("%s: initrd: '%s'\n", __func__, kd->initrd);
+ pb_log("%s: args: '%s'\n", __func__, kd->args);
+
+ if (kd->image)
+ l_image = pb_load_file(kd->image);
+ else {
+ l_image = NULL;
+ pb_log("%s: error null image\n", __func__);
+ }
+
+ l_initrd = kd->initrd ? pb_load_file(kd->initrd) : NULL;
+
+ if (!l_image || (kd->initrd && !l_initrd))
+ result = -1;
+ else
+ result = run_kexec_local(l_image, l_initrd, kd->args);
+
+ //FIXME: bug here!!
+ //free(l_image);
+ //free(l_initrd);
+
+ return result;
+}
+
+/**
+ * pb_elf_hash - Standard elf hash routine.
+ */
+
+unsigned int pb_elf_hash(const char *str)
+{
+ unsigned int h = 0, g;
+
+ while (*str) {
+ h = (h << 4) + *str++;
+ g = h & 0xf0000000;
+ if (g)
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ pb_log("%s: %u\n", __func__, h);
+ return h;
+}
+
+/**
+ * pb_cat_hash - Hashes concatenation of two strings.
+ */
+
+unsigned int pb_cat_hash(const char *a, const char *b)
+{
+ unsigned int h;
+ char *s;
+
+ s = talloc_asprintf(NULL, "%s%s", a, b);
+ h = pb_elf_hash(s);
+ talloc_free(s);
+
+ return h;;
+}
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009 Sony Computer Entertainment Inc.
+ * Copyright 2009 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined(_PB_KEXEC_H)
+#define _PB_KEXEC_H
+
+#include "pb-protocol/pb-protocol.h"
+
+struct pb_system_apps {
+ const char *cp;
+ const char *kexec;
+ const char *mkdir;
+ const char *mount;
+ const char *scp;
+ const char *tftp;
+ const char *umount;
+ const char *wget;
+};
+
+struct pb_kexec_data {
+ char *image;
+ char *initrd;
+ char *args;
+};
+
+int pb_run_system(const char *cmd);
+int pb_run_kexec(const struct pb_kexec_data *kd);
+
+unsigned int pb_elf_hash(const char *str);
+unsigned int pb_cat_hash(const char *a, const char *b);
+
+static inline unsigned int pb_opt_hash(const struct device *dev,
+ const struct boot_option *opt)
+{
+ return pb_cat_hash(dev->name, opt->name);
+}
+
+#endif
Add some system helper routines for UI convenience: pb_run_system() pb_run_kexec() pb_elf_hash() pb_cat_hash() pb_opt_hash() Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> --- This still needs some work to finish, but it is mostly working and is needed to kexec anything. -Geoff rules.mk | 2 ui/common/pb-system.c | 535 ++++++++++++++++++++++++++++++++++++++++++++++++++ ui/common/pb-system.h | 53 ++++ 3 files changed, 589 insertions(+), 1 deletion(-)