|
| 1 | +/*------------------------------------------------------------------------- |
| 2 | + * |
| 3 | + * version.c-- |
| 4 | + * Routines to handle Postgres version number. |
| 5 | + * |
| 6 | + * Copyright (c) 1994, Regents of the University of California |
| 7 | + * |
| 8 | + * |
| 9 | + * IDENTIFICATION |
| 10 | + * $Header: /cvsroot/pgsql/src/utils/Attic/version.c,v 1.1 1996/11/11 13:51:57 bryanh Exp $ |
| 11 | + * |
| 12 | + * NOTES |
| 13 | + * XXX eventually, should be able to handle version identifiers |
| 14 | + * of length != 4. |
| 15 | + * |
| 16 | + * STANDALONE CODE - do not use error routines as this code is linked with |
| 17 | + * stuff that does not cinterface.a |
| 18 | + *------------------------------------------------------------------------- |
| 19 | + */ |
| 20 | +#include <sys/file.h> |
| 21 | +#include <sys/types.h> |
| 22 | +#include <sys/stat.h> |
| 23 | +#include <ctype.h> |
| 24 | +#include <string.h> |
| 25 | +#include <stdio.h> |
| 26 | +#include <unistd.h> |
| 27 | + |
| 28 | +#include "postgres.h" |
| 29 | + |
| 30 | +#include "storage/fd.h" /* for O_ */ |
| 31 | + |
| 32 | +#include "version.h" |
| 33 | + |
| 34 | + |
| 35 | +static void |
| 36 | +PathSetVersionFilePath(const char *path, char *filepathbuf) { |
| 37 | +/*---------------------------------------------------------------------------- |
| 38 | + PathSetVersionFilePath |
| 39 | + |
| 40 | + Destructively change "filepathbuf" to contain the concatenation of "path" |
| 41 | + and the name of the version file name. |
| 42 | +----------------------------------------------------------------------------*/ |
| 43 | + if (strlen(path) > (MAXPGPATH - sizeof(PG_VERFILE) - 1)) |
| 44 | + *filepathbuf = '\0'; |
| 45 | + else |
| 46 | + sprintf(filepathbuf, "%s%c%s", path, SEP_CHAR, PG_VERFILE); |
| 47 | +} |
| 48 | + |
| 49 | + |
| 50 | + |
| 51 | +void |
| 52 | +ValidatePgVersion(const char *path, char **reason_p) { |
| 53 | +/*---------------------------------------------------------------------------- |
| 54 | + Determine whether the PG_VERSION file in directory <path> indicates |
| 55 | + a data version compatible with the version of this program. |
| 56 | + |
| 57 | + If compatible, return <*reason_p> == NULL. Otherwise, malloc space, |
| 58 | + fill it with a text string explaining how it isn't compatible (or why |
| 59 | + we can't tell), and return a pointer to that space as <*reason_p>. |
| 60 | +-----------------------------------------------------------------------------*/ |
| 61 | + int fd; |
| 62 | + char version[4]; |
| 63 | + char full_path[MAXPGPATH+1]; |
| 64 | +#ifndef WIN32 |
| 65 | + struct stat statbuf; |
| 66 | +#else |
| 67 | + struct _stat statbuf; |
| 68 | +#endif |
| 69 | + PathSetVersionFilePath(path, full_path); |
| 70 | + |
| 71 | + if (stat(full_path, &statbuf) < 0) { |
| 72 | + *reason_p = malloc(200); |
| 73 | + sprintf(*reason_p, "File '%s' does not exist.", full_path); |
| 74 | + } else { |
| 75 | + fd = open(full_path, O_RDONLY, 0); |
| 76 | + if (fd < 0) { |
| 77 | + *reason_p = malloc(200); |
| 78 | + sprintf(*reason_p, "Unable to open file '%s'. Errno = %s (%d).", |
| 79 | + full_path, strerror(errno), errno); |
| 80 | + } else { |
| 81 | + if (read(fd, version, 4) < 4 || |
| 82 | + !isascii(version[0]) || !isdigit(version[0]) || |
| 83 | + version[1] != '.' || |
| 84 | + !isascii(version[2]) || !isdigit(version[2]) || |
| 85 | + version[3] != '\n') { |
| 86 | + |
| 87 | + *reason_p = malloc(200); |
| 88 | + sprintf(*reason_p, "File '%s' does not have a valid format " |
| 89 | + "for a PG_VERSION file.", full_path); |
| 90 | + } else { |
| 91 | + if (version[2] != '0' + PG_VERSION || |
| 92 | + version[0] != '0' + PG_RELEASE) { |
| 93 | + *reason_p = malloc(200); |
| 94 | + sprintf(*reason_p, |
| 95 | + "Version number in file '%s' should be %d.%d, " |
| 96 | + "not %c.%c.", |
| 97 | + full_path, |
| 98 | + PG_RELEASE, PG_VERSION, version[0], version[2]); |
| 99 | + } else *reason_p = NULL; |
| 100 | + } |
| 101 | + close(fd); |
| 102 | + } |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | +void |
| 109 | +SetPgVersion(const char *path, char **reason_p) { |
| 110 | +/*--------------------------------------------------------------------------- |
| 111 | + Create the PG_VERSION file in the directory <path>. |
| 112 | + |
| 113 | + If we fail, allocate storage, fill it with a text string explaining why, |
| 114 | + and return a pointer to that storage as <*reason_p>. If we succeed, |
| 115 | + return *reason_p = NULL. |
| 116 | +---------------------------------------------------------------------------*/ |
| 117 | + int fd; |
| 118 | + char version[4]; |
| 119 | + char full_path[MAXPGPATH+1]; |
| 120 | + |
| 121 | + PathSetVersionFilePath(path, full_path); |
| 122 | + |
| 123 | + fd = open(full_path, O_WRONLY|O_CREAT|O_EXCL, 0666); |
| 124 | + if (fd < 0) { |
| 125 | + *reason_p = malloc(100 + strlen(full_path)); |
| 126 | + sprintf(*reason_p, |
| 127 | + "Unable to create file '%s', errno from open(): %s (%d).", |
| 128 | + full_path, strerror(errno), errno); |
| 129 | + } else { |
| 130 | + int rc; /* return code from some function we call */ |
| 131 | + |
| 132 | + version[0] = '0' + PG_RELEASE; |
| 133 | + version[1] = '.'; |
| 134 | + version[2] = '0' + PG_VERSION; |
| 135 | + version[3] = '\n'; |
| 136 | + rc = write(fd, version, 4); |
| 137 | + if (rc != 4) { |
| 138 | + *reason_p = malloc(100 + strlen(full_path)); |
| 139 | + sprintf(*reason_p, |
| 140 | + "Failed to write to file '%s', after it was already " |
| 141 | + "open. Errno from write(): %s (%d)", |
| 142 | + full_path, strerror(errno), errno); |
| 143 | + } else *reason_p = NULL; |
| 144 | + close(fd); |
| 145 | + } |
| 146 | +} |
0 commit comments