3c11e11daa
Change the output of the "directories" and "files" tasks to be less verbose by halving the number of lines in the most common cases.
402 lines
12 KiB
Text
402 lines
12 KiB
Text
# Copyright (c) 2017 The NetBSD Foundation, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This code is derived from software contributed to The NetBSD Foundation
|
|
# by Johnny C. Lam.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# NAME
|
|
# directories.subr -- directory management for packages
|
|
#
|
|
# SYNOPSIS
|
|
# task_directories [-s] add | remove | perms
|
|
# task_directories check-add | check-remove | check-perms
|
|
#
|
|
# DESCRIPTION
|
|
# The task_directories function supports six actions: "add", "remove",
|
|
# "perms", "check-add", "check-remove", and "check-perms".
|
|
#
|
|
# The available options are as follows:
|
|
#
|
|
# -s Silent; don't write to standard output.
|
|
#
|
|
# The task_directories function reads standard input line by line and
|
|
# looks for lines of the form:
|
|
#
|
|
# # DIR: <directory> <flags> [<mode> [<user> [<group>]]]
|
|
#
|
|
# If directory path is relative, then it is assumed to be relative to
|
|
# ${PKG_PREFIX}.
|
|
#
|
|
# The third field in each line is set of flags with the following
|
|
# meaning:
|
|
#
|
|
# f ignore ${PKG_CONFIG} value
|
|
# m directory is created
|
|
# o directory is owned by the package
|
|
# . placeholder flag to ensure the field is non-empty
|
|
#
|
|
# The "add" action creates the directory and sets the permissions on
|
|
# the directory if given. A reference count for the directory will
|
|
# be added for the package.
|
|
#
|
|
# The "remove" action removes the directory. A reference count for
|
|
# the directory will be removed for the package.
|
|
#
|
|
# The "perms" action sets the mode and permissions on the directory
|
|
# if they are given.
|
|
#
|
|
# The "check-add" action will check whether the directory exists or
|
|
# otherwise writes a message to standard output noting the missing
|
|
# directory.
|
|
#
|
|
# The "check-remove" action will check whether the directory has
|
|
# been removed or otherwise writes a message to standard output
|
|
# noting the directory still exist.
|
|
#
|
|
# The "check-perms" action will check whether the directory has the
|
|
# correct permissions or otherwise writes a message to standard
|
|
# output noting the directory has incorrect permissions.
|
|
#
|
|
# RETURN VALUES
|
|
# The "add", "remove", and "perms" actions return 0 if they are
|
|
# successful for all directories, and >0 if an error occurs.
|
|
#
|
|
# The "check-add", "check-remove", and "check-perms" actions return
|
|
# >0 if they write informative messages, and return 0 otherwise.
|
|
#
|
|
# ENVIRONMENT
|
|
# The following variables are used if they are set:
|
|
#
|
|
# PKGNAME
|
|
# The name of the package.
|
|
#
|
|
# PKG_CONFIG
|
|
# If ${PKG_CONFIG} is a "truthy" value, then the "add" and
|
|
# "remove" actions are allowed to make changes to the
|
|
# filesystem as needed.
|
|
#
|
|
# PKG_CONFIG_PERMS
|
|
# If ${PKG_CONFIG_PERMS} is a "truthy" value, then the
|
|
# "perms" action is allowed to make changes to the
|
|
# filesystem as needed.
|
|
#
|
|
# PKG_DESTDIR
|
|
# A "destdir" prefix that is prepended to all filesystem
|
|
# paths. The default value is the empty string.
|
|
#
|
|
# PKG_PREFIX
|
|
# The installation prefix of the package. The default is
|
|
# "/usr/pkg".
|
|
#
|
|
# RMDIR The name or path to the rmdir(1) utility.
|
|
#
|
|
# TASK_MSG
|
|
# String prepended to all normal message written to
|
|
# standard output.
|
|
#
|
|
|
|
__task_directories__="yes"
|
|
|
|
task_load echo
|
|
task_load makedir
|
|
task_load permissions
|
|
task_load refcount
|
|
task_load truthy
|
|
task_load valid_options
|
|
|
|
task_directories()
|
|
{
|
|
: ${RMDIR:=rmdir}
|
|
|
|
: ${PKG_PREFIX:=/usr/pkg}
|
|
: ${PKGNAME:=${0##*/}}
|
|
|
|
: ${PKG_CONFIG:=yes}
|
|
: ${PKG_CONFIG_PERMS:=yes}
|
|
: ${TASK_MSG:=""}
|
|
|
|
local arg
|
|
local echo="task_echo"
|
|
local OPTIND=1
|
|
while getopts ":s" arg "$@"; do
|
|
case $arg in
|
|
s) echo=":" ;;
|
|
*) return 127 ;;
|
|
esac
|
|
done
|
|
shift $(( ${OPTIND} - 1 ))
|
|
[ $# -gt 0 ] || return 127
|
|
|
|
local action="$1"; shift
|
|
case $action in
|
|
add|remove|perms|check-add|check-remove|check-perms)
|
|
: "valid actions" ;;
|
|
*) return 0 ;;
|
|
esac
|
|
|
|
# Guard against ${PKG_PREFIX} == "/".
|
|
local prefix
|
|
case ${PKG_PREFIX}/ in
|
|
//) prefix= ;;
|
|
*) prefix=${PKG_PREFIX} ;;
|
|
esac
|
|
|
|
local pkg_config="yes"
|
|
local pkg_config_perms="yes"
|
|
task_is_truthy "${PKG_CONFIG}" || pkg_config=
|
|
task_is_truthy "${PKG_CONFIG_PERMS}" || pkg_config_perms=
|
|
|
|
local result line_result
|
|
local msg
|
|
local owned makedir removedir changes
|
|
local refcount
|
|
|
|
result=0
|
|
local d_path
|
|
local hash tag path flags mode user group
|
|
while read hash tag path flags mode user group; do
|
|
# Filter for "# DIR:".
|
|
case $hash/$tag in
|
|
"#/DIR:")
|
|
: "use this line" ;;
|
|
*) continue ;;
|
|
esac
|
|
task_valid_options "$flags" "fmo." || continue
|
|
|
|
# Canonicalize paths.
|
|
case $path in
|
|
"") # skip lines without any required args
|
|
continue ;;
|
|
[!/]*) path="$prefix/$path" ;;
|
|
esac
|
|
d_path="${PKG_DESTDIR}$path"
|
|
|
|
msg=
|
|
case $mode/$user/$group in
|
|
//) msg="$d_path" ;;
|
|
[!/]*//)
|
|
msg="$d_path (m=$mode)" ;;
|
|
[!/]*/[!/]*/)
|
|
msg="$d_path (m=$mode, o=$user)" ;;
|
|
[!/]*/[!/]*/[!/]*)
|
|
msg="$d_path (m=$mode, o=$user, g=$group)" ;;
|
|
esac
|
|
|
|
# Set owner values if the directory should be owned by this package.
|
|
owned=
|
|
dir_msg="directory"
|
|
case $flags in
|
|
*o*) owned="yes"
|
|
dir_msg="owned directory"
|
|
if task_refcount prop_exists dirs "$path" owner; then
|
|
# previous owner detected
|
|
if task_refcount prop_match dirs "$path" owner; then
|
|
: "same owner"
|
|
else
|
|
# conflicting owners; failure event
|
|
$echo "${TASK_MSG}! directory owner conflict: $d_path"
|
|
result=1
|
|
continue
|
|
fi
|
|
fi ;;
|
|
esac
|
|
|
|
makedir=
|
|
case $flags in
|
|
*m*) makedir="seen"
|
|
case $flags in
|
|
*f*) # "f" always implies makedir.
|
|
makedir="yes" ;;
|
|
*) # otherwise, makedir only if PKG_CONFIG is truthy.
|
|
[ -z "$pkg_config" ] || makedir="yes" ;;
|
|
esac ;;
|
|
esac
|
|
|
|
removedir=
|
|
case $flags in
|
|
*) removedir="seen"
|
|
case $flags in
|
|
*f*) # "f" always implies removedir.
|
|
removedir="yes" ;;
|
|
*) # otherwise, removedir only if PKG_CONFIG is truthy.
|
|
[ -z "$pkg_config" ] || removedir="yes" ;;
|
|
esac ;;
|
|
esac
|
|
|
|
line_result=0
|
|
changes=
|
|
case $action in
|
|
add) refcount="yes"
|
|
task_refcount exists dirs "$path" || refcount=
|
|
if task_refcount add dirs "$path"; then
|
|
if [ -n "$owned" ]; then
|
|
# Directory is owned by this package.
|
|
if task_refcount prop_put dirs "$path" owner; then
|
|
: "directory owner property added"
|
|
else
|
|
line_result=1
|
|
fi
|
|
fi
|
|
if [ $line_result -gt 0 ]; then
|
|
: "skip directory creation"
|
|
elif [ -d "$d_path" ]; then
|
|
# Directory already exists.
|
|
if [ -z "$refcount" ]; then
|
|
task_refcount prop_put dirs "$path" preexist || line_result=1
|
|
fi
|
|
# Only warn if directory exists if it should be owned.
|
|
if [ -n "$owned" ]; then
|
|
$echo "${TASK_MSG}! $dir_msg already exists: $d_path"
|
|
fi
|
|
elif [ -z "$makedir" ]; then
|
|
: "directory is never created"
|
|
elif [ "$makedir" = "seen" ]; then
|
|
$echo "${TASK_MSG}! $dir_msg creation skipped: $d_path"
|
|
elif task_makedir "$d_path"; then
|
|
# Defer writing output until permissions are set.
|
|
#$echo "${TASK_MSG}> $dir_msg created: $d_path"
|
|
changes="$changes create"
|
|
else
|
|
$echo "${TASK_MSG}! $dir_msg not created: $d_path"
|
|
line_result=1
|
|
fi
|
|
else
|
|
# add refcount failed; skip to next line
|
|
$echo "${TASK_MSG}! refcount add failure: directories $path"
|
|
result=1
|
|
continue
|
|
fi ;;
|
|
check-add)
|
|
if [ -d "$d_path" ]; then
|
|
: "directory already exists"
|
|
elif [ -n "$makedir" ]; then
|
|
task_echo "!!! INFO: ${PKGNAME}: Create directory: $msg"
|
|
line_result=1
|
|
fi ;;
|
|
esac
|
|
if [ $line_result -eq 0 ]; then
|
|
case $mode/$user/$group in
|
|
//) case " $changes " in
|
|
*" create "*)
|
|
$echo "${TASK_MSG}> $dir_msg created: $d_path" ;;
|
|
*) : "no permissions to set" ;;
|
|
esac ;;
|
|
*) case $action in
|
|
add|perms)
|
|
task_refcount prop_put dirs "$path" permissions "$mode" "$user" "$group" || line_result=1
|
|
if [ ! -d "$d_path" ]; then
|
|
$echo "${TASK_MSG}! $dir_msg permissions not set on missing: $msg"
|
|
if [ "$makedir" = "yes" ]; then
|
|
# The directory should have been created; otherwise,
|
|
# it's an error.
|
|
#
|
|
line_result=1
|
|
fi
|
|
elif [ "$action" = "perms" -a -z "$pkg_config_perms" ]; then
|
|
# "perms" action, but PKG_CONFIG_PERMS is not trutyy.
|
|
$echo "${TASK_MSG}! $dir_msg permissions skipped: $msg"
|
|
elif task_set_permissions "$d_path" "$mode" "$user" "$group"; then
|
|
case " $changes " in
|
|
*" create "*)
|
|
$echo "${TASK_MSG}> $dir_msg created: $msg" ;;
|
|
*) $echo "${TASK_MSG}> $dir_msg permissions set: $msg" ;;
|
|
esac
|
|
else
|
|
case " $changes " in
|
|
*" create "*)
|
|
$echo "${TASK_MSG}> $dir_msg created: $d_path" ;;
|
|
*) : "no directory was created" ;;
|
|
esac
|
|
$echo "${TASK_MSG}! $dir_msg permissions not set: $msg"
|
|
line_result=1
|
|
fi ;;
|
|
check-add|check-perms)
|
|
if [ -d "$d_path" ] &&
|
|
task_check_permissions "$d_path" "$mode" "$user" "$group"; then
|
|
: "directory has correct permissions"
|
|
else
|
|
task_echo "!!! INFO: ${PKGNAME}: Set directory permissions: $msg"
|
|
line_result=1
|
|
fi
|
|
esac ;;
|
|
esac
|
|
fi
|
|
if [ $line_result -eq 0 ]; then
|
|
case $action in
|
|
remove) if task_refcount remove dirs "$path"; then
|
|
if task_refcount exists dirs "$path"; then
|
|
# refcount is not zero
|
|
if [ -n "$owned" ]; then
|
|
# owned directory has existing references; failure event.
|
|
$echo "${TASK_MSG}! directory owned but references exist: $path"
|
|
line_result=1
|
|
fi
|
|
else
|
|
# no more references
|
|
if task_refcount prop_exists dirs "$path" preexist; then
|
|
: "directory is preexisting"
|
|
elif [ ! -d "$d_path" ]; then
|
|
: "directory already removed"
|
|
elif [ "$removedir" = "yes" ]; then
|
|
${RMDIR} -p "$d_path" 2>/dev/null
|
|
fi
|
|
# Only warn if the directory is owned by the package.
|
|
if [ -n "$owned" ]; then
|
|
if [ -d "$d_path" ]; then
|
|
$echo "${TASK_MSG}! $dir_msg not removed: $d_path"
|
|
else
|
|
$echo "${TASK_MSG}> $dir_msg removed: $d_path"
|
|
fi
|
|
fi
|
|
# delete the reference count
|
|
task_refcount delete dirs "$path"
|
|
fi
|
|
else
|
|
# remove refcount failed
|
|
$echo "${TASK_MSG}! refcount remove failure: directories $path"
|
|
line_result=1
|
|
fi ;;
|
|
check-remove)
|
|
if task_refcount exists dirs "$path"; then
|
|
: "refcount is not zero"
|
|
elif [ ! -d "$d_path" ]; then
|
|
: "directory already removed"
|
|
elif [ -n "$removedir" -a -n "$owned" ]; then
|
|
# Only warn if the directory is owned by the package.
|
|
task_echo "!!! INFO: ${PKGNAME}: Remove $dir_msg: $d_path"
|
|
line_result=1
|
|
fi
|
|
esac
|
|
fi
|
|
if [ $line_result -gt 0 ]; then
|
|
# Undo changes if there was an error.
|
|
case " $changes " in
|
|
*" create "*)
|
|
${RMDIR} -p "$d_path" 2>/dev/null ;;
|
|
esac
|
|
fi
|
|
[ $line_result -eq 0 ] || result=1
|
|
done
|
|
return $result
|
|
}
|