utils/hooks: Don't fail early if fb0 missing
[petitboot] / utils / pb-plugin
index f87e5fb0e6f15f2ec9c151704c15529722a3c4d8..e107f9648ba2e165aa31d6223e69eec5d8f8812f 100755 (executable)
@@ -18,6 +18,7 @@ Where <command> is one of:
   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
+  lint <FILE>        - perform a pre-distribution check on FILE
 EOF
 }
 
@@ -63,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)
@@ -186,7 +208,7 @@ do_install()
                exit 1
        fi
 
-       . $__dest/$plugin_meta_path
+       parse_meta $__dest/$plugin_meta_path
 
        if ! plugin_abi_check
        then
@@ -228,7 +250,7 @@ do_scan_mount()
                fi
 
                (
-                       . $__meta_tmp/$plugin_meta_path
+                       parse_meta $__meta_tmp/$plugin_meta_path
 
                        plugin_abi_check || exit 1
 
@@ -236,7 +258,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 ]
@@ -370,49 +392,15 @@ do_create()
        fi
 
        # 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" ]
+       parse_meta $meta_file
+
+       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 +431,131 @@ 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)"
+
+       parse_meta "$__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 +816,10 @@ create)
        shift
        do_create $@
        ;;
+lint)
+       shift
+       do_lint $@
+       ;;
 __wrap)
        shift
        do_wrap $@
@@ -717,7 +834,7 @@ __test)
        exit 1
        ;;
 *)
-       echo "Invalid command: $s" >&2
+       echo "Invalid command: $1" >&2
        usage
        exit 1
 esac