summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-03-07 12:54:29 -0800
committerChromeBot <chrome-bot@google.com>2013-03-11 08:38:46 -0700
commitfeb2518166b1cd181e607c611cbb610f0c7300da (patch)
tree33a22857fad5a1f2246caf064b3b4eec8867e00f
parent5fed2a667096341160db8643a4a057e328953a1d (diff)
downloadvboot-factory-spring-3842.B.tar.gz
Wrap all vboot utilities with futility.firmware-spring-3833.Bfactory-spring-3842.B
This moves all the old userspace utilities generated by vboot_reference into a subdirectory not in $PATH, and replaces them with symlinks to a single executable named 'futility'. At the moment that utility just execs the original utilities (optionally logging that fact first). Ultimately, the old utilities will be subsumed into a single binary instead of multiple separate executables. There is a matching CL needed to make the recovery image creation work. BUG=chromium-os:37062 BRANCH=none CQ-DEPEND=CL:44864 TEST=auto To test, build everything, test everything. It should work as before in all cases. I have built normal images, test images, factory installers, recovery images; they all seem to work. I've run trybots on daisy-paladin link-paladin lumpy-paladin and alex-paladin. Change-Id: Ie93db676f2ed2a64e4b13b3b5dc6b65a77db0f8c Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/44871 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Hung-Te Lin <hungte@chromium.org>
-rw-r--r--Makefile66
-rw-r--r--futility/IGNOREME.c12
-rw-r--r--futility/cmd_foo.c22
-rw-r--r--futility/futility.c285
-rw-r--r--futility/futility.h57
-rw-r--r--futility/futility.lds9
-rwxr-xr-xfutility/tests/common.sh47
-rwxr-xr-xfutility/tests/run_futility_tests.sh78
-rw-r--r--utility/dumpRSAPublicKey.c8
-rw-r--r--utility/gbb_utility.cc7
-rw-r--r--utility/tpmc.c11
11 files changed, 565 insertions, 37 deletions
diff --git a/Makefile b/Makefile
index a7101cc4..cd391143 100644
--- a/Makefile
+++ b/Makefile
@@ -37,22 +37,29 @@
# We should only run pwd once, not every time we refer to ${BUILD}.
SRCDIR := $(shell pwd)
-BUILD ?= $(SRCDIR)/build
+BUILD = $(SRCDIR)/build
export BUILD
# Stuff for 'make install'
-INSTALL ?= install
-DESTDIR ?= /usr/local/bin
-
+INSTALL = install
+DESTDIR = /usr/local/bin
+OLDDIR = old_bins
+
+# Where exactly do the pieces go?
+# FT_DIR = futility target directory - where it will be on the target
+# F_DIR = futility install directory - where it gets put right now
+# UB_DIR = userspace binary directory for futility's exec() targets
+# VB_DIR = target vboot directory - for dev-mode-only helpers, keys, etc.
ifeq (${MINIMAL},)
# Host install just puts everything in one place
-UB_DIR=${DESTDIR}
-SB_DIR=${DESTDIR}
-VB_DIR=${DESTDIR}
+FT_DIR=${DESTDIR}
+F_DIR=${DESTDIR}
+UB_DIR=${DESTDIR}/${OLDDIR}
else
# Target install puts things into DESTDIR subdirectories
-UB_DIR=${DESTDIR}/usr/bin
-SB_DIR=${DESTDIR}/sbin
+FT_DIR=/usr/bin
+F_DIR=${DESTDIR}${FT_DIR}
+UB_DIR=${F_DIR}/${OLDDIR}
VB_DIR=${DESTDIR}/usr/share/vboot/bin
endif
@@ -127,6 +134,10 @@ CC ?= gcc
CFLAGS += -DCHROMEOS_ENVIRONMENT -Wall -Werror # HEY: always want last two?
endif
+ifneq (${OLDDIR},)
+CFLAGS += -DOLDDIR=${OLDDIR}
+endif
+
ifneq (${DEBUG},)
CFLAGS += -DVBOOT_DEBUG
endif
@@ -135,6 +146,10 @@ ifeq (${DISABLE_NDEBUG},)
CFLAGS += -DNDEBUG
endif
+ifneq (${FORCE_LOGGING_ON},)
+CFLAGS += -DFORCE_LOGGING_ON=${FORCE_LOGGING_ON}
+endif
+
# Create / use dependency files
CFLAGS += -MMD -MF $@.d
@@ -429,8 +444,13 @@ SIGNING_COMMON = scripts/image_signing/common_minimal.sh
# The unified firmware utility will eventually replace all the others
FUTIL_BIN = ${BUILD}/futility/futility
+# These are the others it will replace.
+FUTIL_OLD = $(notdir ${CGPT} ${UTIL_BINS} ${UTIL_SCRIPTS} \
+ ${SIGNING_SCRIPTS} ${SIGNING_SCRIPTS_DEV})
+
FUTIL_SRCS = \
- futility/IGNOREME.c
+ futility/futility.c \
+ futility/cmd_foo.c
FUTIL_LDS = futility/futility.lds
@@ -696,13 +716,15 @@ utils_install: ${UTIL_BINS} ${UTIL_SCRIPTS}
# And some signing stuff for the target
.PHONY: signing_install
signing_install: ${SIGNING_SCRIPTS} ${SIGNING_SCRIPTS_DEV} ${SIGNING_COMMON}
-ifneq (${MINIMAL},)
@printf " INSTALL SIGNING\n"
${Q}mkdir -p ${UB_DIR}
${Q}${INSTALL} -t ${UB_DIR} ${SIGNING_SCRIPTS}
+ ${Q}${INSTALL} -t ${UB_DIR} ${SIGNING_SCRIPTS_DEV}
+ ${Q}${INSTALL} -t ${UB_DIR} -m 'u=rw,go=r,a-s' ${SIGNING_COMMON}
+ifneq (${VB_DIR},)
${Q}mkdir -p ${VB_DIR}
- ${Q}${INSTALL} -t ${VB_DIR} ${SIGNING_SCRIPTS_DEV}
- ${Q}${INSTALL} -t ${VB_DIR} -m 'u=rw,go=r,a-s' ${SIGNING_COMMON}
+ ${Q}for prog in $(notdir ${SIGNING_SCRIPTS_DEV}); do \
+ ln -sf "${FT_DIR}/futility" "${VB_DIR}/$$prog"; done
endif
# ----------------------------------------------------------------------------
@@ -718,9 +740,10 @@ ${FUTIL_BIN}: ${FUTIL_LDS} ${FUTIL_OBJS}
.PHONY: futil_install
futil_install: ${FUTIL_BIN}
@printf " INSTALL futility\n"
- ${Q}mkdir -p ${UB_DIR}
- ${Q}${INSTALL} -t ${UB_DIR} $^
-
+ ${Q}mkdir -p ${F_DIR}
+ ${Q}${INSTALL} -t ${F_DIR} ${FUTIL_BIN}
+ ${Q}for prog in ${FUTIL_OLD}; do \
+ ln -sf futility "${F_DIR}/$$prog"; done
# ----------------------------------------------------------------------------
# Utility to generate TLCL structure definition header file.
@@ -791,6 +814,10 @@ ${BUILD}/firmware/linktest/main: LIBS = ${FWLIB}
# GBB utility needs C++ linker. TODO: It shouldn't.
${BUILD}/utility/gbb_utility: LD = ${CXX}
+# Because we play some clever linker script games to add new commands without
+# changing any header files, futility must be linked with ld.bfd, not gold.
+${FUTIL_BIN}: LDFLAGS += -fuse-ld=bfd
+
# Some utilities need external crypto functions
${BUILD}/utility/dumpRSAPublicKey: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/pad_digest_utility: LDLIBS += ${CRYPTO_LIBS}
@@ -855,7 +882,7 @@ test_targets:: runcgpttests runmisctests
ifeq (${MINIMAL},)
# Bitmap utility isn't compiled for minimal variant
-test_targets:: runbmptests
+test_targets:: runbmptests runfutiltests
# Scripts don't work under qemu testing
# TODO: convert scripts to makefile so they can be called directly
test_targets:: runtestscripts
@@ -938,9 +965,9 @@ runmisctests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vboot_nvstorage_test
.PHONY: runfutiltests
-runfutiltests: DESTDIR := ${TEST_INSTALL_DIR}
+runfutiltests: override DESTDIR = ${TEST_INSTALL_DIR}
runfutiltests: test_setup install
- @echo "$@ passed"
+ futility/tests/run_futility_tests.sh ${DESTDIR}
# Run long tests, including all permutations of encryption keys (instead of
# just the ones we use) and tests of currently-unused code.
@@ -987,4 +1014,3 @@ coverage:
else
coverage: coverage_init runtests coverage_html
endif
-
diff --git a/futility/IGNOREME.c b/futility/IGNOREME.c
deleted file mode 100644
index c90c87e5..00000000
--- a/futility/IGNOREME.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include <stdio.h>
-
-int main(int argc, char *argv[])
-{
- printf("Pay no attention to that man behind the curtain.\n");
- return 1;
-}
diff --git a/futility/cmd_foo.c b/futility/cmd_foo.c
new file mode 100644
index 00000000..e02a9ffb
--- /dev/null
+++ b/futility/cmd_foo.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+#include "futility.h"
+
+static int do_something(int argc, char *argv[])
+{
+ int i;
+ printf("this is %s\n", __func__);
+ for (i = 0; i < argc; i++)
+ printf("argv[%d] = %s\n", i, argv[i]);
+ return 0;
+}
+
+DECLARE_FUTIL_COMMAND(foo, do_something, "invoke a foo");
+DECLARE_FUTIL_COMMAND(bar, do_something, "go to bar");
+DECLARE_FUTIL_COMMAND(hey, do_something, "shout");
diff --git a/futility/futility.c b/futility/futility.c
new file mode 100644
index 00000000..c30e3e8e
--- /dev/null
+++ b/futility/futility.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "futility.h"
+
+#define MYNAME "futility"
+#ifdef OLDDIR
+#define XSTR(A) STR(A)
+#define STR(A) #A
+#define SUBDIR XSTR(OLDDIR)
+#else
+#define SUBDIR "old_bins"
+#endif
+
+/* File to use for logging, if present */
+#define LOGFILE "/tmp/futility.log"
+
+/* Normally logging will only happen if the logfile already exists. Uncomment
+ * this to force log file creation (and thus logging) always. */
+/* #define FORCE_LOGGING_ON */
+
+/******************************************************************************/
+
+static const char * const usage= "\n\
+Usage: " MYNAME " PROGRAM|COMMAND [args...]\n\
+\n\
+This is the unified firmware utility, which will eventually replace\n\
+all the distinct userspace tools formerly produced by the\n\
+vboot_reference package.\n\
+\n\
+When symlinked under the name of one of those previous tools, it can\n\
+do one of two things: either it will fully implement the original\n\
+behavior, or (until that functionality is complete) it will just exec\n\
+the original binary.\n\
+\n\
+In either case it can append some usage information to " LOGFILE "\n\
+to help improve coverage and correctness.\n\
+\n\
+If you invoke it directly instead of via a symlink, it requires one\n\
+argument, which is the name of the old binary to exec. That binary\n\
+must be located in a directory named \"" SUBDIR "\" underneath\n\
+the " MYNAME " executable.\n\
+\n";
+
+static int help(int argc, char *argv[])
+{
+ futil_cmd_t *cmd;
+ int i;
+
+ fputs(usage, stdout);
+
+ printf("The following commands are built-in:\n");
+
+ for (cmd = futil_cmds_start(); cmd < futil_cmds_end(); cmd++)
+ printf(" %-20s %s\n",
+ cmd->name, cmd->shorthelp);
+
+ printf("\n");
+
+ printf("FYI, you added these args that I'm ignoring:\n");
+ for (i = 0; i < argc; i++)
+ printf("argv[%d] = %s\n", i, argv[i]);
+
+ return 0;
+}
+DECLARE_FUTIL_COMMAND(help, help, "Show a bit of help");
+
+
+/******************************************************************************/
+/* Logging stuff */
+
+static int log_fd = -1;
+
+/* Write the string and a newline. Silently give up on errors */
+static void log_str(char *str)
+{
+ int len, done, n;
+
+ if (log_fd < 0)
+ return;
+
+ if (!str)
+ str = "(NULL)";
+
+ len = strlen(str);
+ if (len == 0) {
+ str = "(EMPTY)";
+ len = strlen(str);
+ }
+
+ for (done = 0; done < len; done += n) {
+ n = write(log_fd, str + done, len - done);
+ if (n < 0)
+ return;
+ }
+
+ write(log_fd, "\n", 1);
+}
+
+static void log_close(void)
+{
+ struct flock lock;
+
+ if (log_fd >= 0) {
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ if (fcntl(log_fd, F_SETLKW, &lock))
+ perror("Unable to unlock log file");
+
+ close(log_fd);
+ log_fd = -1;
+ }
+}
+
+static void log_open(void)
+{
+ struct flock lock;
+ int ret;
+
+#ifdef FORCE_LOGGING_ON
+ log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666);
+#else
+ log_fd = open(LOGFILE, O_WRONLY|O_APPEND);
+#endif
+ if (log_fd < 0) {
+
+ if (errno != EACCES)
+ return;
+
+ /* Permission problems should improve shortly ... */
+ sleep(1);
+ log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666);
+ if (log_fd < 0) /* Nope, they didn't */
+ return;
+ }
+
+ /* Let anyone have a turn */
+ fchmod(log_fd, 0666);
+
+ /* But only one at a time */
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_END;
+
+ ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */
+ if (ret < 0)
+ log_close();
+}
+
+#define CALLER_PREFIX "CALLER:"
+static void log_args(int argc, char *argv[])
+{
+ int i;
+ ssize_t r;
+ pid_t parent;
+ char buf[80];
+ char str_caller[PATH_MAX + sizeof(CALLER_PREFIX)] = CALLER_PREFIX;
+ char *truename = str_caller + sizeof(CALLER_PREFIX) - 1;
+ /* Note: truename starts on the \0 from CALLER_PREFIX, so we can write
+ * PATH_MAX chars into truename and still append a \0 at the end. */
+
+ log_open();
+
+ /* delimiter */
+ log_str("##### HEY #####");
+
+ /* Can we tell who called us? */
+ parent = getppid();
+ snprintf(buf, sizeof(buf), "/proc/%d/exe", parent);
+ r = readlink(buf, truename, PATH_MAX);
+ if (r >= 0) {
+ truename[r] = '\0';
+ log_str(str_caller);
+ }
+
+ /* Now log the stuff about ourselves */
+ for (i = 0; i < argc; i++)
+ log_str(argv[i]);
+
+ log_close();
+}
+
+
+/******************************************************************************/
+/* Here we go */
+
+int main(int argc, char *argv[], char *envp[])
+{
+ char *progname;
+ char truename[PATH_MAX];
+ char oldname[PATH_MAX];
+ char buf[80];
+ pid_t myproc;
+ ssize_t r;
+ char *s;
+ futil_cmd_t *cmd;
+
+ log_args(argc, argv);
+
+ /* How were we invoked? */
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ /* Invoked directly by name */
+ if (0 == strcmp(progname, MYNAME)) {
+ if (argc < 2) { /* must have an argument */
+ fputs(usage, stderr);
+ exit(1);
+ }
+
+ /* We can just pass the rest along, then */
+ argc--;
+ argv++;
+
+ /* So now what name do we want to invoke? */
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+ }
+
+ /* See if it's asking for something we know how to do ourselves */
+ for (cmd = futil_cmds_start(); cmd < futil_cmds_end(); cmd++)
+ if (0 == strcmp(cmd->name, progname))
+ return cmd->handler(argc, argv);
+
+ /* Nope, it must be wrapped */
+
+ /* The old binaries live under the true executable. Find out where that is. */
+ myproc = getpid();
+ snprintf(buf, sizeof(buf), "/proc/%d/exe", myproc);
+ r = readlink(buf, truename, PATH_MAX - 1);
+ if (r < 0) {
+ fprintf(stderr, "%s is lost: %s => %s: %s\n", MYNAME, argv[0],
+ buf, strerror(errno));
+ exit(1);
+ } else if (r == PATH_MAX - 1) {
+ /* Yes, it might _just_ fit, but we'll count that as wrong anyway. We can't
+ * determine the right size using the example in the readlink manpage,
+ * because the /proc symlink returns an st_size of 0. */
+ fprintf(stderr, "%s is too long: %s => %s\n", MYNAME, argv[0], buf);
+ exit(1);
+ }
+
+ truename[r] = '\0';
+ s = strrchr(truename, '/'); /* Find the true directory */
+ if (s) {
+ *s = '\0';
+ } else { /* I don't think this can happen */
+ fprintf(stderr, "%s says %s doesn't make sense\n", MYNAME, truename);
+ exit(1);
+ }
+ /* If the old binary path doesn't fit, just give up. */
+ r = snprintf(oldname, PATH_MAX, "%s/%s/%s", truename, SUBDIR, progname);
+ if (r >= PATH_MAX) {
+ fprintf(stderr, "%s/%s/%s is too long\n", truename, SUBDIR, progname);
+ exit(1);
+ }
+
+ fflush(0);
+ execve(oldname, argv, envp);
+
+ fprintf(stderr, "%s failed to exec %s: %s\n", MYNAME,
+ oldname, strerror(errno));
+ return 1;
+}
diff --git a/futility/futility.h b/futility/futility.h
new file mode 100644
index 00000000..ed268905
--- /dev/null
+++ b/futility/futility.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <stdint.h>
+
+#ifndef VBOOT_REFERENCE_FUTILITY_H_
+#define VBOOT_REFERENCE_FUTILITY_H_
+
+/*
+ Here's a structure to define the commands that futility implements.
+ */
+typedef struct {
+ const char const * name;
+ int (*handler)(int argc, char **argv);
+ const char const * shorthelp;
+} __attribute__ ((aligned (16))) futil_cmd_t ; /* align for x86_64 ABI */
+
+/*
+ * Create an instance in a separate section. We'll have a linker script to
+ * gather them all up later, so we can refer to them without explictly
+ * declaring every function in a header somewhere
+ */
+#define DECLARE_FUTIL_COMMAND(name, handler, shorthelp) \
+ static const char __futil_cmd_name_##name[] = #name; \
+ const futil_cmd_t __futil_cmd_##name \
+ __attribute__((section(".futil_cmds." #name))) \
+ = { __futil_cmd_name_##name, handler, shorthelp }
+
+/*
+ * Functions to find the command table. We have to play some games here,
+ * because the x86_64 ABI says this:
+ *
+ * An array uses the same alignment as its elements, except that a local or
+ * global array variable that requires at least 16 bytes, or a C99 local or
+ * global variable-length array variable, always has alignment of at least
+ * 16 bytes.
+ *
+ * The linker script doesn't know what alignment to use for __futil_cmds_start,
+ * because that's determined at compile-time and unavailable to the script
+ * unless we define one global futil_cmd_t in advance.
+ */
+static inline futil_cmd_t *futil_cmds_start(void)
+{
+ extern uintptr_t __futil_cmds_start[]; /* from linker script */
+ uintptr_t mask = sizeof(futil_cmd_t) - 1;
+ uintptr_t addr = (uintptr_t)(__futil_cmds_start);
+ return (futil_cmd_t *)((addr + mask) & ~mask);
+}
+static inline futil_cmd_t *futil_cmds_end(void)
+{
+ extern uintptr_t __futil_cmds_end[]; /* from linker script */
+ return (futil_cmd_t *)(&__futil_cmds_end[0]);
+}
+
+#endif /* VBOOT_REFERENCE_FUTILITY_H_ */
diff --git a/futility/futility.lds b/futility/futility.lds
index e428ddca..e03ab5c4 100644
--- a/futility/futility.lds
+++ b/futility/futility.lds
@@ -4,4 +4,11 @@
* found in the LICENSE file.
*/
-/* Nothing to see here. Move along... */
+SECTIONS
+{
+ .rodata : {
+ __futil_cmds_start = .;
+ *(SORT(.futil_cmds.*));
+ __futil_cmds_end = .;
+ }
+}
diff --git a/futility/tests/common.sh b/futility/tests/common.sh
new file mode 100755
index 00000000..ed187d7b
--- /dev/null
+++ b/futility/tests/common.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Color output encodings.
+COL_RED='\E[31;1m'
+COL_GREEN='\E[32;1m'
+COL_YELLOW='\E[33;1m'
+COL_BLUE='\E[34;1m'
+COL_STOP='\E[0;m'
+
+# args: [message]
+green() {
+ echo -e "${COL_GREEN}$*${COL_STOP}"
+}
+
+# args: [message]
+yellow() {
+ echo -e "${COL_YELLOW}WARNING: $*${COL_STOP}"
+}
+
+# args: [message]
+red() {
+ echo -e "${COL_RED}$*${COL_STOP}"
+}
+
+# args: [nested level] [message]
+error() {
+ local lev=${1:-}
+ case "${1:-}" in
+ [0-9]*)
+ lev=$1
+ shift
+ ;;
+ *) lev=0
+ ;;
+ esac
+ local x=$(caller $lev)
+ local cline="${x%% *}"
+ local cfile="${x#* }"
+ cfile="${cfile##*/}"
+ local args="$*"
+ local spacer="${args:+: }"
+ red "at ${cfile}, line ${cline}${spacer}${args}" 1>&2
+ exit 1
+}
diff --git a/futility/tests/run_futility_tests.sh b/futility/tests/run_futility_tests.sh
new file mode 100755
index 00000000..ff2de4be
--- /dev/null
+++ b/futility/tests/run_futility_tests.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Load common constants and variables.
+. "$(dirname "$0")/common.sh"
+
+# Where are the programs I'm testing against?
+[ -z "${1:-}" ] && error "Directory argument is required"
+BINDIR="$1"
+shift
+
+FUTILITY="$BINDIR/futility"
+OLDDIR="$BINDIR/old_bins"
+
+BUILD=$(dirname "${BINDIR}")
+
+# Here are the old programs to be wrapped
+# FIXME(chromium-os:37062): There are others besides these.
+# FIXME: dev_debug_vboot isn't tested right now.
+PROGS=${*:-cgpt crossystem dev_sign_file dumpRSAPublicKey
+ dump_fmap dump_kernel_config enable_dev_usb_boot gbb_utility
+ tpm_init_temp_fix tpmc vbutil_firmware vbutil_kernel vbutil_key
+ vbutil_keyblock vbutil_what_keys}
+
+# Get ready
+pass=0
+progs=0
+pwd
+OUTDIR="${BUILD}/tests/futility_test_dir"
+[ -d "$OUTDIR" ] || mkdir -p "$OUTDIR"
+
+# For now just compare results of invoking each program with no args.
+# FIXME(chromium-os:37062): Create true rigorous tests for every program.
+for i in $PROGS; do
+ : $(( progs++ ))
+
+ # Try the real thing first
+ echo -n "$i ... "
+ rc=$("${OLDDIR}/$i" \
+ 1>"${OUTDIR}/$i.stdout.orig" 2>"${OUTDIR}/$i.stderr.orig" \
+ || echo "$?")
+ echo "${rc:-0}" > "${OUTDIR}/$i.return.orig"
+
+ # Then try the symlink
+ rc=$("$BINDIR/$i" 1>"${OUTDIR}/$i.stdout.link" \
+ 2>"${OUTDIR}/$i.stderr.link" || echo "$?")
+ echo "${rc:-0}" > "${OUTDIR}/$i.return.link"
+
+ # And finally try the explicit wrapper
+ rc=$("$FUTILITY" "$i" 1>"${OUTDIR}/$i.stdout.futil" \
+ 2>"${OUTDIR}/$i.stderr.futil" || echo "$?")
+ echo "${rc:-0}" > "${OUTDIR}/$i.return.futil"
+
+ # Different?
+ if cmp -s "${OUTDIR}/$i.return.orig" "${OUTDIR}/$i.return.link" &&
+ cmp -s "${OUTDIR}/$i.stdout.orig" "${OUTDIR}/$i.stdout.link" &&
+ cmp -s "${OUTDIR}/$i.stderr.orig" "${OUTDIR}/$i.stderr.link" &&
+ cmp -s "${OUTDIR}/$i.return.orig" "${OUTDIR}/$i.return.futil" &&
+ cmp -s "${OUTDIR}/$i.stdout.orig" "${OUTDIR}/$i.stdout.futil" &&
+ cmp -s "${OUTDIR}/$i.stderr.orig" "${OUTDIR}/$i.stderr.futil" ; then
+ green "passed"
+ : $(( pass++ ))
+ rm -f ${OUTDIR}/$i.{stdout,stderr,return}.{orig,link,futil}
+ else
+ red "failed"
+ fi
+done
+
+# done
+if [ "$pass" -eq "$progs" ]; then
+ green "Success: $pass / $progs passed"
+ exit 0
+fi
+
+red "FAIL: $pass / $progs passed"
+exit 1
diff --git a/utility/dumpRSAPublicKey.c b/utility/dumpRSAPublicKey.c
index da8597af..113e9a0b 100644
--- a/utility/dumpRSAPublicKey.c
+++ b/utility/dumpRSAPublicKey.c
@@ -141,9 +141,15 @@ int main(int argc, char* argv[]) {
X509* cert = NULL;
RSA* pubkey = NULL;
EVP_PKEY* key;
+ char *progname;
if (argc != 3 || (strcmp(argv[1], "-cert") && strcmp(argv[1], "-pub"))) {
- fprintf(stderr, "Usage: %s <-cert | -pub> <file>\n", argv[0]);
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+ fprintf(stderr, "Usage: %s <-cert | -pub> <file>\n", progname);
return -1;
}
diff --git a/utility/gbb_utility.cc b/utility/gbb_utility.cc
index 52135d01..e68bd9b1 100644
--- a/utility/gbb_utility.cc
+++ b/utility/gbb_utility.cc
@@ -486,6 +486,11 @@ using vboot_reference::GoogleBinaryBlockUtil;
// utility function: provide usage of this utility and exit.
static void usagehelp_exit(const char *prog_name) {
+ const char *basename = strrchr(prog_name, '/');
+ if (basename)
+ basename++;
+ else
+ basename = prog_name;
fprintf(stderr,
"Utility to manage Google Binary Block (GBB)\n"
"Usage: %s [-g|-s|-c] [OPTIONS] bios_file [output_file]\n"
@@ -516,7 +521,7 @@ static void usagehelp_exit(const char *prog_name) {
" %s -g bios.bin\n"
" %s --set --hwid='New Model' -k key.bin bios.bin newbios.bin\n"
" %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n",
- prog_name, prog_name, prog_name, prog_name);
+ basename, basename, basename, basename);
exit(1);
}
diff --git a/utility/tpmc.c b/utility/tpmc.c
index 898e2552..9302dd1e 100644
--- a/utility/tpmc.c
+++ b/utility/tpmc.c
@@ -412,9 +412,16 @@ command_record command_table[] = {
static int n_commands = sizeof(command_table) / sizeof(command_table[0]);
int main(int argc, char* argv[]) {
+ char *progname;
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
if (argc < 2) {
fprintf(stderr, "usage: %s <TPM command> [args]\n or: %s help\n",
- argv[0], argv[0]);
+ progname, progname);
return OTHER_ERROR;
} else {
command_record* c;
@@ -439,7 +446,7 @@ int main(int argc, char* argv[]) {
}
/* No command matched. */
- fprintf(stderr, "%s: unknown command: %s\n", argv[0], cmd);
+ fprintf(stderr, "%s: unknown command: %s\n", progname, cmd);
return OTHER_ERROR;
}
}