1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2025-01-09 14:45:47 +02:00
pg_probackup/validate.c
Michael Paquier f94c5ab447 Sanitize logging facility
--debug and --verbose had actually the same meaning as they were aimed
at giving to the user information regarding how the process is running,
hence both options are merged into --verbose and use elog(LOG) to decide
if a given message should be printed out depending on the verbosity of
the call. This makes a couple of routines more readable as they do not
depend on any boolean checks.

The "_()" have been removed from the code, those are aimed at being used
for translation but having them mandatorily in each log message is just
useless noise. If needed, pgut.c should be updated in consequence to
have a more portable facility.

At the same time this commit takes care of putting into correct shape
some code paths more in-line with PostgreSQL policy. There are surely
more of this kind of ugly stuff but at this stage things are more simple
and more manageable.
2016-01-14 16:36:39 +09:00

192 lines
4.5 KiB
C

/*-------------------------------------------------------------------------
*
* validate.c: validate backup files.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
#include "pg_arman.h"
#include <sys/stat.h>
static bool pgBackupValidateFiles(parray *files, const char *root, bool size_only);
/*
* Validate files in the backup and update its status to OK.
* If any of files are corrupted, update its stutus to CORRUPT.
*/
int
do_validate(pgBackupRange *range)
{
int i;
parray *backup_list;
int ret;
bool another_pg_arman = false;
ret = catalog_lock();
if (ret == 1)
another_pg_arman = true;
/* get backup list matches given range */
backup_list = catalog_get_backup_list(range);
if (!backup_list)
elog(ERROR_SYSTEM, "cannot process any more.");
parray_qsort(backup_list, pgBackupCompareId);
for (i = 0; i < parray_num(backup_list); i++)
{
pgBackup *backup = (pgBackup *)parray_get(backup_list, i);
/* clean extra backups (switch STATUS to ERROR) */
if (!another_pg_arman &&
(backup->status == BACKUP_STATUS_RUNNING ||
backup->status == BACKUP_STATUS_DELETING))
{
backup->status = BACKUP_STATUS_ERROR;
pgBackupWriteIni(backup);
}
/* Validate completed backups only. */
if (backup->status != BACKUP_STATUS_DONE)
continue;
/* validate with CRC value and update status to OK */
pgBackupValidate(backup, false, false);
}
/* cleanup */
parray_walk(backup_list, pgBackupFree);
parray_free(backup_list);
catalog_unlock();
return 0;
}
/*
* Validate each files in the backup with its size.
*/
void
pgBackupValidate(pgBackup *backup,
bool size_only,
bool for_get_timeline)
{
char timestamp[100];
char base_path[MAXPGPATH];
char path[MAXPGPATH];
parray *files;
bool corrupted = false;
time2iso(timestamp, lengthof(timestamp), backup->start_time);
if (!for_get_timeline)
{
if (backup->backup_mode == BACKUP_MODE_FULL ||
backup->backup_mode == BACKUP_MODE_DIFF_PAGE)
elog(INFO, "validate: %s backup and archive log files by %s",
timestamp, (size_only ? "SIZE" : "CRC"));
}
if (!check)
{
if (backup->backup_mode == BACKUP_MODE_FULL ||
backup->backup_mode == BACKUP_MODE_DIFF_PAGE)
{
elog(LOG, "database files...");
pgBackupGetPath(backup, base_path, lengthof(base_path), DATABASE_DIR);
pgBackupGetPath(backup, path, lengthof(path),
DATABASE_FILE_LIST);
files = dir_read_file_list(base_path, path);
if (!pgBackupValidateFiles(files, base_path, size_only))
corrupted = true;
parray_walk(files, pgFileFree);
parray_free(files);
}
/* update status to OK */
if (corrupted)
backup->status = BACKUP_STATUS_CORRUPT;
else
backup->status = BACKUP_STATUS_OK;
pgBackupWriteIni(backup);
if (corrupted)
elog(WARNING, "backup %s is corrupted", timestamp);
else
elog(LOG, "backup %s is valid", timestamp);
}
}
static const char *
get_relative_path(const char *path, const char *root)
{
size_t rootlen = strlen(root);
if (strncmp(path, root, rootlen) == 0 && path[rootlen] == '/')
return path + rootlen + 1;
else
return path;
}
/*
* Validate files in the backup with size or CRC.
*/
static bool
pgBackupValidateFiles(parray *files, const char *root, bool size_only)
{
int i;
for (i = 0; i < parray_num(files); i++)
{
struct stat st;
pgFile *file = (pgFile *) parray_get(files, i);
if (interrupted)
elog(ERROR_INTERRUPTED, "interrupted during validate");
/* skipped backup while differential backup */
if (file->write_size == BYTES_INVALID || !S_ISREG(file->mode))
continue;
/* print progress */
elog(LOG, "(%d/%lu) %s", i + 1, (unsigned long) parray_num(files),
get_relative_path(file->path, root));
/* always validate file size */
if (stat(file->path, &st) == -1)
{
if (errno == ENOENT)
elog(WARNING, "backup file \"%s\" vanished", file->path);
else
elog(ERROR_SYSTEM, "cannot stat backup file \"%s\": %s",
get_relative_path(file->path, root), strerror(errno));
return false;
}
if (file->write_size != st.st_size)
{
elog(WARNING, "size of backup file \"%s\" must be %lu but %lu",
get_relative_path(file->path, root),
(unsigned long) file->write_size,
(unsigned long) st.st_size);
return false;
}
/* validate CRC too */
if (!size_only)
{
pg_crc32 crc;
crc = pgFileGetCRC(file);
if (crc != file->crc)
{
elog(WARNING, "CRC of backup file \"%s\" must be %X but %X",
get_relative_path(file->path, root), file->crc, crc);
return false;
}
}
}
return true;
}