miscinit.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 947 行 · 第 1/2 页
C
947 行
* We need a loop here because of race conditions. But don't loop * forever (for example, a non-writable $PGDATA directory might cause * a failure that won't go away). 100 tries seems like plenty. */ for (ntries = 0;; ntries++) { /* * Try to create the lock file --- O_EXCL makes this atomic. */ fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); if (fd >= 0) break; /* Success; exit the retry loop */ /* * Couldn't create the pid file. Probably it already exists. */ if ((errno != EEXIST && errno != EACCES) || ntries > 100) ereport(FATAL, (errcode_for_file_access(), errmsg("could not create lock file \"%s\": %m", filename))); /* * Read the file to get the old owner's PID. Note race condition * here: file might have been deleted since we tried to create it. */ fd = open(filename, O_RDONLY, 0600); if (fd < 0) { if (errno == ENOENT) continue; /* race condition; try again */ ereport(FATAL, (errcode_for_file_access(), errmsg("could not open lock file \"%s\": %m", filename))); } if ((len = read(fd, buffer, sizeof(buffer) - 1)) <= 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not read lock file \"%s\": %m", filename))); close(fd); buffer[len] = '\0'; encoded_pid = atoi(buffer); /* if pid < 0, the pid is for postgres, not postmaster */ other_pid = (pid_t) (encoded_pid < 0 ? -encoded_pid : encoded_pid); if (other_pid <= 0) elog(FATAL, "bogus data in lock file \"%s\"", filename); /* * Check to see if the other process still exists * * Normally kill() will fail with ESRCH if the given PID doesn't * exist. BeOS returns EINVAL for some silly reason, however. */ if (other_pid != my_pid) { if (kill(other_pid, 0) == 0 || (errno != ESRCH#ifdef __BEOS__ && errno != EINVAL#endif )) { /* lockfile belongs to a live process */ ereport(FATAL, (errcode(ERRCODE_LOCK_FILE_EXISTS), errmsg("lock file \"%s\" already exists", filename), isDDLock ? errhint("Is another %s (PID %d) running in data directory \"%s\"?", (encoded_pid < 0 ? "postgres" : "postmaster"), (int) other_pid, refName) : errhint("Is another %s (PID %d) using socket file \"%s\"?", (encoded_pid < 0 ? "postgres" : "postmaster"), (int) other_pid, refName))); } } /* * No, the creating process did not exist. However, it could be * that the postmaster crashed (or more likely was kill -9'd by a * clueless admin) but has left orphan backends behind. Check for * this by looking to see if there is an associated shmem segment * that is still in use. */ if (isDDLock) { char *ptr; unsigned long id1, id2; ptr = strchr(buffer, '\n'); if (ptr != NULL && (ptr = strchr(ptr + 1, '\n')) != NULL) { ptr++; if (sscanf(ptr, "%lu %lu", &id1, &id2) == 2) { if (PGSharedMemoryIsInUse(id1, id2)) ereport(FATAL, (errcode(ERRCODE_LOCK_FILE_EXISTS), errmsg("pre-existing shared memory block " "(key %lu, ID %lu) is still in use", id1, id2), errhint("If you're sure there are no old " "server processes still running, remove " "the shared memory block with " "the command \"ipcrm\", or just delete the file \"%s\".", filename))); } } } /* * Looks like nobody's home. Unlink the file and try again to * create it. Need a loop because of possible race condition * against other would-be creators. */ if (unlink(filename) < 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not remove old lock file \"%s\": %m", filename), errhint("The file seems accidentally left over, but " "it could not be removed. Please remove the file " "by hand and try again."))); } /* * Successfully created the file, now fill it. */ snprintf(buffer, sizeof(buffer), "%d\n%s\n", amPostmaster ? (int) my_pid : -((int) my_pid), DataDir); errno = 0; if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) { int save_errno = errno; close(fd); unlink(filename); /* if write didn't set errno, assume problem is no disk space */ errno = save_errno ? save_errno : ENOSPC; ereport(FATAL, (errcode_for_file_access(), errmsg("could not write lock file \"%s\": %m", filename))); } close(fd); /* * Arrange for automatic removal of lockfile at proc_exit. */ on_proc_exit(UnlinkLockFile, PointerGetDatum(strdup(filename)));}voidCreateDataDirLockFile(const char *datadir, bool amPostmaster){ char lockfile[MAXPGPATH]; snprintf(lockfile, sizeof(lockfile), "%s/postmaster.pid", datadir); CreateLockFile(lockfile, amPostmaster, true, datadir); /* Save name of lockfile for RecordSharedMemoryInLockFile */ strcpy(directoryLockFile, lockfile);}voidCreateSocketLockFile(const char *socketfile, bool amPostmaster){ char lockfile[MAXPGPATH]; snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile); CreateLockFile(lockfile, amPostmaster, false, socketfile); /* Save name of lockfile for TouchSocketLockFile */ strcpy(socketLockFile, lockfile);}/* * TouchSocketLockFile -- mark socket lock file as recently accessed * * This routine should be called every so often to ensure that the lock file * has a recent mod or access date. That saves it * from being removed by overenthusiastic /tmp-directory-cleaner daemons. * (Another reason we should never have put the socket file in /tmp...) */voidTouchSocketLockFile(void){ /* Do nothing if we did not create a socket... */ if (socketLockFile[0] != '\0') { /* * utime() is POSIX standard, utimes() is a common alternative; if * we have neither, fall back to actually reading the file (which * only sets the access time not mod time, but that should be * enough in most cases). In all paths, we ignore errors. */#ifdef HAVE_UTIME utime(socketLockFile, NULL);#else /* !HAVE_UTIME */#ifdef HAVE_UTIMES utimes(socketLockFile, NULL);#else /* !HAVE_UTIMES */ int fd; char buffer[1]; fd = open(socketLockFile, O_RDONLY | PG_BINARY, 0); if (fd >= 0) { read(fd, buffer, sizeof(buffer)); close(fd); }#endif /* HAVE_UTIMES */#endif /* HAVE_UTIME */ }}/* * Append information about a shared memory segment to the data directory * lock file (if we have created one). * * This may be called multiple times in the life of a postmaster, if we * delete and recreate shmem due to backend crash. Therefore, be prepared * to overwrite existing information. (As of 7.1, a postmaster only creates * one shm seg at a time; but for the purposes here, if we did have more than * one then any one of them would do anyway.) */voidRecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2){ int fd; int len; char *ptr; char buffer[BLCKSZ]; /* * Do nothing if we did not create a lockfile (probably because we are * running standalone). */ if (directoryLockFile[0] == '\0') return; fd = open(directoryLockFile, O_RDWR | PG_BINARY, 0); if (fd < 0) { ereport(LOG, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", directoryLockFile))); return; } len = read(fd, buffer, sizeof(buffer) - 100); if (len <= 0) { ereport(LOG, (errcode_for_file_access(), errmsg("could not read from file \"%s\": %m", directoryLockFile))); close(fd); return; } buffer[len] = '\0'; /* * Skip over first two lines (PID and path). */ ptr = strchr(buffer, '\n'); if (ptr == NULL || (ptr = strchr(ptr + 1, '\n')) == NULL) { elog(LOG, "bogus data in \"%s\"", directoryLockFile); close(fd); return; } ptr++; /* * Append key information. Format to try to keep it the same length * always (trailing junk won't hurt, but might confuse humans). */ sprintf(ptr, "%9lu %9lu\n", id1, id2); /* * And rewrite the data. Since we write in a single kernel call, this * update should appear atomic to onlookers. */ len = strlen(buffer); errno = 0; if (lseek(fd, (off_t) 0, SEEK_SET) != 0 || (int) write(fd, buffer, len) != len) { /* if write didn't set errno, assume problem is no disk space */ if (errno == 0) errno = ENOSPC; ereport(LOG, (errcode_for_file_access(), errmsg("could not write to file \"%s\": %m", directoryLockFile))); close(fd); return; } close(fd);}/*------------------------------------------------------------------------- * Version checking support *------------------------------------------------------------------------- *//* * Determine whether the PG_VERSION file in directory `path' indicates * a data version compatible with the version of this program. * * If compatible, return. Otherwise, ereport(FATAL). */voidValidatePgVersion(const char *path){ char full_path[MAXPGPATH]; FILE *file; int ret; long file_major, file_minor; long my_major = 0, my_minor = 0; char *endptr; const char *version_string = PG_VERSION; my_major = strtol(version_string, &endptr, 10); if (*endptr == '.') my_minor = strtol(endptr + 1, NULL, 10); snprintf(full_path, sizeof(full_path), "%s/PG_VERSION", path); file = AllocateFile(full_path, "r"); if (!file) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" is not a valid data directory", path), errdetail("File \"%s\" is missing.", full_path))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", full_path))); } ret = fscanf(file, "%ld.%ld", &file_major, &file_minor); if (ret != 2) ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" is not a valid data directory", path), errdetail("File \"%s\" does not contain valid data.", full_path), errhint("You may need to initdb."))); FreeFile(file); if (my_major != file_major || my_minor != file_minor) ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("database files are incompatible with server"), errdetail("The data directory was initialized by PostgreSQL version %ld.%ld, " "which is not compatible with this version %s.", file_major, file_minor, version_string)));}/*------------------------------------------------------------------------- * Library preload support *------------------------------------------------------------------------- */#if defined(__mc68000__) && defined(__ELF__)typedef int32 ((*func_ptr) ());#elsetypedef char *((*func_ptr) ());#endif/* * process any libraries that should be preloaded and * optionally pre-initialized */voidprocess_preload_libraries(char *preload_libraries_string){ char *rawstring; List *elemlist; List *l; if (preload_libraries_string == NULL) return; /* Need a modifiable copy of string */ rawstring = pstrdup(preload_libraries_string); /* Parse string into list of identifiers */ if (!SplitIdentifierString(rawstring, ',', &elemlist)) { /* syntax error in list */ pfree(rawstring); freeList(elemlist); ereport(LOG, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid list syntax for parameter \"preload_libraries\""))); return; } foreach(l, elemlist) { char *tok = (char *) lfirst(l); char *sep = strstr(tok, ":"); char *filename = NULL; char *funcname = NULL; func_ptr initfunc; if (sep) { /* * a colon separator implies there is an initialization * function that we need to run in addition to loading the * library */ size_t filename_len = sep - tok; size_t funcname_len = strlen(tok) - filename_len - 1; filename = (char *) palloc(filename_len + 1); memcpy(filename, tok, filename_len); filename[filename_len] = '\0'; funcname = (char *) palloc(funcname_len + 1); strcpy(funcname, sep + 1); } else { /* * no separator -- just load the library */ filename = pstrdup(tok); funcname = NULL; } initfunc = (func_ptr) load_external_function(filename, funcname, true, NULL); if (initfunc) (*initfunc) (); if (funcname) ereport(LOG, (errmsg("preloaded library \"%s\" with initialization function \"%s\"", filename, funcname))); else ereport(LOG, (errmsg("preloaded library \"%s\"", filename))); pfree(filename); if (funcname) pfree(funcname); } pfree(rawstring); freeList(elemlist);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?