diff options
Diffstat (limited to 'src/pkgbuild-check-nonfree')
-rwxr-xr-x | src/pkgbuild-check-nonfree | 309 |
1 files changed, 248 insertions, 61 deletions
diff --git a/src/pkgbuild-check-nonfree b/src/pkgbuild-check-nonfree index 1cc0d9b..7b73745 100755 --- a/src/pkgbuild-check-nonfree +++ b/src/pkgbuild-check-nonfree @@ -1,10 +1,12 @@ #!/usr/bin/env bash +# -*- tab-width: 4 ; sh-basic-offset: 4 -*- # pkgbuild-check-nonfree -# Copyright 2010 Haase Hernández -# Copyright 2010 Joseph Graham -# Copyright 2010 Joshua Ismael -# Copyright 2012-2013 Luke Shumaker +# Copyright (C) 2010 Haase Hernández +# Copyright (C) 2010 Joseph Graham +# Copyright (C) 2010 Joshua Ismael +# Copyright (C) 2010 Nicolás Reynolds +# Copyright (C) 2012-2013 Luke Shumaker # # This file is part of Parabola. # @@ -21,80 +23,61 @@ # You should have received a copy of the GNU General Public License # along with Parabola. If not, see <http://www.gnu.org/licenses/>. -. libremessages -. libreblacklist -. $(librelib conf) - -# Usage: check_deps $pkgbuild -# Check whether a PKGBUILD package depends on non-free packages -check_deps() ( - # Note that we use () instead of {} for this function; so that variables - # from the PKBUILD don't bubble up - local pkgbuild=$1 - load_PKGBUILD "$pkgbuild" - if [[ -z "$pkgname" ]]; then - exit 1 # not a PKGBUILD - fi +# I appologize that this program got *huge*. +# It's not complicated, just long. - msg2 'Looking for unfree dependencies of %s %s' "${pkgbase:-${pkgname[0]}}" "$(get_full_version)" - - local pkgs=( - # packages being built - "${pkgname[@]}" - # depends - "${depends[@]}" "${makedepends[@]}" "${checkdepends[@]}" "${optdepends[@]%%:*}" - # mksource depends - "${mkdepends[@]}" - ) - local ret=0 - for pkg in "${pkgs[@]}"; do - local line="$(blacklist-cat|blacklist-lookup "$pkg")" - local rep="$(blacklist-get-rep <<<"$line")" - if [[ -z $line ]]; then - # not mentioned in blacklist; free - plain '%s: not blacklisted' "$pkg" - continue - elif [[ -z $rep ]]; then - # non-free with no replacement - plain '%s: blacklisted' "$pkg" - ret=1 - else - # non-free with free replacement - if [[ "$rep" == "$pkg" ]]; then - plain '%s: repackaged with the same name' "$pkg" - else - plain '%s: replaced by %s' "$pkg" "$rep" - fi - fi - done - return $ret -) +. $(librelib messages) +. $(librelib conf) +. $(librelib blacklist) usage() { print "Usage: %s [OPTIONS] [PKGBUILD1 PKGBUILD2 ...]" "${0##*/}" + print "Analyzes a PKGBUILD for freedom issues" echo prose 'If no PKGBUILD is specified, `./PKGBUILD` is implied.' echo - print "Exit status:" + print "Exit status (add them for combinations):" print " 0: Everything OK, no freedom issues" print " 1: Ran with error" - print " 15: Depends on non-free packages" + print "Warning-level freedom issues:" + print " 2: Uses unrecognized licenses, check them" + print " 4: Uses GPL-incompatible licenses" + print "Error-level freedom issues:" + print " 8: Uses known unacceptable licenses" + print " 16: Has nonfree dependencies" + print " 32: Is a known nonfree package" echo print "Options:" - flag '-c' 'Use the cached blacklist, do not try downloading.' + flag '-c' 'Use the cached blacklist, do not try downloading' flag '-f' 'Allow running as root user' + echo + flag '-q' 'Be quiet' + flag '-v' 'Be verbose' + echo flag '-h' 'Show this message' } +# Make sure these match pkgbuild-summarize-nonfree +declare -ri _E_OK=0 +declare -ri _E_ERROR=1 +declare -ri _E_LIC_UNKNOWN=2 +declare -ri _E_LIC_NOGPL=4 +declare -ri _E_LIC_NONFREE=8 +declare -ri _E_DEP_NONFREE=16 +declare -ri _E_PKG_NONFREE=32 main() { - local asroot=false + # Parse flags local cache=false - while getopts 'cfh' arg; do + local asroot=false + local v=1 + while getopts 'cfqvh' arg; do case "$arg" in c) cache=true;; f) asroot=true;; - h) usage; return 0;; - *) usage; return 1;; + q) v=0;; + v) v=2;; + h) usage; return $_E_OK;; + *) usage >&2; return $_E_ERROR;; esac done shift $(($OPTIND - 1)) @@ -104,18 +87,222 @@ main() { pkgbuilds=("$@") fi + # Do a check to see if we are running as root if [[ -w / ]] && ! $asroot; then error "Run as normal user, or use the -f option to run as root." return 1 fi - $cache || blacklist-update || return 1 + # Adjust the verbosity + if [[ $v == 0 ]]; then + error() { :; } + warning() { :; } + plain() { :; } + info() { :; } + elif [[ $v == 1 ]]; then + info() { :; } + elif [[ $v == 2 ]]; then + info() { plain "$@"; } + fi + + # Update the blacklist + $cache || blacklist-update || return $_E_ERROR - local ret=0 + # Do the work + declare -i ret=0 + local pkgbuild for pkgbuild in "${pkgbuilds[@]}"; do - check_deps "$pkgbuild" || ret=15 + pkgbuild_check "$pkgbuild" || ret=$(($ret|$?)) done return $ret } +# Helper functions ############################################################# +# These should maybe be moved into lib/conf.sh + +# Usage: var="$(pkgbuild_get_pkg_str ${pkgname} ${varname})" +# Gets a package-level string for a split-package +pkgbuild_get_pkg_str() { + [[ $# == 2 ]] || panic 'malformed call to pkgbuild_get_pkg_str' + local pkg=$1 + local var=$2 + + local indirect=${!var} + eval $(declare -f package_$pkg | sed -rn "s/^\s*${var}(\+?=)/indirect\1/p") + printf '%s' "${indirect}" +} +# Usage: eval $(pkgbuild_get_pkg_ary ${pkgname} ${varname} [$variable_name_to_set]) +# Gets a package-level array for a split-package +pkgbuild_get_pkg_ary() { + [[ $# == 2 ]] || [[ $# == 3 ]] || panic 'malformed call to pkgbuild_get_pkg_ary' + local pkg=$1 + local var=$2 + local out="${3:-$var}" + + local ary="${var}[@]" + local indirect=("${!ary}") + eval $(declare -f package_$pkg | sed -rn "s/^\s*${var}(\+?=)/indirect\1/p") + declare -p indirect|sed "s/ indirect=/ ${out}=/" +} + +# Checker functions ############################################################ + +# Usage: check_lic "${licence}" +# Check a license name to see if it is OK +check_lic() { + [[ $# == 1 ]] || panic 'malformed call to check_license' + local license=$1 + + info 'Checking license: %s' "$license" + + if [[ -e "/usr/share/licenses/common/$license" ]]; then + return $_E_OK + else + case "${license#custom:}" in + WTFPL) + # accept as common, I think it should be in the licenses package + return $_E_OK;; + BSD1|BSD2|BSD3|MIT|X11) + # accept these as common; they can't be included in the + # 'licenses' package because some text must be customized + return $_E_OK;; + BSD4) + warning "The 4-clause BSD license is free but has practical problems." + return $_E_LIC_NOGPL;; + BSD) + warning "License 'BSD' is ambiguous, use 'BSD{1..4}' to specify the number of clauses." + return $_E_LIC_UNKNOWN;; + JSON) + error "License '%s' is a known non-free license." "$license" + return $_E_LIC_NONFREE;; + *) + warning "License '%s' is not a common (recognized) license." "$license" + return $_E_LIC_UNKNOWN;; + esac + fi + panic 'code should never be reached' +} + +# Usage: check_dep "${dependency}" +# Checks for ${dependency} in the blacklist +check_dep() { + [[ $# == 1 ]] || panic 'malformed call to check_dep' + local pkg=$1 + + local line="$(blacklist-cat|blacklist-lookup "$pkg")" + local rep="$(blacklist-get-rep <<<"$line")" + if [[ -z $line ]]; then + # not mentioned in blacklist; free + info '%s: not blacklisted' "$pkg" + return $_E_OK + elif [[ -z $rep ]]; then + # non-free with no replacement + plain '%s: blacklisted' "$pkg" + return $_E_DEP_NONFREE + else + # non-free with free replacement + if [[ "$rep" == "$pkg" ]]; then + info '%s: repackaged with the same name' "$pkg" + else + info '%s: replaced by %s' "$pkg" "$rep" + fi + return $_E_OK + fi + panic 'code should never be reached' +} + +# Usage: check_pkg "${pkgname}" +# Checks for ${pkgname} in the blacklist +check_pkg() { + [[ $# == 1 ]] || panic 'malformed call to check_pkg' + check_dep "$@" + case $? in + $_E_OK) + return $_E_OK;; + $_E_DEP_NONFREE) + return $_E_PKG_NONFREE;; + *) + panic 'unexpected return code from check_dep';; + esac + panic 'code should never be reached' +} + +# Usage: pkgbuild_ckec $pkgbuild +# Check whether a PKGBUILD has any issues (using the above) +pkgbuild_check() ( + [[ $# == 1 ]] || panic 'malformed call to pkgbuild_check' + local pkgbuild=$1 + + load_PKGBUILD "$pkgbuild" + if [[ -z $pkgname ]]; then + return $_E_ERROR # not a PKGBUILD + fi + + declare -i ret=0 # the return status + local dep lic # iterators for us in `for` loops + local ck_deps ck_lics # lists of deps and licenses that have been checked + + if [[ ${#pkgname[@]} == 1 ]]; then + msg2 'Inspecting package pkgname=%q (%s)' "$pkgname" "$(get_full_version)" + else + msg2 'Inspecting split package pkgbase=%q (%s)' "${pkgbase:-${pkgname[0]}}" "$(get_full_version)" + fi + + # Check if this is blacklisted + check_pkg "${pkgbase:-${pkgname[0]}}" || ret=$(($ret|$?)) + # Check if dependencies are blacklisted + for dep in "${depends[@]}" "${makedepends[@]}" "${checkdepends[@]}" \ + "${optdepends[@]%%:*}" "${mkdepends[@]}" + do + check_dep "$dep" || ret=$(($ret|$?)) + ck_deps+=("$dep") + done + # Check the licenses + for lic in "${license[@]}"; do + check_lic "$lic" || ret=$(($ret|$?)) + ck_lics+=("$lic") + done + + if [[ ${#pkgname[@]} == 1 ]]; then + # Non-split package + # Make sure a license is set + if [[ ${#ck_lics[@]} == 0 ]]; then + error "The license array is empty" + ret=$(($ret|$_E_ERROR)) + fi + else + # Split package + # Check the individual split packages + local _pkgname _license _depends _optdepends + for _pkgname in "${pkgname[@]}"; do + msg2 'Inspecting split package pkgname=%q (%s)' "$_pkgname" "$(get_full_version "$_pkgname")" + eval $(pkgbuild_get_pkg_ary "$_pkgname" license _license) + eval $(pkgbuild_get_pkg_ary "$_pkgname" depends _depends) + eval $(pkgbuild_get_pkg_ary "$_pkgname" optdepends _optdepends) + + # Check if this is blacklisted + check_pkg "$_pkgname" || ret=$(($ret|$?)) + # Check if dependencies are blacklisted + for dep in "${_depends[@]}" "${_optdepends[@]%%:*}"; do + if ! in_array "$dep" "${ck_deps[@]}"; then + check_dep "$dep" || ret=$(($ret|$?)) + fi + done + # Check the licenses + for lic in "${_license[@]}"; do + if ! in_array "$lic" "${ck_lics[@]}"; then + check_lic "$lic" || ret=$(($ret|$?)) + fi + done + + if [[ ${#_license[@]} == 0 ]]; then + error "The license array is empty" + ret=$(($ret|$_E_ERROR)) + fi + done + fi + + return $ret +) + main "$@" |