Search code examples
embedded-linuxyocto

Is there a way to create a link for the machine ID without modifying Yocto?


I am running Linux 4.14.149 built with Yocto Zeus (3.0.0). I am running a read only filesystem, and recently found an issue where my UID (/etc/machine-id)was getting changed every boot (a result of this question - https://superuser.com/questions/1668481/dhcpd-doesnt-issue-the-same-lease-after-reboot ).

I am trying to make that file a link to the user-data partition so it will persist across reboots. I have tried making the link as part of a base-files_%.bbappend which is the way I made the link for the hostname (which works). This is the contents of that file (/var/local is our user data partition with is mounted RW in the init script):

FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"

hostname = ""
machine-id = ""

do_install_append() {
    ln -sfn /var/local/etc/hostname ${D}/${sysconfdir}/hostname
    ln -sfn /var/local/etc/machine-id ${D}/${sysconfdir}/machine-id
}

But I am seeing the following error when I tried to build that:

Exception: bb.process.ExecutionError: Execution of '/home/gen-ccm-root/workdir/tools/poky/build-dev/tmp/work/mi_nhep-poky-linux-gnueabi/mi-dev/1.0-r0/temp/run.read_only_rootfs_hook.50286' failed with exit code 1:
touch: cannot touch '/home/gen-ccm-root/workdir/tools/poky/build-dev/tmp/work/mi_nhep-poky-linux-gnueabi/mi-dev/1.0-r0/rootfs/etc/machine-id': No such file or directory
WARNING: exit code 1 from a shell command.

It turns out there are two things that touch that file; the rootfs-postcommands.bbclass and the systemctl python script (found in meta/recipes-core/systemd/systemd-systemctl/systemctl), the former of which (I think) is causing the error. It is failing in the do_rootfs step.

What is the best way to create this link? If there is a choice, I would rather not modify Yocto sources if that is possible.


Solution

  • You can do this by defining your own rootfs post-command, and appending it to ROOTFS_POSTPROCESS_COMMAND so that it runs after Yocto's built-in read_only_rootfs_hook that creates the empty /etc/machine-id file using touch.

    # setup-machine-id-symlink.bbclass
    
    ROOTFS_POSTPROCESS_COMMAND += "install_machine_id_symlink ;"
    install_machine_id_symlink () {
        ln -sfn /var/local/etc/machine-id ${IMAGE_ROOTFS}/etc/machine-id
    }
    
    
    # your-image.bb
    
    inherit setup-machine-id-symlink
    

    The Image Generation docs have more detail on how postprocessing commands are applied during the build.

    Note: You will need to ensure that your persistent partition is mounted early, so that reading /etc/machine-id doesn't result in a broken symlink.


    Alternatively, use bind mounts:

    You could also do this at runtime by installing a systemd service that runs early in the boot sequence and bind mounts your persistent machine-id over the blank one provided by Yocto in the rootfs.

    Using a systemd service (rather than a bind mount entry in /etc/fstab) is necessary because you will need to ensure the persistent machine-id file actually exists before creating the bind mount. Though, you may be able to make use of tmpfiles.d to do that instead.