From dcc406653405c0b97c9474d99a66ac896557734c Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 7 Aug 2015 12:14:42 +0800 Subject: pb-plugin: Update to chroot-style plugins This change uses a chroot for all plugins, so that plugins have complete flexibility with their libraries, dependencies and configuration. We remove the 'install' action, as we simply run the plugin once. Running involves extracting the archive, setting up a root filesystem, and running a chroot. To simplify plugin discovery behaviour, we standardise the plugin file to be at pb-plugin.conf of attached devices, and read the metadatafile straight out of the archive. Signed-off-by: Jeremy Kerr --- utils/pb-plugin | 211 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 118 insertions(+), 93 deletions(-) (limited to 'utils') diff --git a/utils/pb-plugin b/utils/pb-plugin index e71e981..4e41652 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -2,8 +2,11 @@ __dest=/ __pb_mount_dir=/var/petitboot/mnt/dev/ -plugin_dev_meta=pb-plugin.conf -plugin_installed_meta_dir=/etc/preboot-plugins/ +__plugin_basedir=/tmp/ +plugin_file=pb-plugin.cpio.gz +plugin_meta=pb-plugin.conf +plugin_meta_dir=etc/preboot-plugins/ +plugin_meta_path=$plugin_meta_dir$plugin_meta usage() { @@ -11,9 +14,8 @@ usage() Usage: $0 Where is one of: - install - install plugin from FILE/URL + run - run plugin from FILE/URL scan - look for available plugins on attached devices - list - list currently-installed plugins create - create a new plugin archive from DIR EOF } @@ -60,11 +62,41 @@ plugin_info() echo " (version $PLUGIN_VERSION)" } -do_install() +__run_init() { - local url + local base dir + + base=$1 + + for dir in etc dev sys proc + do + 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 +} + +__run_cleanup() +{ + local base + + base=$1 + + [ -e $base/dev/null ] && umount $base/dev + [ -e $base/sys/kernel ] && umount $base/sys + [ -e $base/proc/stat ] && umount $base/proc + rm -rf $base +} + +do_run() +{ + local url executable url=$1 + executable=$2 if [ -z "$url" ] then @@ -72,18 +104,6 @@ do_install() 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" @@ -109,7 +129,7 @@ do_install() echo sha256sum "$file" | cut -f1 -d' ' echo - echo "Do you want to install into the pre-boot environment? (y/N)" + echo "Do you want to run this plugin? (y/N)" read resp case $resp in @@ -121,33 +141,68 @@ do_install() ;; esac + __dest=$(mktemp -d) gunzip -c "$file" | ( cd $__dest && cpio -i -d) if [ $? -ne 0 ] then echo "error: Failed to extract archive $url, exiting" + rm -rf $__dest exit 1 fi + + . $__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 + ) + } do_scan() { - local found + local found dev plugin_path __meta_tmp found=0 for mnt in $__pb_mount_dir/* do dev=$(basename $mnt) - metafile="$mnt/$plugin_dev_meta" - [ -e "$metafile" ] || continue + plugin_path="$mnt/$plugin_file" + + [ -e "$plugin_path" ] || continue + + # extract plugin metadata to a temporary directory + __meta_tmp=$(mktemp -d) + [ -d $__meta_tmp ] || continue + gunzip -c "$plugin_path" | + (cd $__meta_tmp && + cpio -i -d $plugin_meta_path 2>/dev/null) + if ! [ $? = 0 -a -e "$plugin_path" ] + then + rm -rf $__meta_tmp + continue + fi + ( - . $metafile + . $__meta_tmp/$plugin_meta_path + 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 "To run this plugin:\n" + printf " $0 run $plugin_path\n" printf "\n" ) + rm -rf $__meta_tmp found=1 done @@ -157,36 +212,14 @@ do_scan() 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 + local version date executable + local file - dir=$1 + file=$1 cat < $dir/$vendorshortname-$pluginshortname + cat < $file PLUGIN_VENDOR='$vendorname' PLUGIN_NAME='$pluginname' PLUGIN_VERSION='$version' PLUGIN_DATE='$date' +PLUGIN_EXECUTABLE='$executable' EOF } do_create() { - local src found meta_dir_abs meta_file + local src meta_dir_abs meta_file src=$1 if [ -z "$src" ] @@ -255,16 +296,9 @@ do_create() 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 + meta_file=$src/$plugin_meta_path - if [ $found = 0 ] + if [ ! -e $meta_file ] then echo "No plugin metadata file found. " \ "Would you like to create one? (Y/n)" @@ -275,14 +309,7 @@ do_create() 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 + guided_meta $meta_file || exit fi # Sanity check metadata file @@ -308,18 +335,21 @@ do_create() 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 - outfile=pb-plugin.cpio.gz + outfile=$plugin_file ( 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 + ) | gzip -c > $outfile echo echo "Plugin metadata:" @@ -339,12 +369,9 @@ do_create() cat < $mnt_dir/$plugin_dev_meta + echo "PLUGIN_EXECUTABLE=/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 do_scan | grep -q 'test 1' rc=$? @@ -401,6 +432,8 @@ test_scan() test_empty_scan() { + __pb_mount_dir="$test_tmpdir/mnt" + mkdir -p $__pb_mount_dir do_scan | grep -q "No plugins" } @@ -410,10 +443,6 @@ test_setup() 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() @@ -479,18 +508,14 @@ do_tests() } case "$1" in -install) +run) shift - do_install $@ + do_run $@ ;; scan) shift do_scan $@ ;; -list) - shift - do_list $@ - ;; create) shift do_create $@ -- cgit v1.2.1 From cb4a99c73726f316180f1591deb2f23900226920 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 21 Aug 2015 13:12:19 +0800 Subject: pb-plugin: Keep chroot persistent, and create wrapper scripts Rather than having to 'pb-plugin run' multiple times, we want users to be able to execute multiple plugin binaries with more accessible command-line statements. This change reverts to the previous 'install' (rather than 'run') behaviour, and creates wrapper scripts to call into the chroot. Signed-off-by: Jeremy Kerr --- utils/pb-plugin | 94 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 40 deletions(-) (limited to 'utils') diff --git a/utils/pb-plugin b/utils/pb-plugin index 4e41652..598530a 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -7,6 +7,7 @@ plugin_file=pb-plugin.cpio.gz plugin_meta=pb-plugin.conf plugin_meta_dir=etc/preboot-plugins/ plugin_meta_path=$plugin_meta_dir$plugin_meta +plugin_wrapper_dir=/usr/bin usage() { @@ -14,9 +15,9 @@ usage() Usage: $0 Where is one of: - run - run plugin from FILE/URL - scan - look for available plugins on attached devices - create - create a new plugin archive from DIR + install - install plugin from FILE/URL + scan - look for available plugins on attached devices + create - create a new plugin archive from DIR EOF } @@ -62,41 +63,55 @@ 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) - [ -e $base/dev/null ] && umount $base/dev - [ -e $base/sys/kernel ] && umount $base/sys - [ -e $base/proc/stat ] && umount $base/proc - rm -rf $base + cat < $wrapper +#!/bin/sh + +exec $(realpath $0) __wrap '$base' '$binary' "\$@" +EOF + + 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 +144,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,20 +168,13 @@ 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() @@ -259,10 +267,13 @@ EOF cat <2 exit 1 fi - if [ ! -n "$PLUGIN_EXECUTABLE" ] + if [ ! -n "$PLUGIN_EXECUTABLES" ] then - echo "error: no PLUGIN_EXECUTABLE defined in metadata" \ - &>2 + echo "error: no PLUGIN_EXECUTABLES defined in metadata"\ &>2 exit 1 fi @@ -419,7 +429,7 @@ 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; @@ -508,9 +518,9 @@ do_tests() } case "$1" in -run) +install) shift - do_run $@ + do_install $@ ;; scan) shift @@ -520,6 +530,10 @@ create) shift do_create $@ ;; +__wrap) + shift + do_wrap $@ + ;; __test) shift do_tests $@ -- cgit v1.2.1 From 0b71e584078dbe370ed37bcc26f2815d138d28fc Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 27 Aug 2015 16:33:32 +0800 Subject: pb-plugin: Move plugin wrappers to a separate dir Use /var/lib/pb-plugins/bin, to prevent overwriting system binaries. Signed-off-by: Jeremy Kerr --- utils/pb-console | 2 +- utils/pb-plugin | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/pb-console b/utils/pb-console index 36b9c03..5f8ffa6 100644 --- a/utils/pb-console +++ b/utils/pb-console @@ -107,7 +107,7 @@ esac # we may have been run from udev - ensure we have a sensible PATH if [ -z "$PATH" ] then - PATH=/usr/bin:/usr/sbin:/bin:/sbin + PATH=/var/lib/pb-plugins/bin:/usr/bin:/usr/sbin:/bin:/sbin fi export PATH diff --git a/utils/pb-plugin b/utils/pb-plugin index 598530a..1f8a591 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -7,7 +7,7 @@ plugin_file=pb-plugin.cpio.gz plugin_meta=pb-plugin.conf plugin_meta_dir=etc/preboot-plugins/ plugin_meta_path=$plugin_meta_dir$plugin_meta -plugin_wrapper_dir=/usr/bin +plugin_wrapper_dir=/var/lib/pb-plugins/bin usage() { @@ -98,6 +98,8 @@ __create_wrapper() binary=$2 wrapper=$plugin_wrapper_dir/$(basename $binary) + mkdir -p $plugin_wrapper_dir + cat < $wrapper #!/bin/sh -- cgit v1.2.1 From e75fa5f6bf36233c3bd72e9854d244908af9a391 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 2 Sep 2015 15:41:38 +0800 Subject: pb-plugin: Only require a fixed plugin extension, instead of full name Currently, the `pb-plugin scan` code requires a fixed archive name at the root of distributed media. This means that vendors need to have a fixed name, and can only ship one plugin per device. This change shifts the requirement to just a filename extension (.pb-plugin) instead. To handle this, we now look for any plugin with a .pb-plugin extension, and so may find multiple plugins on a device. Signed-off-by: Jeremy Kerr --- utils/pb-plugin | 190 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 139 insertions(+), 51 deletions(-) (limited to 'utils') diff --git a/utils/pb-plugin b/utils/pb-plugin index 1f8a591..c6c9ef9 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -2,8 +2,7 @@ __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 @@ -179,21 +178,20 @@ do_install() 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" ] @@ -215,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 @@ -283,7 +291,9 @@ EOF cat < $file PLUGIN_VENDOR='$vendorname' +PLUGIN_VENDOR_ID='$vendorshortname' PLUGIN_NAME='$pluginname' +PLUGIN_ID='$pluginshortname' PLUGIN_VERSION='$version' PLUGIN_DATE='$date' PLUGIN_EXECUTABLES='$executables' @@ -326,37 +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_EXECUTABLES" ] - then - echo "error: no PLUGIN_EXECUTABLES 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 @@ -369,21 +386,17 @@ do_create() echo echo "User-visible metadata:" - - ( - . $meta_file - plugin_info | sed -e 's/^/ /' - ) + plugin_info | sed -e 's/^/ /' echo - cat </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' + + [ $? = 0 ] || return 1 - do_scan | grep -q 'test 1' - rc=$? + 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() @@ -507,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 ] @@ -514,9 +601,10 @@ do_tests() echo "$n tests passed" else echo "Tests failed" - false fi rm -rf "$tests_tmpdir" + + [ $test_failed = 0 ] } case "$1" in -- cgit v1.2.1 From 94fe62686228cf49dc055c50ce8f7ced3bf3cb96 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 2 Sep 2015 17:13:27 +0800 Subject: pb-plugin: Implement plugin ABI versioning If a future update to plugins is not compatbile with the installed plugin infrastructure, we want to abort the scan / install process. This change adds an ABI version to the script, as well as version (and minimum-supported version) to the plugin metadata. This means we can check before plugin execution. Signed-off-by: Jeremy Kerr --- utils/pb-plugin | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/pb-plugin b/utils/pb-plugin index c6c9ef9..f87e5fb 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -2,6 +2,7 @@ __dest=/ __pb_mount_dir=/var/petitboot/mnt/dev/ +plugin_abi=1 plugin_ext=pb-plugin plugin_meta=pb-plugin.conf plugin_meta_dir=etc/preboot-plugins/ @@ -62,6 +63,23 @@ plugin_info() echo " (version $PLUGIN_VERSION)" } +# How the ABI versioning works: +# +# - This script has an ABI defined ($plugin_abi) +# +# - Plugins have a current ABI number ($PLUGIN_ABI), and a minimum supported +# ABI number ($PLUGIN_ABI_MIN). +# +# - A plugin is OK to run if: +# - the plugin's ABI matches the script ABI, or +# - the plugin's minimum ABI is lower than or equal to the script ABI +plugin_abi_check() +{ + [ -n "$PLUGIN_ABI" ] && + ( [ $PLUGIN_ABI -eq $plugin_abi ] || + [ $PLUGIN_ABI_MIN -le $plugin_abi ] ) +} + do_wrap() { local base binary dir @@ -145,6 +163,7 @@ do_install() echo sha256sum "$file" | cut -f1 -d' ' echo + echo "Do you want to install this plugin? (y/N)" read resp @@ -169,6 +188,14 @@ do_install() . $__dest/$plugin_meta_path + if ! plugin_abi_check + then + echo "Plugin at $url is incompatible with this firmware," \ + "exiting." + rm -rf $__dest + exit 1 + fi + for binary in ${PLUGIN_EXECUTABLES} do __create_wrapper "$__dest" "$binary" @@ -203,6 +230,8 @@ do_scan_mount() ( . $__meta_tmp/$plugin_meta_path + plugin_abi_check || exit 1 + printf "Plugin found on %s:\n" $dev plugin_info printf "\n" @@ -210,8 +239,11 @@ do_scan_mount() printf " $0 run $plugin_path\n" printf "\n" ) + if [ $? = 0 ] + then + found=1 + fi rm -rf $__meta_tmp - found=1 done } @@ -290,6 +322,8 @@ EOF mkdir -p $(dirname $file) cat < $file +PLUGIN_ABI='$plugin_abi' +PLUGIN_ABI_MIN='1' PLUGIN_VENDOR='$vendorname' PLUGIN_VENDOR_ID='$vendorshortname' PLUGIN_NAME='$pluginname' @@ -337,6 +371,15 @@ do_create() # Sanity check metadata file . $meta_file + if [ ! -n "$PLUGIN_ABI" ] + then + echo "error: no PLUGIN_ABI defined in metadata" &>2 + exit 1 + fi + if [ "$PLUGIN_ABI" != "$plugin_abi" ] + then + echo "warning: PLUGIN_ABI (=$PLUGIN_ABI) is not $plugin_abi" &>2 + fi if [ ! -n "$PLUGIN_VENDOR" ] then echo "error: no PLUGIN_VENDOR defined in metadata" &>2 @@ -436,12 +479,23 @@ test_ftp_download() cmp -s "$ref" "$tmp" } +test_abi_check() +{ + ( + plugin_abi=$1 + PLUGIN_ABI=$2 + PLUGIN_ABI_MIN=$3 + plugin_abi_check + ) +} + test_scan() { __pb_mount_dir="$test_tmpdir/mnt" mnt_dir="$__pb_mount_dir/sda" mkdir -p $mnt_dir/$plugin_meta_dir ( + echo "PLUGIN_ABI=$plugin_abi" echo "PLUGIN_NAME=test" echo "PLUGIN_VERSION=1" echo "PLUGIN_EXECUTABLES=/bin/sh" @@ -510,6 +564,7 @@ test_scan_multiple() do mkdir -p $mnt_dir/$plugin_meta_dir ( + echo "PLUGIN_ABI=$plugin_abi" echo "PLUGIN_NAME=test-$i" echo "PLUGIN_VERSION=1" echo "PLUGIN_EXECUTABLES=/bin/sh" @@ -526,6 +581,26 @@ test_scan_multiple() grep -q 'test-1' $outfile && grep -q 'test-2' $outfile } +test_scan_wrongabi() +{ + __pb_mount_dir="$test_tmpdir/mnt" + mnt_dir="$__pb_mount_dir/sda" + mkdir -p $mnt_dir/$plugin_meta_dir + ( + echo "PLUGIN_ABI=$(($plugin_abi + 1))" + echo "PLUGIN_ABI_MIN=$(($plugin_abi + 1))" + echo "PLUGIN_NAME=test" + 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.$plugin_ext + + do_scan | grep -q 'No plugins' +} + test_empty_scan() { __pb_mount_dir="$test_tmpdir/mnt" @@ -590,10 +665,18 @@ do_tests() do_test is_url "git+ssh://example.com/path" do_test test_http_download do_test test_ftp_download + do_test ! test_abi_check + do_test ! test_abi_check 1 + do_test test_abi_check 1 1 + do_test test_abi_check 1 1 1 + do_test test_abi_check 1 2 0 + do_test test_abi_check 1 2 1 + do_test ! test_abi_check 1 2 2 do_test test_scan do_test test_scan_nogzip do_test test_scan_nocpio do_test test_scan_multiple + do_test test_scan_wrongabi do_test test_empty_scan if [ $test_failed = 0 ] -- cgit v1.2.1 From 754a03f3c71527cbf8f707344b44e80f84048943 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 2 Sep 2015 22:54:58 +0800 Subject: pb-plugin: Add lint command This change adds a `lint` command, to do some basic checks on the plugin structure and metadata. Signed-off-by: Jeremy Kerr --- utils/pb-plugin | 181 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 140 insertions(+), 41 deletions(-) (limited to 'utils') diff --git a/utils/pb-plugin b/utils/pb-plugin index f87e5fb..a22e8c4 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -18,6 +18,7 @@ Where is one of: install - install plugin from FILE/URL scan - look for available plugins on attached devices create - create a new plugin archive from DIR + lint - perform a pre-distribution check on FILE EOF } @@ -371,48 +372,14 @@ do_create() # Sanity check metadata file . $meta_file - if [ ! -n "$PLUGIN_ABI" ] - then - echo "error: no PLUGIN_ABI defined in metadata" &>2 - exit 1 - fi - if [ "$PLUGIN_ABI" != "$plugin_abi" ] - then - echo "warning: PLUGIN_ABI (=$PLUGIN_ABI) is not $plugin_abi" &>2 - fi - 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" ] + + errors=0 + warnings=0 + + lint_metadata + + if [ $errors -ne 0 ] then - echo "error: no PLUGIN_EXECUTABLES defined in metadata" &>2 exit 1 fi @@ -443,6 +410,134 @@ but must retain the .$plugin_ext extension to be discoverable. EOF } +lint_fatal() +{ + echo "fatal:" "$@" + [ -d "$__dest" ] && rm -rf "$__dest" + exit 1 +} + +lint_err() +{ + echo "error:" "$@" + errors=$(($errors+1)) +} + +lint_warn() +{ + echo "warning:" "$@" + warnings=$(($warnings+1)) +} + +lint_metadata() +{ + [ -n "$PLUGIN_ABI" ] || + lint_err "no PLUGIN_ABI defined in metadata" + + printf '%s' "$PLUGIN_ABI" | grep -q '[^0-9]' && + lint_err "PLUGIN_ABI has non-numeric characters" + + [ -n "$PLUGIN_ABI_MIN" ] || + lint_err "no PLUGIN_ABI_MIN defined in metadata" + + printf '%s' "$PLUGIN_ABI_MIN" | grep -q '[^0-9]' && + lint_err "PLUGIN_ABI_MIN has non-numeric characters" + + [ "$PLUGIN_ABI" = "$plugin_abi" ] || + lint_warn "PLUGIN_ABI (=$PLUGIN_ABI) is not $plugin_abi" + + [ -n "$PLUGIN_VENDOR" ] || + lint_err "no PLUGIN_VENDOR defined in metadata" + + [ -n "$PLUGIN_VENDOR_ID" ] || + lint_err "no PLUGIN_VENDOR_ID defined in metadata" + + printf '%s' "$PLUGIN_VENDOR_ID" | grep -q '[^a-z0-9-]' && + lint_err "PLUGIN_VENDOR_ID should only contain lowercase" \ + "alphanumerics and hyphens" + + [ -n "$PLUGIN_NAME" ] || + lint_err "no PLUGIN_NAME defined in metadata" + + [ -n "$PLUGIN_ID" ] || + lint_err "no PLUGIN_ID defined in metadata" + + printf '%s' "$PLUGIN_ID" | grep -q '[^a-z0-9-]' && + lint_err "PLUGIN_ID should only contain lowercase" \ + "alphanumerics and hyphens" + + [ "$PLUGIN_VERSION" ] || + lint_err "no PLUGIN_VERSION defined in metadata" + + [ -n "$PLUGIN_DATE" ] || + lint_err "no PLUGIN_DATE defined in metadata" + + [ -n "$PLUGIN_EXECUTABLES" ] || + lint_err "no PLUGIN_EXECUTABLES defined in metadata" +} + +do_lint() +{ + local plugin_file errors warnings __dest executable dir + + plugin_file=$1 + errors=0 + warnings=0 + __dest= + + [ "${plugin_file##*.}" = $plugin_ext ] || + lint_err "Plugin file does not end with $plugin_ext" + + gunzip -c "$plugin_file" > /dev/null 2>&1 || + lint_fatal "Plugin can't be gunzipped" + + gunzip -c "$plugin_file" 2>/dev/null | cpio -t >/dev/null 2>&1 || + lint_fatal "Plugin can't be cpioed" + + __dest=$(mktemp -d) + gunzip -c "$plugin_file" | ( cd $__dest && cpio -i -d 2>/dev/null) + + [ -e "$__dest/$plugin_meta_path" ] || + lint_fatal "No metadata file present (expecting" \ + "$plugin_meta_path)" + + (sh -e "$__dest/$plugin_meta_path") >/dev/null 2>&1 || + lint_err "Plugin metadata file has shell errors" + + . "$__dest/$plugin_meta_path" + lint_metadata + + for executable in ${PLUGIN_EXECUTABLES} + do + exec_path="$__dest/$executable" + [ -e "$exec_path" ] || { + lint_err "PLUGIN_EXECUTABLES item $executable" \ + "doesn't exist" + continue + } + + [ -x "$exec_path" ] || + lint_err "PLUGIN_EXECUTABLES item $executable" \ + "isn't executable" + done + + for dir in dev sys proc var + do + [ -e "$__dest/$dir" ] || continue + + [ -d "$__dest/$dir" ] || + lint_err "/$dir exists, but isn't a directory" + + [ "$(find $__dest/$dir -mindepth 1)" ] && + lint_warn "/$dir contains files/directories," \ + "these will be lost during chroot setup" + done + + printf '%s: %d errors, %d warnings\n' $plugin_file $errors $warnings + rm -rf $__dest + [ $errors = 0 ] +} + test_http_download() { local tmp ref @@ -703,6 +798,10 @@ create) shift do_create $@ ;; +lint) + shift + do_lint $@ + ;; __wrap) shift do_wrap $@ -- cgit v1.2.1 From d4b138a5ea9acda3a4839f89d0fa892f20a4c17a Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 2 Sep 2015 23:08:26 +0800 Subject: pb-console: Always add plugins directory to PATH Signed-off-by: Jeremy Kerr --- utils/pb-console | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/pb-console b/utils/pb-console index 5f8ffa6..c6def47 100644 --- a/utils/pb-console +++ b/utils/pb-console @@ -107,8 +107,9 @@ esac # we may have been run from udev - ensure we have a sensible PATH if [ -z "$PATH" ] then - PATH=/var/lib/pb-plugins/bin:/usr/bin:/usr/sbin:/bin:/sbin + PATH=/usr/bin:/usr/sbin:/bin:/sbin fi +PATH=/var/lib/pb-plugins/bin:$PATH export PATH verbose_opt= -- cgit v1.2.1 From e22d1340b96d3e22a92e8fcaabdcd2d494c1bea9 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 2 Sep 2015 23:10:50 +0800 Subject: pb-plugin: Fix invalid command reference We had the old code for using 'run'. Also, fix the error we see when issuing an invalid command. Signed-off-by: Jeremy Kerr --- utils/pb-plugin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/pb-plugin b/utils/pb-plugin index a22e8c4..fcb7383 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -237,7 +237,7 @@ do_scan_mount() plugin_info printf "\n" printf "To run this plugin:\n" - printf " $0 run $plugin_path\n" + printf " $0 install $plugin_path\n" printf "\n" ) if [ $? = 0 ] @@ -816,7 +816,7 @@ __test) exit 1 ;; *) - echo "Invalid command: $s" >&2 + echo "Invalid command: $1" >&2 usage exit 1 esac -- cgit v1.2.1 From d6f3931ec79f9c9cbcf9daef1f1d0957cb07ffa5 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 11 Sep 2015 12:40:16 +0800 Subject: pb-plugin: Don't execute metadata files Rather than sourcing a plugin's metadata file, explicitly parse variables. Signed-off-by: Jeremy Kerr --- utils/pb-plugin | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'utils') diff --git a/utils/pb-plugin b/utils/pb-plugin index fcb7383..e107f96 100755 --- a/utils/pb-plugin +++ b/utils/pb-plugin @@ -64,6 +64,27 @@ plugin_info() echo " (version $PLUGIN_VERSION)" } +parse_meta() +{ + local file name value IFS + + file=$1 + + IFS='=' + while read -r name value + do + # Ensure we have a sensible variable name + echo "$name" | grep -q '^PLUGIN_[A-Z_]*$' || continue + + # we know that $name has no quoting/expansion chars, but we + # may need to do some basic surrounding-quote removal for + # $value, without evaluating it + value=$(echo "$value" | sed "s/^\([\"']\)\(.*\)\1\$/\2/g") + + export $name="$value" + done < $file +} + # How the ABI versioning works: # # - This script has an ABI defined ($plugin_abi) @@ -187,7 +208,7 @@ do_install() exit 1 fi - . $__dest/$plugin_meta_path + parse_meta $__dest/$plugin_meta_path if ! plugin_abi_check then @@ -229,7 +250,7 @@ do_scan_mount() fi ( - . $__meta_tmp/$plugin_meta_path + parse_meta $__meta_tmp/$plugin_meta_path plugin_abi_check || exit 1 @@ -371,7 +392,7 @@ do_create() fi # Sanity check metadata file - . $meta_file + parse_meta $meta_file errors=0 warnings=0 @@ -501,10 +522,7 @@ do_lint() lint_fatal "No metadata file present (expecting" \ "$plugin_meta_path)" - (sh -e "$__dest/$plugin_meta_path") >/dev/null 2>&1 || - lint_err "Plugin metadata file has shell errors" - - . "$__dest/$plugin_meta_path" + parse_meta "$__dest/$plugin_meta_path" lint_metadata for executable in ${PLUGIN_EXECUTABLES} -- cgit v1.2.1