xref: /OK3568_Linux_fs/yocto/poky/meta/classes/useradd.bbclass (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyuninherit useradd_base
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun# base-passwd-cross provides the default passwd and group files in the
4*4882a593Smuzhiyun# target sysroot, and shadow -native and -sysroot provide the utilities
5*4882a593Smuzhiyun# and support files needed to add and modify user and group accounts
6*4882a593SmuzhiyunDEPENDS:append:class-target = " base-files shadow-native shadow-sysroot shadow base-passwd"
7*4882a593SmuzhiyunPACKAGE_WRITE_DEPS += "shadow-native"
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun# This preinstall function can be run in four different contexts:
10*4882a593Smuzhiyun#
11*4882a593Smuzhiyun# a) Before do_install
12*4882a593Smuzhiyun# b) At do_populate_sysroot_setscene when installing from sstate packages
13*4882a593Smuzhiyun# c) As the preinst script in the target package at do_rootfs time
14*4882a593Smuzhiyun# d) As the preinst script in the target package on device as a package upgrade
15*4882a593Smuzhiyun#
16*4882a593Smuzhiyunuseradd_preinst () {
17*4882a593SmuzhiyunOPT=""
18*4882a593SmuzhiyunSYSROOT=""
19*4882a593Smuzhiyun
20*4882a593Smuzhiyunif test "x$D" != "x"; then
21*4882a593Smuzhiyun	# Installing into a sysroot
22*4882a593Smuzhiyun	SYSROOT="$D"
23*4882a593Smuzhiyun	OPT="--root $D"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun	# Make sure login.defs is there, this is to make debian package backend work
26*4882a593Smuzhiyun	# correctly while doing rootfs.
27*4882a593Smuzhiyun	# The problem here is that if /etc/login.defs is treated as a config file for
28*4882a593Smuzhiyun	# shadow package, then while performing preinsts for packages that depend on
29*4882a593Smuzhiyun	# shadow, there might only be /etc/login.def.dpkg-new there in root filesystem.
30*4882a593Smuzhiyun	if [ ! -e $D${sysconfdir}/login.defs -a -e $D${sysconfdir}/login.defs.dpkg-new ]; then
31*4882a593Smuzhiyun	    cp $D${sysconfdir}/login.defs.dpkg-new $D${sysconfdir}/login.defs
32*4882a593Smuzhiyun	fi
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun	# user/group lookups should match useradd/groupadd --root
35*4882a593Smuzhiyun	export PSEUDO_PASSWD="$SYSROOT"
36*4882a593Smuzhiyunfi
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun# If we're not doing a special SSTATE/SYSROOT install
39*4882a593Smuzhiyun# then set the values, otherwise use the environment
40*4882a593Smuzhiyunif test "x$UA_SYSROOT" = "x"; then
41*4882a593Smuzhiyun	# Installing onto a target
42*4882a593Smuzhiyun	# Add groups and users defined only for this package
43*4882a593Smuzhiyun	GROUPADD_PARAM="${GROUPADD_PARAM}"
44*4882a593Smuzhiyun	USERADD_PARAM="${USERADD_PARAM}"
45*4882a593Smuzhiyun	GROUPMEMS_PARAM="${GROUPMEMS_PARAM}"
46*4882a593Smuzhiyunfi
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun# Perform group additions first, since user additions may depend
49*4882a593Smuzhiyun# on these groups existing
50*4882a593Smuzhiyunif test "x`echo $GROUPADD_PARAM | tr -d '[:space:]'`" != "x"; then
51*4882a593Smuzhiyun	echo "Running groupadd commands..."
52*4882a593Smuzhiyun	# Invoke multiple instances of groupadd for parameter lists
53*4882a593Smuzhiyun	# separated by ';'
54*4882a593Smuzhiyun	opts=`echo "$GROUPADD_PARAM" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'`
55*4882a593Smuzhiyun	remaining=`echo "$GROUPADD_PARAM" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'`
56*4882a593Smuzhiyun	while test "x$opts" != "x"; do
57*4882a593Smuzhiyun		perform_groupadd "$SYSROOT" "$OPT $opts"
58*4882a593Smuzhiyun		if test "x$opts" = "x$remaining"; then
59*4882a593Smuzhiyun			break
60*4882a593Smuzhiyun		fi
61*4882a593Smuzhiyun		opts=`echo "$remaining" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'`
62*4882a593Smuzhiyun		remaining=`echo "$remaining" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'`
63*4882a593Smuzhiyun	done
64*4882a593Smuzhiyunfi
65*4882a593Smuzhiyun
66*4882a593Smuzhiyunif test "x`echo $USERADD_PARAM | tr -d '[:space:]'`" != "x"; then
67*4882a593Smuzhiyun	echo "Running useradd commands..."
68*4882a593Smuzhiyun	# Invoke multiple instances of useradd for parameter lists
69*4882a593Smuzhiyun	# separated by ';'
70*4882a593Smuzhiyun	opts=`echo "$USERADD_PARAM" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'`
71*4882a593Smuzhiyun	remaining=`echo "$USERADD_PARAM" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'`
72*4882a593Smuzhiyun	while test "x$opts" != "x"; do
73*4882a593Smuzhiyun		perform_useradd "$SYSROOT" "$OPT $opts"
74*4882a593Smuzhiyun		if test "x$opts" = "x$remaining"; then
75*4882a593Smuzhiyun			break
76*4882a593Smuzhiyun		fi
77*4882a593Smuzhiyun		opts=`echo "$remaining" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'`
78*4882a593Smuzhiyun		remaining=`echo "$remaining" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'`
79*4882a593Smuzhiyun	done
80*4882a593Smuzhiyunfi
81*4882a593Smuzhiyun
82*4882a593Smuzhiyunif test "x`echo $GROUPMEMS_PARAM | tr -d '[:space:]'`" != "x"; then
83*4882a593Smuzhiyun	echo "Running groupmems commands..."
84*4882a593Smuzhiyun	# Invoke multiple instances of groupmems for parameter lists
85*4882a593Smuzhiyun	# separated by ';'
86*4882a593Smuzhiyun	opts=`echo "$GROUPMEMS_PARAM" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'`
87*4882a593Smuzhiyun	remaining=`echo "$GROUPMEMS_PARAM" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'`
88*4882a593Smuzhiyun	while test "x$opts" != "x"; do
89*4882a593Smuzhiyun		perform_groupmems "$SYSROOT" "$OPT $opts"
90*4882a593Smuzhiyun		if test "x$opts" = "x$remaining"; then
91*4882a593Smuzhiyun			break
92*4882a593Smuzhiyun		fi
93*4882a593Smuzhiyun		opts=`echo "$remaining" | cut -d ';' -f 1 | sed -e 's#[ \t]*$##'`
94*4882a593Smuzhiyun		remaining=`echo "$remaining" | cut -d ';' -f 2- | sed -e 's#[ \t]*$##'`
95*4882a593Smuzhiyun	done
96*4882a593Smuzhiyunfi
97*4882a593Smuzhiyun}
98*4882a593Smuzhiyun
99*4882a593Smuzhiyunuseradd_sysroot () {
100*4882a593Smuzhiyun	# Pseudo may (do_prepare_recipe_sysroot) or may not (do_populate_sysroot_setscene) be running
101*4882a593Smuzhiyun	# at this point so we're explicit about the environment so pseudo can load if
102*4882a593Smuzhiyun	# not already present.
103*4882a593Smuzhiyun	# PSEUDO_SYSROOT can contain references to the build architecture and COMPONENT_DIR
104*4882a593Smuzhiyun	# so needs the STAGING_FIXME below
105*4882a593Smuzhiyun	export PSEUDO="${FAKEROOTENV} ${PSEUDO_SYSROOT}${bindir_native}/pseudo"
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun	# Explicitly set $D since it isn't set to anything
108*4882a593Smuzhiyun	# before do_prepare_recipe_sysroot
109*4882a593Smuzhiyun	D=${STAGING_DIR_TARGET}
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun	# base-passwd's postinst may not have run yet in which case we'll get called later, just exit.
112*4882a593Smuzhiyun	# Beware that in some cases we might see the fake pseudo passwd here, in which case we also must
113*4882a593Smuzhiyun	# exit.
114*4882a593Smuzhiyun	if [ ! -f $D${sysconfdir}/passwd ] ||
115*4882a593Smuzhiyun			grep -q this-is-the-pseudo-passwd $D${sysconfdir}/passwd; then
116*4882a593Smuzhiyun		exit 0
117*4882a593Smuzhiyun	fi
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun	# It is also possible we may be in a recipe which doesn't have useradd dependencies and hence the
120*4882a593Smuzhiyun	# useradd/groupadd tools are unavailable. If there is no dependency, we assume we don't want to
121*4882a593Smuzhiyun	# create users in the sysroot
122*4882a593Smuzhiyun	if ! command -v useradd; then
123*4882a593Smuzhiyun		bbwarn "command useradd not found!"
124*4882a593Smuzhiyun		exit 0
125*4882a593Smuzhiyun	fi
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun	# Add groups and users defined for all recipe packages
128*4882a593Smuzhiyun	GROUPADD_PARAM="${@get_all_cmd_params(d, 'groupadd')}"
129*4882a593Smuzhiyun	USERADD_PARAM="${@get_all_cmd_params(d, 'useradd')}"
130*4882a593Smuzhiyun	GROUPMEMS_PARAM="${@get_all_cmd_params(d, 'groupmems')}"
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun	# Tell the system to use the environment vars
133*4882a593Smuzhiyun	UA_SYSROOT=1
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun	useradd_preinst
136*4882a593Smuzhiyun}
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun# The export of PSEUDO in useradd_sysroot() above contains references to
139*4882a593Smuzhiyun# ${PSEUDO_SYSROOT} and ${PSEUDO_LOCALSTATEDIR}. Additionally, the logging
140*4882a593Smuzhiyun# shell functions use ${LOGFIFO}. These need to be handled when restoring
141*4882a593Smuzhiyun# postinst-useradd-${PN} from the sstate cache.
142*4882a593SmuzhiyunEXTRA_STAGING_FIXMES += "PSEUDO_SYSROOT PSEUDO_LOCALSTATEDIR LOGFIFO"
143*4882a593Smuzhiyun
144*4882a593Smuzhiyunpython useradd_sysroot_sstate () {
145*4882a593Smuzhiyun    scriptfile = None
146*4882a593Smuzhiyun    task = d.getVar("BB_CURRENTTASK")
147*4882a593Smuzhiyun    if task == "package_setscene":
148*4882a593Smuzhiyun        bb.build.exec_func("useradd_sysroot", d)
149*4882a593Smuzhiyun    elif task == "prepare_recipe_sysroot":
150*4882a593Smuzhiyun        # Used to update this recipe's own sysroot so the user/groups are available to do_install
151*4882a593Smuzhiyun        scriptfile = d.expand("${RECIPE_SYSROOT}${bindir}/postinst-useradd-${PN}")
152*4882a593Smuzhiyun        bb.build.exec_func("useradd_sysroot", d)
153*4882a593Smuzhiyun    elif task == "populate_sysroot":
154*4882a593Smuzhiyun        # Used when installed in dependent task sysroots
155*4882a593Smuzhiyun        scriptfile = d.expand("${SYSROOT_DESTDIR}${bindir}/postinst-useradd-${PN}")
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun    if scriptfile:
158*4882a593Smuzhiyun        bb.utils.mkdirhier(os.path.dirname(scriptfile))
159*4882a593Smuzhiyun        with open(scriptfile, 'w') as script:
160*4882a593Smuzhiyun            script.write("#!/bin/sh\n")
161*4882a593Smuzhiyun            bb.data.emit_func("useradd_sysroot", script, d)
162*4882a593Smuzhiyun            script.write("useradd_sysroot\n")
163*4882a593Smuzhiyun        os.chmod(scriptfile, 0o755)
164*4882a593Smuzhiyun}
165*4882a593Smuzhiyun
166*4882a593Smuzhiyundo_prepare_recipe_sysroot[postfuncs] += "${SYSROOTFUNC}"
167*4882a593SmuzhiyunSYSROOTFUNC:class-target = "useradd_sysroot_sstate"
168*4882a593SmuzhiyunSYSROOTFUNC = ""
169*4882a593Smuzhiyun
170*4882a593SmuzhiyunSYSROOT_PREPROCESS_FUNCS += "${SYSROOTFUNC}"
171*4882a593Smuzhiyun
172*4882a593SmuzhiyunSSTATEPREINSTFUNCS:append:class-target = " useradd_sysroot_sstate"
173*4882a593Smuzhiyun
174*4882a593Smuzhiyundo_package_setscene[depends] += "${USERADDSETSCENEDEPS}"
175*4882a593Smuzhiyundo_populate_sysroot_setscene[depends] += "${USERADDSETSCENEDEPS}"
176*4882a593SmuzhiyunUSERADDSETSCENEDEPS: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"
177*4882a593SmuzhiyunUSERADDSETSCENEDEPS = ""
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun# Recipe parse-time sanity checks
180*4882a593Smuzhiyundef update_useradd_after_parse(d):
181*4882a593Smuzhiyun    useradd_packages = d.getVar('USERADD_PACKAGES')
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun    if not useradd_packages:
184*4882a593Smuzhiyun        bb.fatal("%s inherits useradd but doesn't set USERADD_PACKAGES" % d.getVar('FILE', False))
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun    for pkg in useradd_packages.split():
187*4882a593Smuzhiyun        d.appendVarFlag("do_populate_sysroot", "vardeps", "USERADD_PARAM:%s GROUPADD_PARAM:%s GROUPMEMS_PARAM:%s" % (pkg, pkg, pkg))
188*4882a593Smuzhiyun        if not d.getVar('USERADD_PARAM:%s' % pkg) and not d.getVar('GROUPADD_PARAM:%s' % pkg) and not d.getVar('GROUPMEMS_PARAM:%s' % pkg):
189*4882a593Smuzhiyun            bb.fatal("%s inherits useradd but doesn't set USERADD_PARAM, GROUPADD_PARAM or GROUPMEMS_PARAM for package %s" % (d.getVar('FILE', False), pkg))
190*4882a593Smuzhiyun
191*4882a593Smuzhiyunpython __anonymous() {
192*4882a593Smuzhiyun    if not bb.data.inherits_class('nativesdk', d) \
193*4882a593Smuzhiyun        and not bb.data.inherits_class('native', d):
194*4882a593Smuzhiyun        update_useradd_after_parse(d)
195*4882a593Smuzhiyun}
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun# Return a single [GROUP|USER]ADD_PARAM formatted string which includes the
198*4882a593Smuzhiyun# [group|user]add parameters for all USERADD_PACKAGES in this recipe
199*4882a593Smuzhiyundef get_all_cmd_params(d, cmd_type):
200*4882a593Smuzhiyun    import string
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun    param_type = cmd_type.upper() + "_PARAM:%s"
203*4882a593Smuzhiyun    params = []
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun    useradd_packages = d.getVar('USERADD_PACKAGES') or ""
206*4882a593Smuzhiyun    for pkg in useradd_packages.split():
207*4882a593Smuzhiyun        param = d.getVar(param_type % pkg)
208*4882a593Smuzhiyun        if param:
209*4882a593Smuzhiyun            params.append(param.rstrip(" ;"))
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun    return "; ".join(params)
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun# Adds the preinst script into generated packages
214*4882a593Smuzhiyunfakeroot python populate_packages:prepend () {
215*4882a593Smuzhiyun    def update_useradd_package(pkg):
216*4882a593Smuzhiyun        bb.debug(1, 'adding user/group calls to preinst for %s' % pkg)
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun        """
219*4882a593Smuzhiyun        useradd preinst is appended here because pkg_preinst may be
220*4882a593Smuzhiyun        required to execute on the target. Not doing so may cause
221*4882a593Smuzhiyun        useradd preinst to be invoked twice, causing unwanted warnings.
222*4882a593Smuzhiyun        """
223*4882a593Smuzhiyun        preinst = d.getVar('pkg_preinst:%s' % pkg) or d.getVar('pkg_preinst')
224*4882a593Smuzhiyun        if not preinst:
225*4882a593Smuzhiyun            preinst = '#!/bin/sh\n'
226*4882a593Smuzhiyun        preinst += 'bbnote () {\n\techo "NOTE: $*"\n}\n'
227*4882a593Smuzhiyun        preinst += 'bbwarn () {\n\techo "WARNING: $*"\n}\n'
228*4882a593Smuzhiyun        preinst += 'bbfatal () {\n\techo "ERROR: $*"\n\texit 1\n}\n'
229*4882a593Smuzhiyun        preinst += 'perform_groupadd () {\n%s}\n' % d.getVar('perform_groupadd')
230*4882a593Smuzhiyun        preinst += 'perform_useradd () {\n%s}\n' % d.getVar('perform_useradd')
231*4882a593Smuzhiyun        preinst += 'perform_groupmems () {\n%s}\n' % d.getVar('perform_groupmems')
232*4882a593Smuzhiyun        preinst += d.getVar('useradd_preinst')
233*4882a593Smuzhiyun        # Expand out the *_PARAM variables to the package specific versions
234*4882a593Smuzhiyun        for rep in ["GROUPADD_PARAM", "USERADD_PARAM", "GROUPMEMS_PARAM"]:
235*4882a593Smuzhiyun            val = d.getVar(rep + ":" + pkg) or ""
236*4882a593Smuzhiyun            preinst = preinst.replace("${" + rep + "}", val)
237*4882a593Smuzhiyun        d.setVar('pkg_preinst:%s' % pkg, preinst)
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun        # RDEPENDS setup
240*4882a593Smuzhiyun        rdepends = d.getVar("RDEPENDS:%s" % pkg) or ""
241*4882a593Smuzhiyun        rdepends += ' ' + d.getVar('MLPREFIX', False) + 'base-passwd'
242*4882a593Smuzhiyun        rdepends += ' ' + d.getVar('MLPREFIX', False) + 'shadow'
243*4882a593Smuzhiyun        # base-files is where the default /etc/skel is packaged
244*4882a593Smuzhiyun        rdepends += ' ' + d.getVar('MLPREFIX', False) + 'base-files'
245*4882a593Smuzhiyun        d.setVar("RDEPENDS:%s" % pkg, rdepends)
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun    # Add the user/group preinstall scripts and RDEPENDS requirements
248*4882a593Smuzhiyun    # to packages specified by USERADD_PACKAGES
249*4882a593Smuzhiyun    if not bb.data.inherits_class('nativesdk', d) \
250*4882a593Smuzhiyun        and not bb.data.inherits_class('native', d):
251*4882a593Smuzhiyun        useradd_packages = d.getVar('USERADD_PACKAGES') or ""
252*4882a593Smuzhiyun        for pkg in useradd_packages.split():
253*4882a593Smuzhiyun            update_useradd_package(pkg)
254*4882a593Smuzhiyun}
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun# Use the following to extend the useradd with custom functions
257*4882a593SmuzhiyunUSERADDEXTENSION ?= ""
258*4882a593Smuzhiyun
259*4882a593Smuzhiyuninherit ${USERADDEXTENSION}
260