Advice on converting SysVinit file to Systemd services will be helpful.
Currently, I am using a systemv init script which will be executed after every boot on my STM32MP1 based Avenger96 board. Now I have to switch to Systemd from SysVinit. But I am not sure how to convert the init file to relevant systemd files. I am using Yocto with Ubuntu20.04 as build system. If someone help me to get started would be really great. Below is the init script and image recipe which establishes symlink to the init script.
custom-script.sh which is installed in etc/init.d/ directory of the rootfs.
#!/bin/sh
DAEMON="swupdate"
PIDFILE="/var/run/$DAEMON.pid"
PART_STATUS=$(sgdisk -A 4:get:2 /dev/mmcblk0)
if test "${PART_STATUS}" = "4:2:1" ; then
ROOTFS=rootfs-2
else
ROOTFS=rootfs-1
fi
if test -f /update-ok ; then
SURICATTA_ARGS="-c 2"
rm -f /update-ok
fi
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -q -m -S -p "$PIDFILE" -x "/usr/bin/$DAEMON" \
-- -f /etc/swupdate/swupdate.cfg -L -e rootfs,${ROOTFS} -u "${SURICATTA_ARGS}"
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac
Image recipe which creates init.d dir and installs above script and also establishes symlink to rc4.d dir.
custom-image.bb
.
.
inherit update-rc.d
SRC_URI = "file://custom-script.sh \
"
S = "${WORKDIR}"
INITSCRIPT_PACKAGES = "${PN}"
INITSCRIPT_NAME = "custom-script.sh"
INITSCRIPT_PARAMS = "start 99 2 3 4 5 . "
do_install_append() {
install -d ${D}${sysconfdir}/rc4.d
install -d 644 ${D}${sysconfdir}/init.d
install -m 0755 ${WORKDIR}/custom-script.sh ${D}${sysconfdir}/init.d
ln -sf ../init.d/custom-script.sh ${D}${sysconfdir}/rc4.d/S99custom-script.sh
ln -sf ../init.d/custom-script.sh ${D}${sysconfdir}/rc4.d/K99custom-script.sh
}
FILES_${PN} += "${sysconfdir}/init.d"
Now I am trying to do the same functionality of custom-script.sh with systemd. Is it possible to make use of systemd-sysv-generator in this case?
Also, will the dir init.d completely removed once we switch to "systemd"? What will happen to other files which are present in etc/init.d?
Can anyone please help me get started?
Your help will be much appreciated.
Thanks in advance.
P.S: Please let me know if any info is missing here.
/etc/init.d will not get deleted by using systemd
Have you checked /etc/systemd and /usr/lib/systemd on your Ubuntu machine for examples of systemd scripts. Along the manual pages of systemd, you should have enough examples to convert your sysv init script to systemd.
I am using the bash trap to make sure one function runs at any cost. I know trap is not specific to exitO or 1. Here is what I have done.
#!/bin/bash
set -e
#array to store server and deployed status
declare -A server_deployed
#path to file containing the server inventory
readonly filepath="/var/jenkins_home/workspace/server_list.txt"
#array to store to list of IPS
declare -A result #associative array
if [[ $TARGET == "ALL" ]]; then
while read line ; do
server_name=` echo $line | cut -d= -f1 `
result+=(["$server_name"]=${line#*=})
done < $filepath
else
singleserver=`cat $filepath | grep "$TARGET"`
server_name=`echo $singleserver| cut -d= -f1 ` # get the servername
serverip=`echo $singleserver| cut -d= -f2 ` # get tje server ip
result+=(["$server_name"]=$serverip) # gets the ip which is after equalto
fi
#function to send slack notification everytime
function sendMessage(){
for sd in "${!server_deployed[#]}"
do
echo "#########################################################"
echo "Sucecssfully deployed on $sd"
echo "#########################################################"
done
#let find the unsuccess list ,for which we need to find the array diff
for server_name in "${!result[#]}"
do
for sd in "${!server_deployed[#]}"
do
if [[ "$server_name" != "$sd" ]]; then
echo "Failed to deploy on $server_name"
fi
done
done
}
trap "sendMessage" INT EXIT
for server in "${!result[#]}"
do
upstream="MBM-TEST-ADMIN-BUILD"
#bundle filename
bundle="mbm_admin_dist"
name=$server
instance=${result[$name]}
#------copying the hash.php in build job to the deployed server home location
# ssh and move to desired location
sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null /tmp/test/admin_hash.json ubuntu#$instance:/home/ubuntu/
mbmcms_workspace="/var/jenkins_home/workspace/$upstream"
cd $mbmcms_workspace
#remove if exist
if [ -e "$bundle.zip" ]
then
echo "Already Exist so Removing it First !!"
rm -f $bundle.zip
fi
#check if the dist folder exist that comes from successful build
if [ ! -d "dist" ]; then
echo "--------------------------------------------------------------"
echo "The dist folder does not exist, Please run BUILD job First !!"
echo "--------------------------------------------------------------"
exit 1
fi
#zip the file from the TEST & Build jobs
echo "starting to zip mbm-admin dist file created after test and build success!!"
zip --symlinks -x *.git* -r $bundle ./dist
#---------------------------------------------------------------
# copy development.php if non-production else copy production.php
# the file goes to the view/cms/
#---------------------------------------------------------------
sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null development.php ubuntu#$instance:/home/ubuntu
sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null production.php ubuntu#$instance:/home/ubuntu
#copy the bundle file to instance
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r $bundle.zip ubuntu#$instance:/home/ubuntu/
ssh -tt -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu#$instance '
SOURCE_FOLDER='/home/ubuntu/mbm-admin/dist/'
DESTINATION_FOLDER='/home/ubuntu/wpdata/plugins/manager/app/views/admin/admin_console/dist/'
rm -rf mbm-admin
mkdir -p mbm-admin
mv mbm_admin_dist.zip mbm-admin
cd mbm-admin
unzip mbm_admin_dist.zip
rm -f mbm_admin_dist.zip
sudo rsync -arz --force --delete --progress $SOURCE_FOLDER $DESTINATION_FOLDER
#moving the copied file to the /app/views/admin/admin_console
sudo mv /home/ubuntu/development.php /home/ubuntu/wpdata/plugins/manager/app/views/admin/admin_console
sudo mv /home/ubuntu/production.php /home/ubuntu/wpdata/plugins/manager/app/views/admin/admin_console
#moving the hash.php to the desired location
sudo cp -fv /home/ubuntu/admin_hash.json /home/ubuntu/wpdata/plugins/manager/app/views/admin/admin_console/hash.json
'
server_deployed+=(["$server"]="SUCCESS")
done
Here is the trap , as seen the script section
trap "sendMessage" INT EXIT
I need to run the sendMessage function whenever some exit code is
detected or the program exits due to any error.
Problem:
When I put the exit 1 at the end of the script the function gets called by the trap but suppose, If I put it somewhere in the middle or exactly after the main for loop starts the trap does not catch the exit code.
What am I not understanding or missing exactly in here?
I'm working on a script to automate the creation of a .gitconfig file.
This is my main script that calls a function which in turn execute another file.
dotfile.sh
COMMAND_NAME=$1
shift
ARG_NAME=$#
set +a
fail() {
echo "";
printf "\r[${RED}FAIL${RESET}] $1\n";
echo "";
exit 1;
}
set -a
sub_setup() {
info "This may overwrite existing files in your computer. Are you sure? (y/n)";
read -p "" -n 1;
echo "";
if [[ $REPLY =~ ^[Yy]$ ]]; then
for ARG in $ARG_NAME; do
local SCRIPT="~/dotfiles/setup/${ARG}.sh";
[ -f "$SCRIPT" ] && echo "Applying '$ARG'" && . "$SCRIPT" || fail "Unable to find script '$ARG'";
done;
fi;
}
case $COMMAND_NAME in
"" | "-h" | "--help")
sub_help;
;;
*)
CMD=${COMMAND_NAME/*-/}
sub_${CMD} $ARG_NAME 2> /dev/null;
if [ $? = 127 ]; then
fail "'$CMD' is not a known command or has errors.";
fi;
;;
esac;
git.sh
git_config() {
if [ ! -f "~/dotfiles/git/gitconfig_template" ]; then
fail "No gitconfig_template file found in ~/dotfiles/git/";
elif [ -f "~/dotfiles/.gitconfig" ]; then
fail ".gitconfig already exists. Delete the file and retry.";
else
echo "Setting up .gitconfig";
GIT_CREDENTIAL="cache"
[ "$(uname -s)" == "Darwin" ] && GIT_CREDENTIAL="osxkeychain";
user " - What is your GitHub author name?";
read -e GIT_AUTHORNAME;
user " - What is your GitHub author email?";
read -e GIT_AUTHOREMAIL;
user " - What is your GitHub username?";
read -e GIT_USERNAME;
if sed -e "s/AUTHORNAME/$GIT_AUTHORNAME/g" \
-e "s/AUTHOREMAIL/$GIT_AUTHOREMAIL/g" \
-e "s/USERNAME/$GIT_USERNAME/g" \
-e "s/GIT_CREDENTIAL_HELPER/$GIT_CREDENTIAL/g" \
"~/dotfiles/git/gitconfig_template" > "~/dotfiles/.gitconfig"; then
success ".gitconfig has been setup";
else
fail ".gitconfig has not been setup";
fi;
fi;
}
git_config
In the console
$ ./dotfile.sh --setup git
[ ?? ] This may overwrite existing files in your computer. Are you sure? (y/n)
y
Applying 'git'
Setting up .gitconfig
[ .. ] - What is your GitHub author name?
Then I cannot see what I'm typing...
At the bottom of dotfile.sh, I redirect any error that occurs during my function call to /dev/null. But I should normally see what I'm typing. If I remove 2> /dev/null from this line sub_${CMD} $ARG_NAME 2> /dev/null;, it works!! But I don't understand why.
I need this line to prevent my script to echo an error in case my command doesn't exists. I only want my own message.
e.g.
$ ./dotfile --blahblah
./dotfiles: line 153: sub_blahblah: command not found
[FAIL] 'blahblah' is not a known command or has errors
I really don't understand why the input in my sub script is redirected to /dev/null as I mentioned only stderr to be redirected to /dev/null.
Thanks
Do you need the -e option in your read statements?
I did a quick test in an interactive shell. The following command does not echo characters :
read -e TEST 2>/dev/null
The following does echo the characters
read TEST 2>/dev/null
Does somebody how to change the max-job size of beanstalkd ?
I have the problem that I get the message JOB_TOO_BIG and at Adding Job to beanstalkd, it says that the default size is 65k.
Does somebody know how to change that ?
EDIT:
my beanstalkd init-script in the folder /etc/init.d looks like the following (I added the -z option to increase the job size):
#!/bin/sh
#
# Copyright (c) 2007 Javier Fernandez-Sanguino <jfs#debian.org>
#
# This is free software; you may redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2,
# or (at your option) any later version.
#
# This is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License with
# the Debian operating system, in /usr/share/common-licenses/GPL; if
# not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
#
### BEGIN INIT INFO
# Provides: beanstalkd
# Required-Start: $remote_fs $network $local_fs
# Required-Stop: $remote_fs $network $local_fs
# Should-Start: $named
# Should-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: in-memory workqueue service
# Description: beanstalk is a simple, fast, queueing server. Its
# interface is generic, but was originally designed
# for reducing the latency of page views in high-volume
# web applications by running time-consuming tasks
# asynchronously.
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/beanstalkd # Introduce the server's location here
NAME=beanstalkd # Introduce the short server's name here
DESC="in-memory queueing server" # Introduce a short description here
LOGDIR=/var/log/beanstalkd # Log directory to use
BEANSTALKD_LISTEN_ADDR=0.0.0.0
BEANSTALKD_LISTEN_PORT=11300
PIDFILE=/var/run/$NAME.pid
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
# Default options, these can be overriden by the information
# at /etc/default/$NAME
DAEMON_OPTS="-l $BEANSTALKD_LISTEN_ADDR -p $BEANSTALKD_LISTEN_PORT -z 550000000000" # Additional options given to the server
#DIETIME=10 # Time to wait for the server to die, in seconds
# If this value is set too low you might not
# let some servers to die gracefully and
# 'restart' will not work
STARTTIME=1 # Time to wait for the server to start, in seconds
# If this value is set each time the server is
# started (on start or restart) the script will
# stall to try to determine if it is running
# If it is not set and the server takes time
# to setup a pid file the log message might
# be a false positive (says it did not start
# when it actually did)
#LOGFILE=$LOGDIR/$NAME.log # Server logfile
DAEMONUSER=root #beanstalkd # Users to run the daemons as. If this value
# is set start-stop-daemon will chuid the server
# Include defaults if available
if [ -f /etc/default/$NAME ] ; then
. /etc/default/$NAME
fi
# Check that the user exists (if we set a user)
# Does the user exist?
if [ -n "$DAEMONUSER" ] ; then
if getent passwd | grep -q "^$DAEMONUSER:"; then
# Obtain the uid and gid
DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'`
DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'`
else
log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist."
exit 0
fi
fi
set -e
running_pid() {
# Check if a given process pid's cmdline matches a given name
pid=$1
name=$2
[ -z "$pid" ] && return 1
[ ! -d /proc/$pid ] && return 1
cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
# Is this the expected server
[ "$cmd" != "$name" ] && return 1
return 0
}
running() {
# Check if the process is running looking at /proc
# (works for all users)
# No pidfile, probably no daemon present
[ ! -f "$PIDFILE" ] && return 1
pid=`cat $PIDFILE`
running_pid $pid $DAEMON || return 1
return 0
}
start_server() {
# Start the process using the wrapper
if [ "x$START" != "xyes" -a "x$START" != "xtrue" ]; then
echo ""
echo "beanstalkd not configured to start, please edit /etc/default/beanstalkd to enable"
exit 0
fi
if [ -z "$DAEMONUSER" ] ; then
start_daemon -p $PIDFILE $DAEMON $DAEMON_OPTS
errcode=$?
else
# if we are using a daemonuser then change the user id
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--chuid $DAEMONUSER --make-pidfile --oknodo \
--background --exec $DAEMON -- $DAEMON_OPTS
errcode=$?
fi
return $errcode
}
stop_server() {
# Stop the process using the wrapper
if [ -z "$DAEMONUSER" ] ; then
killproc -p $PIDFILE $DAEMON
errcode=$?
else
# if we are using a daemonuser then look for process that match
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
--user $DAEMONUSER \
--exec $DAEMON
errcode=$?
fi
rm -f $PIDFILE
return $errcode
}
reload_server() {
[ ! -f "$PIDFILE" ] && return 1
pid=pidofproc $PIDFILE # This is the daemon's pid
# Send a SIGHUP
kill -1 $pid
return $?
}
force_stop() {
# Force the process to die killing it manually
[ ! -e "$PIDFILE" ] && return
if running ; then
kill -15 $pid
# Is it really dead?
sleep "$DIETIME"s
if running ; then
kill -9 $pid
sleep "$DIETIME"s
if running ; then
echo "Cannot kill $NAME (pid=$pid)!"
exit 0
fi
fi
fi
rm -f $PIDFILE
}
case "$1" in
start)
log_daemon_msg "Starting $DESC " "$NAME"
# Check if it's running first
if running ; then
log_progress_msg "apparently already running"
log_end_msg 0
exit 0
fi
if start_server ; then
# NOTE: Some servers might die some time after they start,
# this code will detect this issue if STARTTIME is set
# to a reasonable value
[ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time
if running ; then
# It's ok, the server started and is running
log_end_msg 0
else
# It is not running after we did start
log_end_msg 1
fi
else
# Either we could not start it
log_end_msg 1
fi
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
if running ; then
# Only stop the server if we see it running
errcode=0
stop_server || errcode=$?
log_end_msg $errcode
else
# If it's not running don't do anything
log_progress_msg "apparently not running"
log_end_msg 0
exit 0
fi
;;
force-stop)
# First try to stop gracefully the program
$0 stop
if running; then
# If it's still running try to kill it more forcefully
log_daemon_msg "Stopping (force) $DESC" "$NAME"
errcode=0
force_stop || errcode=$?
log_end_msg $errcode
fi
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
errcode=0
stop_server || errcode=$?
# Wait some sensible amount, some server need this
[ -n "$DIETIME" ] && sleep $DIETIME
start_server || errcode=$?
[ -n "$STARTTIME" ] && sleep $STARTTIME
running || errcode=$?
log_end_msg $errcode
;;
status)
log_daemon_msg "Checking status of $DESC" "$NAME"
if running ; then
log_progress_msg "running"
log_end_msg 0
else
log_progress_msg "apparently not running ... "
log_end_msg 1
exit 0
fi
;;
reload)
log_warning_msg "Reloading $NAME daemon: not implemented (use restart)."
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0
And my beanstalkd.conf file which is in the folder /etc/default looks like the following:
## Defaults for the beanstalkd init script, /etc/init.d/beanstalkd on
## Debian systems. Append "-b /var/lib/beanstalkd" for persistent
## storage.
BEANSTALKD_LISTEN_ADDR=0.0.0.0
BEANSTALKD_LISTEN_PORT=11300
# create the journal path before use !!!
BEANSTALKD_JOURNAL_PATH="/var/lib/beanstalkd"
DAEMON_OPTS="-l $BEANSTALKD_LISTEN_ADDR -p $BEANSTALKD_LISTEN_PORT -z 550000000000 -b $BEANSTALKD_JOURNAL_PATH -V"
## Uncomment to enable startup during boot.
START=yes
best regards,
The answer by slickorange in the following link might help you:
JOB_TOO_BIG Pheanstalk - what can be done?
The size of beanstalkd job can be increased by adding the following line (or uncomment the existing BEANSTALKD_EXTRA line and edit it):
BEANSTALKD_EXTRA="-z 524280"
The size is specified in bytes, default size being 65535 bytes.
Restart beanstalkd after making the change:
sudo service beanstalkd restart
On Debian 8.7 x64 editing the settings in /etc/default/beanstalkd works. A bug probably.
I have systemctl in Debian 8 and my config looks slightly different from what is suggested here in other answers to increase the limit. This is what I did:
Edit the beanstalkd file in:
nano /etc/sysconfig/beanstalkd
Then increase the limit for MAX_JOB_SIZE from default 65535 to 524280
MAX_JOB_SIZE=-z 524280
Restart beanstalkd and check the status:
service beanstalkd restart
systemctl status beanstalkd
There are settings for the daemon
-b DIR wal directory
-f MS fsync at most once every MS milliseconds (use -f0 for "always fsync")
-F never fsync (default)
-l ADDR listen on address (default is 0.0.0.0)
-p PORT listen on port (default is 11300)
-u USER become user and group
-z BYTES set the maximum job size in bytes (default is 65535)
-s BYTES set the size of each wal file (default is 10485760)
(will be rounded up to a multiple of 512 bytes)
-c compact the binlog (default)
-n do not compact the binlog
-v show version information
-V increase verbosity
-h show this help
So based on your Linux, you should find out where this is kept and change it. Usually it's under beanstalkd.conf
I saw an interesting 'read' loop in an init.d script for CentOS that can be boiled down to essentially this structure:
cat "somefile" | while read var1 var2; do
# do something with vars 1 and 2
done 3<&1
I experimentally took off the "3<&1" redirect and nothing changed in the execution or behavior... What does the final redirect "3<&1" achieve, and why is it done specifically at the end of the loop?
Below you'll find full init script, it's for Gazzang's zNcrypt service that handles key management for encrypted filesystems. The part I'm interested in occur towards the end of the 'start' and 'stop' cases.
#! /bin/sh
#
# zncrypt This script mount and umount all zncrypt directories
#
# chkconfig: - 64 36
# description: zNcrypt start script.
. /etc/rc.d/init.d/functions
if [ -r /usr/lib/zncrypt/zncrypt.functions ]; then
. /usr/lib/zncrypt/zncrypt.functions
else
echo "/usr/lib/zncrypt/zncrypt.functions: File does not exist."
exit 0
fi
ZNCRYPT_LOG_DIR="/var/log/zncrypt"
ZNCRYPT_LOG_ACCESS_FILE=$ZNCRYPT_LOG_DIR"/access.log"
# create zncrypt log directory
mkdir -p "$ZNCRYPT_LOG_DIR"
# create access log file for the kernel module
touch "$ZNCRYPT_LOG_ACCESS_FILE"
case "$1" in
start)
echo "Starting zNcrypt directories"
egrep -v "^[[:space:]]*(#|$)" "$ZTABFILE" | while read mnt src type opts; do
if ! df "$mnt" | grep "$mnt$" >/dev/null; then
action $" * Mounting $src ... " do_mount "$src" "$mnt" "$type" "$opts" < /dev/tty
fi
done 3<&1
;;
stop)
echo "Stopping zNcrypt directories"
egrep -v "^[[:space:]]*(#|$)" "$ZTABFILE" | while read mnt src type opts; do
if df "$mnt" | grep "$mnt$" >/dev/null; then
action $" * Umounting $src ... " do_umount "$mnt"
fi
done 3<&1
if /sbin/lsmod | grep ^zncryptfs &>/dev/null; then
action $" * Unloading module ... " /sbin/rmmod zncryptfs 2>/dev/null && rm /dev/zncrypt 2>/dev/null
fi
;;
status)
show_status
;;
restart)
/bin/bash $0 stop
sleep 1
/bin/bash $0 start
;;
reload|force-reload)
;;
force-start)
;;
*)
echo "Usage: `basename $0` {start|stop|status|restart}"
exit 1
;;
esac
3<&1 tells the bash shell to redirect anything coming from stdout (file descriptor 1) to file descriptor 3. File descriptor 3 would correspond to some file or device opened in the context of the cat/while construct. See this article on standard file descriptors. Also see this related post.