sys-process/glances: 3.1.4.1-r1 amd64 stable, bug #720368
[gentoo.git] / eclass / user.eclass
index 54d7a3fdbe28bc3de68ebfe35ab2cbd974423a38..b70698356a3ab85bd9839c441cf42da47c00a1c0 100644 (file)
@@ -1,4 +1,4 @@
-# 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:
@@ -109,7 +68,7 @@ user_get_nologin() {
 # 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}
@@ -135,7 +94,7 @@ enewuser() {
        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=()
@@ -157,13 +116,13 @@ enewuser() {
                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
@@ -179,7 +138,7 @@ enewuser() {
        else
                eshell=$(user_get_nologin)
        fi
-       einfo " - Shell: ${eshell}"
+       elog " - Shell: ${eshell}"
        opts+=( -s "${eshell}" )
 
        # handle homedir
@@ -187,7 +146,7 @@ enewuser() {
        if [[ -z ${ehome} ]] || [[ ${ehome} == "-1" ]] ; then
                ehome="/dev/null"
        fi
-       einfo " - Home: ${ehome}"
+       elog " - Home: ${ehome}"
        opts+=( -d "${ehome}" )
 
        # handle groups
@@ -212,7 +171,7 @@ enewuser() {
                        opts+=( -G "${exgroups:1}" )
                fi
        fi
-       einfo " - Groups: ${egroups:-(none)}"
+       elog " - Groups: ${egroups:-(none)}"
 
        # handle extra args
        if [[ $# -gt 0 ]] ; then
@@ -220,7 +179,7 @@ enewuser() {
        else
                local comment="added by portage for ${PN}"
                opts+=( -c "${comment}" )
-               einfo " - GECOS: ${comment}"
+               elog " - GECOS: ${comment}"
        fi
 
        # add the user
@@ -245,7 +204,7 @@ enewuser() {
        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}"
@@ -264,7 +223,7 @@ enewuser() {
 # 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}
@@ -289,11 +248,11 @@ enewgroup() {
        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"
@@ -307,7 +266,7 @@ enewgroup() {
                [[ -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
@@ -318,10 +277,10 @@ enewgroup() {
        _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
        }
 
@@ -351,48 +310,6 @@ enewgroup() {
        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:
@@ -434,12 +351,12 @@ esethome() {
                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}"
@@ -465,4 +382,191 @@ esethome() {
        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