You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
4.6 KiB
189 lines
4.6 KiB
2 months ago
|
/*
|
||
|
* A Simple Wrapper for Starting and Stopping of Daemons
|
||
|
*
|
||
|
* (c) 2003 Martin Mares <mj@ucw.cz>
|
||
|
*
|
||
|
* It would seem that we are reinventing the wheel and the
|
||
|
* start-stop-daemon command present in most Linux distributions
|
||
|
* is just what we need, but the usual "does the process already
|
||
|
* exist?" strategies fail in presence of multiple running daemons.
|
||
|
*
|
||
|
* Return codes:
|
||
|
* 101 already running
|
||
|
* 102 not running
|
||
|
*
|
||
|
* NOTE: This utility is obsolete and has been replaced by ucw-daemon-control.
|
||
|
* You need to enable CONFIG_UCW_OBSOLETE_DAEMON_HELPER to compile it.
|
||
|
*/
|
||
|
|
||
|
#include <ucw/lib.h>
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <signal.h>
|
||
|
#include <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <getopt.h>
|
||
|
#include <errno.h>
|
||
|
#include <alloca.h>
|
||
|
|
||
|
enum action {
|
||
|
ACTION_NONE,
|
||
|
ACTION_START,
|
||
|
ACTION_STOP,
|
||
|
ACTION_FORCE_STOP,
|
||
|
ACTION_CHECK,
|
||
|
ACTION_RELOAD
|
||
|
};
|
||
|
|
||
|
static int action;
|
||
|
|
||
|
static struct option options[] = {
|
||
|
{ "pid-file", required_argument, NULL, 'p' },
|
||
|
{ "status-file", required_argument, NULL, 's' },
|
||
|
{ "start", no_argument, &action, ACTION_START },
|
||
|
{ "stop", no_argument, &action, ACTION_STOP },
|
||
|
{ "force-stop", no_argument, &action, ACTION_FORCE_STOP },
|
||
|
{ "check", no_argument, &action, ACTION_CHECK },
|
||
|
{ "reload", no_argument, &action, ACTION_RELOAD },
|
||
|
{ NULL, no_argument, NULL, 0 }
|
||
|
};
|
||
|
|
||
|
static void NONRET
|
||
|
usage(void)
|
||
|
{
|
||
|
fputs("\n\
|
||
|
Usage: ucw-daemon-helper --start <options> -- <daemon> <args>\n\
|
||
|
or: ucw-daemon-helper --stop <options>\n\
|
||
|
or: ucw-daemon-helper --force-stop <options>\n\
|
||
|
or: ucw-daemon-helper --reload <options>\n\
|
||
|
or: ucw-daemon-helper --check <options>\n\
|
||
|
\n\
|
||
|
Options:\n\
|
||
|
--pid-file <name> Name of PID file for this daemon (mandatory)\n\
|
||
|
--status-file <name> Status file used by the daemon (deleted just before starting)\n\
|
||
|
", stderr);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
int c, fd;
|
||
|
char *pidfile = NULL;
|
||
|
char *statfile = NULL;
|
||
|
struct flock fl;
|
||
|
char buf[64];
|
||
|
|
||
|
while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
|
||
|
switch (c)
|
||
|
{
|
||
|
case 0:
|
||
|
break;
|
||
|
case 'p':
|
||
|
pidfile = optarg;
|
||
|
break;
|
||
|
case 's':
|
||
|
statfile = optarg;
|
||
|
break;
|
||
|
default:
|
||
|
usage();
|
||
|
}
|
||
|
if (!pidfile)
|
||
|
usage();
|
||
|
|
||
|
bzero(&fl, sizeof(fl));
|
||
|
fl.l_type = F_WRLCK;
|
||
|
fl.l_whence = SEEK_SET;
|
||
|
|
||
|
switch (action)
|
||
|
{
|
||
|
case ACTION_START:
|
||
|
if (optind >= argc)
|
||
|
usage();
|
||
|
fd = open(pidfile, O_RDWR | O_CREAT, 0666);
|
||
|
if (fd < 0)
|
||
|
die("Unable to create %s: %m", pidfile);
|
||
|
if ((c = fcntl(fd, F_SETLK, &fl)) < 0)
|
||
|
{
|
||
|
if (errno == EAGAIN || errno == EACCES)
|
||
|
return 101;
|
||
|
else
|
||
|
die("fcntl lock on %s failed: %m", pidfile);
|
||
|
}
|
||
|
c = sprintf(buf, "%d\n", getpid());
|
||
|
if (write(fd, buf, c) != c)
|
||
|
die("write on %s failed: %m", pidfile);
|
||
|
if (ftruncate(fd, c) < 0)
|
||
|
die("truncate on %s failed: %m", pidfile);
|
||
|
if (statfile && unlink(statfile) < 0 && errno != ENOENT)
|
||
|
die("unlink(%s) failed: %m", statfile);
|
||
|
setsid();
|
||
|
/* Disconnect from stdin and stdout, leave stderr to the daemon. */
|
||
|
close(0);
|
||
|
open("/dev/null", O_RDWR, 0);
|
||
|
dup2(0, 1);
|
||
|
argv += optind;
|
||
|
argc -= optind;
|
||
|
char **a = alloca(sizeof(char *) * (argc+1));
|
||
|
memcpy(a, argv, sizeof(char *) * argc);
|
||
|
a[argc] = NULL;
|
||
|
execv(a[0], a);
|
||
|
die("Cannot execute %s: %m", a[0]);
|
||
|
case ACTION_STOP:
|
||
|
case ACTION_FORCE_STOP:
|
||
|
case ACTION_CHECK:
|
||
|
case ACTION_RELOAD:
|
||
|
if (optind < argc)
|
||
|
usage();
|
||
|
fd = open(pidfile, O_RDWR);
|
||
|
if (fd < 0)
|
||
|
{
|
||
|
if (errno == ENOENT)
|
||
|
return 102;
|
||
|
else
|
||
|
die("Unable to open %s: %m", pidfile);
|
||
|
}
|
||
|
if ((c = fcntl(fd, F_SETLK, &fl)) >= 0)
|
||
|
{
|
||
|
nopid:
|
||
|
unlink(pidfile);
|
||
|
return 102;
|
||
|
}
|
||
|
if (errno != EAGAIN && errno != EACCES)
|
||
|
die("fcntl lock on %s failed: %m", pidfile);
|
||
|
if ((c = read(fd, buf, sizeof(buf))) < 0)
|
||
|
die("read on %s failed: %m", pidfile);
|
||
|
if (!c)
|
||
|
goto nopid;
|
||
|
if (c >= (int) sizeof(buf) || sscanf(buf, "%d", &c) != 1)
|
||
|
die("PID file syntax error");
|
||
|
int sig = 0;
|
||
|
if (action == ACTION_CHECK || action == ACTION_RELOAD)
|
||
|
{
|
||
|
if (action == ACTION_RELOAD)
|
||
|
sig = SIGHUP;
|
||
|
if (kill(c, sig) < 0 && errno == ESRCH)
|
||
|
goto nopid;
|
||
|
return 0;
|
||
|
}
|
||
|
sig = (action == ACTION_STOP) ? SIGTERM : SIGQUIT;
|
||
|
if (kill(c, sig) < 0)
|
||
|
{
|
||
|
if (errno == ESRCH)
|
||
|
goto nopid;
|
||
|
die("Cannot kill process %d: %m", c);
|
||
|
}
|
||
|
if ((c = fcntl(fd, F_SETLKW, &fl)) < 0)
|
||
|
die("Cannot lock %s: %m", pidfile);
|
||
|
if (statfile)
|
||
|
unlink(statfile);
|
||
|
if (unlink(pidfile) < 0)
|
||
|
die("Cannot unlink %s: %m", pidfile);
|
||
|
return 0;
|
||
|
default:
|
||
|
usage();
|
||
|
}
|
||
|
}
|