ecm.eclass: Set correct KFMIN default for kde-frameworks/*
[gentoo.git] / eclass / user.eclass
1 # Copyright 1999-2019 Gentoo Authors
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: user.eclass
5 # @MAINTAINER:
6 # base-system@gentoo.org (Linux)
7 # Michał Górny <mgorny@gentoo.org> (NetBSD)
8 # @BLURB: user management in ebuilds
9 # @DESCRIPTION:
10 # The user eclass contains a suite of functions that allow ebuilds
11 # to quickly make sure users in the installed system are sane.
12
13 if [[ -z ${_USER_ECLASS} ]]; then
14 _USER_ECLASS=1
15
16 # @FUNCTION: _assert_pkg_ebuild_phase
17 # @INTERNAL
18 # @USAGE: <calling func name>
19 _assert_pkg_ebuild_phase() {
20         case ${EBUILD_PHASE} in
21         setup|preinst|postinst|prerm|postrm) ;;
22         *)
23                 eerror "'$1()' called from '${EBUILD_PHASE}' phase which is not OK:"
24                 eerror "You may only call from pkg_{setup,{pre,post}{inst,rm}} functions."
25                 eerror "Package fails at QA and at life.  Please file a bug."
26                 die "Bad package!  $1 is only for use in some pkg_* functions!"
27         esac
28 }
29
30 # @FUNCTION: egetent
31 # @USAGE: <database> <key>
32 # @DESCRIPTION:
33 # Small wrapper for getent (Linux), nidump (< Mac OS X 10.5),
34 # dscl (Mac OS X 10.5), and pw (FreeBSD) used in enewuser()/enewgroup().
35 #
36 # Supported databases: group passwd
37 egetent() {
38         local db=$1 key=$2
39
40         [[ $# -ge 3 ]] && die "usage: egetent <database> <key>"
41
42         case ${db} in
43         passwd|group) ;;
44         *) die "sorry, database '${db}' not yet supported; file a bug" ;;
45         esac
46
47         case ${CHOST} in
48         *-freebsd*|*-dragonfly*)
49                 case ${db} in
50                 passwd) db="user" ;;
51                 *) ;;
52                 esac
53
54                 # lookup by uid/gid
55                 local opts
56                 if [[ ${key} == [[:digit:]]* ]] ; then
57                         [[ ${db} == "user" ]] && opts="-u" || opts="-g"
58                 fi
59
60                 pw show ${db} ${opts} "${key}" -q
61                 ;;
62         *-openbsd*)
63                 grep "${key}:\*:" /etc/${db}
64                 ;;
65         *)
66                 # ignore nscd output if we're not running as root
67                 type -p nscd >/dev/null && nscd -i "${db}" 2>/dev/null
68                 getent "${db}" "${key}"
69                 ;;
70         esac
71 }
72
73 # @FUNCTION: user_get_nologin
74 # @INTERNAL
75 # @DESCRIPTION:
76 # Find an appropriate 'nologin' shell for the platform, and output
77 # its path.
78 user_get_nologin() {
79         local eshell
80
81         for eshell in /sbin/nologin /usr/sbin/nologin /bin/false /usr/bin/false /dev/null ; do
82                 [[ -x ${ROOT}${eshell} ]] && break
83         done
84
85         if [[ ${eshell} == "/dev/null" ]] ; then
86                 ewarn "Unable to identify the shell to use, proceeding with userland default."
87                 case ${USERLAND} in
88                         GNU)    eshell="/bin/false" ;;
89                         BSD)    eshell="/sbin/nologin" ;;
90                         Darwin) eshell="/usr/sbin/nologin" ;;
91                         *) die "Unable to identify the default shell for userland ${USERLAND}"
92                 esac
93         fi
94
95         echo "${eshell}"
96 }
97
98 # @FUNCTION: enewuser
99 # @USAGE: <user> [-F] [-M] [uid] [shell] [homedir] [groups]
100 # @DESCRIPTION:
101 # Same as enewgroup, you are not required to understand how to properly add
102 # a user to the system.  The only required parameter is the username.
103 # Default uid is (pass -1 for this) next available, default shell is
104 # /bin/false, default homedir is /dev/null, and there are no default groups.
105 #
106 # If -F is passed, enewuser will always enforce specified UID and fail if it
107 # can not be assigned.
108 # If -M is passed, enewuser does not create the home directory if it does not
109 # exist.
110 enewuser() {
111         if [[ ${EUID} != 0 ]] ; then
112                 einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
113                 return 0
114         fi
115         _assert_pkg_ebuild_phase ${FUNCNAME}
116
117         local create_home=1 force_uid=
118         while [[ $1 == -* ]]; do
119                 case $1 in
120                         -F) force_uid=1;;
121                         -M) create_home=;;
122                         *) die "${FUNCNAME}: invalid option ${1}";;
123                 esac
124                 shift
125         done
126
127         # get the username
128         local euser=$1; shift
129         if [[ -z ${euser} ]] ; then
130                 eerror "No username specified !"
131                 die "Cannot call enewuser without a username"
132         fi
133
134         # lets see if the username already exists
135         if [[ -n $(egetent passwd "${euser}") ]] ; then
136                 return 0
137         fi
138         einfo "Adding user '${euser}' to your system ..."
139
140         # options to pass to useradd
141         local opts=()
142
143         # handle uid
144         local euid=$1; shift
145         if [[ -n ${euid} && ${euid} != -1 ]] ; then
146                 if [[ ${euid} -gt 0 ]] ; then
147                         if [[ -n $(egetent passwd ${euid}) ]] ; then
148                                 [[ -n ${force_uid} ]] && die "${FUNCNAME}: UID ${euid} already taken"
149                                 euid="next"
150                         fi
151                 else
152                         eerror "Userid given but is not greater than 0 !"
153                         die "${euid} is not a valid UID"
154                 fi
155         else
156                 [[ -n ${force_uid} ]] && die "${FUNCNAME}: -F with uid==-1 makes no sense"
157                 euid="next"
158         fi
159         if [[ ${euid} == "next" ]] ; then
160                 for ((euid = 999; euid >= 101; euid--)); do
161                         [[ -z $(egetent passwd ${euid}) ]] && break
162                 done
163                 [[ ${euid} -ge 101 ]] || die "${FUNCNAME}: no free UID found"
164         fi
165         opts+=( -u ${euid} )
166         einfo " - Userid: ${euid}"
167
168         # handle shell
169         local eshell=$1; shift
170         if [[ ! -z ${eshell} ]] && [[ ${eshell} != "-1" ]] ; then
171                 if [[ ! -e ${ROOT}${eshell} ]] ; then
172                         eerror "A shell was specified but it does not exist !"
173                         die "${eshell} does not exist in ${ROOT}"
174                 fi
175                 if [[ ${eshell} == */false || ${eshell} == */nologin ]] ; then
176                         eerror "Do not specify ${eshell} yourself, use -1"
177                         die "Pass '-1' as the shell parameter"
178                 fi
179         else
180                 eshell=$(user_get_nologin)
181         fi
182         einfo " - Shell: ${eshell}"
183         opts+=( -s "${eshell}" )
184
185         # handle homedir
186         local ehome=$1; shift
187         if [[ -z ${ehome} ]] || [[ ${ehome} == "-1" ]] ; then
188                 ehome="/dev/null"
189         fi
190         einfo " - Home: ${ehome}"
191         opts+=( -d "${ehome}" )
192
193         # handle groups
194         local egroups=$1; shift
195         local g egroups_arr
196         IFS="," read -r -a egroups_arr <<<"${egroups}"
197         if [[ ${#egroups_arr[@]} -gt 0 ]] ; then
198                 local defgroup exgroups
199                 for g in "${egroups_arr[@]}" ; do
200                         if [[ -z $(egetent group "${g}") ]] ; then
201                                 eerror "You must add group ${g} to the system first"
202                                 die "${g} is not a valid GID"
203                         fi
204                         if [[ -z ${defgroup} ]] ; then
205                                 defgroup=${g}
206                         else
207                                 exgroups+=",${g}"
208                         fi
209                 done
210                 opts+=( -g "${defgroup}" )
211                 if [[ ! -z ${exgroups} ]] ; then
212                         opts+=( -G "${exgroups:1}" )
213                 fi
214         fi
215         einfo " - Groups: ${egroups:-(none)}"
216
217         # handle extra args
218         if [[ $# -gt 0 ]] ; then
219                 die "extra arguments no longer supported; please file a bug"
220         else
221                 local comment="added by portage for ${PN}"
222                 opts+=( -c "${comment}" )
223                 einfo " - GECOS: ${comment}"
224         fi
225
226         # add the user
227         case ${CHOST} in
228         *-freebsd*|*-dragonfly*)
229                 pw useradd "${euser}" "${opts[@]}" || die
230                 ;;
231
232         *-netbsd*)
233                 useradd "${opts[@]}" "${euser}" || die
234                 ;;
235
236         *-openbsd*)
237                 # all ops the same, except the -g vs -g/-G ...
238                 useradd -u ${euid} -s "${eshell}" \
239                         -d "${ehome}" -g "${egroups}" "${euser}" || die
240                 ;;
241
242         *)
243                 useradd -M -N -r "${opts[@]}" "${euser}" || die
244                 ;;
245         esac
246
247         if [[ -n ${create_home} && ! -e ${ROOT}/${ehome} ]] ; then
248                 einfo " - Creating ${ehome} in ${ROOT}"
249                 mkdir -p "${ROOT}/${ehome}"
250                 chown "${euser}" "${ROOT}/${ehome}"
251                 chmod 755 "${ROOT}/${ehome}"
252         fi
253 }
254
255 # @FUNCTION: enewgroup
256 # @USAGE: <group> [gid]
257 # @DESCRIPTION:
258 # This function does not require you to understand how to properly add a
259 # group to the system.  Just give it a group name to add and enewgroup will
260 # do the rest.  You may specify the gid for the group or allow the group to
261 # allocate the next available one.
262 #
263 # If -F is passed, enewgroup will always enforce specified GID and fail if it
264 # can not be assigned.
265 enewgroup() {
266         if [[ ${EUID} != 0 ]] ; then
267                 einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
268                 return 0
269         fi
270         _assert_pkg_ebuild_phase ${FUNCNAME}
271
272         local force_gid=
273         while [[ $1 == -* ]]; do
274                 case $1 in
275                         -F) force_gid=1;;
276                         *) die "${FUNCNAME}: invalid option ${1}";;
277                 esac
278                 shift
279         done
280
281         # get the group
282         local egroup=$1; shift
283         if [[ -z ${egroup} ]] ; then
284                 eerror "No group specified !"
285                 die "Cannot call enewgroup without a group"
286         fi
287
288         # see if group already exists
289         if [[ -n $(egetent group "${egroup}") ]] ; then
290                 return 0
291         fi
292         einfo "Adding group '${egroup}' to your system ..."
293
294         # handle gid
295         local egid=$1; shift
296         if [[ ! -z ${egid} ]] ; then
297                 if [[ ${egid} -gt 0 ]] ; then
298                         if [[ -n $(egetent group ${egid}) ]] ; then
299                                 [[ -n ${force_gid} ]] && die "${FUNCNAME}: GID ${egid} already taken"
300                                 egid="next available; requested gid taken"
301                         fi
302                 else
303                         eerror "Groupid given but is not greater than 0 !"
304                         die "${egid} is not a valid GID"
305                 fi
306         else
307                 [[ -n ${force_gid} ]] && die "${FUNCNAME}: -F with gid==-1 makes no sense"
308                 egid="next available"
309         fi
310         einfo " - Groupid: ${egid}"
311
312         # handle extra
313         if [[ $# -gt 0 ]] ; then
314                 die "extra arguments no longer supported; please file a bug"
315         fi
316
317         # Some targets need to find the next available GID manually
318         _enewgroup_next_gid() {
319                 if [[ ${egid} == *[!0-9]* ]] ; then
320                         # Non numeric
321                         for ((egid = 999; egid >= 101; egid--)) ; do
322                                 [[ -z $(egetent group ${egid}) ]] && break
323                         done
324                         [[ ${egid} -ge 101 ]] || die "${FUNCNAME}: no free GID found"
325                 fi
326         }
327
328         # add the group
329         case ${CHOST} in
330         *-freebsd*|*-dragonfly*)
331                 _enewgroup_next_gid
332                 pw groupadd "${egroup}" -g ${egid} || die
333                 ;;
334
335         *-netbsd*)
336                 _enewgroup_next_gid
337                 groupadd -g ${egid} "${egroup}" || die
338                 ;;
339
340         *)
341                 local opts
342                 if [[ ${egid} == *[!0-9]* ]] ; then
343                         # Non numeric; let groupadd figure out a GID for us
344                         opts=""
345                 else
346                         opts="-g ${egid}"
347                 fi
348                 # We specify -r so that we get a GID in the system range from login.defs
349                 groupadd -r ${opts} "${egroup}" || die
350                 ;;
351         esac
352 }
353
354 # @FUNCTION: egetusername
355 # @USAGE: <uid>
356 # @DESCRIPTION:
357 # Gets the username for given UID.
358 egetusername() {
359         [[ $# -eq 1 ]] || die "usage: egetusername <uid>"
360
361         egetent passwd "$1" | cut -d: -f1
362 }
363
364 # @FUNCTION: egetgroupname
365 # @USAGE: <gid>
366 # @DESCRIPTION:
367 # Gets the group name for given GID.
368 egetgroupname() {
369         [[ $# -eq 1 ]] || die "usage: egetgroupname <gid>"
370
371         egetent group "$1" | cut -d: -f1
372 }
373
374 # @FUNCTION: egethome
375 # @USAGE: <user>
376 # @DESCRIPTION:
377 # Gets the home directory for the specified user.
378 egethome() {
379         local pos
380
381         [[ $# -eq 1 ]] || die "usage: egethome <user>"
382
383         case ${CHOST} in
384         *-freebsd*|*-dragonfly*)
385                 pos=9
386                 ;;
387         *)      # Linux, NetBSD, OpenBSD, etc...
388                 pos=6
389                 ;;
390         esac
391
392         egetent passwd "$1" | cut -d: -f${pos}
393 }
394
395 # @FUNCTION: egetshell
396 # @USAGE: <user>
397 # @DESCRIPTION:
398 # Gets the shell for the specified user.
399 egetshell() {
400         local pos
401
402         [[ $# -eq 1 ]] || die "usage: egetshell <user>"
403
404         case ${CHOST} in
405         *-freebsd*|*-dragonfly*)
406                 pos=10
407                 ;;
408         *)      # Linux, NetBSD, OpenBSD, etc...
409                 pos=7
410                 ;;
411         esac
412
413         egetent passwd "$1" | cut -d: -f${pos}
414 }
415
416 # @FUNCTION: egetcomment
417 # @USAGE: <user>
418 # @DESCRIPTION:
419 # Gets the comment field for the specified user.
420 egetcomment() {
421         local pos
422
423         [[ $# -eq 1 ]] || die "usage: egetshell <user>"
424
425         case ${CHOST} in
426         *-freebsd*|*-dragonfly*)
427                 pos=8
428                 ;;
429         *)      # Linux, NetBSD, OpenBSD, etc...
430                 pos=5
431                 ;;
432         esac
433
434         egetent passwd "$1" | cut -d: -f${pos}
435 }
436
437 # @FUNCTION: egetgroups
438 # @USAGE: <user>
439 # @DESCRIPTION:
440 # Gets all the groups user belongs to.  The primary group is returned
441 # first, then all supplementary groups.  Groups are ','-separated.
442 egetgroups() {
443         [[ $# -eq 1 ]] || die "usage: egetgroups <user>"
444
445         local egroups_arr
446         read -r -a egroups_arr < <(id -G -n "$1")
447
448         local g groups=${egroups_arr[0]}
449         # sort supplementary groups to make comparison possible
450         while read -r g; do
451                 [[ -n ${g} ]] && groups+=",${g}"
452         done < <(printf '%s\n' "${egroups_arr[@]:1}" | sort)
453         echo "${groups}"
454 }
455
456 # @FUNCTION: esethome
457 # @USAGE: <user> <homedir>
458 # @DESCRIPTION:
459 # Update the home directory in a platform-agnostic way.
460 # Required parameters is the username and the new home directory.
461 # Specify -1 if you want to set home to the enewuser default
462 # of /dev/null.
463 # If the new home directory does not exist, it is created.
464 # Any previously existing home directory is NOT moved.
465 esethome() {
466         _assert_pkg_ebuild_phase ${FUNCNAME}
467
468         # get the username
469         local euser=$1; shift
470         if [[ -z ${euser} ]] ; then
471                 eerror "No username specified !"
472                 die "Cannot call esethome without a username"
473         fi
474
475         # lets see if the username already exists
476         if [[ -z $(egetent passwd "${euser}") ]] ; then
477                 ewarn "User does not exist, cannot set home dir -- skipping."
478                 return 1
479         fi
480
481         # handle homedir
482         local ehome=$1; shift
483         if [[ -z ${ehome} ]] ; then
484                 eerror "No home directory specified !"
485                 die "Cannot call esethome without a home directory or '-1'"
486         fi
487
488         if [[ ${ehome} == "-1" ]] ; then
489                 ehome="/dev/null"
490         fi
491
492         # exit with no message if home dir is up to date
493         if [[ $(egethome "${euser}") == ${ehome} ]]; then
494                 return 0
495         fi
496
497         einfo "Updating home for user '${euser}' ..."
498         einfo " - Home: ${ehome}"
499
500         # ensure home directory exists, otherwise update will fail
501         if [[ ! -e ${ROOT}/${ehome} ]] ; then
502                 einfo " - Creating ${ehome} in ${ROOT}"
503                 mkdir -p "${ROOT}/${ehome}"
504                 chown "${euser}" "${ROOT}/${ehome}"
505                 chmod 755 "${ROOT}/${ehome}"
506         fi
507
508         # update the home directory
509         case ${CHOST} in
510         *-freebsd*|*-dragonfly*)
511                 pw usermod "${euser}" -d "${ehome}" && return 0
512                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update home"
513                 eerror "There was an error when attempting to update the home directory for ${euser}"
514                 eerror "Please update it manually on your system:"
515                 eerror "\t pw usermod \"${euser}\" -d \"${ehome}\""
516                 ;;
517
518         *)
519                 usermod -d "${ehome}" "${euser}" && return 0
520                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update home"
521                 eerror "There was an error when attempting to update the home directory for ${euser}"
522                 eerror "Please update it manually on your system (as root):"
523                 eerror "\t usermod -d \"${ehome}\" \"${euser}\""
524                 ;;
525         esac
526 }
527
528 # @FUNCTION: esetshell
529 # @USAGE: <user> <shell>
530 # @DESCRIPTION:
531 # Update the shell in a platform-agnostic way.
532 # Required parameters is the username and the new shell.
533 # Specify -1 if you want to set shell to platform-specific nologin.
534 esetshell() {
535         _assert_pkg_ebuild_phase ${FUNCNAME}
536
537         # get the username
538         local euser=$1; shift
539         if [[ -z ${euser} ]] ; then
540                 eerror "No username specified !"
541                 die "Cannot call esetshell without a username"
542         fi
543
544         # lets see if the username already exists
545         if [[ -z $(egetent passwd "${euser}") ]] ; then
546                 ewarn "User does not exist, cannot set shell -- skipping."
547                 return 1
548         fi
549
550         # handle shell
551         local eshell=$1; shift
552         if [[ -z ${eshell} ]] ; then
553                 eerror "No shell specified !"
554                 die "Cannot call esetshell without a shell or '-1'"
555         fi
556
557         if [[ ${eshell} == "-1" ]] ; then
558                 eshell=$(user_get_nologin)
559         fi
560
561         # exit with no message if shell is up to date
562         if [[ $(egetshell "${euser}") == ${eshell} ]]; then
563                 return 0
564         fi
565
566         einfo "Updating shell for user '${euser}' ..."
567         einfo " - Shell: ${eshell}"
568
569         # update the shell
570         case ${CHOST} in
571         *-freebsd*|*-dragonfly*)
572                 pw usermod "${euser}" -s "${eshell}" && return 0
573                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update shell"
574                 eerror "There was an error when attempting to update the shell for ${euser}"
575                 eerror "Please update it manually on your system:"
576                 eerror "\t pw usermod \"${euser}\" -s \"${eshell}\""
577                 ;;
578
579         *)
580                 usermod -s "${eshell}" "${euser}" && return 0
581                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update shell"
582                 eerror "There was an error when attempting to update the shell for ${euser}"
583                 eerror "Please update it manually on your system (as root):"
584                 eerror "\t usermod -s \"${eshell}\" \"${euser}\""
585                 ;;
586         esac
587 }
588
589 # @FUNCTION: esetcomment
590 # @USAGE: <user> <comment>
591 # @DESCRIPTION:
592 # Update the comment field in a platform-agnostic way.
593 # Required parameters is the username and the new comment.
594 esetcomment() {
595         _assert_pkg_ebuild_phase ${FUNCNAME}
596
597         # get the username
598         local euser=$1; shift
599         if [[ -z ${euser} ]] ; then
600                 eerror "No username specified !"
601                 die "Cannot call esetcomment without a username"
602         fi
603
604         # lets see if the username already exists
605         if [[ -z $(egetent passwd "${euser}") ]] ; then
606                 ewarn "User does not exist, cannot set comment -- skipping."
607                 return 1
608         fi
609
610         # handle comment
611         local ecomment=$1; shift
612         if [[ -z ${ecomment} ]] ; then
613                 eerror "No comment specified !"
614                 die "Cannot call esetcomment without a comment"
615         fi
616
617         # exit with no message if comment is up to date
618         if [[ $(egetcomment "${euser}") == ${ecomment} ]]; then
619                 return 0
620         fi
621
622         einfo "Updating comment for user '${euser}' ..."
623         einfo " - Comment: ${ecomment}"
624
625         # update the comment
626         case ${CHOST} in
627         *-freebsd*|*-dragonfly*)
628                 pw usermod "${euser}" -c "${ecomment}" && return 0
629                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update comment"
630                 eerror "There was an error when attempting to update the comment for ${euser}"
631                 eerror "Please update it manually on your system:"
632                 eerror "\t pw usermod \"${euser}\" -c \"${ecomment}\""
633                 ;;
634
635         *)
636                 usermod -c "${ecomment}" "${euser}" && return 0
637                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update comment"
638                 eerror "There was an error when attempting to update the comment for ${euser}"
639                 eerror "Please update it manually on your system (as root):"
640                 eerror "\t usermod -c \"${ecomment}\" \"${euser}\""
641                 ;;
642         esac
643 }
644
645 # @FUNCTION: esetgroups
646 # @USAGE: <user> <groups>
647 # @DESCRIPTION:
648 # Update the group field in a platform-agnostic way.
649 # Required parameters is the username and the new list of groups,
650 # primary group first.
651 esetgroups() {
652         _assert_pkg_ebuild_phase ${FUNCNAME}
653
654         [[ ${#} -eq 2 ]] || die "Usage: ${FUNCNAME} <user> <groups>"
655
656         # get the username
657         local euser=$1; shift
658
659         # lets see if the username already exists
660         if [[ -z $(egetent passwd "${euser}") ]] ; then
661                 ewarn "User does not exist, cannot set group -- skipping."
662                 return 1
663         fi
664
665         # handle group
666         local egroups=$1; shift
667
668         local g egroups_arr=()
669         IFS="," read -r -a egroups_arr <<<"${egroups}"
670         [[ ${#egroups_arr[@]} -gt 0 ]] || die "${FUNCNAME}: no groups specified"
671
672         for g in "${egroups_arr[@]}" ; do
673                 if [[ -z $(egetent group "${g}") ]] ; then
674                         eerror "You must add group ${g} to the system first"
675                         die "${g} is not a valid GID"
676                 fi
677         done
678
679         local defgroup=${egroups_arr[0]} exgroups_arr=()
680         # sort supplementary groups to make comparison possible
681         readarray -t exgroups_arr < <(printf '%s\n' "${egroups_arr[@]:1}" | sort)
682         local exgroups=${exgroups_arr[*]}
683         exgroups=${exgroups// /,}
684         egroups=${defgroup}${exgroups:+,${exgroups}}
685
686         # exit with no message if group membership is up to date
687         if [[ $(egetgroups "${euser}") == ${egroups} ]]; then
688                 return 0
689         fi
690
691         local opts=( -g "${defgroup}" -G "${exgroups}" )
692         einfo "Updating groups for user '${euser}' ..."
693         einfo " - Groups: ${egroups}"
694
695         # update the group
696         case ${CHOST} in
697         *-freebsd*|*-dragonfly*)
698                 pw usermod "${euser}" "${opts[@]}" && return 0
699                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update groups"
700                 eerror "There was an error when attempting to update the groups for ${euser}"
701                 eerror "Please update it manually on your system:"
702                 eerror "\t pw usermod \"${euser}\" ${opts[*]}"
703                 ;;
704
705         *)
706                 usermod "${opts[@]}" "${euser}" && return 0
707                 [[ $? == 8 ]] && eerror "${euser} is in use, cannot update groups"
708                 eerror "There was an error when attempting to update the groups for ${euser}"
709                 eerror "Please update it manually on your system (as root):"
710                 eerror "\t usermod ${opts[*]} \"${euser}\""
711                 ;;
712         esac
713 }
714
715 fi