LCOV - code coverage report
Current view: top level - src/bin/pg_controldata - pg_controldata.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 88.2 % 153 135
Test Date: 2026-02-26 18:14:42 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * pg_controldata
       3              :  *
       4              :  * reads the data from the control file located at $PGDATA/XLOG_CONTROL_FILE.
       5              :  *
       6              :  * copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001;
       7              :  * license: BSD
       8              :  *
       9              :  * src/bin/pg_controldata/pg_controldata.c
      10              :  */
      11              : 
      12              : /*
      13              :  * We have to use postgres.h not postgres_fe.h here, because there's so much
      14              :  * backend-only stuff in the XLOG include files we need.  But we need a
      15              :  * frontend-ish environment otherwise.  Hence this ugly hack.
      16              :  */
      17              : #define FRONTEND 1
      18              : 
      19              : #include "postgres.h"
      20              : 
      21              : #include <time.h>
      22              : 
      23              : #include "access/transam.h"
      24              : #include "access/xlog.h"
      25              : #include "access/xlog_internal.h"
      26              : #include "catalog/pg_control.h"
      27              : #include "common/controldata_utils.h"
      28              : #include "common/logging.h"
      29              : #include "getopt_long.h"
      30              : #include "pg_getopt.h"
      31              : 
      32              : static void
      33            1 : usage(const char *progname)
      34              : {
      35            1 :     printf(_("%s displays control information of a PostgreSQL database cluster.\n\n"), progname);
      36            1 :     printf(_("Usage:\n"));
      37            1 :     printf(_("  %s [OPTION] [DATADIR]\n"), progname);
      38            1 :     printf(_("\nOptions:\n"));
      39            1 :     printf(_(" [-D, --pgdata=]DATADIR  data directory\n"));
      40            1 :     printf(_("  -V, --version          output version information, then exit\n"));
      41            1 :     printf(_("  -?, --help             show this help, then exit\n"));
      42            1 :     printf(_("\nIf no data directory (DATADIR) is specified, "
      43              :              "the environment variable PGDATA\nis used.\n\n"));
      44            1 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
      45            1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
      46            1 : }
      47              : 
      48              : 
      49              : static const char *
      50           55 : dbState(DBState state)
      51              : {
      52           55 :     switch (state)
      53              :     {
      54            1 :         case DB_STARTUP:
      55            1 :             return _("starting up");
      56           51 :         case DB_SHUTDOWNED:
      57           51 :             return _("shut down");
      58            2 :         case DB_SHUTDOWNED_IN_RECOVERY:
      59            2 :             return _("shut down in recovery");
      60            0 :         case DB_SHUTDOWNING:
      61            0 :             return _("shutting down");
      62            0 :         case DB_IN_CRASH_RECOVERY:
      63            0 :             return _("in crash recovery");
      64            0 :         case DB_IN_ARCHIVE_RECOVERY:
      65            0 :             return _("in archive recovery");
      66            1 :         case DB_IN_PRODUCTION:
      67            1 :             return _("in production");
      68              :     }
      69            0 :     return _("unrecognized status code");
      70              : }
      71              : 
      72              : static const char *
      73           55 : wal_level_str(WalLevel wal_level)
      74              : {
      75           55 :     switch (wal_level)
      76              :     {
      77           19 :         case WAL_LEVEL_MINIMAL:
      78           19 :             return "minimal";
      79           29 :         case WAL_LEVEL_REPLICA:
      80           29 :             return "replica";
      81            7 :         case WAL_LEVEL_LOGICAL:
      82            7 :             return "logical";
      83              :     }
      84            0 :     return _("unrecognized \"wal_level\"");
      85              : }
      86              : 
      87              : 
      88              : int
      89           96 : main(int argc, char *argv[])
      90              : {
      91              :     static struct option long_options[] = {
      92              :         {"pgdata", required_argument, NULL, 'D'},
      93              :         {NULL, 0, NULL, 0}
      94              :     };
      95              : 
      96              :     ControlFileData *ControlFile;
      97              :     bool        crc_ok;
      98           96 :     char       *DataDir = NULL;
      99              :     time_t      time_tmp;
     100              :     struct tm  *tm_tmp;
     101              :     char        pgctime_str[128];
     102              :     char        ckpttime_str[128];
     103              :     char        mock_auth_nonce_str[MOCK_AUTH_NONCE_LEN * 2 + 1];
     104           96 :     const char *strftime_fmt = "%c";
     105              :     const char *progname;
     106              :     char        xlogfilename[MAXFNAMELEN];
     107              :     int         c;
     108              :     int         i;
     109              :     int         WalSegSz;
     110              : 
     111           96 :     pg_logging_init(argv[0]);
     112           96 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
     113           96 :     progname = get_progname(argv[0]);
     114              : 
     115           96 :     if (argc > 1)
     116              :     {
     117           95 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     118              :         {
     119            1 :             usage(progname);
     120            1 :             exit(0);
     121              :         }
     122           94 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     123              :         {
     124           37 :             puts("pg_controldata (PostgreSQL) " PG_VERSION);
     125           37 :             exit(0);
     126              :         }
     127              :     }
     128              : 
     129           58 :     while ((c = getopt_long(argc, argv, "D:", long_options, NULL)) != -1)
     130              :     {
     131            1 :         switch (c)
     132              :         {
     133            0 :             case 'D':
     134            0 :                 DataDir = optarg;
     135            0 :                 break;
     136              : 
     137            1 :             default:
     138              :                 /* getopt_long already emitted a complaint */
     139            1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     140            1 :                 exit(1);
     141              :         }
     142              :     }
     143              : 
     144           57 :     if (DataDir == NULL)
     145              :     {
     146           57 :         if (optind < argc)
     147           56 :             DataDir = argv[optind++];
     148              :         else
     149            1 :             DataDir = getenv("PGDATA");
     150              :     }
     151              : 
     152              :     /* Complain if any arguments remain */
     153           57 :     if (optind < argc)
     154              :     {
     155            0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     156              :                      argv[optind]);
     157            0 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     158            0 :         exit(1);
     159              :     }
     160              : 
     161           57 :     if (DataDir == NULL)
     162              :     {
     163            1 :         pg_log_error("no data directory specified");
     164            1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     165            1 :         exit(1);
     166              :     }
     167              : 
     168              :     /* get a copy of the control file */
     169           56 :     ControlFile = get_controlfile(DataDir, &crc_ok);
     170           55 :     if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
     171              :     {
     172            0 :         pg_log_warning("control file version (%u) does not match the version understood by this program (%u)",
     173              :                        ControlFile->pg_control_version, PG_CONTROL_VERSION);
     174            0 :         pg_log_warning_detail("Either the control file has been created with a different version of PostgreSQL, "
     175              :                               "or it is corrupt.  The results below are untrustworthy.");
     176              :     }
     177           55 :     else if (!crc_ok)
     178              :     {
     179            1 :         pg_log_warning("calculated CRC checksum does not match value stored in control file");
     180            1 :         pg_log_warning_detail("Either the control file is corrupt, or it has a different layout than this program "
     181              :                               "is expecting.  The results below are untrustworthy.");
     182              :     }
     183              : 
     184              :     /* set wal segment size */
     185           55 :     WalSegSz = ControlFile->xlog_seg_size;
     186              : 
     187           55 :     if (!IsValidWalSegSize(WalSegSz))
     188              :     {
     189            1 :         pg_log_warning(ngettext("invalid WAL segment size in control file (%d byte)",
     190              :                                 "invalid WAL segment size in control file (%d bytes)",
     191              :                                 WalSegSz),
     192              :                        WalSegSz);
     193            1 :         pg_log_warning_detail("The WAL segment size must be a power of two between 1 MB and 1 GB.");
     194            1 :         pg_log_warning_detail("The file is corrupt and the results below are untrustworthy.");
     195              :     }
     196              : 
     197              :     /*
     198              :      * This slightly-chintzy coding will work as long as the control file
     199              :      * timestamps are within the range of time_t; that should be the case in
     200              :      * all foreseeable circumstances, so we don't bother importing the
     201              :      * backend's timezone library into pg_controldata.
     202              :      *
     203              :      * Use variable for format to suppress overly-anal-retentive gcc warning
     204              :      * about %c
     205              :      */
     206           55 :     time_tmp = (time_t) ControlFile->time;
     207           55 :     tm_tmp = localtime(&time_tmp);
     208              : 
     209           55 :     if (tm_tmp != NULL)
     210           55 :         strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt, tm_tmp);
     211              :     else
     212            0 :         snprintf(pgctime_str, sizeof(pgctime_str), _("???"));
     213              : 
     214           55 :     time_tmp = (time_t) ControlFile->checkPointCopy.time;
     215           55 :     tm_tmp = localtime(&time_tmp);
     216              : 
     217           55 :     if (tm_tmp != NULL)
     218           55 :         strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt, tm_tmp);
     219              :     else
     220            0 :         snprintf(ckpttime_str, sizeof(ckpttime_str), _("???"));
     221              : 
     222              :     /*
     223              :      * Calculate name of the WAL file containing the latest checkpoint's REDO
     224              :      * start point.
     225              :      *
     226              :      * A corrupted control file could report a WAL segment size of 0 or
     227              :      * negative value, and to guard against division by zero, we need to treat
     228              :      * that specially.
     229              :      */
     230           55 :     if (WalSegSz > 0)
     231              :     {
     232              :         XLogSegNo   segno;
     233              : 
     234           54 :         XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
     235           54 :         XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
     236              :                      segno, WalSegSz);
     237              :     }
     238              :     else
     239            1 :         strcpy(xlogfilename, _("???"));
     240              : 
     241         1815 :     for (i = 0; i < MOCK_AUTH_NONCE_LEN; i++)
     242         1760 :         snprintf(&mock_auth_nonce_str[i * 2], 3, "%02x",
     243         1760 :                  (unsigned char) ControlFile->mock_authentication_nonce[i]);
     244              : 
     245           55 :     printf(_("pg_control version number:            %u\n"),
     246              :            ControlFile->pg_control_version);
     247           55 :     printf(_("Catalog version number:               %u\n"),
     248              :            ControlFile->catalog_version_no);
     249           55 :     printf(_("Database system identifier:           %" PRIu64 "\n"),
     250              :            ControlFile->system_identifier);
     251           55 :     printf(_("Database cluster state:               %s\n"),
     252              :            dbState(ControlFile->state));
     253           55 :     printf(_("pg_control last modified:             %s\n"),
     254              :            pgctime_str);
     255           55 :     printf(_("Latest checkpoint location:           %X/%08X\n"),
     256              :            LSN_FORMAT_ARGS(ControlFile->checkPoint));
     257           55 :     printf(_("Latest checkpoint's REDO location:    %X/%08X\n"),
     258              :            LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo));
     259           55 :     printf(_("Latest checkpoint's REDO WAL file:    %s\n"),
     260              :            xlogfilename);
     261           55 :     printf(_("Latest checkpoint's TimeLineID:       %u\n"),
     262              :            ControlFile->checkPointCopy.ThisTimeLineID);
     263           55 :     printf(_("Latest checkpoint's PrevTimeLineID:   %u\n"),
     264              :            ControlFile->checkPointCopy.PrevTimeLineID);
     265           55 :     printf(_("Latest checkpoint's full_page_writes: %s\n"),
     266              :            ControlFile->checkPointCopy.fullPageWrites ? _("on") : _("off"));
     267           55 :     printf(_("Latest checkpoint's NextXID:          %u:%u\n"),
     268              :            EpochFromFullTransactionId(ControlFile->checkPointCopy.nextXid),
     269              :            XidFromFullTransactionId(ControlFile->checkPointCopy.nextXid));
     270           55 :     printf(_("Latest checkpoint's NextOID:          %u\n"),
     271              :            ControlFile->checkPointCopy.nextOid);
     272           55 :     printf(_("Latest checkpoint's NextMultiXactId:  %u\n"),
     273              :            ControlFile->checkPointCopy.nextMulti);
     274           55 :     printf(_("Latest checkpoint's NextMultiOffset:  %" PRIu64 "\n"),
     275              :            ControlFile->checkPointCopy.nextMultiOffset);
     276           55 :     printf(_("Latest checkpoint's oldestXID:        %u\n"),
     277              :            ControlFile->checkPointCopy.oldestXid);
     278           55 :     printf(_("Latest checkpoint's oldestXID's DB:   %u\n"),
     279              :            ControlFile->checkPointCopy.oldestXidDB);
     280           55 :     printf(_("Latest checkpoint's oldestActiveXID:  %u\n"),
     281              :            ControlFile->checkPointCopy.oldestActiveXid);
     282           55 :     printf(_("Latest checkpoint's oldestMultiXid:   %u\n"),
     283              :            ControlFile->checkPointCopy.oldestMulti);
     284           55 :     printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
     285              :            ControlFile->checkPointCopy.oldestMultiDB);
     286           55 :     printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
     287              :            ControlFile->checkPointCopy.oldestCommitTsXid);
     288           55 :     printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
     289              :            ControlFile->checkPointCopy.newestCommitTsXid);
     290           55 :     printf(_("Time of latest checkpoint:            %s\n"),
     291              :            ckpttime_str);
     292           55 :     printf(_("Fake LSN counter for unlogged rels:   %X/%08X\n"),
     293              :            LSN_FORMAT_ARGS(ControlFile->unloggedLSN));
     294           55 :     printf(_("Minimum recovery ending location:     %X/%08X\n"),
     295              :            LSN_FORMAT_ARGS(ControlFile->minRecoveryPoint));
     296           55 :     printf(_("Min recovery ending loc's timeline:   %u\n"),
     297              :            ControlFile->minRecoveryPointTLI);
     298           55 :     printf(_("Backup start location:                %X/%08X\n"),
     299              :            LSN_FORMAT_ARGS(ControlFile->backupStartPoint));
     300           55 :     printf(_("Backup end location:                  %X/%08X\n"),
     301              :            LSN_FORMAT_ARGS(ControlFile->backupEndPoint));
     302           55 :     printf(_("End-of-backup record required:        %s\n"),
     303              :            ControlFile->backupEndRequired ? _("yes") : _("no"));
     304           55 :     printf(_("wal_level setting:                    %s\n"),
     305              :            wal_level_str(ControlFile->wal_level));
     306           55 :     printf(_("wal_log_hints setting:                %s\n"),
     307              :            ControlFile->wal_log_hints ? _("on") : _("off"));
     308           55 :     printf(_("max_connections setting:              %d\n"),
     309              :            ControlFile->MaxConnections);
     310           55 :     printf(_("max_worker_processes setting:         %d\n"),
     311              :            ControlFile->max_worker_processes);
     312           55 :     printf(_("max_wal_senders setting:              %d\n"),
     313              :            ControlFile->max_wal_senders);
     314           55 :     printf(_("max_prepared_xacts setting:           %d\n"),
     315              :            ControlFile->max_prepared_xacts);
     316           55 :     printf(_("max_locks_per_xact setting:           %d\n"),
     317              :            ControlFile->max_locks_per_xact);
     318           55 :     printf(_("track_commit_timestamp setting:       %s\n"),
     319              :            ControlFile->track_commit_timestamp ? _("on") : _("off"));
     320           55 :     printf(_("Maximum data alignment:               %u\n"),
     321              :            ControlFile->maxAlign);
     322              :     /* we don't print floatFormat since can't say much useful about it */
     323           55 :     printf(_("Database block size:                  %u\n"),
     324              :            ControlFile->blcksz);
     325           55 :     printf(_("Blocks per segment of large relation: %u\n"),
     326              :            ControlFile->relseg_size);
     327           55 :     printf(_("Pages per SLRU segment:               %u\n"),
     328              :            ControlFile->slru_pages_per_segment);
     329           55 :     printf(_("WAL block size:                       %u\n"),
     330              :            ControlFile->xlog_blcksz);
     331           55 :     printf(_("Bytes per WAL segment:                %u\n"),
     332              :            ControlFile->xlog_seg_size);
     333           55 :     printf(_("Maximum length of identifiers:        %u\n"),
     334              :            ControlFile->nameDataLen);
     335           55 :     printf(_("Maximum columns in an index:          %u\n"),
     336              :            ControlFile->indexMaxKeys);
     337           55 :     printf(_("Maximum size of a TOAST chunk:        %u\n"),
     338              :            ControlFile->toast_max_chunk_size);
     339           55 :     printf(_("Size of a large-object chunk:         %u\n"),
     340              :            ControlFile->loblksize);
     341              :     /* This is no longer configurable, but users may still expect to see it: */
     342           55 :     printf(_("Date/time type storage:               %s\n"),
     343              :            _("64-bit integers"));
     344           55 :     printf(_("Float8 argument passing:              %s\n"),
     345              :            (ControlFile->float8ByVal ? _("by value") : _("by reference")));
     346           55 :     printf(_("Data page checksum version:           %u\n"),
     347              :            ControlFile->data_checksum_version);
     348           55 :     printf(_("Default char data signedness:         %s\n"),
     349              :            (ControlFile->default_char_signedness ? _("signed") : _("unsigned")));
     350           55 :     printf(_("Mock authentication nonce:            %s\n"),
     351              :            mock_auth_nonce_str);
     352           55 :     return 0;
     353              : }
        

Generated by: LCOV version 2.0-1