#!/usr/bin/bash # -*- mode: shell-script; indent-tabs-mode: true; tab-width: 4; -*- # Creates system users and groups, based on files in the format described # in sysusers.d(5). Replacement for systemd-sysusers(8) for the use of RPM # # USAGE: # # sysusers.sh [--root ROOTDIR] [--replace CONFIGFILE] [CONFIGFILE...] # # SEE ALSO systemd-sysusers(8) # # Based on sysusers.generate-pre.sh from the Fedora systemd package SYSTEMDIR=/usr/lib/sysusers.d RUNTIMEDIR=/run/sysusers.d SYSTEMCONFDIR=/etc/sysusers.d ROOT=/ REPLACE=# while test $# -gt 0 ; do case "${1}" in --root ) shift ROOT=${1} shift ;; --replace ) shift REPLACE=${1} shift ;; --help ) cat </dev/null } hasuid() { cut -d: -f3 "$ROOT"/etc/passwd | grep "${1}" >/dev/null } hasgroup() { grep "^${1}:" "$ROOT"/etc/group >/dev/null } user() { local user="$1" local uid="$2" local desc="$3" local group="$4" local home="$5" local shell="$6" local expire="$7" [ "$desc" = '-' ] && desc= { [ "$home" = '-' ] || [ "$home" = '' ]; } && home=/ { [ "$shell" = '-' ] || [ "$shell" = '' ]; } && shell=/sbin/nologin if [ "$uid" = '-' ] || [ "$uid" = '' ]; then if ! hasuser "$user" ; then useradd -R "$ROOT" -r -g "${group}" -d "${home}" -s "${shell}" -c "${desc}" "${user}" || : fi else if ! hasuser "${user}" ; then if ! hasuid "${uid}" ; then useradd -R "$ROOT" -r -u "${uid}" -g "${group}" -d "${home}" -s "${shell}" -c "${desc}" "${user}" || : else useradd -R "$ROOT" -r -g "${group}" -d "${home}" -s "${shell}" -c "${desc}" "${user}" || : fi fi fi if [[ $expire ]]; then usermod -e 1 "${user}" fi } group() { local group="$1" local gid="$2" if [ "$gid" = '-' ]; then hasgroup "${group}" || groupadd -R "$ROOT" -f -r "${group}" || : else hasgroup "${group}" || groupadd -R "$ROOT" -f -g "${gid}" -r "${group}" || : fi } addtogroup() { local user="$1" local group="$2" group "${group}" "-" user "${user}" "-" "" "${group}" "" "" "" usermod -R "$ROOT" -a -G "${group}" "$user" || : } parse() { local line arr expire while read -r line || [ -n "$line" ] ; do { [ "${line:0:1}" = '#' ] || [ "${line:0:1}" = ';' ]; } && continue line="${line## *}" [ -z "$line" ] && continue mapfile -t arr < <(xargs -n1 <<<"$line") expire="" case "${arr[0]}" in ('u' | 'u!') if [[ "${arr[0]}" == 'u!' ]]; then expire="1"; fi if [[ "${arr[2]}" == *":"* ]]; then user "${arr[1]}" "${arr[2]%:*}" "${arr[3]}" "${arr[2]#*:}" "${arr[4]}" "${arr[5]}" $expire else group "${arr[1]}" "${arr[2]}" user "${arr[1]}" "${arr[2]}" "${arr[3]}" "${arr[1]}" "${arr[4]}" "${arr[5]}" $expire fi ;; ('g') group "${arr[1]}" "${arr[2]}" ;; ('m') addtogroup "${arr[1]}" "${arr[2]}" ;; esac done } # Make sure etc and the user/group files exist mkdir -p "$ROOT"/etc/ [ -e "$ROOT"/etc/passwd ] || touch "$ROOT"/etc/passwd [ -e "$ROOT"/etc/shadow ] || touch "$ROOT"/etc/shadow [ -e "$ROOT"/etc/group ] || touch "$ROOT"/etc/group # read files from command line for fn in "$@"; do # check if file is replaced by one with higher priority REPLACEDIR=$(dirname "$REPLACE") REPLACENAME=$(basename "$REPLACE") if [[ "$REPLACEDIR" == "${SYSTEMDIR}" ]] ; then if [ -f "${ROOT}${RUNTIMEDIR}/${REPLACENAME}" ] ; then continue fi if [ -f "${ROOT}${SYSTEMCONFDIR}/${REPLACENAME}" ] ; then continue fi fi if [[ "$REPLACEDIR" == "$RUNTIMEDIR" ]] ; then if [ -f "${ROOT}${SYSTEMCONFDIR}/${REPLACENAME}" ] ; then continue fi fi if [ "-" = "$fn" ]; then parse <&0 else [ -r "$fn" ] || continue parse <"$fn" fi done