Workshop o mikrokontrolérech na SKSP 2024.
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

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();
}
}