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