LCOV - code coverage report
Current view: top level - src/bin/pg_resetwal - pg_resetwal.c (source / functions) Hit Total Coverage
Test: PostgreSQL 11devel Lines: 284 537 52.9 %
Date: 2017-11-22 12:18:04 Functions: 10 12 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 142 277 51.3 %

           Branch data     Line data    Source code
       1                 :            : /*-------------------------------------------------------------------------
       2                 :            :  *
       3                 :            :  * pg_resetwal.c
       4                 :            :  *    A utility to "zero out" the xlog when it's corrupt beyond recovery.
       5                 :            :  *    Can also rebuild pg_control if needed.
       6                 :            :  *
       7                 :            :  * The theory of operation is fairly simple:
       8                 :            :  *    1. Read the existing pg_control (which will include the last
       9                 :            :  *       checkpoint record).  If it is an old format then update to
      10                 :            :  *       current format.
      11                 :            :  *    2. If pg_control is corrupt, attempt to intuit reasonable values,
      12                 :            :  *       by scanning the old xlog if necessary.
      13                 :            :  *    3. Modify pg_control to reflect a "shutdown" state with a checkpoint
      14                 :            :  *       record at the start of xlog.
      15                 :            :  *    4. Flush the existing xlog files and write a new segment with
      16                 :            :  *       just a checkpoint record in it.  The new segment is positioned
      17                 :            :  *       just past the end of the old xlog, so that existing LSNs in
      18                 :            :  *       data pages will appear to be "in the past".
      19                 :            :  * This is all pretty straightforward except for the intuition part of
      20                 :            :  * step 2 ...
      21                 :            :  *
      22                 :            :  *
      23                 :            :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      24                 :            :  * Portions Copyright (c) 1994, Regents of the University of California
      25                 :            :  *
      26                 :            :  * src/bin/pg_resetwal/pg_resetwal.c
      27                 :            :  *
      28                 :            :  *-------------------------------------------------------------------------
      29                 :            :  */
      30                 :            : 
      31                 :            : /*
      32                 :            :  * We have to use postgres.h not postgres_fe.h here, because there's so much
      33                 :            :  * backend-only stuff in the XLOG include files we need.  But we need a
      34                 :            :  * frontend-ish environment otherwise.  Hence this ugly hack.
      35                 :            :  */
      36                 :            : #define FRONTEND 1
      37                 :            : 
      38                 :            : #include "postgres.h"
      39                 :            : 
      40                 :            : #include <dirent.h>
      41                 :            : #include <fcntl.h>
      42                 :            : #include <sys/stat.h>
      43                 :            : #include <sys/time.h>
      44                 :            : #include <time.h>
      45                 :            : #include <unistd.h>
      46                 :            : 
      47                 :            : #include "access/transam.h"
      48                 :            : #include "access/tuptoaster.h"
      49                 :            : #include "access/multixact.h"
      50                 :            : #include "access/xlog.h"
      51                 :            : #include "access/xlog_internal.h"
      52                 :            : #include "catalog/catversion.h"
      53                 :            : #include "catalog/pg_control.h"
      54                 :            : #include "common/fe_memutils.h"
      55                 :            : #include "common/restricted_token.h"
      56                 :            : #include "storage/large_object.h"
      57                 :            : #include "pg_getopt.h"
      58                 :            : 
      59                 :            : 
      60                 :            : static ControlFileData ControlFile; /* pg_control values */
      61                 :            : static XLogSegNo newXlogSegNo;  /* new XLOG segment # */
      62                 :            : static bool guessed = false;    /* T if we had to guess at any values */
      63                 :            : static const char *progname;
      64                 :            : static uint32 set_xid_epoch = (uint32) -1;
      65                 :            : static TransactionId set_xid = 0;
      66                 :            : static TransactionId set_oldest_commit_ts_xid = 0;
      67                 :            : static TransactionId set_newest_commit_ts_xid = 0;
      68                 :            : static Oid  set_oid = 0;
      69                 :            : static MultiXactId set_mxid = 0;
      70                 :            : static MultiXactOffset set_mxoff = (MultiXactOffset) -1;
      71                 :            : static uint32 minXlogTli = 0;
      72                 :            : static XLogSegNo minXlogSegNo = 0;
      73                 :            : static int  WalSegSz;
      74                 :            : 
      75                 :            : static void CheckDataVersion(void);
      76                 :            : static bool ReadControlFile(void);
      77                 :            : static void GuessControlValues(void);
      78                 :            : static void PrintControlValues(bool guessed);
      79                 :            : static void PrintNewControlValues(void);
      80                 :            : static void RewriteControlFile(void);
      81                 :            : static void FindEndOfXLOG(void);
      82                 :            : static void KillExistingXLOG(void);
      83                 :            : static void KillExistingArchiveStatus(void);
      84                 :            : static void WriteEmptyXLOG(void);
      85                 :            : static void usage(void);
      86                 :            : 
      87                 :            : 
      88                 :            : int
      89                 :         16 : main(int argc, char *argv[])
      90                 :            : {
      91                 :            :     int         c;
      92                 :         16 :     bool        force = false;
      93                 :         16 :     bool        noupdate = false;
      94                 :         16 :     MultiXactId set_oldestmxid = 0;
      95                 :            :     char       *endptr;
      96                 :            :     char       *endptr2;
      97                 :         16 :     char       *DataDir = NULL;
      98                 :         16 :     char       *log_fname = NULL;
      99                 :            :     int         fd;
     100                 :            : 
     101                 :         16 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
     102                 :            : 
     103                 :         16 :     progname = get_progname(argv[0]);
     104                 :            : 
     105         [ +  - ]:         16 :     if (argc > 1)
     106                 :            :     {
     107 [ +  - ][ -  + ]:         16 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     108                 :            :         {
     109                 :          0 :             usage();
     110                 :          0 :             exit(0);
     111                 :            :         }
     112 [ +  - ][ -  + ]:         16 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     113                 :            :         {
     114                 :          0 :             puts("pg_resetwal (PostgreSQL) " PG_VERSION);
     115                 :          0 :             exit(0);
     116                 :            :         }
     117                 :            :     }
     118                 :            : 
     119                 :            : 
     120         [ +  + ]:         40 :     while ((c = getopt(argc, argv, "c:D:e:fl:m:no:O:x:")) != -1)
     121                 :            :     {
     122   [ -  +  +  +  :         24 :         switch (c)
          +  +  +  +  +  
                   +  - ]
     123                 :            :         {
     124                 :            :             case 'D':
     125                 :          0 :                 DataDir = optarg;
     126                 :          0 :                 break;
     127                 :            : 
     128                 :            :             case 'f':
     129                 :          6 :                 force = true;
     130                 :          6 :                 break;
     131                 :            : 
     132                 :            :             case 'n':
     133                 :          4 :                 noupdate = true;
     134                 :          4 :                 break;
     135                 :            : 
     136                 :            :             case 'e':
     137                 :          2 :                 set_xid_epoch = strtoul(optarg, &endptr, 0);
     138 [ +  - ][ -  + ]:          2 :                 if (endptr == optarg || *endptr != '\0')
     139                 :            :                 {
     140                 :            :                     /*------
     141                 :            :                       translator: the second %s is a command line argument (-e, etc) */
     142                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-e");
     143                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     144                 :          0 :                     exit(1);
     145                 :            :                 }
     146         [ -  + ]:          2 :                 if (set_xid_epoch == -1)
     147                 :            :                 {
     148                 :          0 :                     fprintf(stderr, _("%s: transaction ID epoch (-e) must not be -1\n"), progname);
     149                 :          0 :                     exit(1);
     150                 :            :                 }
     151                 :          2 :                 break;
     152                 :            : 
     153                 :            :             case 'x':
     154                 :          2 :                 set_xid = strtoul(optarg, &endptr, 0);
     155 [ +  - ][ -  + ]:          2 :                 if (endptr == optarg || *endptr != '\0')
     156                 :            :                 {
     157                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-x");
     158                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     159                 :          0 :                     exit(1);
     160                 :            :                 }
     161         [ -  + ]:          2 :                 if (set_xid == 0)
     162                 :            :                 {
     163                 :          0 :                     fprintf(stderr, _("%s: transaction ID (-x) must not be 0\n"), progname);
     164                 :          0 :                     exit(1);
     165                 :            :                 }
     166                 :          2 :                 break;
     167                 :            : 
     168                 :            :             case 'c':
     169                 :          2 :                 set_oldest_commit_ts_xid = strtoul(optarg, &endptr, 0);
     170 [ +  - ][ -  + ]:          2 :                 if (endptr == optarg || *endptr != ',')
     171                 :            :                 {
     172                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-c");
     173                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     174                 :          0 :                     exit(1);
     175                 :            :                 }
     176                 :          2 :                 set_newest_commit_ts_xid = strtoul(endptr + 1, &endptr2, 0);
     177 [ +  - ][ -  + ]:          2 :                 if (endptr2 == endptr + 1 || *endptr2 != '\0')
     178                 :            :                 {
     179                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-c");
     180                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     181                 :          0 :                     exit(1);
     182                 :            :                 }
     183                 :            : 
     184 [ -  + ][ #  # ]:          2 :                 if (set_oldest_commit_ts_xid < 2 &&
     185                 :          0 :                     set_oldest_commit_ts_xid != 0)
     186                 :            :                 {
     187                 :          0 :                     fprintf(stderr, _("%s: transaction ID (-c) must be either 0 or greater than or equal to 2\n"), progname);
     188                 :          0 :                     exit(1);
     189                 :            :                 }
     190                 :            : 
     191 [ -  + ][ #  # ]:          2 :                 if (set_newest_commit_ts_xid < 2 &&
     192                 :          0 :                     set_newest_commit_ts_xid != 0)
     193                 :            :                 {
     194                 :          0 :                     fprintf(stderr, _("%s: transaction ID (-c) must be either 0 or greater than or equal to 2\n"), progname);
     195                 :          0 :                     exit(1);
     196                 :            :                 }
     197                 :          2 :                 break;
     198                 :            : 
     199                 :            :             case 'o':
     200                 :          2 :                 set_oid = strtoul(optarg, &endptr, 0);
     201 [ +  - ][ -  + ]:          2 :                 if (endptr == optarg || *endptr != '\0')
     202                 :            :                 {
     203                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-o");
     204                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     205                 :          0 :                     exit(1);
     206                 :            :                 }
     207         [ -  + ]:          2 :                 if (set_oid == 0)
     208                 :            :                 {
     209                 :          0 :                     fprintf(stderr, _("%s: OID (-o) must not be 0\n"), progname);
     210                 :          0 :                     exit(1);
     211                 :            :                 }
     212                 :          2 :                 break;
     213                 :            : 
     214                 :            :             case 'm':
     215                 :          2 :                 set_mxid = strtoul(optarg, &endptr, 0);
     216 [ +  - ][ -  + ]:          2 :                 if (endptr == optarg || *endptr != ',')
     217                 :            :                 {
     218                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-m");
     219                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     220                 :          0 :                     exit(1);
     221                 :            :                 }
     222                 :            : 
     223                 :          2 :                 set_oldestmxid = strtoul(endptr + 1, &endptr2, 0);
     224 [ +  - ][ -  + ]:          2 :                 if (endptr2 == endptr + 1 || *endptr2 != '\0')
     225                 :            :                 {
     226                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-m");
     227                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     228                 :          0 :                     exit(1);
     229                 :            :                 }
     230         [ -  + ]:          2 :                 if (set_mxid == 0)
     231                 :            :                 {
     232                 :          0 :                     fprintf(stderr, _("%s: multitransaction ID (-m) must not be 0\n"), progname);
     233                 :          0 :                     exit(1);
     234                 :            :                 }
     235                 :            : 
     236                 :            :                 /*
     237                 :            :                  * XXX It'd be nice to have more sanity checks here, e.g. so
     238                 :            :                  * that oldest is not wrapped around w.r.t. nextMulti.
     239                 :            :                  */
     240         [ -  + ]:          2 :                 if (set_oldestmxid == 0)
     241                 :            :                 {
     242                 :          0 :                     fprintf(stderr, _("%s: oldest multitransaction ID (-m) must not be 0\n"),
     243                 :            :                             progname);
     244                 :          0 :                     exit(1);
     245                 :            :                 }
     246                 :          2 :                 break;
     247                 :            : 
     248                 :            :             case 'O':
     249                 :          2 :                 set_mxoff = strtoul(optarg, &endptr, 0);
     250 [ +  - ][ -  + ]:          2 :                 if (endptr == optarg || *endptr != '\0')
     251                 :            :                 {
     252                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-O");
     253                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     254                 :          0 :                     exit(1);
     255                 :            :                 }
     256         [ -  + ]:          2 :                 if (set_mxoff == -1)
     257                 :            :                 {
     258                 :          0 :                     fprintf(stderr, _("%s: multitransaction offset (-O) must not be -1\n"), progname);
     259                 :          0 :                     exit(1);
     260                 :            :                 }
     261                 :          2 :                 break;
     262                 :            : 
     263                 :            :             case 'l':
     264         [ -  + ]:          2 :                 if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
     265                 :            :                 {
     266                 :          0 :                     fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-l");
     267                 :          0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     268                 :          0 :                     exit(1);
     269                 :            :                 }
     270                 :            : 
     271                 :            :                 /*
     272                 :            :                  * XLogFromFileName requires wal segment size which is not yet
     273                 :            :                  * set. Hence wal details are set later on.
     274                 :            :                  */
     275                 :          2 :                 log_fname = pg_strdup(optarg);
     276                 :          2 :                 break;
     277                 :            : 
     278                 :            :             default:
     279                 :          0 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     280                 :          0 :                 exit(1);
     281                 :            :         }
     282                 :            :     }
     283                 :            : 
     284 [ +  - ][ +  - ]:         16 :     if (DataDir == NULL && optind < argc)
     285                 :         16 :         DataDir = argv[optind++];
     286                 :            : 
     287                 :            :     /* Complain if any arguments remain */
     288         [ -  + ]:         16 :     if (optind < argc)
     289                 :            :     {
     290                 :          0 :         fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
     291                 :          0 :                 progname, argv[optind]);
     292                 :          0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
     293                 :            :                 progname);
     294                 :          0 :         exit(1);
     295                 :            :     }
     296                 :            : 
     297         [ -  + ]:         16 :     if (DataDir == NULL)
     298                 :            :     {
     299                 :          0 :         fprintf(stderr, _("%s: no data directory specified\n"), progname);
     300                 :          0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     301                 :          0 :         exit(1);
     302                 :            :     }
     303                 :            : 
     304                 :            :     /*
     305                 :            :      * Don't allow pg_resetwal to be run as root, to avoid overwriting the
     306                 :            :      * ownership of files in the data directory. We need only check for root
     307                 :            :      * -- any other user won't have sufficient permissions to modify files in
     308                 :            :      * the data directory.
     309                 :            :      */
     310                 :            : #ifndef WIN32
     311         [ -  + ]:         16 :     if (geteuid() == 0)
     312                 :            :     {
     313                 :          0 :         fprintf(stderr, _("%s: cannot be executed by \"root\"\n"),
     314                 :            :                 progname);
     315                 :          0 :         fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
     316                 :            :                 progname);
     317                 :          0 :         exit(1);
     318                 :            :     }
     319                 :            : #endif
     320                 :            : 
     321                 :         16 :     get_restricted_token(progname);
     322                 :            : 
     323         [ -  + ]:         16 :     if (chdir(DataDir) < 0)
     324                 :            :     {
     325                 :          0 :         fprintf(stderr, _("%s: could not change directory to \"%s\": %s\n"),
     326                 :          0 :                 progname, DataDir, strerror(errno));
     327                 :          0 :         exit(1);
     328                 :            :     }
     329                 :            : 
     330                 :            :     /* Check that data directory matches our server version */
     331                 :         16 :     CheckDataVersion();
     332                 :            : 
     333                 :            :     /*
     334                 :            :      * Check for a postmaster lock file --- if there is one, refuse to
     335                 :            :      * proceed, on grounds we might be interfering with a live installation.
     336                 :            :      */
     337         [ +  - ]:         16 :     if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
     338                 :            :     {
     339         [ -  + ]:         16 :         if (errno != ENOENT)
     340                 :            :         {
     341                 :          0 :             fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
     342                 :          0 :                     progname, "postmaster.pid", strerror(errno));
     343                 :          0 :             exit(1);
     344                 :            :         }
     345                 :            :     }
     346                 :            :     else
     347                 :            :     {
     348                 :          0 :         fprintf(stderr, _("%s: lock file \"%s\" exists\n"
     349                 :            :                           "Is a server running?  If not, delete the lock file and try again.\n"),
     350                 :            :                 progname, "postmaster.pid");
     351                 :          0 :         exit(1);
     352                 :            :     }
     353                 :            : 
     354                 :            :     /*
     355                 :            :      * Attempt to read the existing pg_control file
     356                 :            :      */
     357         [ -  + ]:         16 :     if (!ReadControlFile())
     358                 :          0 :         GuessControlValues();
     359                 :            : 
     360         [ +  + ]:         16 :     if (log_fname != NULL)
     361                 :          2 :         XLogFromFileName(log_fname, &minXlogTli, &minXlogSegNo, WalSegSz);
     362                 :            : 
     363                 :            :     /*
     364                 :            :      * Also look at existing segment files to set up newXlogSegNo
     365                 :            :      */
     366                 :         16 :     FindEndOfXLOG();
     367                 :            : 
     368                 :            :     /*
     369                 :            :      * If we're not going to proceed with the reset, print the current control
     370                 :            :      * file parameters.
     371                 :            :      */
     372 [ -  + ][ #  # ]:         16 :     if ((guessed && !force) || noupdate)
                 [ +  + ]
     373                 :          4 :         PrintControlValues(guessed);
     374                 :            : 
     375                 :            :     /*
     376                 :            :      * Adjust fields if required by switches.  (Do this now so that printout,
     377                 :            :      * if any, includes these values.)
     378                 :            :      */
     379         [ +  + ]:         16 :     if (set_xid_epoch != -1)
     380                 :          2 :         ControlFile.checkPointCopy.nextXidEpoch = set_xid_epoch;
     381                 :            : 
     382         [ +  + ]:         16 :     if (set_xid != 0)
     383                 :            :     {
     384                 :          2 :         ControlFile.checkPointCopy.nextXid = set_xid;
     385                 :            : 
     386                 :            :         /*
     387                 :            :          * For the moment, just set oldestXid to a value that will force
     388                 :            :          * immediate autovacuum-for-wraparound.  It's not clear whether adding
     389                 :            :          * user control of this is useful, so let's just do something that's
     390                 :            :          * reasonably safe.  The magic constant here corresponds to the
     391                 :            :          * maximum allowed value of autovacuum_freeze_max_age.
     392                 :            :          */
     393                 :          2 :         ControlFile.checkPointCopy.oldestXid = set_xid - 2000000000;
     394         [ -  + ]:          2 :         if (ControlFile.checkPointCopy.oldestXid < FirstNormalTransactionId)
     395                 :          0 :             ControlFile.checkPointCopy.oldestXid += FirstNormalTransactionId;
     396                 :          2 :         ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
     397                 :            :     }
     398                 :            : 
     399         [ +  + ]:         16 :     if (set_oldest_commit_ts_xid != 0)
     400                 :          2 :         ControlFile.checkPointCopy.oldestCommitTsXid = set_oldest_commit_ts_xid;
     401         [ +  + ]:         16 :     if (set_newest_commit_ts_xid != 0)
     402                 :          2 :         ControlFile.checkPointCopy.newestCommitTsXid = set_newest_commit_ts_xid;
     403                 :            : 
     404         [ +  + ]:         16 :     if (set_oid != 0)
     405                 :          2 :         ControlFile.checkPointCopy.nextOid = set_oid;
     406                 :            : 
     407         [ +  + ]:         16 :     if (set_mxid != 0)
     408                 :            :     {
     409                 :          2 :         ControlFile.checkPointCopy.nextMulti = set_mxid;
     410                 :            : 
     411                 :          2 :         ControlFile.checkPointCopy.oldestMulti = set_oldestmxid;
     412         [ -  + ]:          2 :         if (ControlFile.checkPointCopy.oldestMulti < FirstMultiXactId)
     413                 :          0 :             ControlFile.checkPointCopy.oldestMulti += FirstMultiXactId;
     414                 :          2 :         ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
     415                 :            :     }
     416                 :            : 
     417         [ +  + ]:         16 :     if (set_mxoff != -1)
     418                 :          2 :         ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;
     419                 :            : 
     420         [ -  + ]:         16 :     if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
     421                 :            :     {
     422                 :          0 :         ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
     423                 :          0 :         ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
     424                 :            :     }
     425                 :            : 
     426         [ +  + ]:         16 :     if (minXlogSegNo > newXlogSegNo)
     427                 :          2 :         newXlogSegNo = minXlogSegNo;
     428                 :            : 
     429                 :            :     /*
     430                 :            :      * If we had to guess anything, and -f was not given, just print the
     431                 :            :      * guessed values and exit.  Also print if -n is given.
     432                 :            :      */
     433 [ -  + ][ #  # ]:         16 :     if ((guessed && !force) || noupdate)
                 [ +  + ]
     434                 :            :     {
     435                 :          4 :         PrintNewControlValues();
     436         [ -  + ]:          4 :         if (!noupdate)
     437                 :            :         {
     438                 :          0 :             printf(_("\nIf these values seem acceptable, use -f to force reset.\n"));
     439                 :          0 :             exit(1);
     440                 :            :         }
     441                 :            :         else
     442                 :          4 :             exit(0);
     443                 :            :     }
     444                 :            : 
     445                 :            :     /*
     446                 :            :      * Don't reset from a dirty pg_control without -f, either.
     447                 :            :      */
     448 [ -  + ][ #  # ]:         12 :     if (ControlFile.state != DB_SHUTDOWNED && !force)
     449                 :            :     {
     450                 :          0 :         printf(_("The database server was not shut down cleanly.\n"
     451                 :            :                  "Resetting the write-ahead log might cause data to be lost.\n"
     452                 :            :                  "If you want to proceed anyway, use -f to force reset.\n"));
     453                 :          0 :         exit(1);
     454                 :            :     }
     455                 :            : 
     456                 :            :     /*
     457                 :            :      * Else, do the dirty deed.
     458                 :            :      */
     459                 :         12 :     RewriteControlFile();
     460                 :         12 :     KillExistingXLOG();
     461                 :         12 :     KillExistingArchiveStatus();
     462                 :         12 :     WriteEmptyXLOG();
     463                 :            : 
     464                 :         12 :     printf(_("Write-ahead log reset\n"));
     465                 :         12 :     return 0;
     466                 :            : }
     467                 :            : 
     468                 :            : 
     469                 :            : /*
     470                 :            :  * Look at the version string stored in PG_VERSION and decide if this utility
     471                 :            :  * can be run safely or not.
     472                 :            :  *
     473                 :            :  * We don't want to inject pg_control and WAL files that are for a different
     474                 :            :  * major version; that can't do anything good.  Note that we don't treat
     475                 :            :  * mismatching version info in pg_control as a reason to bail out, because
     476                 :            :  * recovering from a corrupted pg_control is one of the main reasons for this
     477                 :            :  * program to exist at all.  However, PG_VERSION is unlikely to get corrupted,
     478                 :            :  * and if it were it would be easy to fix by hand.  So let's make this check
     479                 :            :  * to prevent simple user errors.
     480                 :            :  */
     481                 :            : static void
     482                 :         16 : CheckDataVersion(void)
     483                 :            : {
     484                 :         16 :     const char *ver_file = "PG_VERSION";
     485                 :            :     FILE       *ver_fd;
     486                 :            :     char        rawline[64];
     487                 :            :     int         len;
     488                 :            : 
     489         [ -  + ]:         16 :     if ((ver_fd = fopen(ver_file, "r")) == NULL)
     490                 :            :     {
     491                 :          0 :         fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
     492                 :          0 :                 progname, ver_file, strerror(errno));
     493                 :          0 :         exit(1);
     494                 :            :     }
     495                 :            : 
     496                 :            :     /* version number has to be the first line read */
     497         [ -  + ]:         16 :     if (!fgets(rawline, sizeof(rawline), ver_fd))
     498                 :            :     {
     499         [ #  # ]:          0 :         if (!ferror(ver_fd))
     500                 :            :         {
     501                 :          0 :             fprintf(stderr, _("%s: unexpected empty file \"%s\"\n"),
     502                 :            :                     progname, ver_file);
     503                 :            :         }
     504                 :            :         else
     505                 :            :         {
     506                 :          0 :             fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
     507                 :          0 :                     progname, ver_file, strerror(errno));
     508                 :            :         }
     509                 :          0 :         exit(1);
     510                 :            :     }
     511                 :            : 
     512                 :            :     /* remove trailing newline, handling Windows newlines as well */
     513                 :         16 :     len = strlen(rawline);
     514 [ +  - ][ +  - ]:         16 :     if (len > 0 && rawline[len - 1] == '\n')
     515                 :            :     {
     516                 :         16 :         rawline[--len] = '\0';
     517 [ +  - ][ -  + ]:         16 :         if (len > 0 && rawline[len - 1] == '\r')
     518                 :          0 :             rawline[--len] = '\0';
     519                 :            :     }
     520                 :            : 
     521         [ -  + ]:         16 :     if (strcmp(rawline, PG_MAJORVERSION) != 0)
     522                 :            :     {
     523                 :          0 :         fprintf(stderr, _("%s: data directory is of wrong version\n"
     524                 :            :                           "File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".\n"),
     525                 :            :                 progname, ver_file, rawline, PG_MAJORVERSION);
     526                 :          0 :         exit(1);
     527                 :            :     }
     528                 :            : 
     529                 :         16 :     fclose(ver_fd);
     530                 :         16 : }
     531                 :            : 
     532                 :            : 
     533                 :            : /*
     534                 :            :  * Try to read the existing pg_control file.
     535                 :            :  *
     536                 :            :  * This routine is also responsible for updating old pg_control versions
     537                 :            :  * to the current format.  (Currently we don't do anything of the sort.)
     538                 :            :  */
     539                 :            : static bool
     540                 :         16 : ReadControlFile(void)
     541                 :            : {
     542                 :            :     int         fd;
     543                 :            :     int         len;
     544                 :            :     char       *buffer;
     545                 :            :     pg_crc32c   crc;
     546                 :            : 
     547         [ -  + ]:         16 :     if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
     548                 :            :     {
     549                 :            :         /*
     550                 :            :          * If pg_control is not there at all, or we can't read it, the odds
     551                 :            :          * are we've been handed a bad DataDir path, so give up. User can do
     552                 :            :          * "touch pg_control" to force us to proceed.
     553                 :            :          */
     554                 :          0 :         fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
     555                 :          0 :                 progname, XLOG_CONTROL_FILE, strerror(errno));
     556         [ #  # ]:          0 :         if (errno == ENOENT)
     557                 :          0 :             fprintf(stderr, _("If you are sure the data directory path is correct, execute\n"
     558                 :            :                               "  touch %s\n"
     559                 :            :                               "and try again.\n"),
     560                 :            :                     XLOG_CONTROL_FILE);
     561                 :          0 :         exit(1);
     562                 :            :     }
     563                 :            : 
     564                 :            :     /* Use malloc to ensure we have a maxaligned buffer */
     565                 :         16 :     buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
     566                 :            : 
     567                 :         16 :     len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
     568         [ -  + ]:         16 :     if (len < 0)
     569                 :            :     {
     570                 :          0 :         fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
     571                 :          0 :                 progname, XLOG_CONTROL_FILE, strerror(errno));
     572                 :          0 :         exit(1);
     573                 :            :     }
     574                 :         16 :     close(fd);
     575                 :            : 
     576 [ +  - ][ +  - ]:         16 :     if (len >= sizeof(ControlFileData) &&
     577                 :         16 :         ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
     578                 :            :     {
     579                 :            :         /* Check the CRC. */
     580                 :         16 :         INIT_CRC32C(crc);
     581                 :         16 :         COMP_CRC32C(crc,
     582                 :            :                     buffer,
     583                 :            :                     offsetof(ControlFileData, crc));
     584                 :         16 :         FIN_CRC32C(crc);
     585                 :            : 
     586         [ -  + ]:         16 :         if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
     587                 :            :         {
     588                 :            :             /* We will use the data but treat it as guessed. */
     589                 :          0 :             fprintf(stderr,
     590                 :          0 :                     _("%s: pg_control exists but has invalid CRC; proceed with caution\n"),
     591                 :            :                     progname);
     592                 :          0 :             guessed = true;
     593                 :            :         }
     594                 :            : 
     595                 :         16 :         memcpy(&ControlFile, buffer, sizeof(ControlFile));
     596                 :         16 :         WalSegSz = ControlFile.xlog_seg_size;
     597                 :            : 
     598                 :            :         /* return false if WalSegSz is not valid */
     599 [ +  - ][ +  - ]:         16 :         if (!IsValidWalSegSize(WalSegSz))
         [ +  - ][ -  + ]
     600                 :            :         {
     601                 :          0 :             fprintf(stderr,
     602                 :          0 :                     _("%s: pg_control specifies invalid WAL segment size (%d bytes); proceed with caution \n"),
     603                 :            :                     progname, WalSegSz);
     604                 :          0 :             guessed = true;
     605                 :            :         }
     606                 :            : 
     607                 :         16 :         return true;
     608                 :            :     }
     609                 :            : 
     610                 :            :     /* Looks like it's a mess. */
     611                 :          0 :     fprintf(stderr, _("%s: pg_control exists but is broken or wrong version; ignoring it\n"),
     612                 :            :             progname);
     613                 :          0 :     return false;
     614                 :            : }
     615                 :            : 
     616                 :            : 
     617                 :            : /*
     618                 :            :  * Guess at pg_control values when we can't read the old ones.
     619                 :            :  */
     620                 :            : static void
     621                 :          0 : GuessControlValues(void)
     622                 :            : {
     623                 :            :     uint64      sysidentifier;
     624                 :            :     struct timeval tv;
     625                 :            : 
     626                 :            :     /*
     627                 :            :      * Set up a completely default set of pg_control values.
     628                 :            :      */
     629                 :          0 :     guessed = true;
     630                 :          0 :     memset(&ControlFile, 0, sizeof(ControlFile));
     631                 :            : 
     632                 :          0 :     ControlFile.pg_control_version = PG_CONTROL_VERSION;
     633                 :          0 :     ControlFile.catalog_version_no = CATALOG_VERSION_NO;
     634                 :            : 
     635                 :            :     /*
     636                 :            :      * Create a new unique installation identifier, since we can no longer use
     637                 :            :      * any old XLOG records.  See notes in xlog.c about the algorithm.
     638                 :            :      */
     639                 :          0 :     gettimeofday(&tv, NULL);
     640                 :          0 :     sysidentifier = ((uint64) tv.tv_sec) << 32;
     641                 :          0 :     sysidentifier |= ((uint64) tv.tv_usec) << 12;
     642                 :          0 :     sysidentifier |= getpid() & 0xFFF;
     643                 :            : 
     644                 :          0 :     ControlFile.system_identifier = sysidentifier;
     645                 :            : 
     646                 :          0 :     ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
     647                 :          0 :     ControlFile.checkPointCopy.ThisTimeLineID = 1;
     648                 :          0 :     ControlFile.checkPointCopy.PrevTimeLineID = 1;
     649                 :          0 :     ControlFile.checkPointCopy.fullPageWrites = false;
     650                 :          0 :     ControlFile.checkPointCopy.nextXidEpoch = 0;
     651                 :          0 :     ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;
     652                 :          0 :     ControlFile.checkPointCopy.nextOid = FirstBootstrapObjectId;
     653                 :          0 :     ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
     654                 :          0 :     ControlFile.checkPointCopy.nextMultiOffset = 0;
     655                 :          0 :     ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
     656                 :          0 :     ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
     657                 :          0 :     ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
     658                 :          0 :     ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
     659                 :          0 :     ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
     660                 :          0 :     ControlFile.checkPointCopy.oldestActiveXid = InvalidTransactionId;
     661                 :            : 
     662                 :          0 :     ControlFile.state = DB_SHUTDOWNED;
     663                 :          0 :     ControlFile.time = (pg_time_t) time(NULL);
     664                 :          0 :     ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
     665                 :          0 :     ControlFile.unloggedLSN = 1;
     666                 :            : 
     667                 :            :     /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
     668                 :            : 
     669                 :          0 :     ControlFile.wal_level = WAL_LEVEL_MINIMAL;
     670                 :          0 :     ControlFile.wal_log_hints = false;
     671                 :          0 :     ControlFile.track_commit_timestamp = false;
     672                 :          0 :     ControlFile.MaxConnections = 100;
     673                 :          0 :     ControlFile.max_worker_processes = 8;
     674                 :          0 :     ControlFile.max_prepared_xacts = 0;
     675                 :          0 :     ControlFile.max_locks_per_xact = 64;
     676                 :            : 
     677                 :          0 :     ControlFile.maxAlign = MAXIMUM_ALIGNOF;
     678                 :          0 :     ControlFile.floatFormat = FLOATFORMAT_VALUE;
     679                 :          0 :     ControlFile.blcksz = BLCKSZ;
     680                 :          0 :     ControlFile.relseg_size = RELSEG_SIZE;
     681                 :          0 :     ControlFile.xlog_blcksz = XLOG_BLCKSZ;
     682                 :          0 :     ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE;
     683                 :          0 :     ControlFile.nameDataLen = NAMEDATALEN;
     684                 :          0 :     ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
     685                 :          0 :     ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
     686                 :          0 :     ControlFile.loblksize = LOBLKSIZE;
     687                 :          0 :     ControlFile.float4ByVal = FLOAT4PASSBYVAL;
     688                 :          0 :     ControlFile.float8ByVal = FLOAT8PASSBYVAL;
     689                 :            : 
     690                 :            :     /*
     691                 :            :      * XXX eventually, should try to grovel through old XLOG to develop more
     692                 :            :      * accurate values for TimeLineID, nextXID, etc.
     693                 :            :      */
     694                 :          0 : }
     695                 :            : 
     696                 :            : 
     697                 :            : /*
     698                 :            :  * Print the guessed pg_control values when we had to guess.
     699                 :            :  *
     700                 :            :  * NB: this display should be just those fields that will not be
     701                 :            :  * reset by RewriteControlFile().
     702                 :            :  */
     703                 :            : static void
     704                 :          4 : PrintControlValues(bool guessed)
     705                 :            : {
     706                 :            :     char        sysident_str[32];
     707                 :            : 
     708         [ -  + ]:          4 :     if (guessed)
     709                 :          0 :         printf(_("Guessed pg_control values:\n\n"));
     710                 :            :     else
     711                 :          4 :         printf(_("Current pg_control values:\n\n"));
     712                 :            : 
     713                 :            :     /*
     714                 :            :      * Format system_identifier separately to keep platform-dependent format
     715                 :            :      * code out of the translatable message string.
     716                 :            :      */
     717                 :          4 :     snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
     718                 :            :              ControlFile.system_identifier);
     719                 :            : 
     720                 :          4 :     printf(_("pg_control version number:            %u\n"),
     721                 :            :            ControlFile.pg_control_version);
     722                 :          4 :     printf(_("Catalog version number:               %u\n"),
     723                 :            :            ControlFile.catalog_version_no);
     724                 :          4 :     printf(_("Database system identifier:           %s\n"),
     725                 :            :            sysident_str);
     726                 :          4 :     printf(_("Latest checkpoint's TimeLineID:       %u\n"),
     727                 :            :            ControlFile.checkPointCopy.ThisTimeLineID);
     728         [ +  - ]:          4 :     printf(_("Latest checkpoint's full_page_writes: %s\n"),
     729                 :          4 :            ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
     730                 :          4 :     printf(_("Latest checkpoint's NextXID:          %u:%u\n"),
     731                 :            :            ControlFile.checkPointCopy.nextXidEpoch,
     732                 :            :            ControlFile.checkPointCopy.nextXid);
     733                 :          4 :     printf(_("Latest checkpoint's NextOID:          %u\n"),
     734                 :            :            ControlFile.checkPointCopy.nextOid);
     735                 :          4 :     printf(_("Latest checkpoint's NextMultiXactId:  %u\n"),
     736                 :            :            ControlFile.checkPointCopy.nextMulti);
     737                 :          4 :     printf(_("Latest checkpoint's NextMultiOffset:  %u\n"),
     738                 :            :            ControlFile.checkPointCopy.nextMultiOffset);
     739                 :          4 :     printf(_("Latest checkpoint's oldestXID:        %u\n"),
     740                 :            :            ControlFile.checkPointCopy.oldestXid);
     741                 :          4 :     printf(_("Latest checkpoint's oldestXID's DB:   %u\n"),
     742                 :            :            ControlFile.checkPointCopy.oldestXidDB);
     743                 :          4 :     printf(_("Latest checkpoint's oldestActiveXID:  %u\n"),
     744                 :            :            ControlFile.checkPointCopy.oldestActiveXid);
     745                 :          4 :     printf(_("Latest checkpoint's oldestMultiXid:   %u\n"),
     746                 :            :            ControlFile.checkPointCopy.oldestMulti);
     747                 :          4 :     printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
     748                 :            :            ControlFile.checkPointCopy.oldestMultiDB);
     749                 :          4 :     printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
     750                 :            :            ControlFile.checkPointCopy.oldestCommitTsXid);
     751                 :          4 :     printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
     752                 :            :            ControlFile.checkPointCopy.newestCommitTsXid);
     753                 :          4 :     printf(_("Maximum data alignment:               %u\n"),
     754                 :            :            ControlFile.maxAlign);
     755                 :            :     /* we don't print floatFormat since can't say much useful about it */
     756                 :          4 :     printf(_("Database block size:                  %u\n"),
     757                 :            :            ControlFile.blcksz);
     758                 :          4 :     printf(_("Blocks per segment of large relation: %u\n"),
     759                 :            :            ControlFile.relseg_size);
     760                 :          4 :     printf(_("WAL block size:                       %u\n"),
     761                 :            :            ControlFile.xlog_blcksz);
     762                 :          4 :     printf(_("Bytes per WAL segment:                %u\n"),
     763                 :            :            ControlFile.xlog_seg_size);
     764                 :          4 :     printf(_("Maximum length of identifiers:        %u\n"),
     765                 :            :            ControlFile.nameDataLen);
     766                 :          4 :     printf(_("Maximum columns in an index:          %u\n"),
     767                 :            :            ControlFile.indexMaxKeys);
     768                 :          4 :     printf(_("Maximum size of a TOAST chunk:        %u\n"),
     769                 :            :            ControlFile.toast_max_chunk_size);
     770                 :          4 :     printf(_("Size of a large-object chunk:         %u\n"),
     771                 :            :            ControlFile.loblksize);
     772                 :            :     /* This is no longer configurable, but users may still expect to see it: */
     773                 :          4 :     printf(_("Date/time type storage:               %s\n"),
     774                 :            :            _("64-bit integers"));
     775         [ +  - ]:          4 :     printf(_("Float4 argument passing:              %s\n"),
     776                 :          4 :            (ControlFile.float4ByVal ? _("by value") : _("by reference")));
     777         [ +  - ]:          4 :     printf(_("Float8 argument passing:              %s\n"),
     778                 :          4 :            (ControlFile.float8ByVal ? _("by value") : _("by reference")));
     779                 :          4 :     printf(_("Data page checksum version:           %u\n"),
     780                 :            :            ControlFile.data_checksum_version);
     781                 :          4 : }
     782                 :            : 
     783                 :            : 
     784                 :            : /*
     785                 :            :  * Print the values to be changed.
     786                 :            :  */
     787                 :            : static void
     788                 :          4 : PrintNewControlValues(void)
     789                 :            : {
     790                 :            :     char        fname[MAXFNAMELEN];
     791                 :            : 
     792                 :            :     /* This will be always printed in order to keep format same. */
     793                 :          4 :     printf(_("\n\nValues to be changed:\n\n"));
     794                 :            : 
     795                 :          4 :     XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID,
     796                 :            :                  newXlogSegNo, WalSegSz);
     797                 :          4 :     printf(_("First log segment after reset:        %s\n"), fname);
     798                 :            : 
     799         [ -  + ]:          4 :     if (set_mxid != 0)
     800                 :            :     {
     801                 :          0 :         printf(_("NextMultiXactId:                      %u\n"),
     802                 :            :                ControlFile.checkPointCopy.nextMulti);
     803                 :          0 :         printf(_("OldestMultiXid:                       %u\n"),
     804                 :            :                ControlFile.checkPointCopy.oldestMulti);
     805                 :          0 :         printf(_("OldestMulti's DB:                     %u\n"),
     806                 :            :                ControlFile.checkPointCopy.oldestMultiDB);
     807                 :            :     }
     808                 :            : 
     809         [ -  + ]:          4 :     if (set_mxoff != -1)
     810                 :            :     {
     811                 :          0 :         printf(_("NextMultiOffset:                      %u\n"),
     812                 :            :                ControlFile.checkPointCopy.nextMultiOffset);
     813                 :            :     }
     814                 :            : 
     815         [ -  + ]:          4 :     if (set_oid != 0)
     816                 :            :     {
     817                 :          0 :         printf(_("NextOID:                              %u\n"),
     818                 :            :                ControlFile.checkPointCopy.nextOid);
     819                 :            :     }
     820                 :            : 
     821         [ -  + ]:          4 :     if (set_xid != 0)
     822                 :            :     {
     823                 :          0 :         printf(_("NextXID:                              %u\n"),
     824                 :            :                ControlFile.checkPointCopy.nextXid);
     825                 :          0 :         printf(_("OldestXID:                            %u\n"),
     826                 :            :                ControlFile.checkPointCopy.oldestXid);
     827                 :          0 :         printf(_("OldestXID's DB:                       %u\n"),
     828                 :            :                ControlFile.checkPointCopy.oldestXidDB);
     829                 :            :     }
     830                 :            : 
     831         [ -  + ]:          4 :     if (set_xid_epoch != -1)
     832                 :            :     {
     833                 :          0 :         printf(_("NextXID epoch:                        %u\n"),
     834                 :            :                ControlFile.checkPointCopy.nextXidEpoch);
     835                 :            :     }
     836                 :            : 
     837         [ -  + ]:          4 :     if (set_oldest_commit_ts_xid != 0)
     838                 :            :     {
     839                 :          0 :         printf(_("oldestCommitTsXid:                    %u\n"),
     840                 :            :                ControlFile.checkPointCopy.oldestCommitTsXid);
     841                 :            :     }
     842         [ -  + ]:          4 :     if (set_newest_commit_ts_xid != 0)
     843                 :            :     {
     844                 :          0 :         printf(_("newestCommitTsXid:                    %u\n"),
     845                 :            :                ControlFile.checkPointCopy.newestCommitTsXid);
     846                 :            :     }
     847                 :          4 : }
     848                 :            : 
     849                 :            : 
     850                 :            : /*
     851                 :            :  * Write out the new pg_control file.
     852                 :            :  */
     853                 :            : static void
     854                 :         12 : RewriteControlFile(void)
     855                 :            : {
     856                 :            :     int         fd;
     857                 :            :     char        buffer[PG_CONTROL_FILE_SIZE];   /* need not be aligned */
     858                 :            : 
     859                 :            :     /*
     860                 :            :      * For good luck, apply the same static assertions as in backend's
     861                 :            :      * WriteControlFile().
     862                 :            :      */
     863                 :            :     StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
     864                 :            :                      "pg_control is too large for atomic disk writes");
     865                 :            :     StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
     866                 :            :                      "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
     867                 :            : 
     868                 :            :     /*
     869                 :            :      * Adjust fields as needed to force an empty XLOG starting at
     870                 :            :      * newXlogSegNo.
     871                 :            :      */
     872                 :         12 :     XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD,
     873                 :            :                             ControlFile.checkPointCopy.redo, WalSegSz);
     874                 :         12 :     ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
     875                 :            : 
     876                 :         12 :     ControlFile.state = DB_SHUTDOWNED;
     877                 :         12 :     ControlFile.time = (pg_time_t) time(NULL);
     878                 :         12 :     ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
     879                 :         12 :     ControlFile.minRecoveryPoint = 0;
     880                 :         12 :     ControlFile.minRecoveryPointTLI = 0;
     881                 :         12 :     ControlFile.backupStartPoint = 0;
     882                 :         12 :     ControlFile.backupEndPoint = 0;
     883                 :         12 :     ControlFile.backupEndRequired = false;
     884                 :            : 
     885                 :            :     /*
     886                 :            :      * Force the defaults for max_* settings. The values don't really matter
     887                 :            :      * as long as wal_level='minimal'; the postmaster will reset these fields
     888                 :            :      * anyway at startup.
     889                 :            :      */
     890                 :         12 :     ControlFile.wal_level = WAL_LEVEL_MINIMAL;
     891                 :         12 :     ControlFile.wal_log_hints = false;
     892                 :         12 :     ControlFile.track_commit_timestamp = false;
     893                 :         12 :     ControlFile.MaxConnections = 100;
     894                 :         12 :     ControlFile.max_worker_processes = 8;
     895                 :         12 :     ControlFile.max_prepared_xacts = 0;
     896                 :         12 :     ControlFile.max_locks_per_xact = 64;
     897                 :            : 
     898                 :            :     /* Now we can force the recorded xlog seg size to the right thing. */
     899                 :         12 :     ControlFile.xlog_seg_size = WalSegSz;
     900                 :            : 
     901                 :            :     /* Contents are protected with a CRC */
     902                 :         12 :     INIT_CRC32C(ControlFile.crc);
     903                 :         12 :     COMP_CRC32C(ControlFile.crc,
     904                 :            :                 (char *) &ControlFile,
     905                 :            :                 offsetof(ControlFileData, crc));
     906                 :         12 :     FIN_CRC32C(ControlFile.crc);
     907                 :            : 
     908                 :            :     /*
     909                 :            :      * We write out PG_CONTROL_FILE_SIZE bytes into pg_control, zero-padding
     910                 :            :      * the excess over sizeof(ControlFileData).  This reduces the odds of
     911                 :            :      * premature-EOF errors when reading pg_control.  We'll still fail when we
     912                 :            :      * check the contents of the file, but hopefully with a more specific
     913                 :            :      * error than "couldn't read pg_control".
     914                 :            :      */
     915                 :         12 :     memset(buffer, 0, PG_CONTROL_FILE_SIZE);
     916                 :         12 :     memcpy(buffer, &ControlFile, sizeof(ControlFileData));
     917                 :            : 
     918                 :         12 :     unlink(XLOG_CONTROL_FILE);
     919                 :            : 
     920                 :         12 :     fd = open(XLOG_CONTROL_FILE,
     921                 :            :               O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
     922                 :            :               S_IRUSR | S_IWUSR);
     923         [ -  + ]:         12 :     if (fd < 0)
     924                 :            :     {
     925                 :          0 :         fprintf(stderr, _("%s: could not create pg_control file: %s\n"),
     926                 :          0 :                 progname, strerror(errno));
     927                 :          0 :         exit(1);
     928                 :            :     }
     929                 :            : 
     930                 :         12 :     errno = 0;
     931         [ -  + ]:         12 :     if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
     932                 :            :     {
     933                 :            :         /* if write didn't set errno, assume problem is no disk space */
     934         [ #  # ]:          0 :         if (errno == 0)
     935                 :          0 :             errno = ENOSPC;
     936                 :          0 :         fprintf(stderr, _("%s: could not write pg_control file: %s\n"),
     937                 :          0 :                 progname, strerror(errno));
     938                 :          0 :         exit(1);
     939                 :            :     }
     940                 :            : 
     941         [ -  + ]:         12 :     if (fsync(fd) != 0)
     942                 :            :     {
     943                 :          0 :         fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
     944                 :          0 :         exit(1);
     945                 :            :     }
     946                 :            : 
     947                 :         12 :     close(fd);
     948                 :         12 : }
     949                 :            : 
     950                 :            : 
     951                 :            : /*
     952                 :            :  * Scan existing XLOG files and determine the highest existing WAL address
     953                 :            :  *
     954                 :            :  * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
     955                 :            :  * are assumed valid (note that we allow the old xlog seg size to differ
     956                 :            :  * from what we're using).  On exit, newXlogId and newXlogSeg are set to
     957                 :            :  * suitable values for the beginning of replacement WAL (in our seg size).
     958                 :            :  */
     959                 :            : static void
     960                 :         16 : FindEndOfXLOG(void)
     961                 :            : {
     962                 :            :     DIR        *xldir;
     963                 :            :     struct dirent *xlde;
     964                 :            :     uint64      segs_per_xlogid;
     965                 :            :     uint64      xlogbytepos;
     966                 :            : 
     967                 :            :     /*
     968                 :            :      * Initialize the max() computation using the last checkpoint address from
     969                 :            :      * old pg_control.  Note that for the moment we are working with segment
     970                 :            :      * numbering according to the old xlog seg size.
     971                 :            :      */
     972                 :         16 :     segs_per_xlogid = (UINT64CONST(0x0000000100000000) / ControlFile.xlog_seg_size);
     973                 :         16 :     newXlogSegNo = ControlFile.checkPointCopy.redo / ControlFile.xlog_seg_size;
     974                 :            : 
     975                 :            :     /*
     976                 :            :      * Scan the pg_wal directory to find existing WAL segment files. We assume
     977                 :            :      * any present have been used; in most scenarios this should be
     978                 :            :      * conservative, because of xlog.c's attempts to pre-create files.
     979                 :            :      */
     980                 :         16 :     xldir = opendir(XLOGDIR);
     981         [ -  + ]:         16 :     if (xldir == NULL)
     982                 :            :     {
     983                 :          0 :         fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
     984                 :          0 :                 progname, XLOGDIR, strerror(errno));
     985                 :          0 :         exit(1);
     986                 :            :     }
     987                 :            : 
     988         [ +  + ]:        150 :     while (errno = 0, (xlde = readdir(xldir)) != NULL)
     989                 :            :     {
     990 [ +  + ][ -  + ]:        134 :         if (IsXLogFileName(xlde->d_name) ||
                 [ -  + ]
     991 [ #  # ][ #  # ]:          0 :             IsPartialXLogFileName(xlde->d_name))
     992                 :            :         {
     993                 :            :             unsigned int tli,
     994                 :            :                         log,
     995                 :            :                         seg;
     996                 :            :             XLogSegNo   segno;
     997                 :            : 
     998                 :            :             /*
     999                 :            :              * Note: We don't use XLogFromFileName here, because we want to
    1000                 :            :              * use the segment size from the control file, not the size the
    1001                 :            :              * pg_resetwal binary was compiled with
    1002                 :            :              */
    1003                 :         86 :             sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg);
    1004                 :         86 :             segno = ((uint64) log) * segs_per_xlogid + seg;
    1005                 :            : 
    1006                 :            :             /*
    1007                 :            :              * Note: we take the max of all files found, regardless of their
    1008                 :            :              * timelines.  Another possibility would be to ignore files of
    1009                 :            :              * timelines other than the target TLI, but this seems safer.
    1010                 :            :              * Better too large a result than too small...
    1011                 :            :              */
    1012         [ +  + ]:         86 :             if (segno > newXlogSegNo)
    1013                 :         86 :                 newXlogSegNo = segno;
    1014                 :            :         }
    1015                 :            :     }
    1016                 :            : 
    1017         [ -  + ]:         16 :     if (errno)
    1018                 :            :     {
    1019                 :          0 :         fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
    1020                 :          0 :                 progname, XLOGDIR, strerror(errno));
    1021                 :          0 :         exit(1);
    1022                 :            :     }
    1023                 :            : 
    1024         [ -  + ]:         16 :     if (closedir(xldir))
    1025                 :            :     {
    1026                 :          0 :         fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
    1027                 :          0 :                 progname, XLOGDIR, strerror(errno));
    1028                 :          0 :         exit(1);
    1029                 :            :     }
    1030                 :            : 
    1031                 :            :     /*
    1032                 :            :      * Finally, convert to new xlog seg size, and advance by one to ensure we
    1033                 :            :      * are in virgin territory.
    1034                 :            :      */
    1035                 :         16 :     xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
    1036                 :         16 :     newXlogSegNo = (xlogbytepos + WalSegSz - 1) / WalSegSz;
    1037                 :         16 :     newXlogSegNo++;
    1038                 :         16 : }
    1039                 :            : 
    1040                 :            : 
    1041                 :            : /*
    1042                 :            :  * Remove existing XLOG files
    1043                 :            :  */
    1044                 :            : static void
    1045                 :         12 : KillExistingXLOG(void)
    1046                 :            : {
    1047                 :            :     DIR        *xldir;
    1048                 :            :     struct dirent *xlde;
    1049                 :            :     char        path[MAXPGPATH + sizeof(XLOGDIR)];
    1050                 :            : 
    1051                 :         12 :     xldir = opendir(XLOGDIR);
    1052         [ -  + ]:         12 :     if (xldir == NULL)
    1053                 :            :     {
    1054                 :          0 :         fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
    1055                 :          0 :                 progname, XLOGDIR, strerror(errno));
    1056                 :          0 :         exit(1);
    1057                 :            :     }
    1058                 :            : 
    1059         [ +  + ]:         78 :     while (errno = 0, (xlde = readdir(xldir)) != NULL)
    1060                 :            :     {
    1061 [ +  + ][ -  + ]:         66 :         if (IsXLogFileName(xlde->d_name) ||
                 [ -  + ]
    1062 [ #  # ][ #  # ]:          0 :             IsPartialXLogFileName(xlde->d_name))
    1063                 :            :         {
    1064                 :         30 :             snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
    1065         [ -  + ]:         30 :             if (unlink(path) < 0)
    1066                 :            :             {
    1067                 :          0 :                 fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
    1068                 :          0 :                         progname, path, strerror(errno));
    1069                 :          0 :                 exit(1);
    1070                 :            :             }
    1071                 :            :         }
    1072                 :            :     }
    1073                 :            : 
    1074         [ -  + ]:         12 :     if (errno)
    1075                 :            :     {
    1076                 :          0 :         fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
    1077                 :          0 :                 progname, XLOGDIR, strerror(errno));
    1078                 :          0 :         exit(1);
    1079                 :            :     }
    1080                 :            : 
    1081         [ -  + ]:         12 :     if (closedir(xldir))
    1082                 :            :     {
    1083                 :          0 :         fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
    1084                 :          0 :                 progname, XLOGDIR, strerror(errno));
    1085                 :          0 :         exit(1);
    1086                 :            :     }
    1087                 :         12 : }
    1088                 :            : 
    1089                 :            : 
    1090                 :            : /*
    1091                 :            :  * Remove existing archive status files
    1092                 :            :  */
    1093                 :            : static void
    1094                 :         12 : KillExistingArchiveStatus(void)
    1095                 :            : {
    1096                 :            : #define ARCHSTATDIR XLOGDIR "/archive_status"
    1097                 :            : 
    1098                 :            :     DIR        *xldir;
    1099                 :            :     struct dirent *xlde;
    1100                 :            :     char        path[MAXPGPATH + sizeof(ARCHSTATDIR)];
    1101                 :            : 
    1102                 :         12 :     xldir = opendir(ARCHSTATDIR);
    1103         [ -  + ]:         12 :     if (xldir == NULL)
    1104                 :            :     {
    1105                 :          0 :         fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
    1106                 :          0 :                 progname, ARCHSTATDIR, strerror(errno));
    1107                 :          0 :         exit(1);
    1108                 :            :     }
    1109                 :            : 
    1110         [ +  + ]:         36 :     while (errno = 0, (xlde = readdir(xldir)) != NULL)
    1111                 :            :     {
    1112 [ -  + ][ #  # ]:         24 :         if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
    1113         [ #  # ]:          0 :             (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
    1114         [ #  # ]:          0 :              strcmp(xlde->d_name + XLOG_FNAME_LEN, ".done") == 0 ||
    1115         [ #  # ]:          0 :              strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.ready") == 0 ||
    1116                 :          0 :              strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.done") == 0))
    1117                 :            :         {
    1118                 :          0 :             snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
    1119         [ #  # ]:          0 :             if (unlink(path) < 0)
    1120                 :            :             {
    1121                 :          0 :                 fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
    1122                 :          0 :                         progname, path, strerror(errno));
    1123                 :          0 :                 exit(1);
    1124                 :            :             }
    1125                 :            :         }
    1126                 :            :     }
    1127                 :            : 
    1128         [ -  + ]:         12 :     if (errno)
    1129                 :            :     {
    1130                 :          0 :         fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
    1131                 :          0 :                 progname, ARCHSTATDIR, strerror(errno));
    1132                 :          0 :         exit(1);
    1133                 :            :     }
    1134                 :            : 
    1135         [ -  + ]:         12 :     if (closedir(xldir))
    1136                 :            :     {
    1137                 :          0 :         fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
    1138                 :          0 :                 progname, ARCHSTATDIR, strerror(errno));
    1139                 :          0 :         exit(1);
    1140                 :            :     }
    1141                 :         12 : }
    1142                 :            : 
    1143                 :            : 
    1144                 :            : /*
    1145                 :            :  * Write an empty XLOG file, containing only the checkpoint record
    1146                 :            :  * already set up in ControlFile.
    1147                 :            :  */
    1148                 :            : static void
    1149                 :         12 : WriteEmptyXLOG(void)
    1150                 :            : {
    1151                 :            :     char       *buffer;
    1152                 :            :     XLogPageHeader page;
    1153                 :            :     XLogLongPageHeader longpage;
    1154                 :            :     XLogRecord *record;
    1155                 :            :     pg_crc32c   crc;
    1156                 :            :     char        path[MAXPGPATH];
    1157                 :            :     int         fd;
    1158                 :            :     int         nbytes;
    1159                 :            :     char       *recptr;
    1160                 :            : 
    1161                 :            :     /* Use malloc() to ensure buffer is MAXALIGNED */
    1162                 :         12 :     buffer = (char *) pg_malloc(XLOG_BLCKSZ);
    1163                 :         12 :     page = (XLogPageHeader) buffer;
    1164                 :         12 :     memset(buffer, 0, XLOG_BLCKSZ);
    1165                 :            : 
    1166                 :            :     /* Set up the XLOG page header */
    1167                 :         12 :     page->xlp_magic = XLOG_PAGE_MAGIC;
    1168                 :         12 :     page->xlp_info = XLP_LONG_HEADER;
    1169                 :         12 :     page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
    1170                 :         12 :     page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
    1171                 :         12 :     longpage = (XLogLongPageHeader) page;
    1172                 :         12 :     longpage->xlp_sysid = ControlFile.system_identifier;
    1173                 :         12 :     longpage->xlp_seg_size = WalSegSz;
    1174                 :         12 :     longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
    1175                 :            : 
    1176                 :            :     /* Insert the initial checkpoint record */
    1177                 :         12 :     recptr = (char *) page + SizeOfXLogLongPHD;
    1178                 :         12 :     record = (XLogRecord *) recptr;
    1179                 :         12 :     record->xl_prev = 0;
    1180                 :         12 :     record->xl_xid = InvalidTransactionId;
    1181                 :         12 :     record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
    1182                 :         12 :     record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
    1183                 :         12 :     record->xl_rmid = RM_XLOG_ID;
    1184                 :            : 
    1185                 :         12 :     recptr += SizeOfXLogRecord;
    1186                 :         12 :     *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
    1187                 :         12 :     *(recptr++) = sizeof(CheckPoint);
    1188                 :         12 :     memcpy(recptr, &ControlFile.checkPointCopy,
    1189                 :            :            sizeof(CheckPoint));
    1190                 :            : 
    1191                 :         12 :     INIT_CRC32C(crc);
    1192                 :         12 :     COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
    1193                 :         12 :     COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
    1194                 :         12 :     FIN_CRC32C(crc);
    1195                 :         12 :     record->xl_crc = crc;
    1196                 :            : 
    1197                 :            :     /* Write the first page */
    1198                 :         12 :     XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID,
    1199                 :            :                  newXlogSegNo, WalSegSz);
    1200                 :            : 
    1201                 :         12 :     unlink(path);
    1202                 :            : 
    1203                 :         12 :     fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
    1204                 :            :               S_IRUSR | S_IWUSR);
    1205         [ -  + ]:         12 :     if (fd < 0)
    1206                 :            :     {
    1207                 :          0 :         fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
    1208                 :          0 :                 progname, path, strerror(errno));
    1209                 :          0 :         exit(1);
    1210                 :            :     }
    1211                 :            : 
    1212                 :         12 :     errno = 0;
    1213         [ -  + ]:         12 :     if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
    1214                 :            :     {
    1215                 :            :         /* if write didn't set errno, assume problem is no disk space */
    1216         [ #  # ]:          0 :         if (errno == 0)
    1217                 :          0 :             errno = ENOSPC;
    1218                 :          0 :         fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
    1219                 :          0 :                 progname, path, strerror(errno));
    1220                 :          0 :         exit(1);
    1221                 :            :     }
    1222                 :            : 
    1223                 :            :     /* Fill the rest of the file with zeroes */
    1224                 :         12 :     memset(buffer, 0, XLOG_BLCKSZ);
    1225         [ +  + ]:       1536 :     for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
    1226                 :            :     {
    1227                 :       1524 :         errno = 0;
    1228         [ -  + ]:       1524 :         if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
    1229                 :            :         {
    1230         [ #  # ]:          0 :             if (errno == 0)
    1231                 :          0 :                 errno = ENOSPC;
    1232                 :          0 :             fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
    1233                 :          0 :                     progname, path, strerror(errno));
    1234                 :          0 :             exit(1);
    1235                 :            :         }
    1236                 :            :     }
    1237                 :            : 
    1238         [ -  + ]:         12 :     if (fsync(fd) != 0)
    1239                 :            :     {
    1240                 :          0 :         fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
    1241                 :          0 :         exit(1);
    1242                 :            :     }
    1243                 :            : 
    1244                 :         12 :     close(fd);
    1245                 :         12 : }
    1246                 :            : 
    1247                 :            : 
    1248                 :            : static void
    1249                 :          0 : usage(void)
    1250                 :            : {
    1251                 :          0 :     printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
    1252                 :          0 :     printf(_("Usage:\n  %s [OPTION]... DATADIR\n\n"), progname);
    1253                 :          0 :     printf(_("Options:\n"));
    1254                 :          0 :     printf(_("  -c XID,XID       set oldest and newest transactions bearing commit timestamp\n"));
    1255                 :          0 :     printf(_("                   (zero in either value means no change)\n"));
    1256                 :          0 :     printf(_(" [-D] DATADIR      data directory\n"));
    1257                 :          0 :     printf(_("  -e XIDEPOCH      set next transaction ID epoch\n"));
    1258                 :          0 :     printf(_("  -f               force update to be done\n"));
    1259                 :          0 :     printf(_("  -l WALFILE       force minimum WAL starting location for new write-ahead log\n"));
    1260                 :          0 :     printf(_("  -m MXID,MXID     set next and oldest multitransaction ID\n"));
    1261                 :          0 :     printf(_("  -n               no update, just show what would be done (for testing)\n"));
    1262                 :          0 :     printf(_("  -o OID           set next OID\n"));
    1263                 :          0 :     printf(_("  -O OFFSET        set next multitransaction offset\n"));
    1264                 :          0 :     printf(_("  -V, --version    output version information, then exit\n"));
    1265                 :          0 :     printf(_("  -x XID           set next transaction ID\n"));
    1266                 :          0 :     printf(_("  -?, --help       show this help, then exit\n"));
    1267                 :          0 :     printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
    1268                 :          0 : }

Generated by: LCOV version 1.13