diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index 34ee76a237..4f9de83097 100644 --- a/src/backend/utils/misc/pg_controldata.c +++ b/src/backend/utils/misc/pg_controldata.c @@ -52,6 +52,9 @@ pg_control_system(PG_FUNCTION_ARGS) /* read the control file */ ControlFile = get_controlfile(DataDir, NULL); + if (!ControlFile) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = Int32GetDatum(ControlFile->pg_control_version); nulls[0] = false; @@ -128,6 +131,9 @@ pg_control_checkpoint(PG_FUNCTION_ARGS) /* Read the control file. */ ControlFile = get_controlfile(DataDir, NULL); + if (!ControlFile) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); /* * Calculate name of the WAL file containing the latest checkpoint's REDO @@ -230,6 +236,9 @@ pg_control_recovery(PG_FUNCTION_ARGS) /* read the control file */ ControlFile = get_controlfile(DataDir, NULL); + if (!ControlFile) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = LSNGetDatum(ControlFile->minRecoveryPoint); nulls[0] = false; @@ -295,6 +304,9 @@ pg_control_init(PG_FUNCTION_ARGS) /* read the control file */ ControlFile = get_controlfile(DataDir, NULL); + if (!ControlFile) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = Int32GetDatum(ControlFile->maxAlign); nulls[0] = false; diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index 96619a2076..e92feabade 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -156,6 +156,10 @@ main(int argc, char *argv[]) /* get a copy of the control file */ ControlFile = get_controlfile(DataDir, progname); + if (!ControlFile) + printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n" + "Either the file is corrupt, or it has a different layout than this program\n" + "is expecting. The results below are untrustworthy.\n\n")); /* * This slightly-chintzy coding will work as long as the control file diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index efc07291ad..eb8a67a903 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -19,6 +19,8 @@ #include "postgres_fe.h" +#include "catalog/pg_control.h" +#include "common/controldata_utils.h" #include "libpq-fe.h" #include "pqexpbuffer.h" @@ -96,7 +98,6 @@ static char postopts_file[MAXPGPATH]; static char version_file[MAXPGPATH]; static char pid_file[MAXPGPATH]; static char backup_file[MAXPGPATH]; -static char recovery_file[MAXPGPATH]; static char promote_file[MAXPGPATH]; #ifdef WIN32 @@ -158,6 +159,8 @@ static bool postmaster_is_alive(pid_t pid); static void unlimit_core_size(void); #endif +static DBState get_control_dbstate(void); + #ifdef WIN32 static void @@ -988,12 +991,12 @@ do_stop(void) /* * If backup_label exists, an online backup is running. Warn the user * that smart shutdown will wait for it to finish. However, if - * recovery.conf is also present, we're recovering from an online + * the server is in archive recovery, we're recovering from an online * backup instead of performing one. */ if (shutdown_mode == SMART_MODE && stat(backup_file, &statbuf) == 0 && - stat(recovery_file, &statbuf) != 0) + get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { print_msg(_("WARNING: online backup mode is active\n" "Shutdown will not complete until pg_stop_backup() is called.\n\n")); @@ -1076,12 +1079,12 @@ do_restart(void) /* * If backup_label exists, an online backup is running. Warn the user * that smart shutdown will wait for it to finish. However, if - * recovery.conf is also present, we're recovering from an online + * the server is in archive recovery, we're recovering from an online * backup instead of performing one. */ if (shutdown_mode == SMART_MODE && stat(backup_file, &statbuf) == 0 && - stat(recovery_file, &statbuf) != 0) + get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { print_msg(_("WARNING: online backup mode is active\n" "Shutdown will not complete until pg_stop_backup() is called.\n\n")); @@ -1168,7 +1171,6 @@ do_promote(void) { FILE *prmfile; pgpid_t pid; - struct stat statbuf; pid = get_pgpid(false); @@ -1187,8 +1189,7 @@ do_promote(void) exit(1); } - /* If recovery.conf doesn't exist, the server is not in standby mode */ - if (stat(recovery_file, &statbuf) != 0) + if (get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { write_stderr(_("%s: cannot promote server; " "server is not in standby mode\n"), @@ -2115,6 +2116,35 @@ adjust_data_dir(void) } +static DBState +get_control_dbstate(void) +{ + DBState ret; + + for (;;) + { + ControlFileData *control_file_data = get_controlfile(pg_data, progname); + + if (control_file_data) + { + ret = control_file_data->state; + pfree(control_file_data); + return ret; + } + + if (wait_seconds > 0) + { + pg_usleep(1000000); /* 1 sec */ + wait_seconds--; + continue; + } + + write_stderr(_("%s: control file appears to be corrupt\n"), progname); + exit(1); + } +} + + int main(int argc, char **argv) { @@ -2401,7 +2431,6 @@ main(int argc, char **argv) snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data); snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data); snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data); - snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data); } switch (ctl_command) diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c index 5592fe7039..f218d2558c 100644 --- a/src/common/controldata_utils.c +++ b/src/common/controldata_utils.c @@ -33,9 +33,11 @@ * * Get controlfile values. The caller is responsible * for pfreeing the result. + * + * Returns NULL if the CRC did not match. */ ControlFileData * -get_controlfile(char *DataDir, const char *progname) +get_controlfile(const char *DataDir, const char *progname) { ControlFileData *ControlFile; int fd; @@ -82,13 +84,10 @@ get_controlfile(char *DataDir, const char *progname) FIN_CRC32C(crc); if (!EQ_CRC32C(crc, ControlFile->crc)) -#ifndef FRONTEND - elog(ERROR, _("calculated CRC checksum does not match value stored in file")); -#else - printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n" - "Either the file is corrupt, or it has a different layout than this program\n" - "is expecting. The results below are untrustworthy.\n\n")); -#endif + { + pfree(ControlFile); + return NULL; + } /* Make sure the control file is valid byte order. */ if (ControlFile->pg_control_version % 65536 == 0 && diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h index a355d2252d..f834624e4e 100644 --- a/src/include/common/controldata_utils.h +++ b/src/include/common/controldata_utils.h @@ -12,6 +12,6 @@ #include "catalog/pg_control.h" -extern ControlFileData *get_controlfile(char *DataDir, const char *progname); +extern ControlFileData *get_controlfile(const char *DataDir, const char *progname); #endif /* COMMON_CONTROLDATA_UTILS_H */