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 44 390 : 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 390 : int v1 = 0, 50 390 : v2 = 0; 51 : struct stat st; 52 : 53 390 : snprintf(ver_filename, sizeof(ver_filename), "%s/PG_VERSION", 54 : datadir); 55 : 56 390 : if ((version_fd = fopen(ver_filename, "r")) == NULL) 57 0 : pg_fatal("could not open version file \"%s\": %m", ver_filename); 58 : 59 390 : if (fstat(fileno(version_fd), &st) != 0) 60 0 : pg_fatal("could not stat file \"%s\": %m", ver_filename); 61 390 : if (st.st_size > PG_VERSION_MAX_SIZE) 62 0 : pg_fatal("file \"%s\" is too large", ver_filename); 63 : 64 390 : if (fscanf(version_fd, "%63s", buf) == 0 || 65 390 : sscanf(buf, "%d.%d", &v1, &v2) < 1) 66 0 : pg_fatal("could not parse version file \"%s\"", ver_filename); 67 : 68 390 : fclose(version_fd); 69 : 70 390 : if (version_str) 71 : { 72 350 : *version_str = pg_malloc(PG_VERSION_MAX_SIZE); 73 350 : memcpy(*version_str, buf, st.st_size); 74 : } 75 : 76 390 : if (v1 < 10) 77 : { 78 : /* pre-v10 style, e.g. 9.6.1 */ 79 0 : return v1 * 10000 + v2 * 100; 80 : } 81 : else 82 : { 83 : /* post-v10 style, e.g. 10.1 */ 84 390 : return v1 * 10000; 85 : } 86 : }