diff options
Diffstat (limited to 'src/pkgbuild-check-nonfree')
-rwxr-xr-x | src/pkgbuild-check-nonfree | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/pkgbuild-check-nonfree b/src/pkgbuild-check-nonfree new file mode 100755 index 0000000..67f07bc --- /dev/null +++ b/src/pkgbuild-check-nonfree @@ -0,0 +1,309 @@ +#!/usr/bin/env bash +# -*- tab-width: 4 ; sh-basic-offset: 4 -*- +# pkgbuild-check-nonfree + +# Copyright (C) 2011 Joseph Graham (Xylon) <joe@t67.eu> +# Copyright (C) 2010-2011 Joshua Ismael Haase Hernández (xihh) <hahj87@gmail.com> +# Copyright (C) 2010-2012 Nicolás Reynolds <fauno@parabola.nu> +# Copyright (C) 2012-2013 Luke Shumaker <lukeshu@sbcglobal.net> +# +# License: GNU GPLv3+ +# +# This file is part of Parabola. +# +# Parabola is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Parabola is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Parabola. If not, see <http://www.gnu.org/licenses/>. + +# I appologize that this program got *huge*. +# It's not complicated, just long. + +. "$(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 (add them for combinations):" + print " 0: Everything OK, no freedom issues" + print " 1: Ran with error" + 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 '-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() { + # Parse flags + local cache=false + local asroot=false + local v=1 + while getopts 'cfqvh' arg; do + case "$arg" in + c) cache=true;; + f) asroot=true;; + q) v=0;; + v) v=2;; + h) usage; return $_E_OK;; + *) usage >&2; return $_E_ERROR;; + esac + done + shift $(($OPTIND - 1)) + if [[ $# -lt 1 ]]; then + pkgbuilds=("`pwd`/PKGBUILD") + else + 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 + + # 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 + + # Do the work + declare -i ret=0 + local pkgbuild + for pkgbuild in "${pkgbuilds[@]}"; do + 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 "$@" |