From 8d636690bd5de9525ad41179b0709135e2b94fc7 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Fri, 29 Jun 2018 14:33:52 +0900 Subject: [PATCH] repmgrd: create pid file by default Traditionally repmgrd will only write a pidfile if explicitly requested with -p/--pid-file. However it's normally desirable to have a pidfile, and it's preferable to have one used by default to prevent accidentally starting a second repmgrd instance. Following changes made: - add configuration file parameter "repmgrd_pid_file" (initially overridden by -p/--pid-file for backwards compatibility, though eventually we'll want to drop -p/--pid-file altogether) - add command line option --no-pid-file - if neither "repmgrd_pid_file" nor -p/--pid-file is set, create the pid file in a temporary directory Implements GitHub #457. --- configfile.c | 3 ++ configfile.h | 3 +- repmgr.conf.sample | 5 +++ repmgrd.c | 77 ++++++++++++++++++++++++++++++++++++++++------ repmgrd.h | 4 +++ 5 files changed, 82 insertions(+), 10 deletions(-) diff --git a/configfile.c b/configfile.c index 367938fc..785419e8 100644 --- a/configfile.c +++ b/configfile.c @@ -359,6 +359,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList * options->async_query_timeout = DEFAULT_ASYNC_QUERY_TIMEOUT; options->primary_notification_timeout = DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT; options->repmgrd_standby_startup_timeout = -1; /* defaults to "standby_reconnect_timeout" if not set */ + memset(options->repmgrd_pid_file, 0, sizeof(options->repmgrd_pid_file)); /*------------- * witness settings @@ -604,6 +605,8 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList * options->primary_notification_timeout = repmgr_atoi(value, name, error_list, 0); else if (strcmp(name, "repmgrd_standby_startup_timeout") == 0) options->repmgrd_standby_startup_timeout = repmgr_atoi(value, name, error_list, 0); + else if (strcmp(name, "repmgrd_pid_file") == 0) + strncpy(options->repmgrd_pid_file, value, MAXPGPATH); /* witness settings */ else if (strcmp(name, "witness_sync_interval") == 0) diff --git a/configfile.h b/configfile.h index 2119478c..bc948648 100644 --- a/configfile.h +++ b/configfile.h @@ -131,6 +131,7 @@ typedef struct int async_query_timeout; int primary_notification_timeout; int repmgrd_standby_startup_timeout; + char repmgrd_pid_file[MAXPGPATH]; /* BDR settings */ bool bdr_local_monitoring_only; @@ -196,7 +197,7 @@ typedef struct false, -1, \ DEFAULT_ASYNC_QUERY_TIMEOUT, \ DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT, \ - -1, \ + -1, "", \ /* BDR settings */ \ false, DEFAULT_BDR_RECOVERY_TIMEOUT, \ /* service settings */ \ diff --git a/repmgr.conf.sample b/repmgr.conf.sample index 8a178c78..05b3e7f1 100644 --- a/repmgr.conf.sample +++ b/repmgr.conf.sample @@ -258,6 +258,11 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh" # These settings are only applied when repmgrd is running. Values shown # are defaults. +#repmgrd_pid_file= # Path of PID file to use for repmgrd; if not set, a PID file will + # be generated in a temporary directory specified by the environment + # variable $TMPDIR, or if not set, in "/tmp". This value can be overridden + # by the command line option "-p/--pid-file"; the command line option + # "--no-pid-file" will force PID file creation to be skipped. #failover=manual # one of 'automatic', 'manual'. # determines what action to take in the event of upstream failure # diff --git a/repmgrd.c b/repmgrd.c index a3bec535..6d456918 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -35,8 +35,10 @@ static char *config_file = NULL; static bool verbose = false; -static char *pid_file = NULL; +static char pid_file[MAXPGPATH]; static bool daemonize = false; +static bool show_pid_file = false; +static bool no_pid_file = false; t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER; @@ -101,6 +103,8 @@ main(int argc, char **argv) /* daemon options */ {"daemonize", no_argument, NULL, 'd'}, {"pid-file", required_argument, NULL, 'p'}, + {"show-pid-file", no_argument, NULL, 's'}, + {"no-pid-file", no_argument, NULL, OPT_NO_PID_FILE}, /* logging options */ {"log-level", required_argument, NULL, 'L'}, @@ -113,8 +117,6 @@ main(int argc, char **argv) set_progname(argv[0]); - srand(time(NULL)); - /* Disallow running as root */ if (geteuid() == 0) { @@ -128,6 +130,10 @@ main(int argc, char **argv) exit(1); } + srand(time(NULL)); + + memset(pid_file, 0, MAXPGPATH); + while ((c = getopt_long(argc, argv, "?Vf:L:vdp:m", long_options, &optindex)) != -1) { switch (c) @@ -173,7 +179,15 @@ main(int argc, char **argv) break; case 'p': - pid_file = optarg; + strncpy(pid_file, optarg, MAXPGPATH); + break; + + case 's': + show_pid_file = true; + break; + + case OPT_NO_PID_FILE: + no_pid_file = true; break; /* logging options */ @@ -239,6 +253,48 @@ main(int argc, char **argv) */ load_config(config_file, verbose, false, &config_file_options, argv[0]); + /* Determine pid file location, unless --no-pid-file supplied */ + + if (no_pid_file == false) + { + if (config_file_options.repmgrd_pid_file[0] != '\0') + { + if (pid_file[0] != '\0') + { + log_warning(_("\"repmgrd_pid_file\" will be overridden by --pid-file")); + } + else + { + strncpy(pid_file, config_file_options.repmgrd_pid_file, MAXPGPATH); + } + } + + /* no pid file provided - determine location */ + if (pid_file[0] == '\0') + { + const char *tmpdir = getenv("TMPDIR"); + + if (!tmpdir) + tmpdir = "/tmp"; + + maxpath_snprintf(pid_file, "%s/repmgrd.pid", tmpdir); + } + } + else + { + /* --no-pid-file supplied - overwrite any value provided with --pid-file ... */ + memset(pid_file, 0, MAXPGPATH); + } + + + /* If --show-pid-file supplied, output the location (if set) and exit */ + + if (show_pid_file == true) + { + printf("%s\n", pid_file); + exit(SUCCESS); + } + /* Some configuration file items can be overriden by command line options */ @@ -414,7 +470,7 @@ main(int argc, char **argv) daemonize_process(); } - if (pid_file != NULL) + if (pid_file[0] != '\0') { check_and_create_pid_file(pid_file); } @@ -669,6 +725,8 @@ show_help(void) { printf(_("%s: replication management daemon for PostgreSQL\n"), progname()); puts(""); + printf(_("%s monitors a cluster of servers and optionally performs failover.\n"), progname()); + puts(""); printf(_("Usage:\n")); printf(_(" %s [OPTIONS]\n"), progname()); @@ -688,12 +746,13 @@ show_help(void) puts(""); - printf(_("General configuration options:\n")); + printf(_("Daemon configuration options:\n")); printf(_(" -d, --daemonize detach process from foreground\n")); - printf(_(" -p, --pid-file=PATH write a PID file\n")); + printf(_(" -p, --pid-file=PATH use the specified PID file\n")); + printf(_(" -s, --show-pid-file show PID file which would be used by the current configuration\n")); + printf(_(" --no-pid-file don't write a PID file\n")); puts(""); - printf(_("%s monitors a cluster of servers and optionally performs failover.\n"), progname()); } @@ -802,7 +861,7 @@ terminate(int retval) { logger_shutdown(); - if (pid_file) + if (pid_file[0] != '\0') { unlink(pid_file); } diff --git a/repmgrd.h b/repmgrd.h index df132be6..ad811214 100644 --- a/repmgrd.h +++ b/repmgrd.h @@ -10,6 +10,8 @@ #include #include "portability/instr_time.h" +#define OPT_NO_PID_FILE 1000 + extern volatile sig_atomic_t got_SIGHUP; extern MonitoringState monitoring_state; extern instr_time degraded_monitoring_start; @@ -26,4 +28,6 @@ const char *print_monitoring_state(MonitoringState monitoring_state); void update_registration(PGconn *conn); void terminate(int retval); + + #endif /* _REPMGRD_H_ */