-# Copyright 1999-2019 Gentoo Authors
+# Copyright 1999-2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: user.eclass
if [[ -z ${_USER_ECLASS} ]]; then
_USER_ECLASS=1
+inherit user-info
+
# @FUNCTION: _assert_pkg_ebuild_phase
# @INTERNAL
# @USAGE: <calling func name>
_assert_pkg_ebuild_phase() {
case ${EBUILD_PHASE} in
- setup|preinst|postinst) ;;
+ setup|preinst|postinst|prerm|postrm) ;;
*)
eerror "'$1()' called from '${EBUILD_PHASE}' phase which is not OK:"
- eerror "You may only call from pkg_{setup,preinst,postinst} functions."
+ eerror "You may only call from pkg_{setup,{pre,post}{inst,rm}} functions."
eerror "Package fails at QA and at life. Please file a bug."
die "Bad package! $1 is only for use in some pkg_* functions!"
esac
}
-# @FUNCTION: egetent
-# @USAGE: <database> <key>
-# @DESCRIPTION:
-# Small wrapper for getent (Linux), nidump (< Mac OS X 10.5),
-# dscl (Mac OS X 10.5), and pw (FreeBSD) used in enewuser()/enewgroup().
-#
-# Supported databases: group passwd
-egetent() {
- local db=$1 key=$2
-
- [[ $# -ge 3 ]] && die "usage: egetent <database> <key>"
-
- case ${db} in
- passwd|group) ;;
- *) die "sorry, database '${db}' not yet supported; file a bug" ;;
- esac
-
- case ${CHOST} in
- *-freebsd*|*-dragonfly*)
- case ${db} in
- passwd) db="user" ;;
- *) ;;
- esac
-
- # lookup by uid/gid
- local opts
- if [[ ${key} == [[:digit:]]* ]] ; then
- [[ ${db} == "user" ]] && opts="-u" || opts="-g"
- fi
-
- pw show ${db} ${opts} "${key}" -q
- ;;
- *-openbsd*)
- grep "${key}:\*:" /etc/${db}
- ;;
- *)
- # ignore nscd output if we're not running as root
- type -p nscd >/dev/null && nscd -i "${db}" 2>/dev/null
- getent "${db}" "${key}"
- ;;
- esac
-}
-
# @FUNCTION: user_get_nologin
# @INTERNAL
# @DESCRIPTION:
# exist.
enewuser() {
if [[ ${EUID} != 0 ]] ; then
- einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ ewarn "Insufficient privileges to execute ${FUNCNAME[0]}"
return 0
fi
_assert_pkg_ebuild_phase ${FUNCNAME}
if [[ -n $(egetent passwd "${euser}") ]] ; then
return 0
fi
- einfo "Adding user '${euser}' to your system ..."
+ elog "Adding user '${euser}' to your system ..."
# options to pass to useradd
local opts=()
euid="next"
fi
if [[ ${euid} == "next" ]] ; then
- for ((euid = 101; euid <= 999; euid++)); do
+ for ((euid = 999; euid >= 101; euid--)); do
[[ -z $(egetent passwd ${euid}) ]] && break
done
- [[ ${euid} -le 999 ]] || die "${FUNCNAME}: no free UID found"
+ [[ ${euid} -ge 101 ]] || die "${FUNCNAME}: no free UID found"
fi
opts+=( -u ${euid} )
- einfo " - Userid: ${euid}"
+ elog " - Userid: ${euid}"
# handle shell
local eshell=$1; shift
else
eshell=$(user_get_nologin)
fi
- einfo " - Shell: ${eshell}"
+ elog " - Shell: ${eshell}"
opts+=( -s "${eshell}" )
# handle homedir
if [[ -z ${ehome} ]] || [[ ${ehome} == "-1" ]] ; then
ehome="/dev/null"
fi
- einfo " - Home: ${ehome}"
+ elog " - Home: ${ehome}"
opts+=( -d "${ehome}" )
# handle groups
opts+=( -G "${exgroups:1}" )
fi
fi
- einfo " - Groups: ${egroups:-(none)}"
+ elog " - Groups: ${egroups:-(none)}"
# handle extra args
if [[ $# -gt 0 ]] ; then
else
local comment="added by portage for ${PN}"
opts+=( -c "${comment}" )
- einfo " - GECOS: ${comment}"
+ elog " - GECOS: ${comment}"
fi
# add the user
esac
if [[ -n ${create_home} && ! -e ${ROOT}/${ehome} ]] ; then
- einfo " - Creating ${ehome} in ${ROOT}"
+ elog " - Creating ${ehome} in ${ROOT}"
mkdir -p "${ROOT}/${ehome}"
chown "${euser}" "${ROOT}/${ehome}"
chmod 755 "${ROOT}/${ehome}"
# can not be assigned.
enewgroup() {
if [[ ${EUID} != 0 ]] ; then
- einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ ewarn "Insufficient privileges to execute ${FUNCNAME[0]}"
return 0
fi
_assert_pkg_ebuild_phase ${FUNCNAME}
if [[ -n $(egetent group "${egroup}") ]] ; then
return 0
fi
- einfo "Adding group '${egroup}' to your system ..."
+ elog "Adding group '${egroup}' to your system ..."
# handle gid
local egid=$1; shift
- if [[ ! -z ${egid} ]] ; then
+ if [[ -n ${egid} && ${egid} != -1 ]] ; then
if [[ ${egid} -gt 0 ]] ; then
if [[ -n $(egetent group ${egid}) ]] ; then
[[ -n ${force_gid} ]] && die "${FUNCNAME}: GID ${egid} already taken"
[[ -n ${force_gid} ]] && die "${FUNCNAME}: -F with gid==-1 makes no sense"
egid="next available"
fi
- einfo " - Groupid: ${egid}"
+ elog " - Groupid: ${egid}"
# handle extra
if [[ $# -gt 0 ]] ; then
_enewgroup_next_gid() {
if [[ ${egid} == *[!0-9]* ]] ; then
# Non numeric
- for ((egid = 101; egid <= 999; egid++)) ; do
+ for ((egid = 999; egid >= 101; egid--)) ; do
[[ -z $(egetent group ${egid}) ]] && break
done
- [[ ${egid} -le 999 ]] || die "${FUNCNAME}: no free GID found"
+ [[ ${egid} -ge 101 ]] || die "${FUNCNAME}: no free GID found"
fi
}
esac
}
-# @FUNCTION: egethome
-# @USAGE: <user>
-# @DESCRIPTION:
-# Gets the home directory for the specified user.
-egethome() {
- local pos
-
- [[ $# -eq 1 ]] || die "usage: egethome <user>"
-
- case ${CHOST} in
- *-freebsd*|*-dragonfly*)
- pos=9
- ;;
- *) # Linux, NetBSD, OpenBSD, etc...
- pos=6
- ;;
- esac
-
- egetent passwd "$1" | cut -d: -f${pos}
-}
-
-# @FUNCTION: egetshell
-# @USAGE: <user>
-# @DESCRIPTION:
-# Gets the shell for the specified user.
-egetshell() {
- local pos
-
- [[ $# -eq 1 ]] || die "usage: egetshell <user>"
-
- case ${CHOST} in
- *-freebsd*|*-dragonfly*)
- pos=10
- ;;
- *) # Linux, NetBSD, OpenBSD, etc...
- pos=7
- ;;
- esac
-
- egetent passwd "$1" | cut -d: -f${pos}
-}
-
# @FUNCTION: esethome
# @USAGE: <user> <homedir>
# @DESCRIPTION:
return 0
fi
- einfo "Updating home for user '${euser}' ..."
- einfo " - Home: ${ehome}"
+ elog "Updating home for user '${euser}' ..."
+ elog " - Home: ${ehome}"
# ensure home directory exists, otherwise update will fail
if [[ ! -e ${ROOT}/${ehome} ]] ; then
- einfo " - Creating ${ehome} in ${ROOT}"
+ elog " - Creating ${ehome} in ${ROOT}"
mkdir -p "${ROOT}/${ehome}"
chown "${euser}" "${ROOT}/${ehome}"
chmod 755 "${ROOT}/${ehome}"
esac
}
+# @FUNCTION: esetshell
+# @USAGE: <user> <shell>
+# @DESCRIPTION:
+# Update the shell in a platform-agnostic way.
+# Required parameters is the username and the new shell.
+# Specify -1 if you want to set shell to platform-specific nologin.
+esetshell() {
+ _assert_pkg_ebuild_phase ${FUNCNAME}
+
+ # get the username
+ local euser=$1; shift
+ if [[ -z ${euser} ]] ; then
+ eerror "No username specified !"
+ die "Cannot call esetshell without a username"
+ fi
+
+ # lets see if the username already exists
+ if [[ -z $(egetent passwd "${euser}") ]] ; then
+ ewarn "User does not exist, cannot set shell -- skipping."
+ return 1
+ fi
+
+ # handle shell
+ local eshell=$1; shift
+ if [[ -z ${eshell} ]] ; then
+ eerror "No shell specified !"
+ die "Cannot call esetshell without a shell or '-1'"
+ fi
+
+ if [[ ${eshell} == "-1" ]] ; then
+ eshell=$(user_get_nologin)
+ fi
+
+ # exit with no message if shell is up to date
+ if [[ $(egetshell "${euser}") == ${eshell} ]]; then
+ return 0
+ fi
+
+ elog "Updating shell for user '${euser}' ..."
+ elog " - Shell: ${eshell}"
+
+ # update the shell
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw usermod "${euser}" -s "${eshell}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update shell"
+ eerror "There was an error when attempting to update the shell for ${euser}"
+ eerror "Please update it manually on your system:"
+ eerror "\t pw usermod \"${euser}\" -s \"${eshell}\""
+ ;;
+
+ *)
+ usermod -s "${eshell}" "${euser}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update shell"
+ eerror "There was an error when attempting to update the shell for ${euser}"
+ eerror "Please update it manually on your system (as root):"
+ eerror "\t usermod -s \"${eshell}\" \"${euser}\""
+ ;;
+ esac
+}
+
+# @FUNCTION: esetcomment
+# @USAGE: <user> <comment>
+# @DESCRIPTION:
+# Update the comment field in a platform-agnostic way.
+# Required parameters is the username and the new comment.
+esetcomment() {
+ _assert_pkg_ebuild_phase ${FUNCNAME}
+
+ # get the username
+ local euser=$1; shift
+ if [[ -z ${euser} ]] ; then
+ eerror "No username specified !"
+ die "Cannot call esetcomment without a username"
+ fi
+
+ # lets see if the username already exists
+ if [[ -z $(egetent passwd "${euser}") ]] ; then
+ ewarn "User does not exist, cannot set comment -- skipping."
+ return 1
+ fi
+
+ # handle comment
+ local ecomment=$1; shift
+ if [[ -z ${ecomment} ]] ; then
+ eerror "No comment specified !"
+ die "Cannot call esetcomment without a comment"
+ fi
+
+ # exit with no message if comment is up to date
+ if [[ $(egetcomment "${euser}") == ${ecomment} ]]; then
+ return 0
+ fi
+
+ elog "Updating comment for user '${euser}' ..."
+ elog " - Comment: ${ecomment}"
+
+ # update the comment
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw usermod "${euser}" -c "${ecomment}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update comment"
+ eerror "There was an error when attempting to update the comment for ${euser}"
+ eerror "Please update it manually on your system:"
+ eerror "\t pw usermod \"${euser}\" -c \"${ecomment}\""
+ ;;
+
+ *)
+ usermod -c "${ecomment}" "${euser}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update comment"
+ eerror "There was an error when attempting to update the comment for ${euser}"
+ eerror "Please update it manually on your system (as root):"
+ eerror "\t usermod -c \"${ecomment}\" \"${euser}\""
+ ;;
+ esac
+}
+
+# @FUNCTION: esetgroups
+# @USAGE: <user> <groups>
+# @DESCRIPTION:
+# Update the group field in a platform-agnostic way.
+# Required parameters is the username and the new list of groups,
+# primary group first.
+esetgroups() {
+ _assert_pkg_ebuild_phase ${FUNCNAME}
+
+ [[ ${#} -eq 2 ]] || die "Usage: ${FUNCNAME} <user> <groups>"
+
+ # get the username
+ local euser=$1; shift
+
+ # lets see if the username already exists
+ if [[ -z $(egetent passwd "${euser}") ]] ; then
+ ewarn "User does not exist, cannot set group -- skipping."
+ return 1
+ fi
+
+ # handle group
+ local egroups=$1; shift
+
+ local g egroups_arr=()
+ IFS="," read -r -a egroups_arr <<<"${egroups}"
+ [[ ${#egroups_arr[@]} -gt 0 ]] || die "${FUNCNAME}: no groups specified"
+
+ for g in "${egroups_arr[@]}" ; do
+ if [[ -z $(egetent group "${g}") ]] ; then
+ eerror "You must add group ${g} to the system first"
+ die "${g} is not a valid GID"
+ fi
+ done
+
+ local defgroup=${egroups_arr[0]} exgroups_arr=()
+ # sort supplementary groups to make comparison possible
+ readarray -t exgroups_arr < <(printf '%s\n' "${egroups_arr[@]:1}" | sort)
+ local exgroups=${exgroups_arr[*]}
+ exgroups=${exgroups// /,}
+ egroups=${defgroup}${exgroups:+,${exgroups}}
+
+ # exit with no message if group membership is up to date
+ if [[ $(egetgroups "${euser}") == ${egroups} ]]; then
+ return 0
+ fi
+
+ local opts=( -g "${defgroup}" -G "${exgroups}" )
+ elog "Updating groups for user '${euser}' ..."
+ elog " - Groups: ${egroups}"
+
+ # update the group
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw usermod "${euser}" "${opts[@]}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update groups"
+ eerror "There was an error when attempting to update the groups for ${euser}"
+ eerror "Please update it manually on your system:"
+ eerror "\t pw usermod \"${euser}\" ${opts[*]}"
+ ;;
+
+ *)
+ usermod "${opts[@]}" "${euser}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update groups"
+ eerror "There was an error when attempting to update the groups for ${euser}"
+ eerror "Please update it manually on your system (as root):"
+ eerror "\t usermod ${opts[*]} \"${euser}\""
+ ;;
+ esac
+}
+
fi