Yocto: bbappend file which remove System V init script - init

I'm currently installing dnsmasq with Yocto, but I would like to remove the automatic start.
So I create a .bbappend file and I tried something like :
pkg_postinst_${PN} () {
update-rc.d dnsmasq -f remove
}
But it did not work, I don't know how to proceed to remove this init script with a bbappend file.
Thanks, Pierre-Olivier

The correct way to disable a service under SysV is with INITSCRIPT_PARAMS:
From man update-rc.d
A common system administration error is to delete the links with
the thought that this will "disable" the service, i.e., that this
will pre‐ vent the service from being started. However, if all links
have been deleted then the next time the package is upgraded,
the package's postinst script will run update-rc.d again and this
will reinstall links at their factory default locations. The correct
way to disable services is to configure the service as stopped in
all runlevels in which it is started by default. In the System V
init system this means renaming the service's symbolic links from
S to K.
Let me to reiterate
The correct way to disable services is to configure
the service as stopped in all runlevels in which it
is started by default.
But how we can know all runlevels in which a service is started by default?
Well, if "update-rc.d LSB header" does not exist for /etc/init.d/script
(which is the case for NGINX in Yocto - I use it as an example),
then it is simple:
runlevel 0 - shutdown, => by default stop a service at this runlevel
runlevel 1 - single user mode, => usually stop a service at this runlevel
runlevel 6 - reboot, => that's trivial: stop a service at this runlevel
NGINX is described by nginx.inc file under Yocto meta-openembedded layer:
meta-openembedded/meta-webserver/recipes-httpd/nginx/nginx.inc
NGINX defines initial scripts as follows in nginx.inc file:
INITSCRIPT_NAME = "nginx"
INITSCRIPT_PARAMS = "defaults 92 20"
And the resulting service Start/Kill symlinks in Yocto rootfs are:
rootfs/etc/rc0.d/K20nginx -> ../init.d/nginx # Shutdown runlevel
rootfs/etc/rc1.d/K20nginx -> ../init.d/nginx # Single user mode runlevel
rootfs/etc/rc2.d/S92nginx -> ../init.d/nginx
rootfs/etc/rc3.d/S92nginx -> ../init.d/nginx
rootfs/etc/rc4.d/S92nginx -> ../init.d/nginx
rootfs/etc/rc5.d/S92nginx -> ../init.d/nginx
rootfs/etc/rc6.d/K20nginx -> ../init.d/nginx # Reboot runlevel
Also, this is confirmed by the update-rc.d.bbclass thas executes
update-rc.d during rootfs creation. So, the way update-rc.d is
called in meta/classes/update-rc.d.bbclass file is:
update-rc.d $OPT ${INITSCRIPT_NAME} ${INITSCRIPT_PARAMS}
Bingo!
Conclusion
To disable a service in SysV under Yocto we need to define:
INITSCRIPT_PARAMS = "stop 20 0 1 6 ."
But how to verify the resulting INITSCRIPT_PARAMS?
The effective INITSCRIPT_PARAMS environment variable should
be verified before re-creating rootfs. The proper and simple way
to do it is again using the great bitbake command:
bitbake nginx -e | grep INITSCRIPT_PARAMS
Now, let's re-create the image (core-image-full-cmdline in my case):
bitbake core-image-full-cmdline
We can easily see now, that all the remaining Start/Kill symlinks are:
rootfs/etc/rc0.d/K20nginx -> ../init.d/nginx # Shutdown runlevel
rootfs/etc/rc1.d/K20nginx -> ../init.d/nginx # Single user mode runlevel
rootfs/etc/rc6.d/K20nginx -> ../init.d/nginx # Reboot runlevel
Bingo once again!

Several things:
maybe you're using systemd?
maybe you're bbappending to a wrong version of recipe?
maybe you should try update-rc.d -f dnsmasq remove (notice that -f should be in front of name)
maybe you should try overriding INITSCRIPT_PARAMS like INITSCRIPT_PARAMS = "stop 20 0 1 6 ."?

Related

How to remove getty#tty1 link in yocto dunfell branch at time of compiliation

I am building linux system for raspberrypi4 but for some reason I need to remove getty#tty1 service in yocto.
I have created systemd_%.bbappend file for that.
Host PC is Ubuntu 18.04
this is working with warrior branch
Now, I am trying to compile with dunfell branch in yocto
but at the time of systemd compiling it gives an error like
"cannot remove /etc/systemd/system/getty.target.wants/getty#tty1, no such file or deirectory
But at the end, In final image there I can see getty#tty1.service
Also I can't find any other receipe that creates this link.
systemd_%.bbappend looks like this
DESCRIPTION = "Customization of systemD services."
do_install_append() {
rm ${D}${sysconfdir}/systemd/system/getty.target.wants/getty#tty1.service
}
FILES_${PN} += "${sysconfdir}/systemd/system"
REQUIRED_DISTRO_FEATURES= "systemd"
Thanks
Margish
On more recent versions of systemd (like the one in Yocto dunfell), the links to services are not created by the build system (ninja), but instead by running systemctl preset-all on the running system after installation (see here). This command reads the systemd preset files to determine which units to enable or disable by default.
In Yocto, what this means is that instead of the links being created as part of the systemd recipe, systemctl preset-all is run as part of the IMAGE_PREPROCESS_COMMAND during image creation in image.bbclass (see here). This is why the old method of deleting the symbolic links in /etc/systemd/system from the systemd recipe no longer works.
Instead, what you need to do is modify the 90-systemd.preset file to disable the getty#tty1 preset (or any other default system service) by changing the below line:
enable getty#.service
to this:
disable getty#.service
You can accomplish this using a bbappend file as follows*:
# systemd_%.bbappend
do_install_append() {
# Disable getty#tty1 from starting at boot time.
sed -i -e "s/enable getty#.service/disable getty#.service/g" ${D}${systemd_unitdir}/system-preset/90-systemd.preset
}
*https://stackoverflow.com/a/67505478/286701

Setting up AEM6.3 as a service Linux Redhat version 7.3

I am trying to set up AEM6.3 environment as a service and following below steps. But having some issues-
I have RedHat version 7.3 linux server.
I am taking reference from here
aem file- (/usr/bin/aem)
!/bin/bash
#
# /etc/rc.d/init.d/aem6
#
#
# # of the file to the end of the tags section must begin with a #
# character. After the tags section, there should be a blank line.
# This keeps normal comments in the rest of the file from being
# mistaken for tags, should they happen to fit the pattern.>
#
# chkconfig: 35 85 15
# description: This service manages the Adobe Experience Manager java process.
# processname: aem6
# pidfile: /crx-quickstart/conf/cq.pid
# Source function library.
. /etc/rc.d/init.d/functions
SCRIPT_NAME=`basename $0`
AEM_ROOT=/mnt/crx/author
AEM_USER=root
########
BIN=${AEM_ROOT}/crx-quickstart/bin
START=${BIN}/start
STOP=${BIN}/stop
STATUS="${BIN}/status"
case "$1" in
start)
echo -n "Starting AEM services: "
su - ${AEM_USER} ${START}
touch /var/lock/subsys/$SCRIPT_NAME
;;
stop)
echo -n "Shutting down AEM services: "
su - ${AEM_USER} ${STOP}
rm -f /var/lock/subsys/$SCRIPT_NAME
;;
status)
su - ${AEM_USER} ${STATUS}
;;
restart)
su - ${AEM_USER} ${STOP}
su - ${AEM_USER} ${START}
;;
reload)
;;
*)
echo "Usage: $SCRIPT_NAME {start|stop|status|reload}"
exit 1
;;
esac
aem.system (/etc/systemd/system) (Couldn't find system.d so placed this file systemd)
[Unit]
Description=Adobe Experience Manager
[Service]
Type=simple
ExecStart=/usr/bin/aem start
ExecStop=/usr/bin/aem stop
ExecReload=/usr/bin/aem restart
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
I have provided permissions to both of these files as-
#chmod u+rwx /usr/bin/aem
#chmod u+rwx /etc/systemd/system/aem.system
When I am giving these commands-
#cd /etc/systemd/system
#systemctl enable aem.system
It's giving me below error-
#systemctl enable aem.system
**Failed to execute operation: No such file or directory**
Am I missing any step here?
Thanks!
You are correct in placing the custom unit file in /etc/systemd/system as that is the place for all unpackages files. However, your file should really be called aem.service. To the best of my knowledge, systemd does not pick up files ending in .system. On a side note: Those overly liberal filesystem permissions really are unnecessary, 755 should be more than sufficient.
Also: If there really is a /etc/init.d/aem6 file as the linked guide suggests, systemd's SysV-compatibility layer should be able to read that one in and systemctl enable --now aem6 is everything you need to do.

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.

Where to find logs for a cloud-init user-data script?

I'm initializing spot instances running a derivative of the standard Ubuntu 13.04 AMI by pasting a shell script into the user-data field.
This works. The script runs. But it's difficult to debug because I can't figure out where the output of the script is being logged, if anywhere.
I've looked in /var/log/cloud-init.log, which seems to contain a bunch of stuff that would be relevant to debugging cloud-init, itself, but nothing about my script. I grepped in /var/log and found nothing.
Is there something special I have to do to turn logging on?
The default location for cloud init user data is already /var/log/cloud-init-output.log, in AWS, DigitalOcean and most other cloud providers. You don't need to set up any additional logging to see the output.
You could create a cloud-config file (with "#cloud-config" at the top) for your userdata, use runcmd to call the script, and then enable output logging like this:
output: {all: '| tee -a /var/log/cloud-init-output.log'}
so I tried to replicate your problem. Usually I work in Cloud Config and therefore I just created a simple test user-data script like this:
#!/bin/sh
echo "Hello World. The time is now $(date -R)!" | tee /root/output.txt
echo "I am out of the output file...somewhere?"
yum search git # just for fun
ls
exit 0
Notice that, with CloudInit shell scripts, the user-data "will be executed at rc.local-like level during first boot. rc.local-like means 'very late in the boot sequence'"
After logging in into my instance (a Scientific Linux machine) I first went to /var/log/boot.log and there I found:
Hello World. The time is now Wed, 11 Sep 2013 10:21:37 +0200! I am
out of the file. Log file somewhere? Loaded plugins: changelog,
kernel-module, priorities, protectbase, security,
: tsflags, versionlock 126 packages excluded due to repository priority protections 9 packages excluded due to repository
protections ^Mepel/pkgtags
| 581 kB 00:00
=============================== N/S Matched: git =============================== ^[[1mGit^[[0;10mPython.noarch : Python ^[[1mGit^[[0;10m Library c^[[1mgit^[[0;10m.x86_64 : A fast web
interface for ^[[1mgit^[[0;10m
...
... (more yum search output)
...
bin etc lib lost+found mnt proc sbin srv tmp var
boot dev home lib64 media opt root selinux sys usr
(other unrelated stuff)
So, as you can see, my script ran and was rightly logged.
Also, as expected, I had my forced log 'output.txt' in /root/output.txt with the content:
Hello World. The time is now Wed, 11 Sep 2013 10:21:37 +0200!
So...I am not really sure what is happening in you script.
Make sure you're exiting the script with
exit 0 #or some other code
If it still doesn't work, you should provide more info, like your script, your boot.log, your /etc/rc.local, and your cloudinit.log.
btw: what is your cloudinit version?

Supervisorctl not respecting my configuration

I have set the following in /home/david/conf/supervisor.conf:
[unix_http_server]
file=/home/david/tmp/supervisor.sock
[supervisord]
logfile=/home/david/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
pidfile=/home/david/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200
childlogdir=/home/david/tmp
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///home/david/tmp/supervisor.sock
And started supervisord:
$ supervisord -c /home/david/conf/supervisor.conf
However how come supervisorctl still uses the default http://localhost:9001 as the serverurl?
$ supervisorctl
http://localhost:9001 refused connection
supervisor>
I checked /home/david/tmp and the files supervisord.log and supervisord.pid do exist.
You should run supervisorctl with -c as well. From the documentation (my emphasis):
The Supervisor configuration file is conventionally named
supervisord.conf. It is used by both supervisord and supervisorctl. If
either application is started without the -c option (the option which
is used to tell the application the configuration filename
explicitly), the application will look for a file named
supervisord.conf within the following locations, in the specified
order. It will use the first file it finds.
$CWD/supervisord.conf
$CWD/etc/supervisord.conf
/etc/supervisord.conf
In MacOS, use brew to install
brew install supervisor
Then go to /usr/local/etc/supervisord.ini and comment these lines:
;[unix_http_server]
;file=/usr/local/var/run/supervisor.sock ; the path to the socket file
and uncomment these lines:
[inet_http_server] ; inet (TCP) server disabled by default
port=127.0.0.1:9001 ; ip_address:port specifier, *:port for all iface
Finally restart the daemon:
brew services restart supervisor
That's all you need.
To add to the valid answer above make sure you are putting your config files for the apps you want to monitor under supervisor's config folder as a subfolder called conf.d. This will depend of what method you use to install supervisor, the default package manager or easy_install.
As solution you can make symbolic link to the config file.
Like this for Mac OS:
sudo ln -sv /usr/local/etc/supervisord.ini /etc/supervisord.conf