I am trying to get irTrans and LCDproc working on my machine. irTrans enables remote control functions and sends data to LCDproc. LCDproc enables display on the LCD display on my case. This is for an HTPC running SUSE 11.1 64-bit.
IrTrans has a server application called irserver. LCDproc has a daemon called LCDd. I’ve got both running correctly, but I am having a heck of a time getting startup scripts to run them. I keep getting “no such file or directory” errors in /var/log/boot.msg.
At first I thought it was a permission problem as I wasn’t able to run either program from command line. I fixed that by chmoding them to 776 and changing chgrping them to users. Prior they were root owner and group. Now I can run them at command line, but they still fail in the script. I’ve tried two incarnations of the scripts and both fail. I’ll attach both below. Strangely, I’ve been unable to find much of anything about using PATH variables in startup scripts googling.
This one is my attempt to create a script from the skeleton template.
#!/bin/sh
#
# /etc/init.d/irserver
# and its symbolic link
# /(usr/)local/irtrans/irserver
#
### BEGIN INIT INFO
# Provides: irserver
# Required-Start: $syslog $remote_fs
# Should-Start: $time ypbind smtp
# Required-Stop: $syslog $remote_fs
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: irserver module providing irTrans functionality
# Description: Start irserver to allow irTrans to provide remote control functionality and LCD messages
### END INIT INFO
#
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
IRS_BIN=/usr/local/irtrans/irserver
test -x $IRS_BIN || { echo "$IRS_BIN not installed";
if "$1" = "stop" ]; then exit 0;
else exit 5; fi; }
# Check for existence of needed config file and read it
IRS_CONFIG=/etc/sysconfig/irserver
test -r $IRS_CONFIG || { echo "$IRS_CONFIG does not exist";
if "$1" = "stop" ]; then exit 0;
else exit 6; fi; }
# Read config
. $IRS_CONFIG
. /etc/rc.status
# Reset status of this service
rc_reset
case "$1" in
start)
echo -n "Starting irserver "
## Start daemon with startproc(8). If this fails
## the return value is set appropriately by startproc.
/sbin/startproc $IRS_BIN
# Remember status and be verbose
rc_status -v
;;
stop)
echo -n "Shutting down irserver "
## Stop daemon with killproc(8) and if this fails
## killproc sets the return value according to LSB.
/sbin/killproc -TERM $IRS_BIN
# Remember status and be verbose
rc_status -v
;;
try-restart|condrestart)
## Do a restart only if the service was active before.
## Note: try-restart is now part of LSB (as of 1.9).
## RH has a similar command named condrestart.
if test "$1" = "condrestart"; then
echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
fi
$0 status
if test $? = 0; then
$0 restart
else
rc_reset # Not running is not a failure.
fi
# Remember status and be quiet
rc_status
;;
restart)
## Stop the service and regardless of whether it was
## running or not, start it again.
$0 stop
$0 start
# Remember status and be quiet
rc_status
;;
force-reload)
## Signal the daemon to reload its config. Most daemons
## do this on signal 1 (SIGHUP).
## If it does not support it, restart the service if it
## is running.
echo -n "Reload service irserver "
## if it supports it:
/sbin/killproc -HUP $IRS_BIN
# touch /var/run/FOO.pid
rc_status -v
## Otherwise:
#$0 try-restart
#rc_status
;;
reload)
## Like force-reload, but if daemon does not support
## signaling, do nothing (!)
# If it supports signaling:
echo -n "Reload service irserver "
/sbin/killproc -HUP $IRS_BIN
#touch /var/run/FOO.pid
rc_status -v
## Otherwise if it does not support reload:
#rc_failed 3
#rc_status -v
;;
status)
echo -n "Checking for service irserver "
## Check status with checkproc(8), if process is running
## checkproc will return with exit status 0.
# Return value is slightly different for the status command:
# 0 - service up and running
# 1 - service dead, but /var/run/ pid file exists
# 2 - service dead, but /var/lock/ lock file exists
# 3 - service not running (unused)
# 4 - service status unknown :-(
# 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
# NOTE: checkproc returns LSB compliant status values.
/sbin/checkproc $IRS_BIN
# NOTE: rc_status knows that we called this init script with
# "status" option and adapts its messages accordingly.
rc_status -v
;;
probe)
## Optional: Probe for the necessity of a reload, print out the
## argument to this init script which is required for a reload.
## Note: probe is not (yet) part of LSB (as of 1.9)
# test /etc/FOO/FOO.conf -nt /var/run/FOO.pid && echo reload
# ;;
# *)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
exit 1
;;
esac
rc_exit
This is a modification of one I find on another forum (Ubuntu).
#! /bin/sh
### BEGIN INIT INFO
# Provides: irtrans
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: irserver module providing irTrans functionality
# Description: Start irserver to allow irTrans to provide remote control functionality and LCD messages
### END INIT INFO
# Author: Yippee38 <yippee38@wideopenwest.com>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DESC="IRTrans server"
NAME=irserver
DAEMON=/usr/sbin/$NAME
PIDFILE=/var/run/$NAME.pid
DAEMON_ARGS="-daemon -pidfile $PIDFILE -loglevel 2 -logfile /var/log/irserver.log /dev/ttyUSB0"
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
-x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
-r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
-f /etc/default/rcS ] && . /etc/default/rcS
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
"$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
"$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
"$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) "$VERBOSE" != no ] && log_end_msg 0 ;;
2) "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
"$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) "$VERBOSE" != no ] && log_end_msg 0 ;;
2) "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
:
You don’t say what the actual file that doesn’t exist mentioned in the error message is.
However you are more likely to have success with the one modified from /etc/init.d/skeleton than an Ubuntu script. Ubuntu and Debian scripts make use of start-stop-daemon, which is a Debian-ism.
The permission should be 755 and the file should be owned by root:root. You should be able to execute it from the command line (as root) with /etc/init.d/irserver. Once you get past that, then you can focus on getting it to run from the boot environment.
Then you should run
chkconfig --set irserver on
to install symlinks in the runlevel directories. This uses the metadata at the top of the file which names the dependencies.
In the boot environment, PATH is root’s PATH and rather short. So if your server process calls other programs, you will either need to use the full path to the program, or to change PATH before you start the server process. Just add an export PATH=… somewhere near the top of the script. If your program relies on other environment variables, they should also be set appropriately.
I haven’t been using chkconfig as I’ve been using YaST to add the startup script. I’ll try using it and see if that helps.
How do I add command line arguements to the start script? When I launch irserver, I need to tell it which USB port to use. In CL I do that by adding “/dev/ttyUSB0” at the end of the command. Can I just add that at the end of the start line, or should it go elsewhere?
YaST will do the same thing as chkconfig, no need to worry about that. Once enabled, the symlink will stay in the runlevel directory until removed with chkconfig --set irserver off, or disabled from YaST.
To provide arguments to the init script, just specify them after the action. So something like:
/etc/init.d/irserver start /dev/ttyUSB0
In the script that /dev/ttyUSB0 will be in $2 since $1 will be “start”. Since the boot process will call irserver with only the action, the argument should be made to default to something sensible, for example like this:
device=${2:-/dev/ttyUSB0}
That expression ${2:-/dev/ttyUSB0} returns the value of $2 if set, otherwise substitutes /dev/ttyUSB0. This is explained in the sh man page, under the section Parameter Expansion.
Thanks for that especially. I’ve been looking at the man page for PATH, for init.d, for rc.d, etc., and not finding what I’ve been looking for. I’ll let you know how it goes.
Well you have two things named irserver, /etc/init.d/irserver the init script and /usr/local/irtrans/irserver the server binary. Are you sure it’s not the second that is not found? Because if the script runs, the problem is not with the script but with the invocation of the server process.
Also have a look at man startproc to see if there are any additional options you need. In particular, you may need to deal with the pid file. By default, startproc looks in /var/run/irserver.pid but irserver (the service binary) may have other ideas about a pid file, if it maintains one.
BTW, apparently, editing the script in Windows (on this machine) was a bad idea. I had tons of syntax errors that must have come from it being a .txt file rather than a unicode-8. I had to redo on that machine from a copy of skeleton (which was a pain because of where the PC is).
I’ll have to figure out more about scripting tomorrow. I may have 8 hours of downtime, so I should be able to figure it out in that time.
Actually it’s nothing to do with Unicode, shell scripts are practically all in the ASCII subset of Unicode. It’s because Windows text files use CR-NL as the line terminator, while Unix/Linux uses NL only. So that extra CR at the end of the line causes syntax errors. So just don’t use Windows editors on Linux files. Or at least use editors like vim where you can control the line endings with a set fileformat= command.
I got it running. It took a lot of trial and error, and a ton of my wife helping my debug it. So it works, but the weird thing is it returns “failed”. It is definitely running, but it says failed. Any clues?
rc_status is a shell function that reads the status from the last command executed. If startproc doesn’t reliably return ok status, or leave alone the status from the initial rc_reset, then you can fudge it by calling rc_reset just before the rc_status -v to clear the status to ok. This means your script will always display ok, regardless of whether the service actually started. You would have to fix that by writing some shell code to actually check if the service is ok before calling rc_status.