Yocto: Manipulating users/groups in helper class with fakeroot/pseudo

238 Views Asked by At

Introduction

I wrote a class, call it persist-conf-files, whose purpose is to migrate certain files installed by standard recipes into a different directory and create symbolic links to those files for persistence.

The reason for this is to have a disk partition layout with a read-only, replaceable rootfs partition and a persistent storage partition. The idea is to move certain configuration files installed by a recipe into persistent storage and replace the rootfs version with a symlink. That way when the rootfs is upgraded, the symlink will point to the persistent version.

The solution should retain UID and GID settings, even those made by the useradd class. An example might be a configuration file for a system daemon service that should run as its own user and group rather than run as root.

The user inherits this class in a .bbappend file in another layer and specifies the list of files that should have this treatment inside a PERSIST_CONF_FILES variable.

The problem is that UID and GID settings are not transferred properly to the destination file.

Note that I posted a similar question to the Yocto mailing list last year that received no responses. I've added more context and details to this question.

Implementation

I implemented this logic in a Python function and added it as a task as follows. I abstracted away some details. This class should move /etc/example.conf to /persistent/example.conf while maintaining its UID and GID.

In the base recipe at meta-another-layer/recipes-support/some-package/some-package_0.1.bb:

FILES:${PN} += "${sysconfdir}/example.conf"

inherit useradd
USERADD_PACKAGES = "${PN}"
USERADD_PARAM:${PN} = "--system --home-dir /run/some_package \
                       --no-create-home --shell /sbin/nologin \
                       --user-group some_package \
                      "

do_install:append() {
    install -m 0640 ${S}/example.conf ${D}${sysconfdir}/example.conf
    chgrp -R some_package ${D}${sysconfdir}/example.conf
}

In the bbappend file in my own layer at meta-my-layer/recipes-support/some-package/some-package_%.bbappend:

PERSIST_CONF_FILES = "${sysconfdir}/example.conf"
inherit persist-conf-files

In the bbclass file at meta-my-layer/classes/persist-conf-files.bbclass:

fakeroot python persist_conf_files_copy_and_symlink() {
    import os
    import shutil
...
    for conffile in d.getVar('PERSIST_CONF_FILES').split():
        # get the path relative to `/etc`
        relfile = os.path.relpath(conffile, d.getVar('sysconfdir'))

        # compute the absolute paths to source `/etc` and destination `/persistent`
        sysconfdir_absfile = os.path.join(d.getVar('D'), d.getVar('sysconfdir'), relfile)
        destdir_absfile = os.path.join(d.getVar('D'), 'persistent', relfile)

        # copy the file including all permissions and UID/GID settings
        st = os.stat(sysconfdir_absfile)
        shutil.copy(sysconfdir_absfile, destdir_absfile)
        shutil.chown(destdir_absfile, user=st.st_uid, group=st.st_gid)

        # omitted: replace the original file with a symlink to the copied file
...

}

persist_conf_files_copy_and_symlink[depends] += "virtual/fakeroot-native:do_populate_sysroot"

do_install[postfuncs] += "${PERSISTCONFFILESINSTALLFUNCS}"

PERSISTCONFFILESINSTALLFUNCS_class-target = "persist_conf_files_copy_and_symlink"
PERSISTCONFFILESINSTALLFUNCS = ""

Problem

The problem I'm having is that UID and GID don't seem to be available to the shutil.chown function or they're not read correctly from the pseudo database when os.stat is called. Using the function as shown above, persist-conf-files.bbclass doesn't preserve the UID/GID of the original file (as known to fakeroot/pseudo) and falls back to setting UID:GID=root:root on the copied file instead. During build, bitbake prints a warning like this when building the some-package recipe:

"warning: group some_package does not exist - using root".

Any hints on how I can improve this approach? Is the problem that the system calls made by shutil/os functions aren't handled by pseudo? Should I replace this Python function with a shell function that can use fakeroot?

0

There are 0 best solutions below