Wrap all vboot utilities with futility.

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>
diff --git a/Makefile b/Makefile
index a7101cc..cd39114 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 @@
 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 @@
 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 @@
 # 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 @@
 # 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 @@
 .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 @@
 # 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 @@
 
 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 @@
 	${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 @@
 else
 coverage: coverage_init runtests coverage_html
 endif
-
diff --git a/futility/IGNOREME.c b/futility/IGNOREME.c
deleted file mode 100644
index c90c87e..0000000
--- 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 0000000..e02a9ff
--- /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 0000000..c30e3e8
--- /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 0000000..ed26890
--- /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 e428ddc..e03ab5c 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 0000000..ed187d7
--- /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 0000000..ff2de4b
--- /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 da8597a..113e9a0 100644
--- a/utility/dumpRSAPublicKey.c
+++ b/utility/dumpRSAPublicKey.c
@@ -141,9 +141,15 @@
   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 52135d0..e68bd9b 100644
--- a/utility/gbb_utility.cc
+++ b/utility/gbb_utility.cc
@@ -486,6 +486,11 @@
 
 // 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 @@
     "  %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 898e255..9302dd1 100644
--- a/utility/tpmc.c
+++ b/utility/tpmc.c
@@ -412,9 +412,16 @@
 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 @@
     }
 
     /* 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;
   }
 }