Inclusion of pacwrap-key, some container schema fixes

- Inclusion of pacwrap-key, a fork of pacman-key, adapted for use with
   pacwrap and associated containers. CLI is now reminiscent of pacwrap's
   own native CLI for clean integration.
 - Removed problematic /etc/bash.bashrc fakeroot mount supplanted by
   schema update to /etc/bash.bashrc
 - Inclusion of pacwrap-key with container schema
 - Build and integration scripting cleaned up with improved error handling
This commit is contained in:
Xavier Moffett 2024-02-16 18:17:35 -05:00
parent 62816ddef8
commit b2ebfe7269
15 changed files with 1171 additions and 165 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@
/dist/*.*
/dist/schema
/dist/runtime
/dist/bin

View File

@ -20,3 +20,5 @@ case ${TERM} in
esac
[ -r /usr/share/bash-completion/bash_completion ] && . /usr/share/bash-completion/bash_completion
[[ $FAKECHROOT ]] && cd $HOME

806
dist/src/pacwrap-key vendored Executable file
View File

@ -0,0 +1,806 @@
#!/usr/bin/bash
#
# pacwrap-key - manages pacwrap's keyring
# Based on pacman-key,
# which itself was derived from apt-key.
#
# Copyright (C) 2023-2024 Xavier R.M. <sapphirus@azorium.net>
# Copyright (C) 2010-2021 Pacman Development Team <pacman-dev@archlinux.org>
# SPDX-License-Identifier: GPL-3.0-only
#
# This program 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, version 3.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
# TODO: Provide our own localization
export TEXTDOMAIN='pacwrap-bash'
export TEXTDOMAINDIR='/usr/share/locale'
declare -r VERSION="version_string_placeholder"
[[ ! $PACWRAP_DATA_DIR ]] && PACWRAP_DATA_DIR="$HOME/.local/share/pacwrap"
PACWRAP_KEYRING_DIR="$PACWRAP_DATA_DIR/pacman/gnupg"
TARGETS=()
KEYSERVER=''
USE_COLOR='y'
VERBOSE=0
COLOR_SET=0
RESET=
BOLD=
BLUE=
GREEN=
RED=
YELLOW=
HEADER=
HEADER_RESET=
TAB=$' '
SUB_HEADER=$TAB
SUB_TEXT=$TAB$TAB
CHILD_HEADER=$SUB_TEXT
CHILD_SUBTEXT=$TAB$TAB$TAB
[[ $FAKECHROOT ]] && PACWRAP_KEYRING_DIR="/etc/pacman.d/gnupg";
main() {
parse_params $@
colorize
check
case $SWITCH in
init) initialize ${TARGETS[@]};;
a*) add_keys ${TARGETS[@]};;
d*) delete_keys ${TARGETS[@]};;
e*) edit_keys ${TARGETS[@]};;
E*) export_keys ${TARGETS[@]};;
f*) finger_keys ${TARGETS[@]};;
it*) import_trustdb ${TARGETS[@]};;
i*) import ${TARGETS[@]};;
ls*) list_sigs ${TARGETS[@]};;
lk*) list_keys ${TARGETS[@]};;
p*) populate_keyring ${TARGETS[@]};;
rk*) receive_keys ${TARGETS[@]};;
uk*) refresh_keys ${TARGETS[@]};;
v*) verify_sig ${TARGETS[@]};;
h) man_key;;
V) version;;
DB) ;;
*) invalid_option $SWITCH;;
esac
[[ $SWITCH == *DB* ]] && updatedb
}
parse_params() {
if [[ -z $@ ]]; then
invalid_option
fi
local pos=0
local count=0
while (( $# )); do case $1 in
--nocolor) count=0; USE_COLOR='n'; shift; continue;;
--verbose) count=0; VERBOSE=1; shift; continue;;
--keyserver) shift; count=0 KEYSERVER=$1; shift; continue;;
--import) SWITCH="iDB";;
--import-trustdb) SWITCH="itDB" ;;
--init) SWITCH="init";;
--list-sigs) SWITCH="ls";;
--lsign-key) SWITCH="lskDB";;
--populate) SWITCH+="pkDB";;
--edit-key) SWITCH="e";;
--refresh-keys) SWITCH="uk";;
-u|--updatedb) SWITCH+="DB";;
-a|--add) SWITCH="aDB";;
-d|--delete) SWITCH="dDB";;
-e|--export) SWITCH="EDB";;
-f|--finger) SWITCH="f";;
-l|--list-keys) SWITCH="lk";;
-r|--recv-keys) SWITCH="rkDB";;
-v|--verify) SWITCH="v";;
-h|--help*) SWITCH="h";;
-V|--version) SWITCH="V";;
-*) invalid_option $1;;
*) TARGETS+=($1); shift; continue;
esac
if [[ $count > 0 ]]; then
invalid_option $1
fi
pos+=1; count+=1
shift; done
}
invalid_option() {
colorize
if [[ -z $@ ]]; then
error "$(gettext "Operation not specified")"
else
error "$(gettext "Invalid option '%s'")" "$@"
fi
echo "$(gettext "Try 'pacwrap-key -h' for more information on valid operational parameters.")"
exit 1
}
man_key() {
cat << _USAGE
${HEADER}NAME$HEADER_RESET
${TAB}pacwrap-key
${HEADER}USAGE$HEADER_RESET
${TAB}pacwrap-key [${BOLD}OPERATIONS$RESET] [${BOLD}TARGETS$RESET]
${HEADER}SYNOPSIS$HEADER_RESET
${TAB}Manage pacwrap's gnupg trust database. This utility is only to be used with pacwrap and its associated containers.
${HEADER}OPERATIONS$HEADER_RESET
${SUB_HEADER}-a, --add$RESET
${SUB_TEXT}Add the specified keys (empty for stdin)
${SUB_HEADER}-d, --delete$RESET
${SUB_TEXT}REmove the specified keys from the keyring.
${SUB_HEADER}-e, --export$RESET
${SUB_TEXT}Export the specified or all keyring ids.
${SUB_HEADER}-f, --finger$RESET
${SUB_TEXT}List fingerprint for specified or all keyring ids.
${SUB_HEADER}-l, --list-keys$RESET
${SUB_TEXT}List the specified or all keyring ids.
${SUB_HEADER}-r, --recv-keys$RESET
${SUB_TEXT}Fetch the specified keyrings by id from the default or specified keyserver.
${SUB_HEADER}-u, --updatedb$RESET
${SUB_TEXT}Update the trustdb of pacwrap on this local, standard privileged user.
${SUB_HEADER}--init$RESET
${SUB_TEXT}Initialize the gnupg keyring for use with pacwrap.
${SUB_HEADER}--populate$RESET
${SUB_TEXT}Populate the keyring with default signatures located typically in:
${SUB_TEXT}'/usr/share/pacman/keyrings/'
${SUB_HEADER}--list-sigs$RESET
${SUB_TEXT}List populated keys alongside their signatures.
${SUB_HEADER}--lsign-key$RESET
${SUB_TEXT}Locally sign the specified keyring id.
${SUB_HEADER}--import$RESET
${SUB_TEXT}Locally sign the specified keyring id
${SUB_HEADER}--import-trustdb$RESET
${SUB_TEXT}Locally sign the specified keyring id
${SUB_HEADER}--keyserver $RESET[${BOLD}keyserver$RESET]$BOLD$RESET
${SUB_TEXT}Specify an alternate keyserver
${SUB_HEADER}-h, --help$RESET
${SUB_TEXT}Invokes a printout of this manual to ${BOLD}STDOUT$RESET.
${SUB_HEADER}-v, --version$RESET
${SUB_TEXT}Invokes a printout of version and copyright information to ${BOLD}STDOUT$RESET.
${HEADER}ENVIRONMENT VARIABLES$HEADER_RESET
${SUB_HEADER}PACWRAP_DATA_DIR$RESET
${SUB_TEXT}Overrides the default XDG Directory Specification compliant data directory. Set this$RESET
${SUB_TEXT}environment variable to change the relative target directory for the keystore.$RESET
${HEADER}COPYRIGHT$HEADER_RESET
${TAB}Copyright (C) 2023-2024 Xavier R.M.
${TAB}Copyright (C) 2010-2021 Pacman Development Team
${TAB}This program may be freely redistributed under
${TAB}the terms of the GNU General Public License v3.
_USAGE
}
check() {
if ! type -p gpg >/dev/null; then
error_fatal "$(gettext "Cannot find the %s binary required for all %s operations.")" "gpg" "pacwrap-key"
fi
if [[ $UID == 0 ]] && [[ $PACWRAP_KEYRING_DIR == $PACWRAP_DATA_DIR* ]]; then
error_fatal "$(gettext "Keyring stores held by %s cannot be operated upon as root.")" "pacwrap"
fi
if [[ -d $PACWRAP_KEYRING_DIR ]] && [[ ! -w "$PACWRAP_KEYRING_DIR" ]]; then
error_fatal "$(gettext "Insufficient permissions to operate on designated keystore.")" "pacwrap"
fi
if [[ ! -d $PACWRAP_DATA_DIR ]] && [[ ! $FAKECHROOT ]]; then
if [[ ! -w "$PACWRAP_KEYRING_DIR" ]]; then
error_fatal "$(gettext "Insufficient permissions to operate on designated keystore.")"
else
error_fatal "$(gettext "'%s': pacwrap data directory not found.")" $PACWRAP_DATA_DIR
fi
fi
if [[ ! -d "$PACWRAP_KEYRING_DIR" ]] && [[ ! $FAKECHROOT ]]; then
mkdir -p "$PACWRAP_KEYRING_DIR"
check_keyring
else
check_keyring
fi
GPG_PACWRAP=(gpg --homedir "${PACWRAP_KEYRING_DIR}" --no-permission-warning)
if [[ -n ${KEYSERVER} ]]; then
GPG_PACWRAP+=(--keyserver "${KEYSERVER}")
fi
}
colorize() {
[[ $COLOR_SET == 1 ]] && return
if [[ ! -z $COLORTERM ]] && [[ $TERM != "dummy" ]] && [[ $USE_COLOR != 'n' ]] && [[ -t 2 ]]; then
RESET=""
BOLD=""
BLUE="${BOLD}"
GREEN="${BOLD}"
RED="${BOLD}"
YELLOW="${BOLD}"
fi
HEADER=$BOLD
HEADER_RESET=$RESET
SUB_HEADER=$TAB$BOLD
SUB_TEXT=$TAB$TAB
CHILD_HEADER=$SUB_TEXT$BOLD
CHILD_SUBTEXT=$TAB$TAB$TAB
readonly RESET BOLD BLUE GREEN RED YELLOW \
HEADER HEADER_RESET \
SUB_HEADER SUBTEXT \
CHILD_HEADER CHILD_SUBTEXT; COLOR_SET=1
}
msg() {
(( QUIET )) && return
local mesg=$1; shift
printf "${GREEN}->${RESET}${BOLD} ${mesg}${RESET}\n" "$@"
}
msg2() {
(( QUIET )) && return
local mesg=$1; shift
printf "${GREEN} ✓ ${RESET}${mesg}\n" "$@"
}
ask() {
local mesg=$1; shift
printf "${BLUE}::${RESET}${BOLD} ${mesg}${RESET}" "$@"
}
warning() {
local mesg=$1; shift
printf "${YELLOW}$(gettext "warning:")${RESET} ${mesg}\n" "$@" >&2
}
error() {
local mesg=$1; shift
printf "${RED}$(gettext "error:")${RESET} ${mesg}\n" "$@" >&2
}
error_fatal() {
local mesg=$1; shift
printf "${RED}$(gettext "error:")${RESET} ${mesg}\n" "$@" >&2
exit 1
}
usage() {
pacwrap "$@"
exit 0
}
version() {
cat << ENDOF
${VERSION}
Copyright (C) 2023-2024 Xavier R.M.
Copyright (C) 2010-2021 Pacman Development Team
Website: https://pacwrap.sapphirus.org/
Github: https://github.com/pacwrap/pacwrap
This program may be freely redstributed under the
terms of the GNU General Public License V3 only.
ENDOF
exit 0
}
key_lookup_from_name() {
local ids
mapfile -t ids < \
<("${GPG_PACWRAP[@]}" --search-keys --batch --with-colons "$1" 2>/dev/null |
awk -F: '$1 == "pub" { print $2 }')
# only return success on non-ambiguous lookup
case ${#ids[*]} in
0)
error "$(gettext "Failed to lookup key by name:") %s" "$name"
return 1
;;
1)
printf '%s' "${ids[0]}"
return 0
;;
*)
error "$(gettext "Key name is ambiguous:") %s" "$name"
return 1
;;
esac
}
generate_master_key() {
# Generate the master key, which will be in both pubring and secring
msg "$(gettext "Generating pacwrap master key...")"
"${GPG_PACWRAP[@]}" --gen-key --batch <<EOF
%echo Generating pacwrap keyring master key...
Key-Type: RSA
Key-Length: 4096
Key-Usage: sign
Name-Real: Pacwrap Keyring Master Key
Name-Email: pacwrap@localhost
Expire-Date: 0
%no-protection
%commit
%echo Done
EOF
}
secret_keys_available() {
"${GPG_PACWRAP[@]}" -K --with-colons | wc -l
}
# Adds the given gpg.conf option if it is not present in the file.
# Note that if we find it commented out, we won't add the option.
# args: $1 conffile, $2 option-name, $3 (optional) option-value
add_gpg_conf_option() {
local conffile=$1; shift
# looking for the option 'bare', only leading spaces or # chars allowed,
# followed by at least one space and any other text or the end of line.
if ! grep -q "^[[:space:]#]*$*\([[:space:]].*\)*$" "$conffile" &>/dev/null; then
printf '%s\n' "$*" >> "$conffile"
fi
}
check_keyids_exist() {
local ret=0
for key in "$@"; do
# Verify if the key exists in pacman's keyring
if ! "${GPG_PACWRAP[@]}" --list-keys "$key" &>/dev/null ; then
error "$(gettext "The key identified by %s could not be found locally.")" "$key"
ret=1
fi
done
if (( ret )); then
exit 1
fi
}
key_is_lsigned() {
secret_key=$("${GPG_PACWRAP[@]}" --with-colons --list-secret-key --quiet | awk -F : 'NR==1 {print $5}')
while IFS=: read -r type valid _ _ sign_key _; do
if [[ $type != "sig" || $valid != "!" ]]; then
continue
fi
if [[ "$sign_key" == "$secret_key" ]]; then
return 0
fi
done < <("${GPG_PACWRAP[@]}" --with-colons --check-signatures --quiet "$1")
return 1
}
key_is_revoked() {
while IFS=: read -r type _ _ _ _ _ _ _ _ _ _ flags _; do
if [[ $type != "pub" ]]; then
continue
fi
if [[ $flags == *"D"* ]]; then
return 0
fi
done < <("${GPG_PACWRAP[@]}" --with-colons --list-key --quiet "$1")
return 1
}
initialize() {
local conffile keyserv
# Check for simple existence rather than for a directory as someone
# may want to use a symlink here
[[ -e ${PACWRAP_KEYRING_DIR} ]] || mkdir -p -m 755 "${PACMAN_KEYRING_DIR}"
# keyring files
[[ -f ${PACWRAP_KEYRING_DIR}/pubring.gpg ]] || touch ${PACWRAP_KEYRING_DIR}/pubring.gpg
[[ -f ${PACWRAP_KEYRING_DIR}/secring.gpg ]] || touch ${PACWRAP_KEYRING_DIR}/secring.gpg
[[ -f ${PACWRAP_KEYRING_DIR}/trustdb.gpg ]] || "${GPG_PACWRAP[@]}" --update-trustdb
chmod 644 ${PACWRAP_KEYRING_DIR}/{pubring,trustdb}.gpg
chmod 600 ${PACWRAP_KEYRING_DIR}/secring.gpg
# gpg.conf
conffile="${PACWRAP_KEYRING_DIR}/gpg.conf"
[[ -f $conffile ]] || touch "$conffile"
chmod 644 "$conffile"
add_gpg_conf_option "$conffile" 'no-greeting'
add_gpg_conf_option "$conffile" 'no-permission-warning'
add_gpg_conf_option "$conffile" 'lock-never'
add_gpg_conf_option "$conffile" 'keyserver-options' 'timeout=10'
add_gpg_conf_option "$conffile" 'keyserver-options' 'import-clean'
local gpg_ver=$(gpg --version | awk '{print $3; exit}')
if (( $(vercmp "$gpg_ver" 2.2.17) >= 0 )); then
add_gpg_conf_option "$conffile" 'keyserver-options' 'no-self-sigs-only'
fi
# gpg-agent.conf
agent_conffile="${PACWRAP_KEYRING_DIR}/gpg-agent.conf"
[[ -f $agent_conffile ]] || touch "$agent_conffile"
chmod 644 "$agent_conffile"
add_gpg_conf_option "$agent_conffile" 'disable-scdaemon'
# set up a private signing key (if none available)
if [[ $(secret_keys_available) -lt 1 ]]; then
generate_master_key
UPDATEDB=1
fi
}
populate_keyring() {
local KEYRING_IMPORT_DIR='/usr/share/pacman/keyrings'
local keyring KEYRINGIDS=("$@")
local ret=0
if (( ${#KEYRINGIDS[*]} == 0 )); then
# get list of all available keyrings
shopt -s nullglob
KEYRINGIDS=("$KEYRING_IMPORT_DIR"/*.gpg)
shopt -u nullglob
KEYRINGIDS=("${KEYRINGIDS[@]##*/}")
KEYRINGIDS=("${KEYRINGIDS[@]%.gpg}")
if (( ${#KEYRINGIDS[*]} == 0 )); then
error "$(gettext "No keyring files exist in %s.")" "$KEYRING_IMPORT_DIR"
ret=1
fi
else
# verify listed keyrings exist
for keyring in "${KEYRINGIDS[@]}"; do
if [[ ! -f "$KEYRING_IMPORT_DIR/$keyring.gpg" ]]; then
error "$(gettext "The keyring file %s does not exist.")" "$KEYRING_IMPORT_DIR/$keyring.gpg"
ret=1
fi
done
fi
if (( ret )); then
exit 1
fi
# Variable used for iterating on keyrings
local keys key_id
# Add keys from requested keyrings
for keyring in "${KEYRINGIDS[@]}"; do
msg "$(gettext "Appending keys from %s.gpg...")" "$keyring"
"${GPG_PACWRAP[@]}" --quiet --import "${KEYRING_IMPORT_DIR}/${keyring}.gpg"
done
# Read the trusted key IDs to an array. Because this is an ownertrust
# file, we know we have the full 40 hex digit fingerprint values.
# Format of ownertrust dump file:
# 40CHARFINGERPRINTXXXXXXXXXXXXXXXXXXXXXXX:6:
# 40CHARFINGERPRINTXXXXXXXXXXXXXXXXXXXXXXX:5:
local -A trusted_ids
for keyring in "${KEYRINGIDS[@]}"; do
if [[ -s "${KEYRING_IMPORT_DIR}/${keyring}-trusted" ]]; then
while IFS=: read key_id _; do
# skip blank lines, comments; these are valid in this file
[[ -z $key_id || ${key_id:0:1} = \# ]] && continue
if key_is_lsigned "$key_id" ; then
continue
fi
# Mark this key to be lsigned
trusted_ids[$key_id]=$keyring
done < "${KEYRING_IMPORT_DIR}/${keyring}-trusted"
fi
done
local -A revoked_ids
for keyring in "${KEYRINGIDS[@]}"; do
if [[ -s $KEYRING_IMPORT_DIR/$keyring-revoked ]]; then
while read -r key_id; do
if key_is_revoked "$key_id" ; then
continue
fi
revoked_ids["$key_id"]=1
done <"$KEYRING_IMPORT_DIR/$keyring-revoked"
fi
done
if (( ${#trusted_ids[@]} > 0 )); then
msg "$(gettext "Locally signing trusted keys in keyring...")"
lsign_keys "${!trusted_ids[@]}"
msg "$(gettext "Importing owner trust values...")"
for keyring in "${KEYRINGIDS[@]}"; do
if [[ -s "${KEYRING_IMPORT_DIR}/${keyring}-trusted" ]]; then
"${GPG_PACWRAP[@]}" --import-ownertrust "${KEYRING_IMPORT_DIR}/${keyring}-trusted"
fi
done
fi
if (( ${#revoked_ids[@]} > 0 )); then
local key_count=0
msg "$(gettext "Disabling revoked keys in keyring...")"
for key_id in "${!revoked_ids[@]}"; do
if (( VERBOSE )); then
msg2 "$(gettext "Disabling key %s...")" "${key_id}"
fi
printf 'disable\nquit\n' | LANG=C "${GPG_PACWRAP[@]}" --command-fd 0 --no-auto-check-trustdb --quiet --batch --edit-key "${key_id}" 2>/dev/null
key_count=$((key_count+1))
done
if (( key_count )); then
msg2 "$(gettext "Disabled %s keys.")" "${key_count}"
fi
fi
}
add_keys() {
if ! "${GPG_PACWRAP[@]}" --quiet --batch --import "$@" ; then
error_fatal "$(gettext "A specified keyfile could not be added to the keyring.")"
fi
}
delete_keys() {
check_keyids_exist "$@"
if ! "${GPG_PACWRAP[@]}" --quiet --batch --delete-key --yes "$@" ; then
error_fatal "$(gettext "A specified key could not be removed from the keyring.")"
fi
}
edit_keys() {
check_keyids_exist "$@"
local ret=0
for key in "$@"; do
if ! "${GPG_PACWRAP[@]}" --edit-key "$key" ; then
error "$(gettext "The key identified by %s could not be edited.")" "$key"
ret=1
fi
done
if (( ret )); then
exit 1
fi
}
export_keys() {
check_keyids_exist "$@"
if ! "${GPG_PACWRAP[@]}" --armor --export "$@" ; then
error_fatal "$(gettext "A specified key could not be exported from the keyring.")"
fi
}
finger_keys() {
check_keyids_exist
if ! "${GPG_PACWRAP[@]}" --batch --fingerprint "$@" ; then
error_fatal "$(gettext "The fingerprint of a specified key could not be determined.")"
fi
}
import_trustdb() {
local importdir
local ret=0
for importdir in "$@"; do
if [[ -f "${importdir}/trustdb.gpg" ]]; then
gpg --homedir "${importdir}" --export-ownertrust | \
"${GPG_PACWRAP[@]}" --import-ownertrust -
if (( PIPESTATUS )); then
error "$(gettext "%s could not be imported.")" "${importdir}/trustdb.gpg"
ret=1
fi
else
error "$(gettext "File %s does not exist and could not be imported.")" "${importdir}/trustdb.gpg"
ret=1
fi
done
if (( ret )); then
exit 1
fi
}
import() {
local importdir
local ret=0
for importdir in "$@"; do
if [[ -f "${importdir}/pubring.gpg" ]]; then
if ! "${GPG_PACWRAP[@]}" --quiet --batch --import "${importdir}/pubring.gpg" ; then
error "$(gettext "%s could not be imported.")" "${importdir}/pubring.gpg"
ret=1
fi
else
error "$(gettext "File %s does not exist and could not be imported.")" "${importdir}/pubring.gpg"
ret=1
fi
done
if (( ret )); then
exit 1
fi
}
list_keys() {
check_keyids_exist
if ! "${GPG_PACWRAP[@]}" --batch --list-keys "$@" ; then
error_fatal "$(gettext "A specified key could not be listed.")"
fi
}
list_sigs() {
check_keyids_exist
if ! "${GPG_PACWRAP[@]}" --batch --list-sigs "$@" ; then
error_fatal "$(gettext "A specified signature could not be listed.")"
fi
}
lsign_keys() {
check_keyids_exist
local ret=0
local key_count=0
for key_id in "$@"; do
if (( VERBOSE )); then
msg2 "$(gettext "Locally signing key %s...")" "${key_id}"
fi
# we cannot use --yes here as gpg would still ask for confirmation if a key has more than one uid
printf 'y\ny\n' | LANG=C "${GPG_PACWRAP[@]}" --command-fd 0 --quiet --batch --lsign-key "${key_id}" 2>/dev/null
if (( PIPESTATUS[1] )); then
error "$(gettext "%s could not be locally signed.")" "${key_id}"
ret=1
fi
key_count=$((key_count+1))
done
if (( ret )); then
exit 1
fi
if (( key_count )); then
msg2 "$(gettext "Locally signed %s keys.")" "${key_count}"
fi
}
receive_keys() {
local ret=0 name id keyids emails
# if the key is not a hex ID, do a lookup
for name; do
if [[ $name = ?(0x)+([0-9a-fA-F]) ]]; then
keyids+=("$name")
elif [[ $name = *@*.* ]]; then
emails+=("$name")
elif id=$(key_lookup_from_name "$name"); then
keyids+=("$id")
fi
done
(( ${#keyids[*]}+${#emails[*]} > 0 )) || exit 1
if (( ${#emails[*]} > 0 )) && \
! "${GPG_PACWRAP[@]}" --auto-key-locate clear,nodefault,wkd,keyserver \
--locate-key "${emails[@]}" ; then
error "$(gettext "Remote key not fetched correctly from WKD or keyserver.")"
ret=1
fi
if (( ${#keyids[*]} > 0 )) && ! "${GPG_PACWRAP[@]}" --recv-keys "${keyids[@]}" ; then
error "$(gettext "Remote key not fetched correctly from keyserver.")"
ret=1
fi
exit $ret
}
check_keyring() {
if [[ ! -d "$PACWRAP_KEYRING_DIR" ]]; then
error_fatal "$(gettext "Keyring store not found in pacwrap data directory.")" "gpg" "pacwrap-key"
fi
}
refresh_keys() {
local ret=0 ids masterkey emails
check_keyids_exist "$@"
# don't try to refresh the user's local masterkey
masterkey="$("${GPG_PACWRAP[@]}" --list-keys --with-colons pacman@localhost |
awk -F: '$1 == "pub" { print $5 }')"
mapfile -t ids < \
<("${GPG_PACWRAP[@]}" --list-keys --with-colons "$@" |
awk -F: '$1 == "pub" { print $5 }' | grep -vx "$masterkey")
for id in "${ids[@]}"; do
mapfile -t emails < \
<("${GPG_PACWRAP[@]}" --list-keys --list-options show-only-fpr-mbox "$id" |
awk '{print $2 }')
# first try looking up the key in a WKD (only works by email address)
for email in "${emails[@]}"; do
"${GPG_PACWRAP[@]}" --locate-external-keys "$email" && break
done
# if no key was found, fall back to using the keyservers (with the key fingerprint instead)
if (( $? )) && ! "${GPG_PACWRAP[@]}" --refresh-keys "$id"; then
error "$(gettext "Could not update key: %s")" "$id"
ret=1
fi
done
exit $ret
}
verify_sig() {
local ret=0 sig=$1 file=$2
if [[ -z $file && -f ${sig%.*} ]]; then
file=${sig%.*}
fi
if [[ -n $file ]]; then
local files=("$sig" "$file")
msg "Checking %s... (detached)" "$sig"
else
local files=("$sig")
msg "Checking %s... (embedded)" "$sig"
fi
if grep -q 'BEGIN PGP SIGNATURE' "$sig"; then
error_fatal "$(gettext "Cannot use armored signatures for packages: %s")" "$sig"
fi
"${GPG_PACWRAP[@]}" --status-fd 1 --verify "${files[@]}" | grep -qE '^\[GNUPG:\] TRUST_(FULLY|ULTIMATE).*$'
# return error if GnuPG fails to verify the signature
if [[ "${PIPESTATUS[0]}" -ne 0 ]]; then
error "$(gettext "The signature verification for %s failed.")" "$sig"
ret=1
fi
# return error if the signature is not trusted fully or ultimately
if [[ "${PIPESTATUS[1]}" -ne 0 ]]; then
error "$(gettext "The signature %s is not trusted.")" "$sig"
ret=1
fi
exit $ret
}
updatedb() {
msg "$(gettext "Updating trust database...")"
if ! "${GPG_PACWRAP[@]}" --batch --check-trustdb ; then
error_fatal "$(gettext "Trust database could not be updated.")"
fi
}
# PROGRAM START
if ! type gettext &>/dev/null; then
gettext() {
echo "$@"
}
fi
main $@

61
dist/tools/clean.sh vendored
View File

@ -5,57 +5,60 @@
# Copyright (C) 2023-2024 Xavier R.M.
# sapphirus(at)azorium(dot)net
#
# This program 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, with only version 3 of the License.
#
# This program 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, with only version 3 of the License.
# This program 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.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
if ! [[ -z $COLORTERM ]] || [[ $TERM == "dummy" ]]; then
BOLD=$(tput bold)
GREEN=$(tput setaf 2)
RED=$(tput setaf 1)
RESET=$(tput sgr0)
fi
if [[ ! -d "$PWD/dist/tools/" ]]; then echo "This script may only be executed via the workspace root directory."; exit 2; fi
if [[ ! -f ./dist/tools/common.sh ]]; then echo "Common script is missing. Ensure the source tree is intact."; exit 2; fi
DIST_RUNTIME="./dist/runtime"
DIST_BASE="./dist/pacwrap-base-dist"
DIST_SCHEMA="./dist/schema"
source ./dist/tools/common.sh
DIST_BIN="$PWD/dist/bin"
DIST_RUNTIME="$PWD/dist/runtime"
DIST_SCHEMA="$PWD/dist/schema"
runtime() {
if [[ -d "$DIST_RUNTIME" ]]; then
rm -r "$DIST_RUNTIME"
mkdir -p "$DIST_RUNTIME"
echo "$BOLD$GREEN Cleaned$RESET container runtime"
fi
cleaned "container runtime"
fi
}
filesystem() {
if [[ -d "$DIST_SCHEMA" ]]; then
rm -r "$DIST_SCHEMA"
mkdir -p "$DIST_SCHEMA"
echo "$BOLD$GREEN Cleaned$RESET container schema"
fi
cleaned "container schema"
fi
}
invalid() {
echo $BOLD$RED"error:$RESET Invalid parameter '$1'"
bin() {
if [[ -d "$DIST_BIN" ]]; then
rm -r "$DIST_BIN"
mkdir -p "$DIST_BIN"
cleaned "bin artifacts"
fi
}
main() {
for var in "$@"; do case $var in
schema) filesystem;;
runtime) runtime;;
all) filesystem
schema) filesystem;;
runtime) runtime;;
bin) bin;;
all) bin
filesystem
runtime;;
*) invalid $var;;
*) error_fatal "Invalid parameter '$1'";;
esac; done
}

56
dist/tools/common.sh vendored Executable file
View File

@ -0,0 +1,56 @@
#!/bin/bash
#
# pacwrap - common.sh
#
# Copyright (C) 2023-2024 Xavier R.M.
# sapphirus(at)azorium(dot)net
#
# This program 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, with only version 3 of the License.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
[[ ! -z $COMMON_SCRIPT ]] && return
if [[ -t 2 ]] && [[ ! -z $COLORTERM ]] && [[ $TERM != "dummy" ]]; then
BOLD=""
RED=""
GREEN=""
RESET=""
fi
error_fatal() {
echo $BOLD$RED"error:$RESET $@";
exit 1
}
error() {
echo $BOLD$RED"error:$RESET $@";
}
packaged() {
echo "$GREEN$BOLD Packaged$RESET $@"
}
cleaned() {
echo "$BOLD$GREEN Cleaned$RESET $@"
}
validate_args() {
[[ -z "$1" ]] && error_fatal "release target not specified."
case $1 in
release);;
debug) ;;
*) error_fatal "release target $1 is invalid.";;
esac
}
COMMON_SCRIPT=1; readonly COMMON_SCRIPT BOLD RED GREEN RESET

91
dist/tools/key.sh vendored Executable file
View File

@ -0,0 +1,91 @@
#!/bin/bash
#
# pacwrap - key.sh
#
# This script packages pacwrap-key and defines version information within the script
#
# Copyright (C) 2023-2024 Xavier R.M.
# sapphirus(at)azorium(dot)net#
#
# This program 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, with only version 3 of the License.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
if [[ ! -d "$PWD/dist/tools/" ]]; then echo "This script may only be executed via the workspace root directory."; exit 2; fi
if [[ ! -f ./dist/tools/common.sh ]]; then echo "Common script is missing. Ensure the source tree is intact."; exit 2; fi
source ./dist/tools/common.sh
#
# Environment variables
#
DIST_BIN="./dist/bin"
DIST_SRC="./dist/src/pacwrap-key"
DIST_PKG="./dist/bin/pacwrap-key"
#
# Main function
#
main() {
validate_args $1
prepare_and_validate
package $1
packaged "pacwrap-key [$1]"
}
#
# Validate and prepare staging environment
#
prepare_and_validate() {
[[ ! -f "$DIST_SRC" ]] && error_fatal "'$DIST_SRC': file not found"
clean
mkdir -p $DIST_BIN
}
#
# Clean build artifacts
#
clean() {
if [[ -f "$DIST_PKG" ]]; then
rm $DIST_PKG
cleaned "pacwrap-key"
fi
}
#
# Populate version string and package script
#
package() {
local version_string=$(version_string $1 | head -n1 | sed -e 's/[]\/$*.^[]/\\&/g')
local placeholder="version_string_placeholder"
sed -e "s/$placeholder/$version_string/g" < $DIST_SRC > $DIST_PKG
}
version_string() {
local git=$(git rev-parse --short HEAD)
local release=
local dev=
case $1 in
release) release="RELEASE"
date=$(git log -1 --date=format:%d/%m/%Y --format=%ad);;
debug) release="DEV"
date=$(date +'%d/%m/%Y %T');;
esac
eval $(cat pacwrap/Cargo.toml | grep version | head -n1 | sed -e "s/version = /local version=/g")
echo "$version-$git-$release ($date)"
}
main $@

30
dist/tools/package.sh vendored Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
#
# pacwrap - package.sh
#
# This script calls upon various binaries to build resources and package artifacts
#
# Copyright (C) 2023-2024 Xavier R.M.
# sapphirus(at)azorium(dot)net
#
# This program 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, with only version 3 of the License.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
if [[ ! -d "$PWD/dist/tools/" ]]; then echo "This script may only be executed via the workspace root directory."; exit 2; fi
if [[ ! -f ./dist/tools/common.sh ]]; then echo "Common script is missing. Ensure the source tree is intact."; exit 2; fi
source ./dist/tools/common.sh
validate_args $1
./target/$1/pacwrap --help=all --format=man > ./dist/bin/pacwrap.1; if [[ $? != 0 ]]; then error_fatal "Generation of manpage failed."; fi
./target/$1/pacwrap --help=pacwrap.yml --format=man > ./dist/bin/pacwrap.yml.2; if [[ $? != 0 ]]; then error_fatal "Generation of manpage failed"; fi
./dist/tools/runtime.sh $1; if [[ $? != 0 ]]; then error_fatal "Build of container runtime failed."; fi

29
dist/tools/prepare.sh vendored Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
#
# pacwrap - prepare.sh
#
# This script calls upon various binaries to build resources and package artifacts
#
# Copyright (C) 2023-2024 Xavier R.M.
# sapphirus(at)azorium(dot)net#
#
# This program 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, with only version 3 of the License.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
if [[ ! -d "$PWD/dist/tools/" ]]; then echo "This script may only be executed via the workspace root directory."; exit 2; fi
if [[ ! -f ./dist/tools/common.sh ]]; then echo "Common script is missing. Ensure the source tree is intact."; exit 2; fi
source ./dist/tools/common.sh
validate_args $1; if [[ $? != 0 ]]; then error_fatal "Argument validation failed."; fi
./dist/tools/key.sh $1; if [[ $? != 0 ]]; then error_fatal "Packaging of pacwrap-key failed."; fi
./dist/tools/schema.sh $1; if [[ $? != 0 ]]; then error_fatal "Build of container schema failed."; fi

131
dist/tools/runtime.sh vendored
View File

@ -8,25 +8,22 @@
# Copyright (C) 2023-2024 Xavier R.M.
# sapphirus(at)azorium(dot)net
#
# This program 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, with only version 3 of the License.
#
# This program 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, with only version 3 of the License.
# This program 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.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
if ! [[ -z $COLORTERM ]] || [[ $TERM == "dummy" ]]; then
BOLD=$(tput bold)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
RESET=$(tput sgr0)
fi
if [[ ! -d "$PWD/dist/tools/" ]]; then echo "This script may only be executed via the workspace root directory."; exit 2; fi
if [[ ! -f ./dist/tools/common.sh ]]; then echo "Common script is missing. Ensure the source tree is intact."; exit 2; fi
source ./dist/tools/common.sh
#
# Environment variables
@ -36,6 +33,7 @@ BIN_DIR="/bin"
ETC_DIR="/etc"
DEST_DIR="$PWD/dist/runtime"
DIST_SRC="$PWD/dist/src"
DIST_BIN="$PWD/dist/bin"
FAKEROOT="/libfakeroot"
FAKEROOT_DIR="/usr/lib/libfakeroot"
FAKEROOT_SRC="$FAKEROOT_DIR/libfakeroot.so"
@ -54,43 +52,50 @@ BIN_UTILS="bash busybox faked fakeroot find gpg grep getopt sed"
# Array of coreutils to include within the runtime environment
#
COREUTILS="cat chgrp chmod chown chroot cp cut dd df dir du head id install link ln ls mkdir mktemp mv pathchk pwd readlink realpath rm rmdir shred sort split stat sum tail tee touch tr truncate tsort unlink wc"
#
# Array of binaries to derive library paths
#
LIB_BINS="bash ls gpg grep"
#
# Copy libraries
# Main function
#
# $@: takes an array of system library paths
#
copy_libs() {
for path in ${@}; do
ldd $path | sed -e "s/.*=> //g;s/ (.*)//g;s/\t.*//g" | xargs cp -Lt $DEST_DIR$LIB_DIR
done
}
#
# Copy binaries
#
# $@: takes an array of system binaries located in /usr/bin
#
copy_bins() {
for bin in ${@}; do
cp /usr/bin/$bin $DEST_DIR$BIN_DIR/$bin
# Remove debuglink section, to ensure the Arch Build System doesn't complain
objcopy --remove-section=.gnu_debuglink $DEST_DIR$BIN_DIR/$bin 2>/dev/null
done
main() {
validate_args $1
prepare_and_validate $1
populate_lib
populate_bin
populate_etc
busybox_links
packaged "container runtime [$1]"
}
#
# Validate and prepare staging environment
#
prepare_and_validate() {
clean
local agent="./target/$1/pacwrap-agent"
if [[ ! -f "$agent" ]]; then
error_fatal "agent binary not built."
fi
BIN_PATHS=("$agent")
clean
mkdir -p $DEST_DIR$LIB_DIR$FAKEROOT$FAKECHROOT $DEST_DIR$BIN_DIR $DEST_DIR$ETC_DIR
if [[ ! -d "$DEST_DIR$LIB_DIR" ]] || [[ ! -d $DEST_DIR$BIN_DIR ]]; then
echo $BOLD$RED"error:$RESET '$DEST_DIR': directory not found.";
exit 1
if [[ ! -d "$DEST_DIR$LIB_DIR" ]] || [[ ! -d $DEST_DIR$BIN_DIR ]]; then
error_fatal "'$DEST_DIR': directory not found."
fi
for bin in $LIB_BINS; do
local path=$(type -P $bin)
[[ -z $path ]] && error_fatal "'$bin' dependency not fulfilled"
BIN_PATHS+=("$path")
done
}
#
@ -100,7 +105,7 @@ clean() {
if [[ -d "$DEST_DIR" ]]; then
rm -r "$DEST_DIR"
mkdir -p "$DEST_DIR"
echo "$BOLD$GREEN Cleaned$RESET container runtime"
cleaned "container runtime"
fi
}
@ -108,7 +113,7 @@ clean() {
# Populate libraries for container runtime
#
populate_lib() {
copy_libs ./target/$1/pacwrap-agent /usr/bin/gpg /usr/bin/bash /usr/bin/ls /usr/bin/grep
copy_libs ${BIN_PATHS[@]}
cp -L $FAKEROOT_SRC $FAKEROOT_DEST
cp -L $FAKECHROOT_SRC $FAKECHROOT_DEST
ln -s .$FAKEROOT/libfakeroot.so $DEST_DIR$LIB_DIR/libfakeroot.so
@ -124,7 +129,7 @@ populate_lib() {
# Populate binaries for container runtime
#
populate_bin() {
cp ./target/$1/pacwrap-agent $DEST_DIR$BIN_DIR/agent
cp ${BIN_PATHS[0]} $DEST_DIR$BIN_DIR/agent
copy_bins $BIN_UTILS $COREUTILS
ln -s bash $DEST_DIR$BIN_DIR/sh
ln -s ld-linux-x86-64.so.2 $DEST_DIR$BIN_DIR/ld-linux.so.2
@ -151,28 +156,28 @@ busybox_links() {
}
#
# Main function
# Copy libraries
#
main() {
if [[ -z $1 ]]; then
echo $BOLD$RED"error:$RESET target not specified.";
exit 1
fi
# $@: takes an array of system library paths
#
copy_libs() {
for path in ${@}; do
ldd $path | sed -e "s/.*=> //g;s/ (.*)//g;s/\t.*//g" | xargs cp -Lt $DEST_DIR$LIB_DIR
done
}
case $1 in
release);;
debug);;
*) echo $BOLD$RED"error:$RESET target $1 is invalid.";
exit 1;;
esac
#
# Copy binaries
#
# $@: takes an array of system binaries located in /usr/bin
#
copy_bins() {
for bin in ${@}; do
cp $(type -P $bin) $DEST_DIR$BIN_DIR/$bin
prepare_and_validate
populate_lib $1
populate_bin $1
populate_etc
busybox_links
echo "$GREEN$BOLD Packaged$RESET container runtime [$1]"
# Remove debuglink section, to ensure the Arch Build System doesn't complain
objcopy --remove-section=.gnu_debuglink $DEST_DIR$BIN_DIR/$bin 2>/dev/null
done
}
main $@

106
dist/tools/schema.sh vendored
View File

@ -8,53 +8,58 @@
# Copyright (C) 2023-2024 Xavier R.M.
# sapphirus(at)azorium(dot)net
#
# This program 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, with only version 3 of the License.
#
# This program 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, with only version 3 of the License.
# This program 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.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
if ! [[ -z $COLORTERM ]] || [[ $TERM == "dummy" ]]; then
BOLD=$(tput bold)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
RESET=$(tput sgr0)
fi
if [[ ! -d "$PWD/dist/tools/" ]]; then echo "This script may only be executed via the workspace root directory."; exit 2; fi
if [[ ! -f ./dist/tools/common.sh ]]; then echo "Common script is missing. Ensure the source tree is intact."; exit 2; fi
source ./dist/tools/common.sh
#
# Environment variables
#
USR_DIR="/usr"
ETC_DIR="/etc"
DEST_DIR="./dist/schema"
DIST_SRC="./dist/src"
DEST_DIR="$PWD/dist/schema"
DIST_SRC="$PWD/dist/src"
DIST_BIN="$PWD/dist/bin"
#
# Main function
#
main() {
prepare_and_validate
populate_usr
populate_etc
create_archive $1
packaged "container schema [$1]"
}
#
# Validate and prepare staging environment
#
prepare_and_validate() {
clean
mkdir -p $DEST_DIR$USR_DIR $DEST_DIR$ETC_DIR
mkdir -p $DEST_DIR$USR_DIR $DEST_DIR$ETC_DIR $DIST_BIN
if [[ ! -d "$DEST_DIR$LIB_DIR" ]] || [[ ! -d $DEST_DIR$BIN_DIR ]]; then
echo $BOLD$RED"error:$RESET '$DEST_DIR': directory not found.";
exit 1
error_fatal "'$DEST_DIR': directory not found."
fi
}
#
# Populate container skeleton archive
#
create_archive() {
cd $DEST_DIR
tar acf ../filesystem.tar.zst *
if [[ ! -d "$DIST_SRC" ]]; then
error_fatal "'$DIST_SRC': directory not found."
fi
}
#
@ -64,10 +69,18 @@ clean() {
if [[ -d "$DEST_DIR" ]]; then
rm -r "$DEST_DIR"
mkdir -p "$DEST_DIR"
echo "$BOLD$GREEN Cleaned$RESET container schema"
cleaned "container schema"
fi
}
#
# Populate container skeleton archive
#
create_archive() {
cd $DEST_DIR
tar acf ../bin/filesystem.tar.zst *
}
#
# Populate usr for container filesystem
#
@ -75,17 +88,18 @@ populate_usr() {
mkdir -p "${DEST_DIR}/usr/share/libalpm/hooks/" \
"${DEST_DIR}/usr/share/libalpm/scripts/" \
"${DEST_DIR}/usr/local/bin" \
"${DEST_DIR}/usr/lib/"
"${DEST_DIR}/usr/lib/"
ln -s /usr/lib/flatpak-xdg-utils/xdg-open "${DEST_DIR}/usr/local/bin/"
ln -s /usr/lib/flatpak-xdg-utils/xdg-email "${DEST_DIR}/usr/local/bin/"
install -Dm 644 "$DIST_SRC/0-pacwrap-dist.hook" "${DEST_DIR}/usr/share/libalpm/hooks/0-pacwrap-dist.hook"
install -Dm 644 "$DIST_SRC/42-trust-permission.hook" "${DEST_DIR}/usr/share/libalpm/hooks/42-trust-permission.hook"
# TODO: Perhaps identify ourselves as our own distribution of Arch Linux?
# install -Dm 644 "$DIST_SRC/os-release" "${DEST_DIR}/usr/lib/os-release"
install -Dm 755 "$DIST_SRC/pacwrap-dist" "${DEST_DIR}/usr/share/libalpm/scripts/pacwrap-dist"
install -Dm 644 "$DIST_SRC/0-pacwrap-dist.hook" "${DEST_DIR}/usr/share/libalpm/hooks/0-pacwrap-dist.hook"
install -Dm 644 "$DIST_SRC/42-trust-permission.hook" "${DEST_DIR}/usr/share/libalpm/hooks/42-trust-permission.hook"
# TODO: Perhaps identify ourselves as our own distribution of Arch Linux?
# install -Dm 644 "$DIST_SRC/os-release" "${DEST_DIR}/usr/lib/os-release"
install -Dm 755 "$DIST_SRC/pacwrap-dist" "${DEST_DIR}/usr/share/libalpm/scripts/pacwrap-dist"
install -Dm 755 "$DIST_BIN/pacwrap-key" "${DEST_DIR}/usr/bin/pacwrap-key"
}
#
@ -113,28 +127,4 @@ populate_etc() {
cp "$DIST_SRC/bash.bashrc" "$DEST_DIR$ETC_DIR"
}
#
# Main function
#
main() {
if [[ -z $1 ]]; then
echo $BOLD$RED"error:$RESET target not specified.";
exit 1
fi
case $1 in
release);;
debug);;
*) echo $BOLD$RED"error:$RESET target $1 is invalid.";
exit 1;;
esac
prepare_and_validate
populate_usr
populate_etc
create_archive $1
echo "$GREEN$BOLD Packaged$RESET container schema [$1]"
}
main $@

View File

@ -33,7 +33,7 @@ pub static PROCESS_SLEEP_DURATION: Duration = Duration::from_millis(250);
pub const BWRAP_EXECUTABLE: &str = "bwrap";
pub const DBUS_PROXY_EXECUTABLE: &str = "xdg-dbus-proxy";
pub const DEFAULT_PATH: &str = "/usr/local/bin:/bin:/usr/bin/";
pub const PACMAN_KEY_SCRIPT: &str = "pacman-key";
pub const PACMAN_KEY_SCRIPT: &str = "pacwrap-key";
pub const RUNTIME_DIRECTORY: &str = "/usr/share/pacwrap/runtime";
pub const RUNTIME_TLS_STORE: &str = "/etc/ca-certificates/extracted/tls-ca-bundle.pem";

View File

@ -181,7 +181,6 @@ pub fn fakeroot_container(exec_type: ExecutionType, trap: Option<fn(i32)>, ins:
} else {
process.arg("--hostname").arg("FakeChroot")
.arg("--ro-bind").arg("/etc/resolv.conf").arg("/mnt/fs/etc/resolv.conf")
.arg("--ro-bind").arg(&format!("{}/etc/bash.bashrc",*DIST_IMG)).arg("/mnt/fs/etc/bash.bashrc")
.arg("--bind").arg(ins.vars().pacman_gnupg()).arg("/mnt/fs/etc/pacman.d/gnupg")
.arg("--bind").arg(ins.vars().pacman_cache()).arg("/mnt/fs/var/cache/pacman/pkg")
.arg("--setenv").arg("EUID").arg("0")
@ -264,12 +263,9 @@ pub fn transaction_agent(ins: &ContainerHandle, params: TransactionParameters, m
}
}
pub fn pacman_key(path: &str, cmd: Vec<&str>) -> Result<()> {
pub fn pacwrap_key(cmd: Vec<&str>) -> Result<()> {
match Command::new(PACMAN_KEY_SCRIPT)
.stderr(Stdio::null())
.env("EUID", "0")
.arg("--gpgdir")
.arg(path)
.args(cmd)
.spawn()
{

View File

@ -33,7 +33,7 @@ use crate::{
err,
error,
error::*,
exec::pacman_key,
exec::pacwrap_key,
sync::event::download::{self, DownloadEvent},
ErrorKind,
};
@ -174,8 +174,6 @@ fn alpm_handle(insvars: &ContainerVariables, db_path: String, remotes: &AlpmConf
handle
}
//TODO: Port pacman-key to Rust
pub fn instantiate_trust() -> Result<()> {
let path = &format!("{}/pacman/gnupg/", *DATA_DIR);
@ -193,8 +191,8 @@ pub fn instantiate_trust() -> Result<()> {
err!(ErrorKind::IOError(path.into(), error.kind()))?
}
pacman_key(path, vec!["--init"])?;
pacman_key(path, vec!["--populate"])
pacwrap_key(vec!["--init"])?;
pacwrap_key(vec!["--populate"])
}
fn register_remote(mut handle: Alpm, config: &AlpmConfigData) -> Alpm {

View File

@ -196,8 +196,7 @@ impl<'a> TransactionAggregator<'a> {
}
pub fn keyring_update(&mut self, inshandle: &ContainerHandle) -> Result<()> {
fakeroot_container(NonInteractive, None, inshandle, vec!["/usr/bin/pacman-key", "--populate", "archlinux"])?;
fakeroot_container(NonInteractive, None, inshandle, vec!["/usr/bin/pacman-key", "--updatedb"])?;
fakeroot_container(NonInteractive, None, inshandle, vec!["/usr/bin/pacwrap-key", "--populate", "archlinux"])?;
self.keyring = true;
Ok(())
}

View File

@ -58,7 +58,7 @@ fn main() {
panic!("Unsupported build target. Please refer to the build documentation for further information.")
} else if built && (!Path::new("../dist/").exists() || !Path::new("../dist/tools/").exists()) {
panic!("Distribution directory is missing. Please refer to the build documentation for further information.")
} else if built && !Path::new("../dist/filesystem.tar.zst").exists() {
} else if built && !Path::new("../dist/bin/filesystem.tar.zst").exists() {
panic!("Container fileystem schema is missing. Please refer to the build documentation for further information.")
}
@ -72,6 +72,6 @@ fn main() {
println!("cargo:rustc-env=PACWRAP_BUILD={}", release(debug));
if built {
schema::serialize_path("../dist/filesystem.tar.zst", "../dist/filesystem.dat");
schema::serialize_path("../dist/bin/filesystem.tar.zst", "../dist/bin/filesystem.dat");
}
}