1 /*-------------------------------------------------------------------------
2  *
3  * controldata_utils.c
4  *		Common code for control data file output.
5  *
6  *
7  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *	  src/common/controldata_utils.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 
17 #ifndef FRONTEND
18 #include "postgres.h"
19 #else
20 #include "postgres_fe.h"
21 #endif
22 
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 
27 #include "catalog/pg_control.h"
28 #include "common/controldata_utils.h"
29 #include "port/pg_crc32c.h"
30 
31 /*
32  * get_controlfile(char *DataDir, const char *progname)
33  *
34  * Get controlfile values. The caller is responsible
35  * for pfreeing the result.
36  */
37 ControlFileData *
get_controlfile(char * DataDir,const char * progname)38 get_controlfile(char *DataDir, const char *progname)
39 {
40 	ControlFileData *ControlFile;
41 	int			fd;
42 	char		ControlFilePath[MAXPGPATH];
43 	pg_crc32c	crc;
44 	int			r;
45 
46 	ControlFile = palloc(sizeof(ControlFileData));
47 	snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
48 
49 	if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
50 #ifndef FRONTEND
51 		ereport(ERROR,
52 				(errcode_for_file_access(),
53 				 errmsg("could not open file \"%s\" for reading: %m",
54 						ControlFilePath)));
55 #else
56 	{
57 		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
58 				progname, ControlFilePath, strerror(errno));
59 		exit(EXIT_FAILURE);
60 	}
61 #endif
62 
63 	r = read(fd, ControlFile, sizeof(ControlFileData));
64 	if (r != sizeof(ControlFileData))
65 	{
66 		if (r < 0)
67 #ifndef FRONTEND
68 			ereport(ERROR,
69 					(errcode_for_file_access(),
70 					 errmsg("could not read file \"%s\": %m", ControlFilePath)));
71 #else
72 		{
73 			fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
74 					progname, ControlFilePath, strerror(errno));
75 			exit(EXIT_FAILURE);
76 		}
77 #endif
78 		else
79 #ifndef FRONTEND
80 			ereport(ERROR,
81 					(errmsg("could not read file \"%s\": read %d of %d",
82 							ControlFilePath, r, (int) sizeof(ControlFileData))));
83 #else
84 		{
85 			fprintf(stderr, _("%s: could not read file \"%s\": read %d of %d\n"),
86 					progname, ControlFilePath, r, (int) sizeof(ControlFileData));
87 			exit(EXIT_FAILURE);
88 		}
89 #endif
90 	}
91 
92 	close(fd);
93 
94 	/* Check the CRC. */
95 	INIT_CRC32C(crc);
96 	COMP_CRC32C(crc,
97 				(char *) ControlFile,
98 				offsetof(ControlFileData, crc));
99 	FIN_CRC32C(crc);
100 
101 	if (!EQ_CRC32C(crc, ControlFile->crc))
102 #ifndef FRONTEND
103 		elog(ERROR, _("calculated CRC checksum does not match value stored in file"));
104 #else
105 		printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n"
106 				 "Either the file is corrupt, or it has a different layout than this program\n"
107 				 "is expecting.  The results below are untrustworthy.\n\n"));
108 #endif
109 
110 	/* Make sure the control file is valid byte order. */
111 	if (ControlFile->pg_control_version % 65536 == 0 &&
112 		ControlFile->pg_control_version / 65536 != 0)
113 #ifndef FRONTEND
114 		elog(ERROR, _("byte ordering mismatch"));
115 #else
116 		printf(_("WARNING: possible byte ordering mismatch\n"
117 				 "The byte ordering used to store the pg_control file might not match the one\n"
118 				 "used by this program.  In that case the results below would be incorrect, and\n"
119 				 "the PostgreSQL installation would be incompatible with this data directory.\n"));
120 #endif
121 
122 	return ControlFile;
123 }
124