4 __pb_mount_dir=/var/petitboot/mnt/dev/
7 plugin_meta=pb-plugin.conf
8 plugin_meta_dir=etc/preboot-plugins/
9 plugin_meta_path=$plugin_meta_dir$plugin_meta
10 plugin_wrapper_dir=/var/lib/pb-plugins/bin
17 Where <command> is one of:
18 install <FILE|URL> - install plugin from FILE/URL
19 scan - look for available plugins on attached devices
20 create <DIR> - create a new plugin archive from DIR
21 lint <FILE> - perform a pre-distribution check on FILE
42 wget -O - "$url" > $file
45 ncftpget -c "$url" > $file
48 echo "error: Unsuported protocol $proto" >&2
56 if [ "$PLUGIN_VENDOR" ]
58 title="$PLUGIN_VENDOR: $PLUGIN_NAME"
64 echo " (version $PLUGIN_VERSION)"
67 # How the ABI versioning works:
69 # - This script has an ABI defined ($plugin_abi)
71 # - Plugins have a current ABI number ($PLUGIN_ABI), and a minimum supported
72 # ABI number ($PLUGIN_ABI_MIN).
74 # - A plugin is OK to run if:
75 # - the plugin's ABI matches the script ABI, or
76 # - the plugin's minimum ABI is lower than or equal to the script ABI
79 [ -n "$PLUGIN_ABI" ] &&
80 ( [ $PLUGIN_ABI -eq $plugin_abi ] ||
81 [ $PLUGIN_ABI_MIN -le $plugin_abi ] )
92 for dir in etc dev sys proc var
94 [ -e "$base/$dir" ] || mkdir -p "$base/$dir"
97 cp /etc/resolv.conf $base/etc
98 mount -o bind /dev $base/dev
99 mount -o bind /sys $base/sys
100 mount -o bind /proc $base/proc
101 mount -o bind /var $base/var
103 chroot "$base" "$binary" "$@"
113 local base binary wrapper
117 wrapper=$plugin_wrapper_dir/$(basename $binary)
119 mkdir -p $plugin_wrapper_dir
124 exec $(realpath $0) __wrap '$base' '$binary' "\$@"
132 local url name file __dest
138 echo "error: install requires a file/URL argument." >&2
147 trap "rm '$file'" EXIT
148 download "$url" "$file"
151 echo "error: failed to download $url" >&2
158 echo "error: $file doesn't exist or is not readable" >&2
163 echo "File '$name' has the following sha256 checksum:"
165 sha256sum "$file" | cut -f1 -d' '
168 echo "Do you want to install this plugin? (y/N)"
181 gunzip -c "$file" | ( cd $__dest && cpio -i -d)
185 echo "error: Failed to extract archive $url, exiting"
190 . $__dest/$plugin_meta_path
192 if ! plugin_abi_check
194 echo "Plugin at $url is incompatible with this firmware," \
200 for binary in ${PLUGIN_EXECUTABLES}
202 __create_wrapper "$__dest" "$binary"
205 echo "Plugin installed"
211 local mnt dev plugin_path __meta_tmp
215 for plugin_path in $mnt/*.$plugin_ext
217 [ -e "$plugin_path" ] || continue
219 # extract plugin metadata to a temporary directory
220 __meta_tmp=$(mktemp -d)
221 [ -d $__meta_tmp ] || continue
222 gunzip -c "$plugin_path" 2>/dev/null |
224 cpio -i -d $plugin_meta_path 2>/dev/null)
225 if ! [ $? = 0 -a -e "$plugin_path" ]
232 . $__meta_tmp/$plugin_meta_path
234 plugin_abi_check || exit 1
236 printf "Plugin found on %s:\n" $dev
239 printf "To run this plugin:\n"
240 printf " $0 install $plugin_path\n"
255 for mnt in $__pb_mount_dir/*
262 echo "No plugins found"
268 local vendorname vendorshortname
269 local pluginname pluginnhortname
270 local version date executable
277 Enter the vendor company / author name. This can contain spaces.
278 (eg. 'Example Corporation')
283 Enter the vendor shortname. This should be a single-word abbreviation, in all
284 lower-case. This is only used in internal filenames.
286 Typically, a stock-ticker name is used for this (eg 'exco')
292 Enter the descriptive plugin name. This can contain spaces, but should only be
293 a few words in length (eg 'RAID configuration utility')
299 Enter the plugin shortname. This should not contain spaces, but hyphens are
300 fine (eg 'raid-config'). This is only used in internal filnames.
307 Enter the plugin version. This should not contain spaces (eg 1.2):
313 Enter the full path (within the plugin root) to the plugin executable file(s).
314 These will be exposed as wrapper scripts, to be run from the standard petitboot
315 shell environment (eg, /usr/bin/my-raid-config).
317 If multiple executables are provided, separate with a space.
321 date=$(date +%Y-%m-%d)
323 mkdir -p $(dirname $file)
326 PLUGIN_ABI='$plugin_abi'
328 PLUGIN_VENDOR='$vendorname'
329 PLUGIN_VENDOR_ID='$vendorshortname'
330 PLUGIN_NAME='$pluginname'
331 PLUGIN_ID='$pluginshortname'
332 PLUGIN_VERSION='$version'
334 PLUGIN_EXECUTABLES='$executables'
341 local src meta_dir_abs meta_file
346 echo "error: missing source directory" >&2
353 echo "error: source directory missing" >&2
357 meta_file=$src/$plugin_meta_path
359 if [ ! -e $meta_file ]
361 echo "No plugin metadata file found. " \
362 "Would you like to create one? (Y/n)"
366 echo "Cancelled, exiting"
370 guided_meta $meta_file || exit
373 # Sanity check metadata file
386 outfile=${PLUGIN_ID}-${PLUGIN_VERSION}.${plugin_ext}
390 find -mindepth 1 | cpio -o -Hnewc -v
391 ) | gzip -c > $outfile
394 echo "Plugin metadata:"
395 sed -e 's/^/ /' $meta_file
398 echo "User-visible metadata:"
399 plugin_info | sed -e 's/^/ /'
407 Ship this file in the top-level-directory of a USB device or CD to have it
408 automatically discoverable by 'pb-plugin scan'. This file can be re-named,
409 but must retain the .$plugin_ext extension to be discoverable.
416 [ -d "$__dest" ] && rm -rf "$__dest"
423 errors=$(($errors+1))
429 warnings=$(($warnings+1))
434 [ -n "$PLUGIN_ABI" ] ||
435 lint_err "no PLUGIN_ABI defined in metadata"
437 printf '%s' "$PLUGIN_ABI" | grep -q '[^0-9]' &&
438 lint_err "PLUGIN_ABI has non-numeric characters"
440 [ -n "$PLUGIN_ABI_MIN" ] ||
441 lint_err "no PLUGIN_ABI_MIN defined in metadata"
443 printf '%s' "$PLUGIN_ABI_MIN" | grep -q '[^0-9]' &&
444 lint_err "PLUGIN_ABI_MIN has non-numeric characters"
446 [ "$PLUGIN_ABI" = "$plugin_abi" ] ||
447 lint_warn "PLUGIN_ABI (=$PLUGIN_ABI) is not $plugin_abi"
449 [ -n "$PLUGIN_VENDOR" ] ||
450 lint_err "no PLUGIN_VENDOR defined in metadata"
452 [ -n "$PLUGIN_VENDOR_ID" ] ||
453 lint_err "no PLUGIN_VENDOR_ID defined in metadata"
455 printf '%s' "$PLUGIN_VENDOR_ID" | grep -q '[^a-z0-9-]' &&
456 lint_err "PLUGIN_VENDOR_ID should only contain lowercase" \
457 "alphanumerics and hyphens"
459 [ -n "$PLUGIN_NAME" ] ||
460 lint_err "no PLUGIN_NAME defined in metadata"
462 [ -n "$PLUGIN_ID" ] ||
463 lint_err "no PLUGIN_ID defined in metadata"
465 printf '%s' "$PLUGIN_ID" | grep -q '[^a-z0-9-]' &&
466 lint_err "PLUGIN_ID should only contain lowercase" \
467 "alphanumerics and hyphens"
469 [ "$PLUGIN_VERSION" ] ||
470 lint_err "no PLUGIN_VERSION defined in metadata"
472 [ -n "$PLUGIN_DATE" ] ||
473 lint_err "no PLUGIN_DATE defined in metadata"
475 [ -n "$PLUGIN_EXECUTABLES" ] ||
476 lint_err "no PLUGIN_EXECUTABLES defined in metadata"
481 local plugin_file errors warnings __dest executable dir
488 [ "${plugin_file##*.}" = $plugin_ext ] ||
489 lint_err "Plugin file does not end with $plugin_ext"
491 gunzip -c "$plugin_file" > /dev/null 2>&1 ||
492 lint_fatal "Plugin can't be gunzipped"
494 gunzip -c "$plugin_file" 2>/dev/null | cpio -t >/dev/null 2>&1 ||
495 lint_fatal "Plugin can't be cpioed"
498 gunzip -c "$plugin_file" | ( cd $__dest && cpio -i -d 2>/dev/null)
500 [ -e "$__dest/$plugin_meta_path" ] ||
501 lint_fatal "No metadata file present (expecting" \
504 (sh -e "$__dest/$plugin_meta_path") >/dev/null 2>&1 ||
505 lint_err "Plugin metadata file has shell errors"
507 . "$__dest/$plugin_meta_path"
510 for executable in ${PLUGIN_EXECUTABLES}
512 exec_path="$__dest/$executable"
513 [ -e "$exec_path" ] || {
514 lint_err "PLUGIN_EXECUTABLES item $executable" \
519 [ -x "$exec_path" ] ||
520 lint_err "PLUGIN_EXECUTABLES item $executable" \
524 for dir in dev sys proc var
526 [ -e "$__dest/$dir" ] || continue
528 [ -d "$__dest/$dir" ] ||
529 lint_err "/$dir exists, but isn't a directory"
531 [ "$(find $__dest/$dir -mindepth 1)" ] &&
532 lint_warn "/$dir contains files/directories," \
533 "these will be lost during chroot setup"
536 printf '%s: %d errors, %d warnings\n' $plugin_file $errors $warnings
545 tmp=$(mktemp -p $test_tmpdir)
546 ref=$(mktemp -p $test_tmpdir)
555 download http://example.com/test $tmp
563 tmp=$(mktemp -p $test_tmpdir)
564 ref=$(mktemp -p $test_tmpdir)
573 download ftp://example.com/test $tmp
589 __pb_mount_dir="$test_tmpdir/mnt"
590 mnt_dir="$__pb_mount_dir/sda"
591 mkdir -p $mnt_dir/$plugin_meta_dir
593 echo "PLUGIN_ABI=$plugin_abi"
594 echo "PLUGIN_NAME=test"
595 echo "PLUGIN_VERSION=1"
596 echo "PLUGIN_EXECUTABLES=/bin/sh"
597 ) > $mnt_dir/$plugin_meta_path
600 find -mindepth 1 | cpio -o -Hnewc 2>/dev/null
601 ) | gzip -c > $mnt_dir/test.$plugin_ext
603 do_scan | grep -q 'test'
608 __pb_mount_dir="$test_tmpdir/mnt"
609 mnt_dir="$__pb_mount_dir/sda"
610 stderr_file="$test_tmpdir/stderr"
613 echo "invalid" > $mnt_dir/nogzip.$plugin_ext
615 do_scan 2>$stderr_file | grep -q 'No plugins'
617 [ $? = 0 ] || return 1
619 if [ -s "$stderr_file" ]
621 echo "Scan with invalid (non-gzip) file produced error output" \
631 __pb_mount_dir="$test_tmpdir/mnt"
632 mnt_dir="$__pb_mount_dir/sda"
633 stderr_file="$test_tmpdir/stderr"
636 echo "invalid" | gzip -c > $mnt_dir/nogzip.$plugin_ext
638 do_scan 2>$stderr_file | grep -q 'No plugins'
640 [ $? = 0 ] || return 1
642 if [ -s "$stderr_file" ]
644 echo "Scan with invalid (non-cpio) file produced error output" \
654 __pb_mount_dir="$test_tmpdir/mnt"
655 mnt_dir="$__pb_mount_dir/sda"
656 outfile=$test_tmpdir/scan.out
660 mkdir -p $mnt_dir/$plugin_meta_dir
662 echo "PLUGIN_ABI=$plugin_abi"
663 echo "PLUGIN_NAME=test-$i"
664 echo "PLUGIN_VERSION=1"
665 echo "PLUGIN_EXECUTABLES=/bin/sh"
666 ) > $mnt_dir/$plugin_meta_path
669 find -mindepth 1 | cpio -o -Hnewc 2>/dev/null
670 ) | gzip -c > $mnt_dir/test-${i}.$plugin_ext
671 rm -rf $mnt_dir/$plugin_meta_dir
676 grep -q 'test-1' $outfile && grep -q 'test-2' $outfile
681 __pb_mount_dir="$test_tmpdir/mnt"
682 mnt_dir="$__pb_mount_dir/sda"
683 mkdir -p $mnt_dir/$plugin_meta_dir
685 echo "PLUGIN_ABI=$(($plugin_abi + 1))"
686 echo "PLUGIN_ABI_MIN=$(($plugin_abi + 1))"
687 echo "PLUGIN_NAME=test"
688 echo "PLUGIN_VERSION=1"
689 echo "PLUGIN_EXECUTABLES=/bin/sh"
690 ) > $mnt_dir/$plugin_meta_path
693 find -mindepth 1 | cpio -o -Hnewc 2>/dev/null
694 ) | gzip -c > $mnt_dir/test.$plugin_ext
696 do_scan | grep -q 'No plugins'
701 __pb_mount_dir="$test_tmpdir/mnt"
702 mkdir -p $__pb_mount_dir
703 do_scan | grep -q "No plugins"
710 test_tmpdir="$tests_tmpdir/$n"
752 tests_tmpdir=$(mktemp -d)
755 do_test ! is_url "/test"
756 do_test ! is_url "./test"
757 do_test ! is_url "../test"
758 do_test ! is_url "test"
759 do_test is_url "http://example.com/path"
760 do_test is_url "git+ssh://example.com/path"
761 do_test test_http_download
762 do_test test_ftp_download
763 do_test ! test_abi_check
764 do_test ! test_abi_check 1
765 do_test test_abi_check 1 1
766 do_test test_abi_check 1 1 1
767 do_test test_abi_check 1 2 0
768 do_test test_abi_check 1 2 1
769 do_test ! test_abi_check 1 2 2
771 do_test test_scan_nogzip
772 do_test test_scan_nocpio
773 do_test test_scan_multiple
774 do_test test_scan_wrongabi
775 do_test test_empty_scan
777 if [ $test_failed = 0 ]
779 echo "$n tests passed"
783 rm -rf "$tests_tmpdir"
814 echo "error: Missing command" >&2
819 echo "Invalid command: $1" >&2