Yocto recipe to update /etc/fstab - yocto

I'm having trouble updating the /etc/fstab of my Linux distribution, when building it with Yocto. I'm pretty new to Yocto, so maybe I'm off my rocker.
My latest attempt is to add a recipe named base-files_%.bbappend.
mount_smackfs () {
cat >> ${IMAGE_ROOTFS}/etc/fstab <<EOF
# Generated from smack-userspace
smackfs /smack smackfs smackfsdefault=* 0 0
EOF
}
ROOTFS_POSTPROCESS_COMMAND += "mount_smackfs; "
But, the output /etc/fstab on the distribution hasn't changed. So the questions are:
Is there a better way to do this?
How can I tell if my .bbappend file was actually executed?

ROOTFS_POSTPROCESS_COMMAND is handled in image recipes and not in package recipes. You have 2 possibilities.
Update your fstab in base-files_%.bbappend:
do_install_append () {
cat >> ${D}${sysconfdir}/fstab <<EOF
# Generated from smack-userspace
smackfs /smack smackfs smackfsdefault=* 0 0
EOF
}
Update the fstab in your image's recipe: In this case, you just append
what you wrote above (in your post) in the image's recipe.

Create a new layer using
yocto-layer create mylayer
inside it, create a folder called recipes-core and inside this folder
create another folder called base-files.
Inside this folder create a file called base-files_%.bbappend, with the following content:
FILESEXTRAPATHS_append := "${THISDIR}/${PN}:"
Create another folder called base-files, inside which you should put a file called fstab with your configurations.
Make sure to enable your new layer in the bblayers.conf and it will work correctly, no need to create any append recipe or thing.
I had this issue and solved it using this method today.

Given the following directory structure:
.
└── recipes-core/
└── base-files/
├── base-files/
│ └── fstab
└── base-files_%.bbappend
and the following content for the recipe base-files_%.bbappend in question
DESCRIPTION = "Allows to customize the fstab"
PR = "r0"
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
SRC_URI += " \
file://fstab \
"
do_install_append(){
install -m 0644 ${WORKDIR}/fstab ${D}${sysconfdir}/
}
You can specify the fstab you want in that file and include this in your own custom layer. Once the compilation is finished you will have the custom fstab on the target system.

Related

how to get ${THISDIR} inside do_unpack_append in .bbappend file

I'm attempting to replace a file from another layer with a .bbappend file. My goal is to overwrite a specific configuration file with a customized one during the unpack stage.
In my .bbappend I'm attempting to append the do_unpack to copy a file from the same directory as the .bbappend file into the working directory ${WORKDIR} The problem is: When inside do_unpack_append, ${THISDIR} is returning the directory of the original .bb recipe, rather than the directory of .bbappend
Here's an example:
The original recipe resides in: meta-origLayer/recipe.bb
My *.bbappend resides in: meta-newLayer/recipe.bbappend
recipe.bbappend:
`FILESEXTRAPATHS_prepend := "${THISDIR}:"`
do_unpack_append(){
bb.build.exec_func('replace_file', d)
}
replace_file(){
cp -f ${THISDIR}/fileToBeReplaced ${WORKDIR}/fileToBeReplaced
echo ${THISDIR} > ${WORKDIR}/shouldContain_meta-newLayer
}
There are two issues with recipe.bbappend:
I would expect the file shouldContain_meta-newLayer to contain meta-newLayer, but instead it contains meta-origLayer.
I'd primarily like to understand why ${THISDIR} behaves differently when placed inside do_unpack_append() from when it is used for prepending FILESEXTRAPATHS
When running bitbake, the recipe fails, producing the following error:
cp: cannot stat '/fileToBeReplaced': No such file or directory
This error occurs because fileToBeReplaced resides in a subdirectory of meta-origLayer (i.e. meta-origLayer/machine1/fileToBeReplaced) and the .bbappend expects to find the file in /fileToBeReplaced
My Question. . .
I have assumed ${THISDIR} would behave consistently within the same .bbappend, but it doesn't appear to. What is the best way to reference meta-newLayer/fileToBeReplaced from within do_unpack_append()?
This *.bbappend correctly overwrites fileToBeReplaced in the working directory during the unpack task:
FILESEXTRAPATHS_prepend := "${THISDIR}:"
SRC_URI_append += " file://fileToBeReplaced "
SAVED_DIR := "${THISDIR}"
do_unpack_append(){
bb.build.exec_func('replace_file', d)
}
replace_file(){
cp -f ${SAVED_DIR}/fileToBeReplaced ${WORKDIR}/fileToBeReplaced
}
Thanks for the explanation between bbappend parsing and execution johannes-schaub-ltb

Yocto: Install different config files based on MACHINE type or target image

I've got a couple of HW platforms (same cpu, etc.) that require different asound.conf files.
The way that I'm controlling the target platform is via the MACHINE variable and target image (i.e., MACHINE=machine_1 nice bitbake machine-1-bringup-image)
Normally, if just replacing the conf file I'd just create an alsa-state.bbappend and create a do_install_append function to replace it.
However since the different HW platforms require differ conf files I'm unsure how to handle it.
I've tried putting some logic into the append file do_install_append function but it's not working out. It's not always picking up the correct file (like it thinks that nothing has changed so that it uses the previous cached conf?)
Here's an example of one of the append files that I've tried:
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
SRC_URI += " \ file://asound_MACHINE1.conf \
file://asound_MACHINE2.conf \ "
do_install_append() {
echo " alsa-state.bbappend MACHINE: ${MACHINE}"
if [ "${MACHINE}" = "machine_1" ]; then
echo " machine_1"
echo " installing ${WORKDIR}/asound_MACHINE1.conf to ${D}${sysconfdir}/asound.conf"
install -m 644 ${WORKDIR}/asound_MACHINE1.conf {D}${sysconfdir}/asound.conf
else
echo " installing ${WORKDIR}/asound_MACHINE2.conf to ${D}${sysconfdir}/asound.conf"
install -m 644 ${WORKDIR}/asound_MACHINE2.conf ${D}${sysconfdir}/asound.conf
fi
}
I can see the correct echoes in the logs per the logic.
At any rate I don't think that the path I'm going down is the best way to deal with this.
Is there a 'standard' way to have different files installed based on either the target image or MACHINE variable?
do_install_append () {
// install common things here
}
do_install_append_machine-1 () {
// install machine-1 specific things here
}
do_install_append_machine-2 () {
// install machine-2 specific things here
}
The value of MACHINE is automatically added to OVERRIDES, which can be used at the end of a function append to have a MACHINE-specific addition to a function.
Maybe useful: https://www.yoctoproject.org/docs/2.4/mega-manual/mega-manual.html#var-OVERRIDES
You can have configuration files in machine specific directories in your particular case (just a specific configuration file for each machine). OpenEmbedded will fetch the most specific one. The directory structure in your recipe directory will look like:
files/<machine1>/asound.conf
files/<machine2>/asound.conf
And your alsa-state.bbappend will contain just one line (you don't need to change do_install because alsa-state.bb already installs asound.conf):
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
BTW: We are using that setup to have specific asound.state file per machine in our project.
Moreover, OpenEmbedded will detect that SRC_URI contains machine specific file and change the PACKAGE_ARCH accordingly, see: https://www.yoctoproject.org/docs/2.5/mega-manual/mega-manual.html#var-SRC_URI_OVERRIDES_PACKAGE_ARCH
Few more words on machine, distro or arch specific files: OE is trying to fetch the most specific file in file:// fetcher. It searches also in the directories named by distro (e.g files/<distro>/asound.conf) and architecture (e.g. armv7a, arm). It might be useful if you want to have file specific for some set of devices. More information: https://www.yoctoproject.org/docs/2.5/mega-manual/mega-manual.html#var-FILESOVERRIDES and also https://www.yoctoproject.org/docs/2.5/mega-manual/mega-manual.html#best-practices-to-follow-when-creating-layers (section "Place Machine-Specific Files in Machine-Specific Locations")
The above answer by clsulliv worked better than advertised. For future reference below is the append file I used:
FILESEXTRAPATHS_prepend:= "${THISDIR}/${PN}:"
SRC_URI += " \
file://machine1_asound.conf \
file://machine2_asound.conf \
"
do_install_append_machine1() {
echo " machine1"
echo " installing ${WORKDIR}/machine1_asound.conf to ${D}${sysconfdir}/asound.conf"
install -m 644 ${WORKDIR}/machine1_asound.conf ${D}${sysconfdir}/asound.conf
}
do_install_append_machine2() {
echo " machine2"
echo " installing ${WORKDIR}/machine2_asound.conf to ${D}${sysconfdir}/asound.conf"
install -m 644 ${WORKDIR}/machine2_asound.conf ${D}${sysconfdir}/asound.conf
}
Thanks for the help!

How do I add script files to a Raspberry Pi filesystem using a custom Yocto recipe?

I have a working Yocto image for a RaspberryPi3. I want to add 3 script files /etc/ppp/peers/. I would have thought that adding non-compiled files to the root file-system was a fairly generic thing to do but the only examples I can find are using compiled files and inheriting the autotools recipe.
Is there an example of how to add text files or script files to a Yocto root filesystem this somewhere?
Either a How To write up or an existing recipe that takes a set of text files and places them onto the target's rootfs.
I must be missing something because I cannot get the file files onto the system.
I tried using do_deploy, but that puts files into my ../tmp/deploy/images/raspberrypi3/etc/ppp/ which would be helpful for scripts to aid in image deployment. It is not what I want though as the scripts need to be on the target.
Running a do_install() with or without a blank do_compile() has not resulted in things getting onto the target either. Unless there is something about using ${sysconfdir} or ${IMAGE_ROOTFS} or ${S} or ${D} or ${DEPLOYDIR} or ${WORKDIR} which is particular to the Pi. I'd provide an example of my script but having changed it so many times in the last two days there is not much worth of sharing just one iteration.
Anything that resembles the following with;
${IMAGE_ROOTFS} possibly substituted for ${D} or missing
do_install replaced with do_deploy.
There are probably other permutations that I have tried.
#
# Copy the ppp script files for <vendor> chips to the target filesystem
# These files are based on the details provided in
#
SUMMARY = "PPP Scripts for ..."
SECTION = "net"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
DESCRIPTION = "A set of Linux PPP scripts blar blar"
RDEPENDS_${PN} = "ppp"
SRC_URI += "file://<provider>-ppp"
SRC_URI += "file://<provider>-chat-connect"
SRC_URI += "file://<provider>-chat-disconnect"
S = "${WORKDIR}"
#PACKAGES =+ "${PN} ${PN}-staticdev"
#DEPLOYDIR = "${WORKDIR}/deploy-${PN}"
#D = "${DEPLOYDIR}"
inherit allarch
# Install script on target's root file-system
do_install () {
# Install init script and default settings
install -d ${IMAGE_ROOTFS}${sysconfdir}
install -d ${IMAGE_ROOTFS}${sysconfdir}/ppp/
install -d ${IMAGE_ROOTFS}${sysconfdir}/ppp/peers/
install -m 0755 ${S}/<provider>-ppp ${IMAGE_ROOTFS}${sysconfdir}/ppp/peers/
install -m 0755 ${S}/<provider>-chat-connect ${IMAGE_ROOTFS}${sysconfdir}/ppp/peers/
install -m 0755 ${S}/<provider>-chat-disconnect ${IMAGE_ROOTFS}${sysconfdir}/ppp/peers/
}
# Mark the files which are part of this package
FILES_${PN} += "${sysconfdir}/ppp/"
FILES_${PN} += "${sysconfdir}/ppp/peers/"
FILES_${PN} += "${sysconfdir}/ppp/peers/<provider>-ppp"
FILES_${PN} += "${sysconfdir}/ppp/peers/<provider>-chat-connect"
FILES_${PN} += "${sysconfdir}/ppp/peers/<provider>-chat-disconnect"
I can find a lot of helloworld.c and automate examples. There must be some basic ones for adding scripts somewhere? My googlefu is very weak, I blame a lingering cold.
You should be using install -m 0755 ${WORKDIR}/<provider>-ppp ${D}${sysconfdir}/ppp/peer in your recipe. Have you added the resulting package to your image recipe? You could look at ${WORKDIR}/packages-split/${PN} to confirm that your files have been properly packaged.

Post-install script on Yocto-built linux

I need to run a script on a target OS built by Yocto.
This script needs to be ran as part of the install and thus must be ran only once (either after the entire OS install or on the first boot). It cannot be ran on the host system, as it depends on the hardware IO which exists only on the target.
An additional, minor, constraint is that the rootfs is mounted as read only, but I guess that can be avoided by having the script re-mount as rw and again remount as r after the execution or something along those lines.
Any help is appreciated.
I ended up doing what shibley had written. Here's a detailed howto:
Create a new layer
Put the desired layer wherever your other layers are. Mine are in stuff directory, next to the build directory.
Make the following files/directories:
meta_mylayer
├── conf
│   └── layer.conf
└── recipes-core
└── mylayer-initscript
├── initscript.bb
└── files
├── initscript.service
└── initscript.sh
meta_mylayer is the name of your new layer.
Let's define the layer in conf/layer.conf and tell it where to search for the recipes:
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "meta-mylayer"
BBFILE_PATTERN_meta-mylayer := "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-mylayer = "99"
The recipes are defined by the name of the .bb file. This layer only has one recipe, named initscript.
initscript.bb contains the recipe information. The following recipe will add our initscript service and put the actual install script, initscript.sh, into /usr/sbin/
SUMMARY = "Initial boot script"
DESCRIPTION = "Script to do any first boot init, started as a systemd service which removes itself once finished"
LICENSE = "CLOSED"
PR = "r3"
SRC_URI = " \
file://initscript.sh \
file://initscript.service \
"
do_compile () {
}
do_install () {
install -d ${D}/${sbindir}
install -m 0755 ${WORKDIR}/initscript.sh ${D}/${sbindir}
install -d ${D}${systemd_unitdir}/system/
install -m 0644 ${WORKDIR}/initscript.service ${D}${systemd_unitdir}/system
}
NATIVE_SYSTEMD_SUPPORT = "1"
SYSTEMD_PACKAGES = "${PN}"
SYSTEMD_SERVICE_${PN} = "initscript.service"
inherit allarch systemd
install -d will create any directories needed for the specified path, while install -m 0644 will copy the specified file with 644 permissions. ${D} is the destination directory, by default it's ${WORKDIR}/image
Create the systemd service definition
I won't go into much details about how systemd works, but will rather paste the service definition:
[Unit]
Description=start initscript upon first boot
[Service]
Type=simple
ExecStart=/bin/sh -c 'sleep 5 ; /usr/sbin/initscript.sh'
Do note the script location at /usr/sbin/ - that's where it will be copied by the last line of our do_install function above.
Lastly, our initscript.sh script itself:
#!/bin/sh
logger "starting initscript"
# do some work here. Mount rootfs as rw if needed.
logger "initscript work done"
#job done, remove it from systemd services
systemctl disable initscript.service
logger "initscript disabled"
Register the layer
We need to register our new layer, so that bitbake knows it's there.
Edit the build/conf/bblayers.conf file and add the following line to the BASELAYERS variable:
${TOPDIR}/../stuff/meta-mylayer \
Now that the bitbake recognizes our layer, we need to add our recipe to the image.
Edit the build/conf/local.conf and add the initscript recipe to the IMAGE_INSTALL_append variable. Here's how it looks like when added next to the python.
IMAGE_INSTALL_append = " python initscript"
Run the build
Run the build like you usually do. For example:
bitbake angstrom-lxde-image
After you install the build and boot for the first time, your initscript.sh will be executed.
The basic approach is to write a systemd service. The service can be enabled by default as defined in the yocto recipe systemd configuration. The script or application evoked by the service will disable the service when the script/application completes - ie. systemctl disable foo. Therefore, the service will not run in future boots.
As you mentioned, the rootfs will require mounting as rw for this to work.
Thanks, this helped out. I needed to add
[Install]
WantedBy=multi-user.target
to the initscript.service to get it working
A simple solution is to use a package post/install script that stops itself running at rootfs time (exit 1 if $D is set). This will result in it running at first boot. Yes, the script will need to remount the root fs.
Besides, I don't know how to address the issue that rootfs is mounted as read-only, you can use pkg_postinst_ontarget_${PN}
Add this to one of your recipes:
pkg_postinst_ontarget_${PN}() {
#!/bin/bash
// bash script you want to run
echo Post Install Script Test > /dev/ttyS1
}
${PN} will be replaced with the package name the recipes corresponds to.
The script will be run only once, on the first boot on the target machine as a post-install script of the package.

bitbake recipe - doing a simple copy of the image

I am attempting to write a recipe that would simple copy two files (MyfileA , MyfileB) to a specific directory when the overall image is built. This is what my directory structure looks like:
MyDir/MyRecipe.bb
MyDir/files/MyfileA
MyDir/files/MyfileB
I would like the two files to be copied to a folder in home (which would not exist initially hence the directories should be created)The folder lets say is called "Testfolder"
This is what my bitbake file looks like
DESCRIPTION = "Testing Bitbake file"
PR = "r0"
SRC_URI = "file://MyfileA \
file://MyfileB "
do_install() {
install -d MyfileA ~/TestFolder/
}
Kindly let me know if I am doing something wrong here?
When i run bitbake on this I get the following
The BBPATH variable is not set and bitbake did not find a conf/bblayers.conf file in the expected location.
Maybe you accidentally invoked bitbake from the wrong directory?
DEBUG: Removed the following variables from the environment: LANG, LS_COLORS, LESSCLOSE, XDG_RUNTIME_DIR, SHLVL, SSH_TTY, OLDPWD, LESSOPEN, SSH_CLIENT, MAIL, SSH_CONNECTION, XDG_SESSION_ID, _, BUILDDIR
Any help in this regard would be appreciated.
First of all, to create your own meta-layer, you should run command yocto-layer create MyRecipe in your Yocto Environment. This is to make sure that you have all the necessary element in your meta layer. Make sure to put the new meta-layer into conf/bblayers.conf
Creating HelloWorld Recipe Video can be found here
Second, to copy a file from one to another directories.
DESCRIPTION = "Testing Bitbake file"
SECTION = "TESTING"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
PR = "r0"
SRC_URI = "file://MyfileA \
file://MyfileB "
#specify where to get the files
S = "${WORKDIR}"
inherit allarch
#create the folder in target machine
#${D} is the directory of the target machine
#move the file from working directory to the target machine
do_install() {
install -d ${D}/TestFolder
install -m ${WORKDIR}/MyfileA ${D}/TestFolder
}
To get more in details, this is my understanding of how the files move around in Yocto.
You have a directory that stored metadata in /sourced/meta-mylayer/recipes-myRecipe/. In that directory, there would be a folder with the same name as the recipe. I.E. myRecipe/ myRecipe_001.bb.
You would store the files that are related to myRecipe.bb (usually it is a patch) in myRecipe/ so that SRC_URI will get into that myRecipe/ directory to grab files. I.E. myFileA, myFileB
Then, you specify the S. This is the location in the Build Directory where unpacked recipe source code resides. By that mean, myFileA and myFileB are moved/copied to there when myRecipe builds.
Usually, S is equal to ${WORKDIR}, this is equivalent to ${TMPDIR}/work/${MULTIMACH_TARGET_SYS}/${PN}/${EXTENDPE}${PV}-${PR}
The actual directory depends on several things:
TMPDIR: The top-level build output directory
MULTIMACH_TARGET_SYS: The target system identifier
PN: The recipe name
EXTENDPE: The epoch - (if PE is not specified, which is usually the case for most recipes, then EXTENDPE is blank)
PV: The recipe version
PR: The recipe revision
After that, we inherit allarch. This class is used for architecture independent recipes/data files (usually scripts).
Then, the last thing we have to do is copy the files.
${D} is the location in the Build Directory where components are installed by do_install task. This location defaults to ${WORKDIR}/image
${WORKDIR}/image can also be described as the / directory in the target system.
Go to ${D} directory and create a folder call TestFolder
Then, copy myFileA from ${WORKDIR} to the ${D}/TestFolder
P.S. Please add comment to fix. There might be mistaken information here, cause I learned all this by myself.