Start-Stop-Daemon Quoted Arguments Misinterpreted

start-stop-daemon quoted arguments misinterpreted

I thought I'd post the final quotations used in my working init script:

COMMAND="/path/to/script -opt param param2 param3"
DAEMON_OPTS=" 0.0.0.0:$PORT -dest $OUTPUT_DIRECTORY -command"

start-stop-daemon --start --background --make-pidfile --pidfile $PID --exec $DAEMON -- $DAEMON_OPTS "\"$COMMAND\""

Obviously an incomplete and non-functional example but I hope you get the gist of it. The double quotations with the inner pair escaped is what did the trick.

Why start-stop-daemon needs privileges?

start-stop-daemon can also set the user ID for the daemon process.

That said, you'd generally use start-stop-daemon from a script in /etc/rc.d, which is run with root privileges either from the init system that is being used this week (sysvinit, upstart, systemd, ...) and/or from the service(8) command.

So, if a user should be able to start/stop the service (which is a rather uncommon scenario), you'd use the sudoers file to grant them access to the service command, with the name of your service as a mandatory first argument.

In general though, write your service so it can be simply started at boot or during installation, and used by users as long as it's running. If the user needs to be able to start and stop instances of the service, then your daemon is in the business of managing instances, and the instance manager should be continually running, and users then contact this service via a socket (so users don't need sudo at all, which would make the lives of many administrators who don't install sudo quite a bit easier).

How do I run Java as a service on Ubuntu?

I don't mean to sidetrack, but I've deployed Java applications on Ubuntu in production since 2010 and had very little success with Upstart. I use init.d scripts and start-stop-daemon. Side bonus: it works on more distros.

Create /etc/init.d/my-java-app:

#!/bin/sh
#
# my-java-app My Java App
#
# chkconfig: - 80 05
# description: Enable My Java Application
#

### BEGIN INIT INFO
# Provides: my-java-app
# Required-Start: $remote_fs $network
# Required-Stop: $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: My Java Application
# Short-Description: Enable My Java Application
### END INIT INFO

DESC="my java app"
NAME=my-java-app
PIDFILE=/var/run/$NAME.pid
RUN_AS=ubuntu
WORK_DIR=/home/ubuntu/admin
DAEMON=/usr/bin/mvn
DAEMON_OPTS="spring-boot:run"

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

do_start() {
start-stop-daemon --start --quiet --make-pidfile --pidfile $PIDFILE \
--background \
--chuid $RUN_AS \
--chdir $WORK_DIR \
--exec $DAEMON -- $DAEMON_OPTS
}

do_stop() {
start-stop-daemon --stop --quiet --pidfile $PIDFILE
if [ -e $PIDFILE ]
then rm $PIDFILE
fi
}

case "$1" in
start)
echo -n "Starting $DESC: $NAME"
do_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
do_stop
echo "."
;;
restart)
echo -n "Restarting $DESC: $NAME"
do_stop
sleep 1
do_start
echo "."
;;
status)
status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
;;
*)
echo "usage: $NAME {start|stop|restart}"
exit 1
;;
esac

Make it belong to root, make it executable, and set it up to run on startup with:

sudo chown root:root /etc/init.d/my-java-app
sudo chmod 755 /etc/init.d/my-java-app
sudo update-rc.d my-java-app defaults

To start the service you can run:

sudo service my-java-app start

To stop the service you can run:

sudo service my-java-app stop

This is based on a simplified version of the /etc/init.d/skeleton file included by Ubuntu.

The man page for start-stop-daemon is worth looking at if you want to tweak this further.b

Run Emacs as a daemon and then the emacs binary

The quote is misleading. After you have started a server you can happily run either emacs or emacsclient as you wish. The latter will connect to your server; the former will (as usual) start a new separate instance of Emacs.

What is the best way to ensure only one instance of a Bash script is running?

If the script is the same across all users, you can use a lockfile approach. If you acquire the lock, proceed else show a message and exit.

As an example:

[Terminal #1] $ lockfile -r 0 /tmp/the.lock
[Terminal #1] $

[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] lockfile: Sorry, giving up on "/tmp/the.lock"

[Terminal #1] $ rm -f /tmp/the.lock
[Terminal #1] $

[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] $

After /tmp/the.lock has been acquired your script will be the only one with access to execution. When you are done, just remove the lock. In script form this might look like:

#!/bin/bash

lockfile -r 0 /tmp/the.lock || exit 1

# Do stuff here

rm -f /tmp/the.lock

Does a finally block always get executed in Java?

Yes, finally will be called after the execution of the try or catch code blocks.

The only times finally won't be called are:

  1. If you invoke System.exit()
  2. If you invoke Runtime.getRuntime().halt(exitStatus)
  3. If the JVM crashes first
  4. If the JVM reaches an infinite loop (or some other non-interruptable, non-terminating statement) in the try or catch block
  5. If the OS forcibly terminates the JVM process; e.g., kill -9 <pid> on UNIX
  6. If the host system dies; e.g., power failure, hardware error, OS panic, et cetera
  7. If the finally block is going to be executed by a daemon thread and all other non-daemon threads exit before finally is called


Related Topics



Leave a reply



Submit