Add pidfile support (closes: #1651)

This commit is contained in:
Arnaud Andre 2015-09-16 01:21:42 +02:00
parent 4d632694e6
commit de6f874d5e
4 changed files with 151 additions and 5 deletions

View file

@ -60,6 +60,8 @@ Optional arguments:
-a, --auth pass Simple text password (only in VRRPv2) -a, --auth pass Simple text password (only in VRRPv2)
-f, --foreground Execute uvrrpd in foreground -f, --foreground Execute uvrrpd in foreground
-s, --script Path of hook script (default /etc/uvrrpd/uvrrpd-switch.sh) -s, --script Path of hook script (default /etc/uvrrpd/uvrrpd-switch.sh)
-F --pidfile Create pid file 'name
Default /var/run/uvrrp_${vrid}.pid
-d, --debug -d, --debug
-h, --help -h, --help
``` ```

138
uvrrpd.c
View file

@ -23,6 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <sys/file.h>
#include "uvrrpd.h" #include "uvrrpd.h"
#include "vrrp.h" #include "vrrp.h"
@ -35,12 +36,19 @@
#include "log.h" #include "log.h"
/* global constants */
unsigned long reg = 0UL; unsigned long reg = 0UL;
int background = 1; int background = 1;
char *loglevel = NULL; char *loglevel = NULL;
char *pidfile_name = NULL;
/* local methods */
static void signal_handler(int sig); static void signal_handler(int sig);
static void signal_setup(void); static void signal_setup(void);
static int pidfile_init(int vrid);
static void pidfile_unlink(void);
static void pidfile_check(int vrid);
static void pidfile(int vrid);
/** /**
* main() - entry point * main() - entry point
@ -64,6 +72,12 @@ int main(int argc, char *argv[])
if (! !vrrp_options(&vrrp, &vnet, argc, argv)) if (! !vrrp_options(&vrrp, &vnet, argc, argv))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* pidfile init && check */
if (pidfile_init(vrrp.vrid) != 0)
exit(EXIT_FAILURE);
pidfile_check(vrrp.vrid);
/* logs */ /* logs */
log_open("uvrrpd", (char const *) loglevel); log_open("uvrrpd", (char const *) loglevel);
@ -96,6 +110,10 @@ int main(int argc, char *argv[])
else else
chdir("/"); chdir("/");
/* pidfile */
pidfile(vrrp.vrid);
/* process */ /* process */
set_bit(KEEP_GOING, &reg); set_bit(KEEP_GOING, &reg);
while (test_bit(KEEP_GOING, &reg) && !vrrp_process(&vrrp, &vnet)); while (test_bit(KEEP_GOING, &reg) && !vrrp_process(&vrrp, &vnet));
@ -105,7 +123,7 @@ int main(int argc, char *argv[])
if (vnet.family == AF_INET) if (vnet.family == AF_INET)
vrrp_arp_cleanup(&vnet); vrrp_arp_cleanup(&vnet);
else /* AF_INET6 */ else /* AF_INET6 */
vrrp_na_cleanup(&vnet); vrrp_na_cleanup(&vnet);
vrrp_cleanup(&vrrp); vrrp_cleanup(&vrrp);
@ -114,6 +132,8 @@ int main(int argc, char *argv[])
log_close(); log_close();
free(loglevel); free(loglevel);
pidfile_unlink();
free(pidfile_name);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -201,3 +221,119 @@ static void signal_setup(void)
sigprocmask(SIG_BLOCK, &sa.sa_mask, NULL); sigprocmask(SIG_BLOCK, &sa.sa_mask, NULL);
} }
/**
* pidfile_init()
*/
static int pidfile_init(int vrid)
{
int max_len = NAME_MAX + PATH_MAX;
if (pidfile_name == NULL) {
pidfile_name = malloc(max_len);
if (pidfile_name == NULL) {
log_error("vrid %d :: malloc - %m", vrid);
return -1;
}
snprintf(pidfile_name, max_len, PIDFILE_NAME, vrid);
}
return 0;
}
/**
* pidfile_unlink() - remove pidfile
*/
static void pidfile_unlink(void)
{
if (pidfile_name)
unlink(pidfile_name);
}
/**
* pidfile_check()
*/
static void pidfile_check(int vrid)
{
struct flock fl;
int err, fd;
fd = open(pidfile_name, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
if (errno == ENOENT)
return;
fprintf(stderr, "vrid %d :: error opening PID file %s: %m\n",
vrid, pidfile_name);
exit(EXIT_FAILURE);
}
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
err = fcntl(fd, F_GETLK, &fl);
close(fd);
if (err < 0) {
fprintf(stderr, "vrid %d :: error getting PID file %s lock: %m",
vrid, pidfile_name);
exit(EXIT_FAILURE);
}
if (fl.l_type == F_UNLCK)
return;
fprintf(stderr, "vrid %d :: uvrrpd is already running (pid %d)\n", vrid,
(int) fl.l_pid);
exit(EXIT_FAILURE);
}
/**
* pid_file()
*/
static void pidfile(int vrid)
{
struct flock fl;
char buf[16];
int err, fd;
fd = open(pidfile_name,
O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
if (fd < 0) {
log_error("vrid %d :: error opening PID file %s: %m\n", vrid,
pidfile_name);
exit(EXIT_FAILURE);
}
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
err = fcntl(fd, F_SETLK, &fl);
if (err < 0) {
if (errno == EACCES || errno == EAGAIN) {
log_error("vrid %d :: uvrrpd is already running\n",
vrid);
exit(EXIT_FAILURE);
}
log_error("vrid %d :: error setting PID file %s lock: %m\n",
vrid, pidfile_name);
exit(EXIT_FAILURE);
}
atexit(pidfile_unlink);
err = snprintf(buf, sizeof(buf), "%d\n", (int) getpid());
if (err < 0) {
perror("snprintf");
exit(EXIT_FAILURE);
}
err = write(fd, buf, err);
if (err < 0) {
log_error("vrid %d :: error writing PID to PID file %s: %m\n",
vrid, pidfile_name);
exit(EXIT_FAILURE);
}
}

View file

@ -24,6 +24,8 @@
#include "bits.h" #include "bits.h"
#define PIDFILE_NAME "/var/run/uvrrpd_%d.pid"
/** /**
* uvrrpd_control * uvrrpd_control
* Enum server control register flags * Enum server control register flags

View file

@ -33,6 +33,7 @@
/* from uvrrpd.c */ /* from uvrrpd.c */
extern int background; extern int background;
extern char *loglevel; extern char *loglevel;
extern char *pidfile_name;
/** /**
* vrrp_usage() * vrrp_usage()
@ -58,9 +59,8 @@ static void vrrp_usage(void)
" -a, --auth pass Simple text password (only in VRRPv2)\n" " -a, --auth pass Simple text password (only in VRRPv2)\n"
" -f, --foreground Execute uvrrpd in foreground\n" " -f, --foreground Execute uvrrpd in foreground\n"
" -s, --script Path of hook script (default /etc/uvrrpd/uvrrpd-switch.sh)\n" " -s, --script Path of hook script (default /etc/uvrrpd/uvrrpd-switch.sh)\n"
#if 0 /* todo */ " -F --pidfile name Create pid file 'name'\n"
" --pidfile name Create pid file 'name'\n" " Default /var/run/uvrrp_${vrid}.pid\n"
#endif
" -d, --debug\n" " -h, --help\n"); " -d, --debug\n" " -h, --help\n");
} }
@ -84,13 +84,14 @@ int vrrp_options(struct vrrp *vrrp, struct vrrp_net *vnet, int argc,
{"auth", required_argument, 0, 'a'}, {"auth", required_argument, 0, 'a'},
{"foreground", no_argument, 0, 'f'}, {"foreground", no_argument, 0, 'f'},
{"script", required_argument, 0, 's'}, {"script", required_argument, 0, 's'},
{"pidfile", required_argument, 0, 'F'},
{"debug", no_argument, 0, 'd'}, {"debug", no_argument, 0, 'd'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
}; };
while ((optc = while ((optc =
getopt_long(argc, argv, "v:i:p:t:P:r:6a:fs:dh", opts, getopt_long(argc, argv, "v:i:p:t:P:r:6a:fs:F:dh", opts,
NULL)) != EOF) { NULL)) != EOF) {
switch (optc) { switch (optc) {
@ -193,6 +194,11 @@ int vrrp_options(struct vrrp *vrrp, struct vrrp_net *vnet, int argc,
} }
break; break;
/* pidfile */
case 'F':
pidfile_name = strndup(optarg, NAME_MAX + PATH_MAX);
break;
/* debug */ /* debug */
case 'd': case 'd':
loglevel = strndup("debug", 6); loglevel = strndup("debug", 6);