diff options
Diffstat (limited to 'meta/classes/useradd.bbclass')
| -rw-r--r-- | meta/classes/useradd.bbclass | 271 |
1 files changed, 178 insertions, 93 deletions
diff --git a/meta/classes/useradd.bbclass b/meta/classes/useradd.bbclass index 928f619b7c..4373677bd6 100644 --- a/meta/classes/useradd.bbclass +++ b/meta/classes/useradd.bbclass @@ -1,13 +1,18 @@ +inherit useradd_base + # base-passwd-cross provides the default passwd and group files in the # target sysroot, and shadow -native and -sysroot provide the utilities # and support files needed to add and modify user and group accounts -DEPENDS_append = "${USERADDDEPENDS}" -USERADDDEPENDS = " base-passwd shadow-native shadow-sysroot shadow" -USERADDDEPENDS_virtclass-nativesdk = "" - -# This preinstall function will be run in two contexts: once for the -# native sysroot (as invoked by the useradd_sysroot() wrapper), and -# also as the preinst script in the target package. +DEPENDS_append_class-target = " base-files shadow-native shadow-sysroot shadow base-passwd" +PACKAGE_WRITE_DEPS += "shadow-native" + +# This preinstall function can be run in four different contexts: +# +# a) Before do_install +# b) At do_populate_sysroot_setscene when installing from sstate packages +# c) As the preinst script in the target package at do_rootfs time +# d) As the preinst script in the target package on device as a package upgrade +# useradd_preinst () { OPT="" SYSROOT="" @@ -17,147 +22,227 @@ if test "x$D" != "x"; then SYSROOT="$D" OPT="--root $D" - # Add groups and users defined for all recipe packages - GROUPADD_PARAM="${@get_all_cmd_params(d, 'group')}" - USERADD_PARAM="${@get_all_cmd_params(d, 'user')}" -else + # Make sure login.defs is there, this is to make debian package backend work + # correctly while doing rootfs. + # The problem here is that if /etc/login.defs is treated as a config file for + # shadow package, then while performing preinsts for packages that depend on + # shadow, there might only be /etc/login.def.dpkg-new there in root filesystem. + if [ ! -e $D${sysconfdir}/login.defs -a -e $D${sysconfdir}/login.defs.dpkg-new ]; then + cp $D${sysconfdir}/login.defs.dpkg-new $D${sysconfdir}/login.defs + fi + + # user/group lookups should match useradd/groupadd --root + export PSEUDO_PASSWD="$SYSROOT:${STAGING_DIR_NATIVE}" +fi + +# If we're not doing a special SSTATE/SYSROOT install +# then set the values, otherwise use the environment +if test "x$UA_SYSROOT" = "x"; then # Installing onto a target # Add groups and users defined only for this package GROUPADD_PARAM="${GROUPADD_PARAM}" USERADD_PARAM="${USERADD_PARAM}" + GROUPMEMS_PARAM="${GROUPMEMS_PARAM}" fi # Perform group additions first, since user additions may depend # on these groups existing -if test "x$GROUPADD_PARAM" != "x"; then +if test "x`echo $GROUPADD_PARAM | tr -d '[:space:]'`" != "x"; then echo "Running groupadd commands..." # Invoke multiple instances of groupadd for parameter lists # separated by ';' - opts=`echo "$GROUPADD_PARAM" | cut -d ';' -f 1` - remaining=`echo "$GROUPADD_PARAM" | cut -d ';' -f 2-` + opts=`echo "$GROUPADD_PARAM" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'` + remaining=`echo "$GROUPADD_PARAM" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'` while test "x$opts" != "x"; do - groupname=`echo "$opts" | awk '{ print $NF }'` - group_exists=`grep "^$groupname:" $SYSROOT/etc/group || true` - if test "x$group_exists" = "x"; then - eval $PSEUDO groupadd $OPT $opts - else - echo "Note: group $groupname already exists, not re-creating it" - fi - + perform_groupadd "$SYSROOT" "$OPT $opts" if test "x$opts" = "x$remaining"; then break fi - opts=`echo "$remaining" | cut -d ';' -f 1` - remaining=`echo "$remaining" | cut -d ';' -f 2-` + opts=`echo "$remaining" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'` + remaining=`echo "$remaining" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'` done fi -if test "x$USERADD_PARAM" != "x"; then +if test "x`echo $USERADD_PARAM | tr -d '[:space:]'`" != "x"; then echo "Running useradd commands..." # Invoke multiple instances of useradd for parameter lists # separated by ';' - opts=`echo "$USERADD_PARAM" | cut -d ';' -f 1` - remaining=`echo "$USERADD_PARAM" | cut -d ';' -f 2-` + opts=`echo "$USERADD_PARAM" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'` + remaining=`echo "$USERADD_PARAM" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'` while test "x$opts" != "x"; do - # useradd does not have a -f option, so we have to check if the - # username already exists manually - username=`echo "$opts" | awk '{ print $NF }'` - user_exists=`grep "^$username:" $SYSROOT/etc/passwd || true` - if test "x$user_exists" = "x"; then - eval $PSEUDO useradd $OPT $opts - else - echo "Note: username $username already exists, not re-creating it" + perform_useradd "$SYSROOT" "$OPT $opts" + if test "x$opts" = "x$remaining"; then + break fi + opts=`echo "$remaining" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'` + remaining=`echo "$remaining" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'` + done +fi +if test "x`echo $GROUPMEMS_PARAM | tr -d '[:space:]'`" != "x"; then + echo "Running groupmems commands..." + # Invoke multiple instances of groupmems for parameter lists + # separated by ';' + opts=`echo "$GROUPMEMS_PARAM" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'` + remaining=`echo "$GROUPMEMS_PARAM" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'` + while test "x$opts" != "x"; do + perform_groupmems "$SYSROOT" "$OPT $opts" if test "x$opts" = "x$remaining"; then break fi - opts=`echo "$remaining" | cut -d ';' -f 1` - remaining=`echo "$remaining" | cut -d ';' -f 2-` + opts=`echo "$remaining" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'` + remaining=`echo "$remaining" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'` done fi } useradd_sysroot () { - export PSEUDO="${STAGING_DIR_NATIVE}${bindir}/pseudo" - export PSEUDO_LOCALSTATEDIR="${STAGING_DIR_TARGET}${localstatedir}/pseudo" + # Pseudo may (do_prepare_recipe_sysroot) or may not (do_populate_sysroot_setscene) be running + # at this point so we're explicit about the environment so pseudo can load if + # not already present. + export PSEUDO="${FAKEROOTENV} PSEUDO_LOCALSTATEDIR=${STAGING_DIR_TARGET}${localstatedir}/pseudo ${PSEUDO_SYSROOT}${bindir_native}/pseudo" # Explicitly set $D since it isn't set to anything - # before do_install + # before do_prepare_recipe_sysroot D=${STAGING_DIR_TARGET} + + # base-passwd's postinst may not have run yet in which case we'll get called later, just exit. + # Beware that in some cases we might see the fake pseudo passwd here, in which case we also must + # exit. + if [ ! -f $D${sysconfdir}/passwd ] || + grep -q this-is-the-pseudo-passwd $D${sysconfdir}/passwd; then + exit 0 + fi + + # It is also possible we may be in a recipe which doesn't have useradd dependencies and hence the + # useradd/groupadd tools are unavailable. If there is no dependency, we assume we don't want to + # create users in the sysroot + if ! command -v useradd; then + exit 0 + fi + + # Add groups and users defined for all recipe packages + GROUPADD_PARAM="${@get_all_cmd_params(d, 'groupadd')}" + USERADD_PARAM="${@get_all_cmd_params(d, 'useradd')}" + GROUPMEMS_PARAM="${@get_all_cmd_params(d, 'groupmems')}" + + # Tell the system to use the environment vars + UA_SYSROOT=1 + useradd_preinst } -useradd_sysroot_sstate () { - if [ "${BB_CURRENTTASK}" = "populate_sysroot_setscene" ] - then - useradd_sysroot - fi +python useradd_sysroot_sstate () { + task = d.getVar("BB_CURRENTTASK") + if task == "package_setscene": + bb.build.exec_func("useradd_sysroot", d) + elif task == "prepare_recipe_sysroot": + # Used to update this recipe's own sysroot so the user/groups are available to do_install + scriptfile = d.expand("${RECIPE_SYSROOT}${bindir}/postinst-useradd-${PN}") + bb.utils.mkdirhier(os.path.dirname(scriptfile)) + with open(scriptfile, 'w') as script: + script.write("#!/bin/sh\n") + bb.data.emit_func("useradd_sysroot", script, d) + script.write("useradd_sysroot\n") + os.chmod(scriptfile, 0o755) + bb.build.exec_func("useradd_sysroot", d) + elif task == "populate_sysroot": + # Used when installed in dependent task sysroots + scriptfile = d.expand("${SYSROOT_DESTDIR}${bindir}/postinst-useradd-${PN}") + bb.utils.mkdirhier(os.path.dirname(scriptfile)) + with open(scriptfile, 'w') as script: + script.write("#!/bin/sh\n") + bb.data.emit_func("useradd_sysroot", script, d) + script.write("useradd_sysroot\n") + os.chmod(scriptfile, 0o755) } -do_install[prefuncs] += "${SYSROOTFUNC}" -SYSROOTFUNC = "useradd_sysroot" -SYSROOTFUNC_virtclass-nativesdk = "" -SSTATEPOSTINSTFUNCS += "${SYSROOTPOSTFUNC}" -SYSROOTPOSTFUNC = "useradd_sysroot_sstate" -SYSROOTPOSTFUNC_virtclass-nativesdk = "" +do_prepare_recipe_sysroot[postfuncs] += "${SYSROOTFUNC}" +SYSROOTFUNC_class-target = "useradd_sysroot_sstate" +SYSROOTFUNC = "" + +SYSROOT_PREPROCESS_FUNCS += "${SYSROOTFUNC}" + +SSTATEPREINSTFUNCS_append_class-target = " useradd_sysroot_sstate" + +do_package_setscene[depends] += "${USERADDSETSCENEDEPS}" +do_populate_sysroot_setscene[depends] += "${USERADDSETSCENEDEPS}" +USERADDSETSCENEDEPS_class-target = "${MLPREFIX}base-passwd:do_populate_sysroot_setscene pseudo-native:do_populate_sysroot_setscene shadow-native:do_populate_sysroot_setscene ${MLPREFIX}shadow-sysroot:do_populate_sysroot_setscene" +USERADDSETSCENEDEPS = "" # Recipe parse-time sanity checks def update_useradd_after_parse(d): - useradd_packages = d.getVar('USERADD_PACKAGES', True) + useradd_packages = d.getVar('USERADD_PACKAGES') - if not useradd_packages: - raise bb.build.FuncFailed, "%s inherits useradd but doesn't set USERADD_PACKAGES" % d.getVar('FILE') + if not useradd_packages: + bb.fatal("%s inherits useradd but doesn't set USERADD_PACKAGES" % d.getVar('FILE', False)) - for pkg in useradd_packages.split(): - if not d.getVar('USERADD_PARAM_%s' % pkg, True) and not d.getVar('GROUPADD_PARAM_%s' % pkg, True): - raise bb.build.FuncFailed, "%s inherits useradd but doesn't set USERADD_PARAM or GROUPADD_PARAM for package %s" % (d.getVar('FILE'), pkg) + for pkg in useradd_packages.split(): + if not d.getVar('USERADD_PARAM_%s' % pkg) and not d.getVar('GROUPADD_PARAM_%s' % pkg) and not d.getVar('GROUPMEMS_PARAM_%s' % pkg): + bb.fatal("%s inherits useradd but doesn't set USERADD_PARAM, GROUPADD_PARAM or GROUPMEMS_PARAM for package %s" % (d.getVar('FILE', False), pkg)) python __anonymous() { - update_useradd_after_parse(d) + if not bb.data.inherits_class('nativesdk', d) \ + and not bb.data.inherits_class('native', d): + update_useradd_after_parse(d) } # Return a single [GROUP|USER]ADD_PARAM formatted string which includes the # [group|user]add parameters for all USERADD_PACKAGES in this recipe def get_all_cmd_params(d, cmd_type): - import string - - param_type = cmd_type.upper() + "ADD_PARAM_%s" - params = [] + import string + + param_type = cmd_type.upper() + "_PARAM_%s" + params = [] - useradd_packages = d.getVar('USERADD_PACKAGES', True) or "" - for pkg in useradd_packages.split(): - param = d.getVar(param_type % pkg, True) - if param: - params.append(param) + useradd_packages = d.getVar('USERADD_PACKAGES') or "" + for pkg in useradd_packages.split(): + param = d.getVar(param_type % pkg) + if param: + params.append(param.rstrip(" ;")) - return string.join(params, "; ") + return "; ".join(params) # Adds the preinst script into generated packages fakeroot python populate_packages_prepend () { - def update_useradd_package(pkg): - bb.debug(1, 'adding user/group calls to preinst for %s' % pkg) - - """ - useradd preinst is appended here because pkg_preinst may be - required to execute on the target. Not doing so may cause - useradd preinst to be invoked twice, causing unwanted warnings. - """ - preinst = d.getVar('pkg_preinst_%s' % pkg, True) or d.getVar('pkg_preinst', True) - if not preinst: - preinst = '#!/bin/sh\n' - preinst += d.getVar('useradd_preinst', True) - d.setVar('pkg_preinst_%s' % pkg, preinst) - - # RDEPENDS setup - rdepends = d.getVar("RDEPENDS_%s" % pkg, True) or "" - rdepends += " base-passwd shadow" - d.setVar("RDEPENDS_%s" % pkg, rdepends) - - # Add the user/group preinstall scripts and RDEPENDS requirements - # to packages specified by USERADD_PACKAGES - if not bb.data.inherits_class('nativesdk', d): - useradd_packages = d.getVar('USERADD_PACKAGES', True) or "" - for pkg in useradd_packages.split(): - update_useradd_package(pkg) + def update_useradd_package(pkg): + bb.debug(1, 'adding user/group calls to preinst for %s' % pkg) + + """ + useradd preinst is appended here because pkg_preinst may be + required to execute on the target. Not doing so may cause + useradd preinst to be invoked twice, causing unwanted warnings. + """ + preinst = d.getVar('pkg_preinst_%s' % pkg) or d.getVar('pkg_preinst') + if not preinst: + preinst = '#!/bin/sh\n' + preinst += 'bbnote () {\n\techo "NOTE: $*"\n}\n' + preinst += 'bbwarn () {\n\techo "WARNING: $*"\n}\n' + preinst += 'bbfatal () {\n\techo "ERROR: $*"\n\texit 1\n}\n' + preinst += 'perform_groupadd () {\n%s}\n' % d.getVar('perform_groupadd') + preinst += 'perform_useradd () {\n%s}\n' % d.getVar('perform_useradd') + preinst += 'perform_groupmems () {\n%s}\n' % d.getVar('perform_groupmems') + preinst += d.getVar('useradd_preinst') + d.setVar('pkg_preinst_%s' % pkg, preinst) + + # RDEPENDS setup + rdepends = d.getVar("RDEPENDS_%s" % pkg) or "" + rdepends += ' ' + d.getVar('MLPREFIX', False) + 'base-passwd' + rdepends += ' ' + d.getVar('MLPREFIX', False) + 'shadow' + # base-files is where the default /etc/skel is packaged + rdepends += ' ' + d.getVar('MLPREFIX', False) + 'base-files' + d.setVar("RDEPENDS_%s" % pkg, rdepends) + + # Add the user/group preinstall scripts and RDEPENDS requirements + # to packages specified by USERADD_PACKAGES + if not bb.data.inherits_class('nativesdk', d) \ + and not bb.data.inherits_class('native', d): + useradd_packages = d.getVar('USERADD_PACKAGES') or "" + for pkg in useradd_packages.split(): + update_useradd_package(pkg) } + +# Use the following to extend the useradd with custom functions +USERADDEXTENSION ?= "" + +inherit ${USERADDEXTENSION} |
