forked from Lainports/freebsd-ports
Repeat after me: If you change IFS, it will break something unexpected.
The problem is that we use IFS to change read's field separator. This
has the side effect of changing how sh(1) splits all string, including
in command parsing functions.
In this case, unless quoted, the strings are always splitted using IFS.
So changing IFS will change how these strings are splitted, and you end
up having a headache. For example:
$ GID_FILES="foo bar"
$ set -x
$ echo $GID_FILES
+ echo foo bar
foo bar
$ IFS=:
$ GID_FILES="foo bar"
$ set -x
$ echo $GID_FILES
+ echo 'foo bar'
foo bar
In the first case, it runs echo with two arguments, first is foo, second is bar.
In the second case, it runs echo with one argument, 'foo bar'.
To fix this, restrict the time during which IFS changes to only one
command, set, and use positional parameters to extract values.
Reported by: feld
Sponsored by: Absolight
Differential Revision: https://reviews.freebsd.org/D11632
213 lines
5.4 KiB
Bash
213 lines
5.4 KiB
Bash
#!/bin/sh
|
|
# $FreeBSD$
|
|
#
|
|
# MAINTAINER: portmgr@FreeBSD.org
|
|
|
|
set -e
|
|
|
|
. "${dp_SCRIPTSDIR}/functions.sh"
|
|
|
|
validate_env dp_ECHO_MSG dp_GID_FILES dp_GID_OFFSET dp_GROUPS_BLACKLIST \
|
|
dp_INSTALL dp_OPSYS dp_OSVERSION dp_PREFIX dp_PW dp_SCRIPTSDIR \
|
|
dp_UG_DEINSTALL dp_UG_INSTALL dp_UID_FILES dp_UID_OFFSET \
|
|
dp_USERS_BLACKLIST
|
|
|
|
[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_DO_USERS_GROUPS}" ] && set -x
|
|
|
|
set -u
|
|
|
|
USERS=$1
|
|
GROUPS=$2
|
|
|
|
error() {
|
|
${dp_ECHO_MSG} "${1}"
|
|
|
|
exit 1
|
|
}
|
|
|
|
# Lines from GID and UID files both contain *. As we do not need any pathname
|
|
# expansion, disable globbing.
|
|
set -f
|
|
|
|
rm -f "${dp_UG_INSTALL}" "${dp_UG_DEINSTALL}" || :
|
|
|
|
# Before FreeBSD 10.2, PW did not have -R support.
|
|
if [ "${dp_OPSYS}" = FreeBSD ] ; then
|
|
cat >> "${dp_UG_INSTALL}" <<-eot
|
|
if [ -n "\${PKG_ROOTDIR}" ] && [ "\${PKG_ROOTDIR}" != "/" ]; then
|
|
PW="${dp_PW} -R \${PKG_ROOTDIR}"
|
|
else
|
|
PW=${dp_PW}
|
|
fi
|
|
eot
|
|
else
|
|
echo "PW=${dp_PW}" >> "${dp_UG_INSTALL}"
|
|
fi
|
|
|
|
# Both scripts need to start the same, so
|
|
cp -f "${dp_UG_INSTALL}" "${dp_UG_DEINSTALL}"
|
|
|
|
if [ -n "${GROUPS}" ]; then
|
|
for file in ${dp_GID_FILES}; do
|
|
if [ ! -f "${file}" ]; then
|
|
error "** ${file} doesn't exist. Exiting."
|
|
fi
|
|
done
|
|
${dp_ECHO_MSG} "===> Creating groups."
|
|
echo "echo \"===> Creating groups.\"" >> "${dp_UG_INSTALL}"
|
|
for group in ${GROUPS}; do
|
|
# _bgpd:*:130:
|
|
if ! grep -q "^${group}:" ${dp_GID_FILES}; then \
|
|
error "** Cannot find any information about group \`${group}' in ${dp_GID_FILES}."
|
|
fi
|
|
while read -r line; do
|
|
# Do not change IFS for more than one command, if we
|
|
# changed IFS around the while read, it would mess up
|
|
# the string splitting in the heredoc command.
|
|
o_IFS=${IFS}
|
|
IFS=":"
|
|
set -- ${line}
|
|
IFS=${o_IFS}
|
|
group=$1
|
|
gid=$3
|
|
if [ -z "${gid}" ]; then
|
|
error "Group line for group ${group} has no gid"
|
|
fi
|
|
gid=$((gid+dp_GID_OFFSET))
|
|
cat >> "${dp_UG_INSTALL}" <<-eot2
|
|
if ! \${PW} groupshow $group >/dev/null 2>&1; then
|
|
echo "Creating group '$group' with gid '$gid'."
|
|
\${PW} groupadd $group -g $gid
|
|
else
|
|
echo "Using existing group '$group'."
|
|
fi
|
|
eot2
|
|
done <<-eot
|
|
$(grep -h "^${group}:" ${dp_GID_FILES} | head -n 1)
|
|
eot
|
|
done
|
|
fi
|
|
|
|
if [ -n "${USERS}" ]; then
|
|
for file in ${dp_UID_FILES}; do
|
|
if [ ! -f "${file}" ]; then
|
|
error "** ${file} doesn't exist. Exiting."
|
|
fi
|
|
done
|
|
|
|
${dp_ECHO_MSG} "===> Creating users"
|
|
echo "echo \"===> Creating users\"" >> "${dp_UG_INSTALL}"
|
|
|
|
for user in ${USERS}; do
|
|
# _bgpd:*:130:130:BGP Daemon:/var/empty:/sbin/nologin
|
|
if ! grep -q "^${user}:" ${dp_UID_FILES} ; then
|
|
error "** Cannot find any information about user \`${user}' in ${dp_UID_FILES}."
|
|
fi
|
|
while read -r line; do
|
|
# Do not change IFS for more than one command, if we
|
|
# changed IFS around the while read, it would mess up
|
|
# the string splitting in the heredoc command.
|
|
o_IFS=${IFS}
|
|
IFS=":"
|
|
set -- ${line}
|
|
IFS=${o_IFS}
|
|
login=$1
|
|
uid=$3
|
|
gid=$4
|
|
class=$5
|
|
gecos=$8
|
|
homedir=$9
|
|
shell=${10}
|
|
if [ -z "$uid" ] || [ -z "$gid" ] || [ -z "$homedir" ] || [ -z "$shell" ]; then
|
|
error "User line for ${user} is invalid"
|
|
fi
|
|
uid=$((uid+dp_UID_OFFSET))
|
|
gid=$((gid+dp_GID_OFFSET))
|
|
if [ -n "$class" ]; then
|
|
class="-L $class"
|
|
fi
|
|
homedir=$(echo "$homedir" | sed "s|^/usr/local|${dp_PREFIX}|")
|
|
cat >> "${dp_UG_INSTALL}" <<-eot2
|
|
if ! \${PW} usershow $login >/dev/null 2>&1; then
|
|
echo "Creating user '$login' with uid '$uid'."
|
|
\${PW} useradd $login -u $uid -g $gid $class -c "$gecos" -d $homedir -s $shell
|
|
else
|
|
echo "Using existing user '$login'."
|
|
fi
|
|
eot2
|
|
case $homedir in
|
|
/|/nonexistent|/var/empty)
|
|
;;
|
|
*)
|
|
group=$(awk -F: -v gid=${gid} '$3 == gid { print $1 }' ${dp_GID_FILES})
|
|
echo "${dp_INSTALL} -d -g $group -o $login $homedir" >> "${dp_UG_INSTALL}"
|
|
;;
|
|
esac
|
|
done <<-eot
|
|
$(grep -h "^${user}:" ${dp_UID_FILES} | head -n 1)
|
|
eot
|
|
done
|
|
fi
|
|
|
|
if [ -n "${GROUPS}" ]; then
|
|
for group in ${GROUPS}; do
|
|
# mail:*:6:postfix,clamav
|
|
while read -r line; do
|
|
# Do not change IFS for more than one command, if we
|
|
# changed IFS around the while read, it would mess up
|
|
# the string splitting in the heredoc command.
|
|
o_IFS=${IFS}
|
|
IFS=":"
|
|
# As some lines do not have a fourth argument, provide
|
|
# one so $4 always exists.
|
|
set -- ${line} ""
|
|
IFS=${o_IFS}
|
|
group=$1
|
|
gid=$3
|
|
members=$4
|
|
gid=$((gid+dp_GID_OFFSET))
|
|
o_IFS=${IFS}
|
|
IFS=","
|
|
set -- ${members}
|
|
IFS=${o_IFS}
|
|
for login in "$@"; do
|
|
for user in ${USERS}; do
|
|
if [ -n "${user}" ] && [ "${user}" = "${login}" ]; then
|
|
cat >> "${dp_UG_INSTALL}" <<-eot2
|
|
if ! \${PW} groupshow ${group} | grep -qw ${login}; then
|
|
echo "Adding user '${login}' to group '${group}'."
|
|
\${PW} groupmod ${group} -m ${login}
|
|
fi
|
|
eot2
|
|
fi
|
|
done
|
|
done
|
|
done <<-eot
|
|
$(grep -h "^${group}:" ${dp_GID_FILES} | head -n 1)
|
|
eot
|
|
done
|
|
fi
|
|
|
|
if [ -n "${USERS}" ]; then
|
|
for user in ${USERS}; do
|
|
if ! echo "${dp_USERS_BLACKLIST}" | grep -qw "${user}"; then
|
|
cat >> "${dp_UG_DEINSTALL}" <<-eot
|
|
if \${PW} usershow ${user} >/dev/null 2>&1; then
|
|
echo "==> You should manually remove the \"${user}\" user. "
|
|
fi
|
|
eot
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [ -n "${GROUPS}" ]; then
|
|
for group in ${GROUPS}; do
|
|
if ! echo "${dp_GROUPS_BLACKLIST}" | grep -qw "${group}"; then
|
|
cat >> "${dp_UG_DEINSTALL}" <<-eot
|
|
if \${PW} groupshow ${group} >/dev/null 2>&1; then
|
|
echo "==> You should manually remove the \"${group}\" group "
|
|
fi
|
|
eot
|
|
fi
|
|
done
|
|
fi
|