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 + -
显示快捷键?