]> git.ozlabs.org Git - petitboot/blobdiff - utils/pb-plugin
pb-plugin: Only require a fixed plugin extension, instead of full name
[petitboot] / utils / pb-plugin
index 4e4165257e21b6bfa11b215c1ace2fa79317d220..c6c9ef97ccc4dd7f7e02196f03a978c48ce7bc41 100755 (executable)
@@ -2,11 +2,11 @@
 
 __dest=/
 __pb_mount_dir=/var/petitboot/mnt/dev/
-__plugin_basedir=/tmp/
-plugin_file=pb-plugin.cpio.gz
+plugin_ext=pb-plugin
 plugin_meta=pb-plugin.conf
 plugin_meta_dir=etc/preboot-plugins/
 plugin_meta_path=$plugin_meta_dir$plugin_meta
+plugin_wrapper_dir=/var/lib/pb-plugins/bin
 
 usage()
 {
@@ -14,9 +14,9 @@ usage()
 Usage: $0 <command>
 
 Where <command> is one of:
-  run <FILE|URL>      - run plugin from FILE/URL
-  scan                - look for available plugins on attached devices
-  create <DIR>        - create a new plugin archive from DIR
+  install <FILE|URL> - install plugin from FILE/URL
+  scan               - look for available plugins on attached devices
+  create <DIR>       - create a new plugin archive from DIR
 EOF
 }
 
@@ -62,41 +62,57 @@ plugin_info()
        echo "  (version $PLUGIN_VERSION)"
 }
 
-__run_init()
+do_wrap()
 {
-       local base dir
+       local base binary dir
 
        base=$1
+       binary=$2
+       shift 2
 
-       for dir in etc dev sys proc
+       for dir in etc dev sys proc var
        do
-               mkdir -p $base/$dir
+               [ -e "$base/$dir" ] || mkdir -p "$base/$dir"
        done
 
        cp /etc/resolv.conf $base/etc
        mount -o bind /dev $base/dev
        mount -o bind /sys $base/sys
        mount -o bind /proc $base/proc
+       mount -o bind /var $base/var
+
+       chroot "$base" "$binary" "$@"
+
+       umount $base/dev
+       umount $base/sys
+       umount $base/proc
+       umount $base/var
 }
 
-__run_cleanup()
+__create_wrapper()
 {
-       local base
+       local base binary wrapper
 
        base=$1
+       binary=$2
+       wrapper=$plugin_wrapper_dir/$(basename $binary)
+
+       mkdir -p $plugin_wrapper_dir
+
+       cat <<EOF > $wrapper
+#!/bin/sh
+
+exec $(realpath $0) __wrap '$base' '$binary' "\$@"
+EOF
 
-       [ -e $base/dev/null ] && umount $base/dev
-       [ -e $base/sys/kernel ] && umount $base/sys
-       [ -e $base/proc/stat ] && umount $base/proc
-       rm -rf $base
+       chmod a+x $wrapper
 }
 
-do_run()
+do_install()
 {
-       local url executable
+       local url name file __dest
 
        url=$1
-       executable=$2
 
        if [ -z "$url" ]
        then
@@ -129,7 +145,7 @@ do_run()
        echo
        sha256sum "$file" | cut -f1 -d' '
        echo
-       echo "Do you want to run this plugin? (y/N)"
+       echo "Do you want to install this plugin? (y/N)"
        read resp
 
        case $resp in
@@ -153,37 +169,29 @@ do_run()
 
        . $__dest/$plugin_meta_path
 
-       (
-               executable=${PLUGIN_EXECUTABLE:-$executable}
-
-               __run_init $__dest
-
-               printf "Entering plugin\n"
-               plugin_info
-
-               chroot $__dest $executable
-
-               printf "\nExiting plugin & cleaning up\n"
-               __run_cleanup $__dest
-       )
+       for binary in ${PLUGIN_EXECUTABLES}
+       do
+               __create_wrapper "$__dest" "$binary"
+       done
 
+       echo "Plugin installed"
+       plugin_info
 }
 
-do_scan()
+do_scan_mount()
 {
-       local found dev plugin_path __meta_tmp
-       found=0
-       for mnt in $__pb_mount_dir/*
-       do
-               dev=$(basename $mnt)
-               plugin_path="$mnt/$plugin_file"
+       local mnt dev plugin_path __meta_tmp
+       mnt=$1
+       dev=$(basename $mnt)
 
+       for plugin_path in $mnt/*.$plugin_ext
+       do
                [ -e "$plugin_path" ] || continue
 
                # extract plugin metadata to a temporary directory
                __meta_tmp=$(mktemp -d)
                [ -d $__meta_tmp ] || continue
-               gunzip -c "$plugin_path" |
+               gunzip -c "$plugin_path" 2>/dev/null |
                        (cd $__meta_tmp &&
                                cpio -i -d $plugin_meta_path 2>/dev/null)
                if ! [ $? = 0 -a -e "$plugin_path" ]
@@ -205,6 +213,16 @@ do_scan()
                rm -rf $__meta_tmp
                found=1
        done
+}
+
+do_scan()
+{
+       local found mnt
+       found=0
+       for mnt in $__pb_mount_dir/*
+       do
+               do_scan_mount $mnt
+       done
 
        if [ "$found" = 0 ]
        then
@@ -259,10 +277,13 @@ EOF
 
 cat <<EOF
 
-Enter the full path (within the plugin root) to the plugin executable file.
-This will be the default action when the plugin is run. (eg /usr/bin/my-util)
+Enter the full path (within the plugin root) to the plugin executable file(s).
+These will be exposed as wrapper scripts, to be run from the standard petitboot
+shell environment (eg, /usr/bin/my-raid-config).
+
+If multiple executables are provided, separate with a space.
 EOF
-       read executable
+       read executables
 
        date=$(date +%Y-%m-%d)
 
@@ -270,10 +291,12 @@ EOF
 
        cat <<EOF > $file
 PLUGIN_VENDOR='$vendorname'
+PLUGIN_VENDOR_ID='$vendorshortname'
 PLUGIN_NAME='$pluginname'
+PLUGIN_ID='$pluginshortname'
 PLUGIN_VERSION='$version'
 PLUGIN_DATE='$date'
-PLUGIN_EXECUTABLE='$executable'
+PLUGIN_EXECUTABLES='$executables'
 EOF
 
 }
@@ -313,38 +336,44 @@ do_create()
        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
-               if [ ! -n "$PLUGIN_EXECUTABLE" ]
-               then
-                       echo "error: no PLUGIN_EXECUTABLE defined in metadata" \
-                               &>2
-                       exit 1
-               fi
-
-       ) || exit 1
+       . $meta_file
+       if [ ! -n "$PLUGIN_VENDOR" ]
+       then
+               echo "error: no PLUGIN_VENDOR defined in metadata" &>2
+               exit 1
+       fi
+       if [ ! -n "$PLUGIN_VENDOR_ID" ]
+       then
+               echo "error: no PLUGIN_VENDOR_ID 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_ID" ]
+       then
+               echo "error: no PLUGIN_ID 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
+       if [ ! -n "$PLUGIN_EXECUTABLES" ]
+       then
+               echo "error: no PLUGIN_EXECUTABLES defined in metadata" &>2
+               exit 1
+       fi
 
-       outfile=$plugin_file
+       outfile=${PLUGIN_ID}-${PLUGIN_VERSION}.${plugin_ext}
 
        (
                cd $src
@@ -357,21 +386,17 @@ do_create()
        echo
 
        echo "User-visible metadata:"
-
-       (
-               . $meta_file
-               plugin_info | sed -e 's/^/  /'
-       )
+       plugin_info | sed -e 's/^/  /'
 
        echo
 
-
 cat <<EOF
 Plugin created in:
   $outfile
 
 Ship this file in the top-level-directory of a USB device or CD to have it
-automatically discoverable by 'pb-plugin scan'.
+automatically discoverable by 'pb-plugin scan'. This file can be re-named,
+but must retain the .$plugin_ext extension to be discoverable.
 EOF
 }
 
@@ -419,15 +444,86 @@ test_scan()
        (
                echo "PLUGIN_NAME=test"
                echo "PLUGIN_VERSION=1"
-               echo "PLUGIN_EXECUTABLE=/bin/sh"
+               echo "PLUGIN_EXECUTABLES=/bin/sh"
        ) > $mnt_dir/$plugin_meta_path
        (
                cd $mnt_dir;
                find -mindepth 1 | cpio -o -Hnewc 2>/dev/null
-       ) | gzip -c > $mnt_dir/$plugin_file
+       ) | gzip -c > $mnt_dir/test.$plugin_ext
+
+       do_scan | grep -q 'test'
+}
+
+test_scan_nogzip()
+{
+       __pb_mount_dir="$test_tmpdir/mnt"
+       mnt_dir="$__pb_mount_dir/sda"
+       stderr_file="$test_tmpdir/stderr"
+
+       mkdir -p $mnt_dir
+       echo "invalid" > $mnt_dir/nogzip.$plugin_ext
+
+       do_scan 2>$stderr_file | grep -q 'No plugins'
+
+       [ $? = 0 ] || return 1
+
+       if [ -s "$stderr_file" ]
+       then
+               echo "Scan with invalid (non-gzip) file produced error output" \
+                       >&2
+               cat "$stderr_file"
+               return 1
+       fi
+       true
+}
+
+test_scan_nocpio()
+{
+       __pb_mount_dir="$test_tmpdir/mnt"
+       mnt_dir="$__pb_mount_dir/sda"
+       stderr_file="$test_tmpdir/stderr"
+
+       mkdir -p $mnt_dir
+       echo "invalid" | gzip -c > $mnt_dir/nogzip.$plugin_ext
+
+       do_scan 2>$stderr_file | grep -q 'No plugins'
 
-       do_scan | grep -q 'test 1'
-       rc=$?
+       [ $? = 0 ] || return 1
+
+       if [ -s "$stderr_file" ]
+       then
+               echo "Scan with invalid (non-cpio) file produced error output" \
+                       >&2
+               cat "$stderr_file"
+               return 1
+       fi
+       true
+}
+
+test_scan_multiple()
+{
+       __pb_mount_dir="$test_tmpdir/mnt"
+       mnt_dir="$__pb_mount_dir/sda"
+       outfile=$test_tmpdir/scan.out
+
+       for i in 1 2
+       do
+               mkdir -p $mnt_dir/$plugin_meta_dir
+               (
+                       echo "PLUGIN_NAME=test-$i"
+                       echo "PLUGIN_VERSION=1"
+                       echo "PLUGIN_EXECUTABLES=/bin/sh"
+               ) > $mnt_dir/$plugin_meta_path
+               (
+                       cd $mnt_dir;
+                       find -mindepth 1 | cpio -o -Hnewc 2>/dev/null
+               ) | gzip -c > $mnt_dir/test-${i}.$plugin_ext
+               rm -rf $mnt_dir/$plugin_meta_dir
+       done
+
+       do_scan >$outfile
+
+       grep -q 'test-1' $outfile && grep -q 'test-2' $outfile
 }
 
 test_empty_scan()
@@ -495,6 +591,9 @@ do_tests()
        do_test test_http_download
        do_test test_ftp_download
        do_test test_scan
+       do_test test_scan_nogzip
+       do_test test_scan_nocpio
+       do_test test_scan_multiple
        do_test test_empty_scan
 
        if [ $test_failed = 0 ]
@@ -502,15 +601,16 @@ do_tests()
                echo "$n tests passed"
        else
                echo "Tests failed"
-               false
        fi
        rm -rf "$tests_tmpdir"
+
+       [ $test_failed = 0 ]
 }
 
 case "$1" in
-run)
+install)
        shift
-       do_run $@
+       do_install $@
        ;;
 scan)
        shift
@@ -520,6 +620,10 @@ create)
        shift
        do_create $@
        ;;
+__wrap)
+       shift
+       do_wrap $@
+       ;;
 __test)
        shift
        do_tests $@