xref: /OK3568_Linux_fs/buildroot/support/scripts/mkusers (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/usr/bin/env bash
2*4882a593Smuzhiyunset -e
3*4882a593Smuzhiyunmyname="${0##*/}"
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun#----------------------------------------------------------------------------
6*4882a593Smuzhiyun# Configurable items
7*4882a593SmuzhiyunMIN_UID=1000
8*4882a593SmuzhiyunMAX_UID=1999
9*4882a593SmuzhiyunMIN_GID=1000
10*4882a593SmuzhiyunMAX_GID=1999
11*4882a593Smuzhiyun# No more is configurable below this point
12*4882a593Smuzhiyun#----------------------------------------------------------------------------
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun#----------------------------------------------------------------------------
15*4882a593Smuzhiyunerror() {
16*4882a593Smuzhiyun    local fmt="${1}"
17*4882a593Smuzhiyun    shift
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun    printf "%s: " "${myname}" >&2
20*4882a593Smuzhiyun    printf "${fmt}" "${@}" >&2
21*4882a593Smuzhiyun}
22*4882a593Smuzhiyunfail() {
23*4882a593Smuzhiyun    error "$@"
24*4882a593Smuzhiyun    exit 1
25*4882a593Smuzhiyun}
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun#----------------------------------------------------------------------------
28*4882a593Smuzhiyunif [ ${#} -ne 2 ]; then
29*4882a593Smuzhiyun    fail "usage: %s USERS_TABLE TARGET_DIR\n"
30*4882a593Smuzhiyunfi
31*4882a593SmuzhiyunUSERS_TABLE="${1}"
32*4882a593SmuzhiyunTARGET_DIR="${2}"
33*4882a593Smuzhiyunshift 2
34*4882a593SmuzhiyunPASSWD="${TARGET_DIR}/etc/passwd"
35*4882a593SmuzhiyunSHADOW="${TARGET_DIR}/etc/shadow"
36*4882a593SmuzhiyunGROUP="${TARGET_DIR}/etc/group"
37*4882a593Smuzhiyun# /etc/gshadow is not part of the standard skeleton, so not everybody
38*4882a593Smuzhiyun# will have it, but some may have it, and its content must be in sync
39*4882a593Smuzhiyun# with /etc/group, so any use of gshadow must be conditional.
40*4882a593SmuzhiyunGSHADOW="${TARGET_DIR}/etc/gshadow"
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun# We can't simply source ${BR2_CONFIG} as it may contains constructs
43*4882a593Smuzhiyun# such as:
44*4882a593Smuzhiyun#    BR2_DEFCONFIG="$(CONFIG_DIR)/defconfig"
45*4882a593Smuzhiyun# which when sourced from a shell script will eventually try to execute
46*4882a593Smuzhiyun# a command named 'CONFIG_DIR', which is plain wrong for virtually every
47*4882a593Smuzhiyun# systems out there.
48*4882a593Smuzhiyun# So, we have to scan that file instead. Sigh... :-(
49*4882a593SmuzhiyunPASSWD_METHOD="$( sed -r -e '/^BR2_TARGET_GENERIC_PASSWD_METHOD="(.*)"$/!d;'    \
50*4882a593Smuzhiyun                         -e 's//\1/;'                                           \
51*4882a593Smuzhiyun                         "${BR2_CONFIG}"                                        \
52*4882a593Smuzhiyun                )"
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun#----------------------------------------------------------------------------
55*4882a593Smuzhiyunget_uid() {
56*4882a593Smuzhiyun    local username="${1}"
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun    awk -F: -v username="${username}"                           \
59*4882a593Smuzhiyun        '$1 == username { printf( "%d\n", $3 ); }' "${PASSWD}"
60*4882a593Smuzhiyun}
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun#----------------------------------------------------------------------------
63*4882a593Smuzhiyunget_ugid() {
64*4882a593Smuzhiyun    local username="${1}"
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun    awk -F: -v username="${username}"                          \
67*4882a593Smuzhiyun        '$1 == username { printf( "%d\n", $4 ); }' "${PASSWD}"
68*4882a593Smuzhiyun}
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun#----------------------------------------------------------------------------
71*4882a593Smuzhiyunget_gid() {
72*4882a593Smuzhiyun    local group="${1}"
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun    awk -F: -v group="${group}"                             \
75*4882a593Smuzhiyun        '$1 == group { printf( "%d\n", $3 ); }' "${GROUP}"
76*4882a593Smuzhiyun}
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun#----------------------------------------------------------------------------
79*4882a593Smuzhiyunget_members() {
80*4882a593Smuzhiyun    local group="${1}"
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun    awk -F: -v group="${group}"                             \
83*4882a593Smuzhiyun        '$1 == group { printf( "%s\n", $4 ); }' "${GROUP}"
84*4882a593Smuzhiyun}
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun#----------------------------------------------------------------------------
87*4882a593Smuzhiyunget_username() {
88*4882a593Smuzhiyun    local uid="${1}"
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun    awk -F: -v uid="${uid}"                                 \
91*4882a593Smuzhiyun        '$3 == uid { printf( "%s\n", $1 ); }' "${PASSWD}"
92*4882a593Smuzhiyun}
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun#----------------------------------------------------------------------------
95*4882a593Smuzhiyunget_group() {
96*4882a593Smuzhiyun    local gid="${1}"
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun    awk -F: -v gid="${gid}"                             \
99*4882a593Smuzhiyun        '$3 == gid { printf( "%s\n", $1 ); }' "${GROUP}"
100*4882a593Smuzhiyun}
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun#----------------------------------------------------------------------------
103*4882a593Smuzhiyunget_ugroup() {
104*4882a593Smuzhiyun    local username="${1}"
105*4882a593Smuzhiyun    local ugid
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun    ugid="$( get_ugid "${username}" )"
108*4882a593Smuzhiyun    if [ -n "${ugid}" ]; then
109*4882a593Smuzhiyun        get_group "${ugid}"
110*4882a593Smuzhiyun    fi
111*4882a593Smuzhiyun}
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun#----------------------------------------------------------------------------
114*4882a593Smuzhiyun# Sanity-check the new user/group:
115*4882a593Smuzhiyun#   - check the gid is not already used for another group
116*4882a593Smuzhiyun#   - check the group does not already exist with another gid
117*4882a593Smuzhiyun#   - check the user does not already exist with another gid
118*4882a593Smuzhiyun#   - check the uid is not already used for another user
119*4882a593Smuzhiyun#   - check the user does not already exist with another uid
120*4882a593Smuzhiyun#   - check the user does not already exist in another group
121*4882a593Smuzhiyuncheck_user_validity() {
122*4882a593Smuzhiyun    local username="${1}"
123*4882a593Smuzhiyun    local uid="${2}"
124*4882a593Smuzhiyun    local group="${3}"
125*4882a593Smuzhiyun    local gid="${4}"
126*4882a593Smuzhiyun    local _uid _ugid _gid _username _group _ugroup
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun    _group="$( get_group "${gid}" )"
129*4882a593Smuzhiyun    _gid="$( get_gid "${group}" )"
130*4882a593Smuzhiyun    _ugid="$( get_ugid "${username}" )"
131*4882a593Smuzhiyun    _username="$( get_username "${uid}" )"
132*4882a593Smuzhiyun    _uid="$( get_uid "${username}" )"
133*4882a593Smuzhiyun    _ugroup="$( get_ugroup "${username}" )"
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun    if [ "${username}" = "root" ]; then
136*4882a593Smuzhiyun        fail "invalid username '%s\n'" "${username}"
137*4882a593Smuzhiyun    fi
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun    if [ ${gid} -lt -1 -o ${gid} -eq 0 ]; then
140*4882a593Smuzhiyun        fail "invalid gid '%d' for '%s'\n" ${gid} "${username}"
141*4882a593Smuzhiyun    elif [ ${gid} -ne -1 ]; then
142*4882a593Smuzhiyun        # check the gid is not already used for another group
143*4882a593Smuzhiyun        if [ -n "${_group}" -a "${_group}" != "${group}" ]; then
144*4882a593Smuzhiyun            fail "gid '%d' for '%s' is already used by group '%s'\n" \
145*4882a593Smuzhiyun                 ${gid} "${username}" "${_group}"
146*4882a593Smuzhiyun        fi
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun        # check the group does not already exists with another gid
149*4882a593Smuzhiyun        # Need to split the check in two, otherwise '[' complains it
150*4882a593Smuzhiyun        # is missing arguments when _gid is empty
151*4882a593Smuzhiyun        if [ -n "${_gid}" ] && [ ${_gid} -ne ${gid} ]; then
152*4882a593Smuzhiyun            fail "group '%s' for '%s' already exists with gid '%d' (wants '%d')\n" \
153*4882a593Smuzhiyun                 "${group}" "${username}" ${_gid} ${gid}
154*4882a593Smuzhiyun        fi
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun        # check the user does not already exists with another gid
157*4882a593Smuzhiyun        # Need to split the check in two, otherwise '[' complains it
158*4882a593Smuzhiyun        # is missing arguments when _ugid is empty
159*4882a593Smuzhiyun        if [ -n "${_ugid}" ] && [ ${_ugid} -ne ${gid} ]; then
160*4882a593Smuzhiyun            fail "user '%s' already exists with gid '%d' (wants '%d')\n" \
161*4882a593Smuzhiyun                 "${username}" ${_ugid} ${gid}
162*4882a593Smuzhiyun        fi
163*4882a593Smuzhiyun    fi
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun    if [ ${uid} -lt -1 -o ${uid} -eq 0 ]; then
166*4882a593Smuzhiyun        fail "invalid uid '%d' for '%s'\n" ${uid} "${username}"
167*4882a593Smuzhiyun    elif [ ${uid} -ne -1 ]; then
168*4882a593Smuzhiyun        # check the uid is not already used for another user
169*4882a593Smuzhiyun        if [ -n "${_username}" -a "${_username}" != "${username}" ]; then
170*4882a593Smuzhiyun            fail "uid '%d' for '%s' already used by user '%s'\n" \
171*4882a593Smuzhiyun                 ${uid} "${username}" "${_username}"
172*4882a593Smuzhiyun        fi
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun        # check the user does not already exists with another uid
175*4882a593Smuzhiyun        # Need to split the check in two, otherwise '[' complains it
176*4882a593Smuzhiyun        # is missing arguments when _uid is empty
177*4882a593Smuzhiyun        if [ -n "${_uid}" ] && [ ${_uid} -ne ${uid} ]; then
178*4882a593Smuzhiyun            fail "user '%s' already exists with uid '%d' (wants '%d')\n" \
179*4882a593Smuzhiyun                 "${username}" ${_uid} ${uid}
180*4882a593Smuzhiyun        fi
181*4882a593Smuzhiyun    fi
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun    # check the user does not already exist in another group
184*4882a593Smuzhiyun    if [ -n "${_ugroup}" -a "${_ugroup}" != "${group}" ]; then
185*4882a593Smuzhiyun        fail "user '%s' already exists with group '%s' (wants '%s')\n" \
186*4882a593Smuzhiyun             "${username}" "${_ugroup}" "${group}"
187*4882a593Smuzhiyun    fi
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun    return 0
190*4882a593Smuzhiyun}
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun#----------------------------------------------------------------------------
193*4882a593Smuzhiyun# Generate a unique GID for given group. If the group already exists,
194*4882a593Smuzhiyun# then simply report its current GID. Otherwise, generate the lowest GID
195*4882a593Smuzhiyun# that is:
196*4882a593Smuzhiyun#   - not 0
197*4882a593Smuzhiyun#   - comprised in [MIN_GID..MAX_GID]
198*4882a593Smuzhiyun#   - not already used by a group
199*4882a593Smuzhiyungenerate_gid() {
200*4882a593Smuzhiyun    local group="${1}"
201*4882a593Smuzhiyun    local gid
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun    gid="$( get_gid "${group}" )"
204*4882a593Smuzhiyun    if [ -z "${gid}" ]; then
205*4882a593Smuzhiyun        for(( gid=MIN_GID; gid<=MAX_GID; gid++ )); do
206*4882a593Smuzhiyun            if [ -z "$( get_group "${gid}" )" ]; then
207*4882a593Smuzhiyun                break
208*4882a593Smuzhiyun            fi
209*4882a593Smuzhiyun        done
210*4882a593Smuzhiyun        if [ ${gid} -gt ${MAX_GID} ]; then
211*4882a593Smuzhiyun            fail "can not allocate a GID for group '%s'\n" "${group}"
212*4882a593Smuzhiyun        fi
213*4882a593Smuzhiyun    fi
214*4882a593Smuzhiyun    printf "%d\n" "${gid}"
215*4882a593Smuzhiyun}
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun#----------------------------------------------------------------------------
218*4882a593Smuzhiyun# Add a group; if it does already exist, remove it first
219*4882a593Smuzhiyunadd_one_group() {
220*4882a593Smuzhiyun    local group="${1}"
221*4882a593Smuzhiyun    local gid="${2}"
222*4882a593Smuzhiyun    local members
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun    # Generate a new GID if needed
225*4882a593Smuzhiyun    if [ ${gid} -eq -1 ]; then
226*4882a593Smuzhiyun        gid="$( generate_gid "${group}" )"
227*4882a593Smuzhiyun    fi
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun    members=$(get_members "$group")
230*4882a593Smuzhiyun    # Remove any previous instance of this group, and re-add the new one
231*4882a593Smuzhiyun    sed -i --follow-symlinks -e '/^'"${group}"':.*/d;' "${GROUP}"
232*4882a593Smuzhiyun    printf "%s:x:%d:%s\n" "${group}" "${gid}" "${members}" >>"${GROUP}"
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun    # Ditto for /etc/gshadow if it exists
235*4882a593Smuzhiyun    if [ -f "${GSHADOW}" ]; then
236*4882a593Smuzhiyun        sed -i --follow-symlinks -e '/^'"${group}"':.*/d;' "${GSHADOW}"
237*4882a593Smuzhiyun        printf "%s:*::\n" "${group}" >>"${GSHADOW}"
238*4882a593Smuzhiyun    fi
239*4882a593Smuzhiyun}
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun#----------------------------------------------------------------------------
242*4882a593Smuzhiyun# Generate a unique UID for given username. If the username already exists,
243*4882a593Smuzhiyun# then simply report its current UID. Otherwise, generate the lowest UID
244*4882a593Smuzhiyun# that is:
245*4882a593Smuzhiyun#   - not 0
246*4882a593Smuzhiyun#   - comprised in [MIN_UID..MAX_UID]
247*4882a593Smuzhiyun#   - not already used by a user
248*4882a593Smuzhiyungenerate_uid() {
249*4882a593Smuzhiyun    local username="${1}"
250*4882a593Smuzhiyun    local uid
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun    uid="$( get_uid "${username}" )"
253*4882a593Smuzhiyun    if [ -z "${uid}" ]; then
254*4882a593Smuzhiyun        for(( uid=MIN_UID; uid<=MAX_UID; uid++ )); do
255*4882a593Smuzhiyun            if [ -z "$( get_username "${uid}" )" ]; then
256*4882a593Smuzhiyun                break
257*4882a593Smuzhiyun            fi
258*4882a593Smuzhiyun        done
259*4882a593Smuzhiyun        if [ ${uid} -gt ${MAX_UID} ]; then
260*4882a593Smuzhiyun            fail "can not allocate a UID for user '%s'\n" "${username}"
261*4882a593Smuzhiyun        fi
262*4882a593Smuzhiyun    fi
263*4882a593Smuzhiyun    printf "%d\n" "${uid}"
264*4882a593Smuzhiyun}
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun#----------------------------------------------------------------------------
267*4882a593Smuzhiyun# Add given user to given group, if not already the case
268*4882a593Smuzhiyunadd_user_to_group() {
269*4882a593Smuzhiyun    local username="${1}"
270*4882a593Smuzhiyun    local group="${2}"
271*4882a593Smuzhiyun    local _f
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun    for _f in "${GROUP}" "${GSHADOW}"; do
274*4882a593Smuzhiyun        [ -f "${_f}" ] || continue
275*4882a593Smuzhiyun        sed -r -i --follow-symlinks \
276*4882a593Smuzhiyun                  -e 's/^('"${group}"':.*:)(([^:]+,)?)'"${username}"'(,[^:]+*)?$/\1\2\4/;'  \
277*4882a593Smuzhiyun                  -e 's/^('"${group}"':.*)$/\1,'"${username}"'/;'                           \
278*4882a593Smuzhiyun                  -e 's/,+/,/'                                                              \
279*4882a593Smuzhiyun                  -e 's/:,/:/'                                                              \
280*4882a593Smuzhiyun                  "${_f}"
281*4882a593Smuzhiyun    done
282*4882a593Smuzhiyun}
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun#----------------------------------------------------------------------------
285*4882a593Smuzhiyun# Encode a password
286*4882a593Smuzhiyunencode_password() {
287*4882a593Smuzhiyun    local passwd="${1}"
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun    mkpasswd -m "${PASSWD_METHOD}" "${passwd}"
290*4882a593Smuzhiyun}
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun#----------------------------------------------------------------------------
293*4882a593Smuzhiyun# Add a user; if it does already exist, remove it first
294*4882a593Smuzhiyunadd_one_user() {
295*4882a593Smuzhiyun    local username="${1}"
296*4882a593Smuzhiyun    local uid="${2}"
297*4882a593Smuzhiyun    local group="${3}"
298*4882a593Smuzhiyun    local gid="${4}"
299*4882a593Smuzhiyun    local passwd="${5}"
300*4882a593Smuzhiyun    local home="${6}"
301*4882a593Smuzhiyun    local shell="${7}"
302*4882a593Smuzhiyun    local groups="${8}"
303*4882a593Smuzhiyun    local comment="${9}"
304*4882a593Smuzhiyun    local _f _group _home _shell _gid _passwd
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun    # First, sanity-check the user
307*4882a593Smuzhiyun    check_user_validity "${username}" "${uid}" "${group}" "${gid}"
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun    # Generate a new UID if needed
310*4882a593Smuzhiyun    if [ ${uid} -eq -1 ]; then
311*4882a593Smuzhiyun        uid="$( generate_uid "${username}" )"
312*4882a593Smuzhiyun    fi
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun    # Remove any previous instance of this user
315*4882a593Smuzhiyun    for _f in "${PASSWD}" "${SHADOW}"; do
316*4882a593Smuzhiyun        sed -r -i --follow-symlinks -e '/^'"${username}"':.*/d;' "${_f}"
317*4882a593Smuzhiyun    done
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun    _gid="$( get_gid "${group}" )"
320*4882a593Smuzhiyun    _shell="${shell}"
321*4882a593Smuzhiyun    if [ "${shell}" = "-" ]; then
322*4882a593Smuzhiyun        _shell="/bin/false"
323*4882a593Smuzhiyun    fi
324*4882a593Smuzhiyun    case "${home}" in
325*4882a593Smuzhiyun        -)  _home="/";;
326*4882a593Smuzhiyun        /)  fail "home can not explicitly be '/'\n";;
327*4882a593Smuzhiyun        /*) _home="${home}";;
328*4882a593Smuzhiyun        *)  fail "home must be an absolute path\n";;
329*4882a593Smuzhiyun    esac
330*4882a593Smuzhiyun    case "${passwd}" in
331*4882a593Smuzhiyun        -)
332*4882a593Smuzhiyun            _passwd=""
333*4882a593Smuzhiyun            ;;
334*4882a593Smuzhiyun        !=*)
335*4882a593Smuzhiyun            _passwd='!'"$( encode_password "${passwd#!=}" )"
336*4882a593Smuzhiyun            ;;
337*4882a593Smuzhiyun        =*)
338*4882a593Smuzhiyun            _passwd="$( encode_password "${passwd#=}" )"
339*4882a593Smuzhiyun            ;;
340*4882a593Smuzhiyun        *)
341*4882a593Smuzhiyun            _passwd="${passwd}"
342*4882a593Smuzhiyun            ;;
343*4882a593Smuzhiyun    esac
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun    printf "%s:x:%d:%d:%s:%s:%s\n"              \
346*4882a593Smuzhiyun           "${username}" "${uid}" "${_gid}"     \
347*4882a593Smuzhiyun           "${comment}" "${_home}" "${_shell}"  \
348*4882a593Smuzhiyun           >>"${PASSWD}"
349*4882a593Smuzhiyun    printf "%s:%s:::::::\n"      \
350*4882a593Smuzhiyun           "${username}" "${_passwd}"   \
351*4882a593Smuzhiyun           >>"${SHADOW}"
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun    # Add the user to its additional groups
354*4882a593Smuzhiyun    if [ "${groups}" != "-" ]; then
355*4882a593Smuzhiyun        for _group in ${groups//,/ }; do
356*4882a593Smuzhiyun            add_user_to_group "${username}" "${_group}"
357*4882a593Smuzhiyun        done
358*4882a593Smuzhiyun    fi
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun    # If the user has a home, chown it
361*4882a593Smuzhiyun    # (Note: stdout goes to the fakeroot-script)
362*4882a593Smuzhiyun    if [ "${home}" != "-" ]; then
363*4882a593Smuzhiyun        mkdir -p "${TARGET_DIR}/${home}"
364*4882a593Smuzhiyun        printf "chown -h -R %d:%d '%s'\n" "${uid}" "${_gid}" "${TARGET_DIR}/${home}"
365*4882a593Smuzhiyun    fi
366*4882a593Smuzhiyun}
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun#----------------------------------------------------------------------------
369*4882a593Smuzhiyunmain() {
370*4882a593Smuzhiyun    local username uid group gid passwd home shell groups comment
371*4882a593Smuzhiyun    local line
372*4882a593Smuzhiyun    local -a ENTRIES
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun    # Some sanity checks
375*4882a593Smuzhiyun    if [ ${MIN_UID} -le 0 ]; then
376*4882a593Smuzhiyun        fail "MIN_UID must be >0 (currently %d)\n" ${MIN_UID}
377*4882a593Smuzhiyun    fi
378*4882a593Smuzhiyun    if [ ${MIN_GID} -le 0 ]; then
379*4882a593Smuzhiyun        fail "MIN_GID must be >0 (currently %d)\n" ${MIN_GID}
380*4882a593Smuzhiyun    fi
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun    # Read in all the file in memory, exclude empty lines and comments
383*4882a593Smuzhiyun    while read line; do
384*4882a593Smuzhiyun        ENTRIES+=( "${line}" )
385*4882a593Smuzhiyun    done < <( sed -r -e 's/#.*//; /^[[:space:]]*$/d;' "${USERS_TABLE}" )
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun    # We first create groups whose gid is not -1, and then we create groups
388*4882a593Smuzhiyun    # whose gid is -1 (automatic), so that, if a group is defined both with
389*4882a593Smuzhiyun    # a specified gid and an automatic gid, we ensure the specified gid is
390*4882a593Smuzhiyun    # used, rather than a different automatic gid is computed.
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun    # First, create all the main groups which gid is *not* automatic
393*4882a593Smuzhiyun    for line in "${ENTRIES[@]}"; do
394*4882a593Smuzhiyun        read username uid group gid passwd home shell groups comment <<<"${line}"
395*4882a593Smuzhiyun        [ ${gid} -ge 0 ] || continue    # Automatic gid
396*4882a593Smuzhiyun        add_one_group "${group}" "${gid}"
397*4882a593Smuzhiyun    done
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun    # Then, create all the main groups which gid *is* automatic
400*4882a593Smuzhiyun    for line in "${ENTRIES[@]}"; do
401*4882a593Smuzhiyun        read username uid group gid passwd home shell groups comment <<<"${line}"
402*4882a593Smuzhiyun        [ ${gid} -eq -1 ] || continue    # Non-automatic gid
403*4882a593Smuzhiyun        add_one_group "${group}" "${gid}"
404*4882a593Smuzhiyun    done
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun    # Then, create all the additional groups
407*4882a593Smuzhiyun    # If any additional group is already a main group, we should use
408*4882a593Smuzhiyun    # the gid of that main group; otherwise, we can use any gid
409*4882a593Smuzhiyun    for line in "${ENTRIES[@]}"; do
410*4882a593Smuzhiyun        read username uid group gid passwd home shell groups comment <<<"${line}"
411*4882a593Smuzhiyun        if [ "${groups}" != "-" ]; then
412*4882a593Smuzhiyun            for g in ${groups//,/ }; do
413*4882a593Smuzhiyun                add_one_group "${g}" -1
414*4882a593Smuzhiyun            done
415*4882a593Smuzhiyun        fi
416*4882a593Smuzhiyun    done
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun    # When adding users, we do as for groups, in case two packages create
419*4882a593Smuzhiyun    # the same user, one with an automatic uid, the other with a specified
420*4882a593Smuzhiyun    # uid, to ensure the specified uid is used, rather than an incompatible
421*4882a593Smuzhiyun    # uid be generated.
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun    # Now, add users whose uid is *not* automatic
424*4882a593Smuzhiyun    for line in "${ENTRIES[@]}"; do
425*4882a593Smuzhiyun        read username uid group gid passwd home shell groups comment <<<"${line}"
426*4882a593Smuzhiyun        [ "${username}" != "-" ] || continue # Magic string to skip user creation
427*4882a593Smuzhiyun        [ ${uid} -ge 0         ] || continue # Automatic uid
428*4882a593Smuzhiyun        add_one_user "${username}" "${uid}" "${group}" "${gid}" "${passwd}" \
429*4882a593Smuzhiyun                     "${home}" "${shell}" "${groups}" "${comment}"
430*4882a593Smuzhiyun    done
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun    # Finally, add users whose uid *is* automatic
433*4882a593Smuzhiyun    for line in "${ENTRIES[@]}"; do
434*4882a593Smuzhiyun        read username uid group gid passwd home shell groups comment <<<"${line}"
435*4882a593Smuzhiyun        [ "${username}" != "-" ] || continue # Magic string to skip user creation
436*4882a593Smuzhiyun        [ ${uid} -eq -1        ] || continue # Non-automatic uid
437*4882a593Smuzhiyun        add_one_user "${username}" "${uid}" "${group}" "${gid}" "${passwd}" \
438*4882a593Smuzhiyun                     "${home}" "${shell}" "${groups}" "${comment}"
439*4882a593Smuzhiyun    done
440*4882a593Smuzhiyun}
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun#----------------------------------------------------------------------------
443*4882a593Smuzhiyunmain "${@}"
444