Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * version.c
4 : : * Routine to retrieve information of PG_VERSION
5 : : *
6 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/fe_utils/version.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #include "postgres_fe.h"
17 : :
18 : : #include <sys/stat.h>
19 : :
20 : : #include "common/logging.h"
21 : : #include "fe_utils/version.h"
22 : :
23 : : /*
24 : : * Assumed maximum size of PG_VERSION. This should be more than enough for
25 : : * any version numbers that need to be handled.
26 : : */
27 : : #define PG_VERSION_MAX_SIZE 64
28 : :
29 : : /*
30 : : * get_pg_version
31 : : *
32 : : * Retrieve the major version number of the given data folder, from
33 : : * PG_VERSION. The result returned is a version number, that can be used
34 : : * for comparisons based on PG_VERSION_NUM. For example, if PG_VERSION
35 : : * contains "18\n", this function returns 180000.
36 : : *
37 : : * This supports both the pre-v10 and the post-v10 version numbering.
38 : : *
39 : : * Optionally, "version_str" can be specified to store the contents
40 : : * retrieved from PG_VERSION. It is allocated by this routine; the
41 : : * caller is responsible for pg_free()-ing it.
42 : : */
43 : : uint32
13 michael@paquier.xyz 44 :GNC 195 : get_pg_version(const char *datadir, char **version_str)
45 : : {
46 : : FILE *version_fd;
47 : : char ver_filename[MAXPGPATH];
48 : : char buf[PG_VERSION_MAX_SIZE];
49 : 195 : int v1 = 0,
50 : 195 : v2 = 0;
51 : : struct stat st;
52 : :
53 : 195 : snprintf(ver_filename, sizeof(ver_filename), "%s/PG_VERSION",
54 : : datadir);
55 : :
56 [ - + ]: 195 : if ((version_fd = fopen(ver_filename, "r")) == NULL)
13 michael@paquier.xyz 57 :UNC 0 : pg_fatal("could not open version file \"%s\": %m", ver_filename);
58 : :
13 michael@paquier.xyz 59 [ - + ]:GNC 195 : if (fstat(fileno(version_fd), &st) != 0)
13 michael@paquier.xyz 60 :UNC 0 : pg_fatal("could not stat file \"%s\": %m", ver_filename);
13 michael@paquier.xyz 61 [ - + ]:GNC 195 : if (st.st_size > PG_VERSION_MAX_SIZE)
13 michael@paquier.xyz 62 :UNC 0 : pg_fatal("file \"%s\" is too large", ver_filename);
63 : :
13 michael@paquier.xyz 64 [ + - ]:GNC 195 : if (fscanf(version_fd, "%63s", buf) == 0 ||
65 [ - + ]: 195 : sscanf(buf, "%d.%d", &v1, &v2) < 1)
13 michael@paquier.xyz 66 :UNC 0 : pg_fatal("could not parse version file \"%s\"", ver_filename);
67 : :
13 michael@paquier.xyz 68 :GNC 195 : fclose(version_fd);
69 : :
70 [ + + ]: 195 : if (version_str)
71 : : {
72 : 175 : *version_str = pg_malloc(PG_VERSION_MAX_SIZE);
73 : 175 : memcpy(*version_str, buf, st.st_size);
74 : : }
75 : :
76 [ - + ]: 195 : if (v1 < 10)
77 : : {
78 : : /* pre-v10 style, e.g. 9.6.1 */
13 michael@paquier.xyz 79 :UNC 0 : return v1 * 10000 + v2 * 100;
80 : : }
81 : : else
82 : : {
83 : : /* post-v10 style, e.g. 10.1 */
13 michael@paquier.xyz 84 :GNC 195 : return v1 * 10000;
85 : : }
86 : : }
|