diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2015-03-23 13:58:57 +0800 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2015-03-27 13:22:41 +0800 |
commit | 4f03d0c241df6e9e94efdc6729085d47417f0bac (patch) | |
tree | 9c2b75882e1a80de746da1bec35a7a2c54e0b8e2 /utils | |
parent | 900412ec49f30fbb7872a5ff38538a19c17e20a2 (diff) | |
download | petitboot-4f03d0c241df6e9e94efdc6729085d47417f0bac.zip petitboot-4f03d0c241df6e9e94efdc6729085d47417f0bac.tar.gz |
utils/pb-plugin: Add pb-plugin script
Add a little script for downloading and/or extracting a plugin into a
petitboot environment
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'utils')
-rw-r--r-- | utils/Makefile.am | 2 | ||||
-rwxr-xr-x | utils/pb-plugin | 513 |
2 files changed, 514 insertions, 1 deletions
diff --git a/utils/Makefile.am b/utils/Makefile.am index c373943..9b36619 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -12,7 +12,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -dist_sbin_SCRIPTS += utils/pb-udhcpc +dist_sbin_SCRIPTS += utils/pb-udhcpc utils/pb-plugin dist_pkglibexec_SCRIPTS = utils/pb-console sbin_PROGRAMS += utils/pb-event utils/pb-config diff --git a/utils/pb-plugin b/utils/pb-plugin new file mode 100755 index 0000000..e71e981 --- /dev/null +++ b/utils/pb-plugin @@ -0,0 +1,513 @@ +#!/bin/sh + +__dest=/ +__pb_mount_dir=/var/petitboot/mnt/dev/ +plugin_dev_meta=pb-plugin.conf +plugin_installed_meta_dir=/etc/preboot-plugins/ + +usage() +{ + cat <<EOF +Usage: $0 <command> + +Where <command> is one of: + install <FILE|URL> - install plugin from FILE/URL + scan - look for available plugins on attached devices + list - list currently-installed plugins + create <DIR> - create a new plugin archive from DIR +EOF +} + +is_url() +{ + local url tmp + url=$1 + tmp=${url#*://} + [ "$url" != "$tmp" ] +} + +download() +{ + local url file proto + url=$1 + file=$2 + proto=${url%://*} + + case "$proto" in + http) + wget -O - "$url" > $file + ;; + ftp) + ncftpget -c "$url" > $file + ;; + *) + echo "error: Unsuported protocol $proto" >&2 + false + esac +} + +plugin_info() +{ + local title + if [ "$PLUGIN_VENDOR" ] + then + title="$PLUGIN_VENDOR: $PLUGIN_NAME" + else + title="$PLUGIN_NAME" + fi + + echo "$title" + echo " (version $PLUGIN_VERSION)" +} + +do_install() +{ + local url + + url=$1 + + if [ -z "$url" ] + then + echo "error: install requires a file/URL argument." >&2 + exit 1 + fi + + if [ ! -d "$__dest" ] + then + echo "error: destination directory '$__dest' doesn't exist" >&2 + exit 1 + fi + + if [ ! -w "$__dest" ] + then + echo "error: destination directory isn't writeable" >&2 + exit 1 + fi + + name=${url##*/} + + if is_url "$url" + then + file=$(mktemp) + trap "rm '$file'" EXIT + download "$url" "$file" + if [ $? -ne 0 ] + then + echo "error: failed to download $url" >&2 + exit 1 + fi + else + file=$url + if [ ! -r "$file" ] + then + echo "error: $file doesn't exist or is not readable" >&2 + exit 1 + fi + fi + + echo "File '$name' has the following sha256 checksum:" + echo + sha256sum "$file" | cut -f1 -d' ' + echo + echo "Do you want to install into the pre-boot environment? (y/N)" + read resp + + case $resp in + [yY]|[yY][eE][sS]) + ;; + *) + echo "Cancelled" + exit 0 + ;; + esac + + gunzip -c "$file" | ( cd $__dest && cpio -i -d) + + if [ $? -ne 0 ] + then + echo "error: Failed to extract archive $url, exiting" + exit 1 + fi +} + +do_scan() +{ + local found + found=0 + for mnt in $__pb_mount_dir/* + do + dev=$(basename $mnt) + metafile="$mnt/$plugin_dev_meta" + [ -e "$metafile" ] || continue + ( + . $metafile + printf "Plugin found on %s:\n" $dev + plugin_info + printf "\n" + printf "To install this plugin, run:\n" + printf " $0 install $mnt/$PLUGIN_FILE\n" + printf "\n" + ) + found=1 + done + + if [ "$found" = 0 ] + then + echo "No plugins found" + fi +} + +do_list() +{ + local found + found=0 + for meta in $plugin_installed_meta_dir/* + do + [ -e "$meta" ] || continue + [ $found = 0 ] && printf "Installed plugins:\n" + found=1 + ( + . $meta + plugin_info + echo + ) + done + + if [ "$found" = 0 ] + then + echo "No plugins installed" + fi +} + +guided_meta() +{ + local vendorname vendorshortname + local pluginname pluginnhortname + local version date + local dir + + dir=$1 + +cat <<EOF + +Enter the vendor company / author name. This can contain spaces. +(eg. 'Example Corporation') +EOF + read vendorname +cat <<EOF + +Enter the vendor shortname. This should be a single-word abbreviation, in all +lower-case. This is only used in internal filenames. + +Typically, a stock-ticker name is used for this (eg 'exco') +EOF + read vendorshortname + +cat <<EOF + +Enter the descriptive plugin name. This can contain spaces, but should only be +a few words in length (eg 'RAID configuration utility') +EOF + read pluginname + +cat <<EOF + +Enter the plugin shortname. This should not contain spaces, but hyphens are +fine (eg 'raid-config'). This is only used in internal filnames. +EOF + read pluginshortname + + +cat <<EOF + +Enter the plugin version. This should not contain spaces (eg 1.2): +EOF + read version + + date=$(date +%Y-%m-%d) + + mkdir -p $dir + + cat <<EOF > $dir/$vendorshortname-$pluginshortname +PLUGIN_VENDOR='$vendorname' +PLUGIN_NAME='$pluginname' +PLUGIN_VERSION='$version' +PLUGIN_DATE='$date' +EOF + +} + +do_create() +{ + local src found meta_dir_abs meta_file + src=$1 + + if [ -z "$src" ] + then + echo "error: missing source directory" >&2 + usage + exit 1 + fi + + if [ ! -d "$src" ] + then + echo "error: source directory missing" >&2 + exit 1 + fi + + meta_dir_abs="$src/$plugin_installed_meta_dir" + found=0 + for meta in $meta_dir_abs/* + do + [ -e "$meta" ] || continue + found=$(($found+1)) + meta_file=$meta + done + + if [ $found = 0 ] + then + echo "No plugin metadata file found. " \ + "Would you like to create one? (Y/n)" + read resp + case "$resp" in + [nN]|[nN][oO]) + echo "Cancelled, exiting" + exit 1 + ;; + esac + guided_meta $meta_dir_abs || exit + meta_file=$meta_dir_abs/* + fi + + if [ $found -gt 1 ] + then + echo "error: Multiple metadata files found in $meta_dir_abs" >&2 + exit 1 + fi + + # Sanity check metadata file + ( + . $meta_file + if [ ! -n "$PLUGIN_VENDOR" ] + then + echo "error: no PLUGIN_VENDOR defined in metadata" &>2 + exit 1 + fi + if [ ! -n "$PLUGIN_NAME" ] + then + echo "error: no PLUGIN_NAME defined in metadata" &>2 + exit 1 + fi + if [ ! -n "$PLUGIN_VERSION" ] + then + echo "error: no PLUGIN_VERSION defined in metadata" &>2 + exit 1 + fi + if [ ! -n "$PLUGIN_DATE" ] + then + echo "error: no PLUGIN_DATE defined in metadata" &>2 + exit 1 + fi + + ) || exit 1 + + outfile=pb-plugin.cpio.gz + + ( + cd $src + find -mindepth 1 | cpio -o -Hnewc -v + ) | gzip -c > pb-plugin.cpio.gz + + cp $meta_file $plugin_dev_meta + echo "PLUGIN_FILE='$outfile'" >> $plugin_dev_meta + + echo + echo "Plugin metadata:" + sed -e 's/^/ /' $meta_file + echo + + echo "User-visible metadata:" + + ( + . $meta_file + plugin_info | sed -e 's/^/ /' + ) + + echo + + +cat <<EOF +Plugin created in: + $outfile + +Metadata in: + $plugin_dev_meta + +If you rename $outfile (or distribute it in a non-root directory), then +also update the PLUGIN_FILE variable in $plugin_dev_meta. +EOF +} + +test_http_download() +{ + local tmp ref + + tmp=$(mktemp -p $test_tmpdir) + ref=$(mktemp -p $test_tmpdir) + + echo $RANDOM > $ref + + wget() + { + cat $ref + } + + download http://example.com/test $tmp + cmp -s "$ref" "$tmp" +} + +test_ftp_download() +{ + local tmp ref + + tmp=$(mktemp -p $test_tmpdir) + ref=$(mktemp -p $test_tmpdir) + + echo $RANDOM > $ref + + ncftpget() + { + cat $ref + } + + download ftp://example.com/test $tmp + cmp -s "$ref" "$tmp" +} + +test_scan() +{ + __pb_mount_dir="$test_tmpdir/mnt" + mnt_dir="$__pb_mount_dir/sda" + mkdir -p $mnt_dir + ( + echo "PLUGIN_NAME=test" + echo "PLUGIN_VERSION=1" + echo "PLUGIN_FILE=data/pb-plugin.cpio.gz" + ) > $mnt_dir/$plugin_dev_meta + + do_scan | grep -q 'test 1' + rc=$? +} + +test_empty_scan() +{ + do_scan | grep -q "No plugins" +} + +test_setup() +{ + n=$(($n+1)) + + test_tmpdir="$tests_tmpdir/$n" + mkdir "$test_tmpdir" + __test_dest="$test_tmpdir/base" + mkdir "$__test_dest" + [ -d "$__test_dest" ] || exit 1 + __dest=$__test_dest +} + +test_teardown() +{ + true +} + +test_failed=0 +do_test() +{ + local tstr op + + tstr="$@" + op=-eq + + if [ "x$1" = "x!" ] + then + op=-ne + shift + fi + + test_setup + ( $@ ) + local rc=$? + test_teardown + + if [ $rc $op 0 ] + then + echo PASS: "$tstr" + else + echo FAIL: "$tstr" + test_failed=1 + false + fi +} + +do_tests() +{ + local tests_tmpdir n + + tests_tmpdir=$(mktemp -d) + n=0 + + do_test ! is_url "/test" + do_test ! is_url "./test" + do_test ! is_url "../test" + do_test ! is_url "test" + do_test is_url "http://example.com/path" + do_test is_url "git+ssh://example.com/path" + do_test test_http_download + do_test test_ftp_download + do_test test_scan + do_test test_empty_scan + + if [ $test_failed = 0 ] + then + echo "$n tests passed" + else + echo "Tests failed" + false + fi + rm -rf "$tests_tmpdir" +} + +case "$1" in +install) + shift + do_install $@ + ;; +scan) + shift + do_scan $@ + ;; +list) + shift + do_list $@ + ;; +create) + shift + do_create $@ + ;; +__test) + shift + do_tests $@ + ;; +"") + echo "error: Missing command" >&2 + usage + exit 1 + ;; +*) + echo "Invalid command: $s" >&2 + usage + exit 1 +esac + + |