diff sbin/fports @ 814:2310764e5c4e

fports: Implement a global "--jail/-j" option: execute the fports commands in a jail. The jail just needs to have an installed "pkg" command.
author Franz Glasner <fzglas.hg@dom66.de>
date Sat, 09 Nov 2024 00:47:05 +0100
parents 70e08ff3db45
children e2f262ec2bf4
line wrap: on
line diff
--- a/sbin/fports	Fri Nov 08 12:57:59 2024 +0100
+++ b/sbin/fports	Sat Nov 09 00:47:05 2024 +0100
@@ -23,8 +23,8 @@
 USAGE='
 USAGE: fports -h|--help
        fports -V|--version
-       fports deptree [-l maxlevel|--maxlevel=maxlevel] [-r|--reverse] [-t|--list|--transitive] package...
-       fports detail [-A] [-b|--nofreebsd|--no-freebsd] [-f|--filter-unused] [-n|--noauto|--no-auto] [-m|--mapped] [package...]
+       fports [GLOBAL-OPTIONS] deptree [-l maxlevel|--maxlevel=maxlevel] [-r|--reverse] [-t|--list|--transitive] package...
+       fports [GLOBAL-OPTIONS] detail [-A] [-b|--nofreebsd|--no-freebsd] [-f|--filter-unused] [-n|--noauto|--no-auto] [-m|--mapped] [package...]
 
 GLOBAL OPTIONS:
 
@@ -32,6 +32,9 @@
 
   -h, --help     Print this help message to stdout and exit.
 
+  -j JAIL, --jail=JAIL
+                 Execute in given jail JAIL.
+
 '
 
 
@@ -66,12 +69,18 @@
 #:
 #: Implementation of the "deptree" command.
 #:
+#: Args:
+#:   $1 (str, null): The jail to attach to
+#:   $2...: the command's options and arguments
+#:
 command_deptree() {
-    local opt_reversed opt_maxlevel opt_flat
+    local opt_jail opt_reversed opt_maxlevel opt_flat
     # $@
 
     local opt
 
+    opt_jail="${1}"
+    shift
     opt_maxlevel=0
     opt_reversed=no
     opt_flat=no
@@ -94,10 +103,14 @@
     shift $((OPTIND-1))
     OPTIND=1
 
+    if [ -n "${opt_jail}" ]; then
+        can_call_command "${opt_jail}" || fatal "${EX_UNAVAILABLE}" "jail \`${opt_jail}' does not exist or attaching denied"
+    fi
+
     if checkyesno opt_reversed; then
-        _command_deptree_reversed "${opt_maxlevel}" "${opt_flat}" "$@"
+        _command_deptree_reversed "${opt_jail}" "${opt_maxlevel}" "${opt_flat}" "$@"
     else
-        _command_deptree_normal "${opt_maxlevel}" "${opt_flat}" "$@"
+        _command_deptree_normal "${opt_jail}" "${opt_maxlevel}" "${opt_flat}" "$@"
     fi
 }
 
@@ -106,13 +119,14 @@
 #: Implementation of printing a "normal" dependency tree
 #:
 _command_deptree_normal() {
-    local maxlevel flat     # $@
+    local jail maxlevel flat     # $@
 
     local pkgdeps pkgqueue curdeps pkg n v flatdeps
 
-    maxlevel="${1}"
-    flat="${2}"
-    shift 2
+    jail="${1}"
+    maxlevel="${2}"
+    flat="${3}"
+    shift 3
 
     # shellcheck disable=SC2034    # pkgqueue seems unused
     pkgqueue=''
@@ -120,7 +134,7 @@
                             # resolution
 
     for pkg in "$@"; do
-        if ! "${PKG}" query '%n' "${pkg}" 1>/dev/null 2>/dev/null ; then
+        if ! call_pkg "${opt_jail}" query '%n' "${pkg}" 1>/dev/null 2>/dev/null ; then
             farray_release pkgqueue
             fatal "${EX_DATAERR}" "Package not found: ${pkg}"
         fi
@@ -137,7 +151,7 @@
                 farray_append curdeps "${n}=${v}"
                 farray_append pkgqueue "${n}"
             done <<EOF_01a8cebe-8659-4e32-87a4-bbce117e386b
-$(LC_ALL=C.UTF-8 "${PKG}" query '%dn %dv' "${pkg}")
+$(call_pkg "${opt_jail}" query '%dn %dv' "${pkg}")
 EOF_01a8cebe-8659-4e32-87a4-bbce117e386b
             falist_set pkgdeps "${pkg}" "${curdeps}"
             farray_release curdeps
@@ -149,12 +163,12 @@
     if checkyesno flat; then
         for pkg in "$@"; do
             _flatten_pkgdeps flatdeps "${pkgdeps}" "${pkg}"
-            _print_flatdeps '-->' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${flatdeps}"
+            _print_flatdeps '-->' "${pkg}" "$(call_pkg "${opt_jail}" query '%v' "${pkg}")" "${flatdeps}"
             falist_release "${flatdeps}"
         done
     else
         for pkg in "$@"; do
-            _print_dependency_tree 0 "${maxlevel}" '-->' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${pkgdeps}"
+            _print_dependency_tree 0 "${maxlevel}" '-->' "${pkg}" "$(call_pkg "${opt_jail}" query '%v' "${pkg}")" "${pkgdeps}"
         done
     fi
     falist_release pkgdeps
@@ -165,14 +179,15 @@
 #: Implementation of printing a reversed dependency tree
 #:
 _command_deptree_reversed() {
-    local maxlevel flat  # $@
+    local jail maxlevel flat  # $@
 
     local pkgdeps pkgqueue curdeps pkg n v flatdeps
 
-    maxlevel="${1}"
+    jail="${1}"
+    maxlevel="${2}"
     # shellcheck disable=SC2034    # appears unused
-    flat="${2}"
-    shift 2
+    flat="${3}"
+    shift 3
 
     # shellcheck disable=SC2034    # pkgqueue seems unused
     pkgqueue=''
@@ -180,7 +195,7 @@
                             # resolution
 
     for pkg in "$@"; do
-        if ! "${PKG}" query '%n' "${pkg}" 1>/dev/null 2>/dev/null ; then
+        if ! call_pkg "${opt_jail}" query '%n' "${pkg}" 1>/dev/null 2>/dev/null ; then
             farray_release pkgqueue
             fatal "${EX_DATAERR}" "Package not found: ${pkg}"
         fi
@@ -197,7 +212,7 @@
                 farray_append curdeps "${n}=${v}"
                 farray_append pkgqueue "${n}"
             done <<EOF_5079e996-c6d2-4e6d-825d-53183a64ab06
-$(LC_ALL=C.UTF-8 "${PKG}" query '%rn %rv' "${pkg}")
+$(call_pkg "${opt_jail}" query '%rn %rv' "${pkg}")
 EOF_5079e996-c6d2-4e6d-825d-53183a64ab06
             falist_set pkgdeps "${pkg}" "${curdeps}"
             farray_release curdeps
@@ -209,12 +224,12 @@
     if checkyesno flat; then
         for pkg in "$@"; do
             _flatten_pkgdeps flatdeps "${pkgdeps}" "${pkg}"
-            _print_flatdeps '<--' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${flatdeps}"
+            _print_flatdeps '<--' "${pkg}" "$(call_pkg "${opt_jail}" query '%v' "${pkg}")" "${flatdeps}"
             falist_release "${flatdeps}"
         done
     else
         for pkg in "$@"; do
-            _print_dependency_tree 0 "${maxlevel}" '<--' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${pkgdeps}"
+            _print_dependency_tree 0 "${maxlevel}" '<--' "${pkg}" "$(call_pkg "${opt_jail}" query '%v' "${pkg}")" "${pkgdeps}"
         done
     fi
     falist_release pkgdeps
@@ -343,8 +358,13 @@
 #:
 #: Implementation of the "detail" command.
 #:
+#: Args:
+#:   $1 (str, null): The jail to attach to
+#:   $2...: The command's options and arguments
+#:
 command_detail() {
-    local opt_nofreebsd  opt_filterunused opt_noauto opt_mapped opt_nofreebsd
+    local opt_jail opt_nofreebsd  opt_filterunused opt_noauto \
+          opt_mapped opt_nofreebsd
     # $@
 
     local package \
@@ -353,6 +373,8 @@
           repo title_printed indexfile _dummy opt acookie \
           pkglabel pkgdescr pkgversion mapped_package
 
+    opt_jail="${1}"
+    shift
     do_sort=no
     opt_filterunused=no
     opt_nofreebsd=no
@@ -394,24 +416,27 @@
     shift $((OPTIND-1))
     OPTIND=1
 
+    if [ -n "${opt_jail}" ]; then
+        can_call_command "${opt_jail}" || fatal "${EX_UNAVAILABLE}" "jail \`${opt_jail}' does not exist or attaching denied"
+    fi
+
     packages=''
     farray_create packages
     repositories=''
-    get_active_repositories repositories
+    get_active_repositories repositories "${opt_jail}"
     packagemapping=''
-    init_package_mapping packagemapping
-    falist_set packagemapping "uwsginl" "uwsgi"
-    indexfile="$(get_local_index_file)"
+    init_package_mapping packagemapping "${opt_jail}"
+    indexfile="$(get_local_index_file "${opt_jail}")"
 
     if checkyesno opt_nofreebsd; then
         while IFS='|' read -r package repo; do
             [ "${repo}" != 'FreeBSD' ] && farray_append packages "${package}"
         done <<EOF_1fa6f326-49e6-4b01-a7ea-52372d00df1e
-$(LC_ALL=C.UTF-8 "${PKG}" query '%n|%R')
+$(call_pkg "${opt_jail}" query '%n|%R')
 EOF_1fa6f326-49e6-4b01-a7ea-52372d00df1e
     fi
     if checkyesno opt_noauto; then
-        for package in $(LC_ALL=C.UTF-8 "${PKG}" query -e '%a = 0' '%n'); do
+        for package in $(call_pkg "${opt_jail}" query -e '%a = 0' '%n'); do
             farray_append packages "${package}"
         done
     fi
@@ -431,12 +456,12 @@
     prev_package=''    # to skip duplicate packages
     while farray_tryget package packages "${idx}"; do
         if [ "${prev_package}" != "${package}" ]; then
-            _package_max_detail "${package}" "${packagemapping}" "${repositories}" "${indexfile}" "${opt_filterunused}"
+            _package_max_detail "${package}" "${packagemapping}" "${repositories}" "${indexfile}" "${opt_filterunused}" "${opt_jail}"
             prev_package="${package}"
         fi
         idx=$((idx + 1))
     done
- 
+
     falist_release "${packagemapping}"
     farray_release "${repositories}"
     farray_release "${packages}"
@@ -455,9 +480,11 @@
 #:   $4 (str, null): The local index file if it exists
 #:   $5 (bool): Flag whether to suppress details for repositories that do
 #:              not contain the package `$1`
+#:   $6 (str, null): The jail where the packages live
 #:
 _package_max_detail() {
-    local package packagemapping repositories indexfile opt_filterunused
+    local package packagemapping repositories indexfile \
+          opt_filterunused opt_jail
 
     local instver instrepo repo title_printed _dummy \
           pkglabel pkgdescr pkgversion mapped_package
@@ -467,30 +494,31 @@
     repositories="${3}"
     indexfile="${4}"
     opt_filterunused="${5}"
+    opt_jail="${6}"
 
     # shellcheck disable=SC2034    # appears unused
     title_printed=no
     IFS='|' read -r instver instrepo <<EOF_e9bd7819-b4c5-4a86-b984-f5226db58cb1
-$(LC_ALL=C.UTF-8 "${PKG}" query '%v|%R' "${package}")
+$(call_pkg "${opt_jail}" query '%v|%R' "${package}")
 EOF_e9bd7819-b4c5-4a86-b984-f5226db58cb1
     print_title title_printed "${package}" "${instver}" "${instrepo}"
     if [ -n "${indexfile}" ]; then
         read -r _dummy pkglabel pkgdescr <<EOF_b1f225bd-d234-4a23-8a2a-40c2e5b7ff3c
-$(LC_ALL=C.UTF-8 "${PKG}" version -U -I -n "${package}" -v "${indexfile}")
+$(call_pkg "${opt_jail}" version -U -I -n "${package}" -v "${indexfile}")
 EOF_b1f225bd-d234-4a23-8a2a-40c2e5b7ff3c
-        pkgversion="$(parse_index_file_for_package_version "${indexfile}" "${package}")"
+        pkgversion="$(parse_index_file_for_package_version "${indexfile}" "${package}" "${opt_jail}")"
         _shall_print_package_detail_item "${pkglabel}" "${opt_filterunused}" && print_detail_item "INDEX" "${pkgversion}" "${pkglabel}" "${pkgdescr}"
     fi
-    farray_for_each repositories _package_repository_detail "${package}" "${opt_filterunused}" 0
+    farray_for_each repositories _package_repository_detail "${package}" "${opt_filterunused}" "${opt_jail}" 0
     mapped_package="$(get_package_mapping "${packagemapping}" "${package}")"
     if [ -n "${mapped_package}" ]; then
         printf '%18s %s\n' "--------------->" "${mapped_package}"
         if [ -n "${indexfile}" ]; then
-            pkgversion="$(parse_index_file_for_package_version "${indexfile}" "${mapped_package}")"
-            pkglabel="$(LC_ALL=C.UTF-8 "${PKG}" version --test-version "${instver}" "${pkgversion}")"
+            pkgversion="$(parse_index_file_for_package_version "${indexfile}" "${mapped_package}" "${opt_jail}")"
+            pkglabel="$(call_pkg "${opt_jail}" version --test-version "${instver}" "${pkgversion}")"
             print_detail_item "INDEX" "${pkgversion}" "${pkglabel}" '' 19
         fi
-        farray_for_each repositories _mapped_package_repository_detail "${mapped_package}" "{instver}" "${opt_filterunused}" 19
+        farray_for_each repositories _mapped_package_repository_detail "${mapped_package}" "{instver}" "${opt_filterunused}" "${opt_jail}" 19
     fi
 }
 
@@ -525,10 +553,12 @@
 #:   $3: The element value (i.e. repository name)
 #:   $4 (str): The (master) package name
 #:   $5 (flag): The global flat whether to filter repository printing
-#:   $6 (int, optional): The extra indent value to forward to called functions
+#:   $6 (str, null): The jail in which the package data live
+#:   $7 (int, optional): The extra indent value to forward to called functions
 #:
 _package_repository_detail() {
-    local repositories idx reponame package extraindent opt_filterunused
+    local repositories idx reponame package extraindent opt_filterunused \
+          opt_jail
 
     local _dummy \
           pkglabel pkgdescr pkgversion
@@ -539,12 +569,13 @@
     reponame="${3}"
     package="${4}"
     opt_filterunused="${5}"
-    extraindent="${6:-0}"
-    
+    opt_jail="${6}"
+    extraindent="${7:-0}"
+
     read -r _dummy  pkglabel pkgdescr <<EOF_19cf2d80-4eb9-4cda-bd4d-96b04e769206
-$(LC_ALL=C.UTF-8 "${PKG}" version -U -R -r "${reponame}" -n "${package}" -v)
+$(call_pkg "${opt_jail}" version -U -R -r "${reponame}" -n "${package}" -v)
 EOF_19cf2d80-4eb9-4cda-bd4d-96b04e769206
-    pkgversion="$(LC_ALL=C.UTF-8 "${PKG}" rquery -U -r "${reponame}" '%v' "${package}")"
+    pkgversion="$(call_pkg "${opt_jail}" rquery -U -r "${reponame}" '%v' "${package}")"
     _shall_print_package_detail_item "${pkglabel}" "${opt_filterunused}" && print_detail_item "${reponame}" "${pkgversion}" "${pkglabel}" "${pkgdescr}" "${extraindent}"
 }
 
@@ -560,11 +591,12 @@
 #:   $4 (str): The mapped package name
 #:   $5 (str): The parent package version
 #:   $6 (flag): The global flat whether to filter repository printing
-#:   $7 (int, optional): The extra indent value to forward to called functions
+#:   $7 (str, null): The jail where the package data live
+#:   $8 (int, optional): The extra indent value to forward to called functions
 #:
 _mapped_package_repository_detail() {
     local repositories idx reponame package parent_pkgversion \
-          opt_filterunused extraindent
+          opt_filterunused extraindent opt_jail
 
     local _dummy \
           pkglabel pkgversion
@@ -576,10 +608,11 @@
     package="${4}"
     parent_pkgversion="${5}"
     opt_filterunused="${6}"
-    extraindent="${7:-0}"
+    opt_jail="${7}"
+    extraindent="${8:-0}"
 
-    pkgversion="$(LC_ALL=C.UTF-8 "${PKG}" rquery -U -r "${reponame}" '%v' "${package}")"
-    pkglabel="$(LC_ALL=C.UTF-8 "${PKG}" version --test-version "${parent_pkgversion}" "${pkgversion}")"
+    pkgversion="$(call_pkg "${opt_jail}" rquery -U -r "${reponame}" '%v' "${package}")"
+    pkglabel="$(call_pkg "${opt_jail}" version --test-version "${parent_pkgversion}" "${pkgversion}")"
     _shall_print_package_detail_item "${pkglabel}" "${opt_filterunused}" && print_detail_item "${reponame}" "${pkgversion}" "${pkglabel}" '' "${extraindent}"
 }
 
@@ -659,8 +692,10 @@
 #
 # Global option handling
 #
-while getopts "Vh-:" _opt ; do
-    postprocess_getopts_for_long "Vh-:" _opt "version" "help" ""
+
+opt_jail=''
+while getopts "Vhj:-:" _opt ; do
+    postprocess_getopts_for_long "Vhj-:" _opt "version" "help" "jail=" ""
     case "${_opt}" in
         V|version)
             printf 'fports %s\n' '@@SIMPLEVERSIONSTR@@'
@@ -670,6 +705,9 @@
             echo "${USAGE}"
             exit 0
             ;;
+        j|jail)
+            opt_jail="${OPTARG}"
+            ;;
         \?)
             exit 2;
             ;;
@@ -693,9 +731,9 @@
     '')
         fatal 2 "no command given";;
     deptree)
-        command_deptree "$@";;
+        command_deptree "${opt_jail}" "$@";;
     detail)
-        command_detail "$@";;
+        command_detail "${opt_jail}" "$@";;
     *)
         fatal 2 "unknown command \`${command}'";;
 esac