Compare commits

...

8 Commits

Author SHA1 Message Date
Laurence Withers b2aadf503b Bump version 2013-11-10 12:27:57 +00:00
Laurence Withers 639944b905 Simplify daemon and always close file descriptors
Use daemon(3) to daemonise rather than writing our own code. Since we
use the mode of daemon(3) which closes the standard 3 file descriptors,
if the user requests logging to one of those we dup(2) the original
first. We must also take care to always close any newly-opened file
descriptors before execve(2) of the child.
2012-10-02 19:58:05 +00:00
Laurence Withers c55693ce1c Add respawn checking feature
Add a feature which allows arbitrary checks to be performed whenever the child
process is about to be respawned. Currently implemented checks allow running of
a command (via system(3)) or testing the existence of a file.

This was developed to be used to stop respawns of a daemon that was started in
response to a udev hotplug event, but it is generally applicable to many other
scenarios.
2012-10-02 19:33:18 +00:00
Laurence Withers b17eed9466 SIGTERM handler: use _exit(2), not exit(3)
exit(3) is not async-signal safe (presumably due to atexit(3) processing),
so use _exit(2) instead. This was clearly an omission from the original
code which even had a comment to the effect that _exit(2) needed to be
used. In all likelihood this never caused any problems as atexit(3)
functionality is not used.
2012-10-02 18:52:11 +00:00
Laurence Withers b26bd15791 Treat SIGINT similarly to SIGTERM
Treat SIGINT similarly to SIGTERM; exit when it is received. This gives the
desired behaviour of having a foreground daemonitor be stopped by pressing
ctrl-C on its controlling tty.
2012-10-02 18:50:46 +00:00
Laurence Withers f611c2acf7 Update build system 2012-10-02 09:54:56 +00:00
Laurence Withers 4a50315f12 Bump version 2009-04-06 15:00:26 +00:00
Laurence Withers 45bbf6bf1c Upgrade build system 2009-04-06 15:00:13 +00:00
17 changed files with 315 additions and 242 deletions

10
README
View File

@ -1,8 +1,10 @@
daemonitor
==============================================================================
(c)2007, Laurence Withers, <l@lwithers.me.uk>.
Released under the GNU GPLv3. See file COPYING or
http://www.gnu.org/copyleft/gpl.html for details.
========================================================================
Copyright: ©20072012, Güralp Systems Limited
Author: Laurence Withers <lwithers@guralp.com>
License: GPLv3
See file COPYING for detail license information.
Really Quick Instructions
-------------------------

7
config
View File

@ -1,10 +1,9 @@
# daemonitor/config
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072012, Güralp Systems Limited
# Author: Laurence Withers <lwithers@guralp.com>
# License: GPLv3
#
# This file contains options used to build daemonitor.

15
make.sh
View File

@ -1,9 +1,9 @@
#!/bin/sh
#!/bin/bash
# daemonitor/make.sh
#
# (c)2006-2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072012, Güralp Systems Limited
# Author: Laurence Withers <lwithers@guralp.com>
# License: GPLv3
#
@ -15,19 +15,19 @@ then
echo "Configuration file not found???"
exit 1
fi
source "config" # don't fail on error, since last command in config might return false
source "./config" # don't fail on error, since last command in config might return false
# Get version information
source version || exit 1
source "./version" || exit 1
VERSION="${VERMAJOR}.${VERMINOR}.${VERMICRO}"
# Get standard functions
[ -z "${VERBOSE}" ] && VERBOSE="0"
source scripts/functions.sh || exit 1
source "./scripts/functions.sh" || exit 1
# List of directories which will be emptied by clean.
@ -292,5 +292,4 @@ done
exit 0
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

View File

@ -1,9 +1,9 @@
#!/bin/sh
#!/bin/bash
# daemonitor/test.sh
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072012, Güralp Systems Limited
# Author: Laurence Withers <lwithers@guralp.com>
# License: GPLv3
#
# Running this script on its own will display a summary of all the
@ -21,12 +21,7 @@ run_test() {
return 1
fi
if [ $# -eq 0 ]
then
LD_LIBRARY_PATH="obj" ${EXE} || return 1
else
LD_LIBRARY_PATH="obj" ${EXE} "$*" || return 1
fi
LD_LIBRARY_PATH="obj:${LD_LIBRARY_PATH}" "${EXE}" "$@" || return 1
return 0
}
@ -38,14 +33,15 @@ print_tests() {
echo "---------------------------------------------------------------------"
for EXE in obj/tests/*
do
[ -x ${EXE} ] || continue
NAME=$(echo ${EXE} | sed 's,obj/tests/,,')
[ -x "${EXE}" ] || continue
NAME="$(echo "${EXE}" | sed 's,obj/tests/,,')"
echo -ne "${NAME}\t"
LD_LIBRARY_PATH="obj" ${EXE} --print-summary
LD_LIBRARY_PATH="obj:${LD_LIBRARY_PATH}" "${EXE}" --print-summary
done
}
# Main script
if [ $# -eq 0 ]
then
@ -53,7 +49,6 @@ then
exit 0
fi
run_test $*
run_test "$@"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

1
scripts/.gitignore vendored
View File

@ -7,6 +7,7 @@ build.docs.none
build.files.none
build.firmware.gpasm
build.firmware.sdcc
build.header.c
build.lib.c
build.lib.c++
build.make.none

View File

@ -1,8 +1,8 @@
# daemonitor/scripts/functions.sh
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072012, Güralp Systems Limited
# Author: Laurence Withers, <lwithers@guralp.com>
# License: GPLv3
#
# Common functions
@ -63,5 +63,4 @@ do_cmd_redir() {
fi
}
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

View File

@ -1,8 +1,8 @@
# daemonitor/scripts/paths
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072012, Güralp Systems Limited
# Author: Laurence Withers, <lwithers@guralp.com>
# License: GPLv3
#
# Default path setup. Not meant for editing; use environment variables
# to override values if needed.
@ -60,5 +60,4 @@ fi
[ -z "${WEBDIR}" ] && WEBDIR="${SRVDIR}/http"
[ -z "${CGIDIR}" ] && CGIDIR="${WEBDIR}/cgi-bin"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -1,9 +1,9 @@
/* daemonitor/src/daemonitor/200_log.c
*
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
* Copyright: ©20072012, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
@ -170,16 +170,25 @@ void log_func_syslog(int level, const char* fmt, ...)
/* log_destination_set()
* Set `log_func' function pointer.
*/
void log_destination_set(enum log_destination_t dest)
void
log_destination_set(enum log_destination_t dest)
{
switch(dest) {
case log_destination_stdout:
log_func_fd = STDOUT_FILENO;
log_func_fd = dup(STDOUT_FILENO);
if(log_func_fd == -1) {
printf("dup() failed: %m.");
exit(1);
}
log_func = log_func_file;
break;
case log_destination_stderr:
log_func_fd = STDERR_FILENO;
log_func_fd = dup(STDERR_FILENO);
if(log_func_fd == -1) {
fprintf(stderr, "dup() failed: %m.");
exit(1);
}
log_func = log_func_file;
break;
@ -210,6 +219,5 @@ int log_destination_set_file(const char* filename)
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -1,160 +0,0 @@
/* daemonitor/src/daemonitor/400_daemon.c
*
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* DAEMON ROUTINES ********************************************************************************
*
* This file provides the daemonise() routine, which makes the process a daemon (fork() + setsid()
* so that the process lives in the background, also opens /dev/console). It also provides the
* close_file_descriptors() routine, which clears all file descriptors but 0, 1 and 2.
*/
/* PUBLIC API ************************************************************************************/
/* daemonise()
* Performs a fork() and setsid() so that the process lives in the background. It closes stdin,
* stdout and stderr and opens /dev/null and/or /dev/console instead, as appropriate. On error,
* this function exits the program.
*/
void daemonise(void);
/* close_file_descriptors()
* Closes all file descriptors but stdin, stdout and stderr. Should be called whether we are
* daemonising or not.
*/
void close_file_descriptors(void);
/* IMPLEMENTATION ********************************************************************************/
void daemonise(void)
{
int fd;
pid_t pid;
/* close stdin and reopen it as /dev/null */
TEMP_FAILURE_RETRY( close(STDIN_FILENO) );
fd = open("/dev/null", O_RDONLY);
switch(fd) {
case -1:
LOG(LOG_CRIT, "Could not open `/dev/null' (%m).");
exit(1);
case STDIN_FILENO:
break;
default:
LOG(LOG_CRIT, "Opened `/dev/null' for stdin, but got file descriptor %d instead.", fd);
exit(1);
}
/* close stdout and reopen it as /dev/console if possible, or /dev/null if not */
TEMP_FAILURE_RETRY( close(STDOUT_FILENO) );
fd = open("/dev/console", O_WRONLY | O_NOCTTY);
if(fd == -1) {
LOG(LOG_WARNING, "Could not open `/dev/console' for stdout (%m).");
fd = open("/dev/null", O_WRONLY);
}
switch(fd) {
case -1:
LOG(LOG_CRIT, "Could not open `/dev/null' (%m).");
exit(1);
case STDOUT_FILENO:
break;
default:
LOG(LOG_CRIT, "Opened `/dev/null' for stdout, but got file descriptor %d instead.", fd);
exit(1);
}
/* close stderr and reopen it as /dev/console if possible, or /dev/null if not */
TEMP_FAILURE_RETRY( close(STDERR_FILENO) );
fd = open("/dev/console", O_WRONLY | O_NOCTTY);
if(fd == -1) {
LOG(LOG_WARNING, "Could not open `/dev/console' for stderr (%m).");
/* force fd closed again, in case glibc kindly connected it to syslog for us */
TEMP_FAILURE_RETRY( close(STDERR_FILENO) );
fd = open("/dev/null", O_WRONLY);
}
switch(fd) {
case -1:
LOG(LOG_CRIT, "Could not open `/dev/null' (%m).");
exit(1);
case STDERR_FILENO:
break;
default:
LOG(LOG_CRIT, "Opened `/dev/null' for stderr, but got file descriptor %d instead.", fd);
exit(1);
}
/* daemonise */
pid = fork();
if(pid == (pid_t)-1) {
LOG(LOG_CRIT, "Could not fork daemonised process (%m).");
exit(1);
}
if(pid) {
/* parent */
_exit(0); /* don't call atexit() et al. in parent */
}
setsid();
LOG(LOG_NOTICE, "Daemonised, PID %lu.", (unsigned long)getpid());
}
/* close_file_descriptors()
* Adapted from libgslutil (GPL-3).
*/
void close_file_descriptors(void)
{
DIR* d;
struct dirent* de;
int i, end, dfd;
d = opendir("/proc/self/fd");
if(!d) {
/* backup method */
for(i = STDERR_FILENO + 1, end = getdtablesize(); i < end; ++i) {
close(i);
}
return;
}
dfd = dirfd(d);
while( (de = readdir(d)) ) {
if(de->d_name[0] == '.') continue;
i = strtol(de->d_name, 0, 10);
if(i == dfd) continue; /* skip file descriptor associated with `DIR* d' */
if(i <= STDERR_FILENO) continue; /* leave stdin, stdout, stderr alone */
TEMP_FAILURE_RETRY( close(i) );
}
closedir(d);
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -1,9 +1,9 @@
/* daemonitor/src/daemonitor/600_run_program.c
*
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
* Copyright: ©20072012, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
@ -45,8 +45,8 @@ volatile int sigterm_received = 0;
/* close_file_descriptors()
* Closes all file descriptors but stdin, stdout and stderr. Should be called whether we are
* daemonising or not.
* Closes all file descriptors but stdin, stdout and stderr (which it leaves
* unchanged).
*/
void close_file_descriptors(void);
@ -56,6 +56,38 @@ void close_file_descriptors(void);
/* close_file_descriptors()
* Adapted from libgslutil (GPL-3).
*/
void
close_file_descriptors(void)
{
DIR* d;
struct dirent* de;
int i, end, dfd;
d = opendir("/proc/self/fd");
if(!d) {
/* backup method */
for(i = STDERR_FILENO + 1, end = getdtablesize(); i < end; ++i) {
close(i);
}
return;
}
dfd = dirfd(d);
while( (de = readdir(d)) ) {
if(de->d_name[0] == '.') continue;
i = strtol(de->d_name, 0, 10);
if(i == dfd) continue; /* skip file descriptor associated with `DIR* d' */
if(i <= STDERR_FILENO) continue; /* leave stdin, stdout, stderr alone */
TEMP_FAILURE_RETRY( close(i) );
}
closedir(d);
}
/* crash()
* Crash the program. This is better than just calling exit() because it doesn't clean up. We
* should leave our PID file lying around to look like we crashed. This function is paranoid.
@ -113,6 +145,8 @@ void run_program(const char* exe_path, char** argv)
/* child -- execute new process */
if(pid == 0) {
close_file_descriptors();
/* clear the child's signal mask */
sigemptyset(&ss);
sigprocmask(SIG_SETMASK, &ss, 0);
@ -203,6 +237,5 @@ void run_program(const char* exe_path, char** argv)
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -1,9 +1,9 @@
/* daemonitor/src/daemonitor/700_signal.c
*
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
* Copyright: ©20072012, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
@ -45,7 +45,7 @@ void sigterm_handler(int signum __attribute__((unused)))
/* uck -- we can't call exit() because it's not async-signal-safe, so we must call _exit() and
* clean up manually, with no logging */
unlink(pidfile_filename);
exit(0);
_exit(0);
}
@ -72,8 +72,9 @@ void signal_setup(void)
sigdelset(&ss, SIGSEGV);
sigdelset(&ss, SIGBUS);
/* we'd like to deal with SIGTERM specially */
/* we'd like to deal with SIGTERM/SIGINT specially */
sigdelset(&ss, SIGTERM);
sigdelset(&ss, SIGINT);
/* don't block SIGCHLD or wait(2) won't work */
sigdelset(&ss, SIGCHLD);
@ -90,9 +91,10 @@ void signal_setup(void)
sigaction(SIGBUS, &sa, 0);
sigaction(SIGCHLD, &sa, 0);
/* install our own handler for SIGTERM */
/* install our own handler for SIGTERM/SIGINT */
sa.sa_handler = sigterm_handler;
sigaction(SIGTERM, &sa, 0);
sigaction(SIGINT, &sa, 0);
}

186
src/daemonitor/800_checks.c Normal file
View File

@ -0,0 +1,186 @@
/* daemonitor/src/daemonitor/800_checks.c
*
* Copyright: ©2012, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
/* RESPAWN CHECKS **************************************************************
*
* This file implements functionality for various checks that may be carried
* out whenever the child process needs to be respawned. An arbitrary number of
* checks may be registered; if any single check fails, the entire test counts
* as failing. The result of the checks is found by calling run_checks().
*
* A failed check will log details at LOG_NOTICE (or above).
*/
/* PUBLIC API *****************************************************************/
/* check_command_register()
* cmd: A command (passed to system(3)) to run. If it exits with code 0, the
* check passes.
*/
void check_command_register(const char* cmd);
/* check_file_register()
* path: A file to test. If it exists, the check passes.
*/
void check_file_register(const char* cmd);
/* run_checks()
* Returns 0 if all checks succeeded (including when none are registered) and
* non-0 if any check failed.
*/
int run_checks(void);
/* IMPLEMENTATION *************************************************************/
enum check_type {
check_type_command,
check_type_file,
};
/* struct check
* check_head
* A linked list of the checks that are to be run.
*/
struct check {
enum check_type type;
/* can be the argument for system(3) or the path to check for a file */
const char* arg;
/* linked list structure */
struct check* next;
};
struct check* check_head = 0;
/* check_generic_register()
* Instantiates a struct check and adds it to the list at check_head.
*/
void
check_generic_register(enum check_type type, const char* arg)
{
struct check* c;
c = malloc(sizeof(*c));
c->type = type;
c->arg = arg;
c->next = check_head;
check_head = c;
}
void
check_command_register(const char* cmd)
{
check_generic_register(check_type_command, cmd);
}
int
check_command_run(const struct check* iter)
{
int ret;
ret = system(iter->arg);
if(ret == -1) {
LOG(LOG_ERR, "Unable to run check command \"%s\": %m.", iter->arg);
return 0; /* don't exit just because system(3) failed */
}
if(WIFSIGNALED(ret)) {
LOG(LOG_WARNING, "Check command \"%s\" killed by signal (%s). Exiting.",
iter->arg, strsignal(WTERMSIG(ret)));
return -1;
}
if(!WIFEXITED(ret)) {
LOG(LOG_WARNING, "Unrecognised exit code 0x%X from check command "
"\"%s\".", ret, iter->arg);
return 0;
}
if(WEXITSTATUS(ret)) {
LOG(LOG_NOTICE, "Check command \"%s\" signalled failure (exit code "
"%d). Exiting.", iter->arg, WEXITSTATUS(ret));
return -1;
}
return 0;
}
void
check_file_register(const char* path)
{
check_generic_register(check_type_file, path);
}
int
check_file_run(const struct check* iter)
{
int ret;
ret = access(iter->arg, F_OK);
if(ret) {
LOG(LOG_NOTICE, "Check file \"%s\" does not exist. Exiting.",
iter->arg);
return -1;
}
return 0;
}
int
run_checks(void)
{
const struct check* iter;
for(iter = check_head; iter; iter = iter->next) {
switch(iter->type) {
case check_type_command:
if(check_command_run(iter)) return -1;
break;
case check_type_file:
if(check_file_run(iter)) return -1;
break;
}
}
return 0;
}
/* options for text editors
vim: expandtab:ts=4:sw=4
*/

View File

@ -1,9 +1,9 @@
/* daemonitor/src/daemonitor/999_main.c
*
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
* Copyright: ©20072012, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
@ -37,6 +37,10 @@ void usage(void)
" " DEFAULT_RESTART_INTERVAL_S "). May be 0 to restart immediately.\n"
" -E, --environment <path> Name of file containing environment variables for\n"
" child process, one NAME=VALUE entry per line.\n"
" -C, --check-command <cmd> Runs <cmd> via /bin/sh before restarting a service\n"
" that has exited. Stops if <cmd> fails.\n"
" -F, --check-file <path> Checks that <path> exists before restarting a service\n"
" that has exited. Stops if it does not exist.\n"
"", stderr);
}
@ -53,6 +57,8 @@ struct option options[] = {
{ "pidfile", required_argument, 0, 'p' },
{ "restart-interval", required_argument, 0, 'R' },
{ "environment", required_argument, 0, 'E' },
{ "check-command", required_argument, 0, 'C' },
{ "check-file", required_argument, 0, 'F' },
{ 0, 0, 0, 0 }
};
@ -61,7 +67,7 @@ struct option options[] = {
/* optstr
* The list of short commandline options for getopt(3). Sorted alphabetically, lowercase first.
*/
const char* optstr = "dhl:p:E:R:V";
const char* optstr = "dhl:p:C:E:F:R:V";
@ -73,7 +79,7 @@ int main(int argc, char* argv[])
{
char* endp;
const char* log_argument = 0, * pidfile_argument = 0, * restart_argument = 0;
int daemon = 0, restart_interval = DEFAULT_RESTART_INTERVAL;
int do_daemon = 0, restart_interval = DEFAULT_RESTART_INTERVAL;
/* safety */
close_file_descriptors(); /* leaves stdout etc. open */
@ -85,11 +91,13 @@ int main(int argc, char* argv[])
case '?': LOG_ANYWHERE("Invalid commandline options."); return 1;
case 'h': usage(); return 1;
case 'V': fputs("daemonitor " VERSION "\n", stderr); return 1;
case 'd': ++daemon; break;
case 'd': ++do_daemon; break;
case 'l': log_argument = optarg; break;
case 'p': pidfile_argument = optarg; break;
case 'R': restart_argument = optarg; break;
case 'E': set_environment_file(optarg); break;
case 'C': check_command_register(optarg); break;
case 'F': check_file_register(optarg); break;
}
}
opts_done:
@ -128,7 +136,12 @@ int main(int argc, char* argv[])
if(load_child_environ()) return 1;
/* daemonise? */
if(daemon) daemonise();
if(do_daemon) {
if(daemon(0, 0)) {
LOG(LOG_CRIT, "daemon() failed: %m.");
return 1;
}
}
/* write a PID file */
if(pidfile_argument) {
@ -150,6 +163,8 @@ int main(int argc, char* argv[])
LOG(LOG_NOTICE, "Sleeping for %d seconds.", restart_interval);
safe_sleep_fixed(restart_interval, 0);
}
if(run_checks()) return 0;
}
return 0;
@ -158,6 +173,5 @@ int main(int argc, char* argv[])
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -6,7 +6,7 @@
if [ -z ${daemonitor_BUILT} ]
then
daemonitor="obj/daemonitor"
EXTRAS="-D_GNU_SOURCE"
EXTRAS="-std=gnu99 -D_GNU_SOURCE -DAPP_NAME=\"daemonitor\""
echo "Building application ${daemonitor}..."
@ -37,5 +37,4 @@ then
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -8,5 +8,4 @@ echo "Installing binaries into '${SBINDIR}'"
install_file "${daemonitor}" "${SBINDIR}" 0755 || return 1
print_success "Done"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -14,5 +14,4 @@ then
MONOLITHIC_DOC="${MONOLITHIC_DOC} ${SRC}"
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -1,8 +1,8 @@
# daemonitor/version
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072012, Güralp Systems Limited
# Author: Laurence Withers <lwithers@guralp.com>
# License: GPLv3
#
@ -11,7 +11,6 @@
# expected to be in 'major.minor.micro' format.
VERMAJOR=1
VERMINOR=0
VERMICRO=1
VERMICRO=3
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4:syntax=sh