mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 00:51:29 +00:00
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>
This commit is contained in:
committed by
ChromeBot
parent
5fed2a6670
commit
feb2518166
64
Makefile
64
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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
22
futility/cmd_foo.c
Normal file
22
futility/cmd_foo.c
Normal file
@@ -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");
|
||||
285
futility/futility.c
Normal file
285
futility/futility.c
Normal file
@@ -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;
|
||||
}
|
||||
57
futility/futility.h
Normal file
57
futility/futility.h
Normal file
@@ -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_ */
|
||||
@@ -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 = .;
|
||||
}
|
||||
}
|
||||
|
||||
47
futility/tests/common.sh
Executable file
47
futility/tests/common.sh
Executable file
@@ -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
|
||||
}
|
||||
78
futility/tests/run_futility_tests.sh
Executable file
78
futility/tests/run_futility_tests.sh
Executable file
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user