dfmgr.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 625 行 · 第 1/2 页

C
625
字号
/*------------------------------------------------------------------------- * * dfmgr.c *	  Dynamic function manager code. * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.96 2008/01/01 19:45:53 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <sys/stat.h>#ifndef WIN32_ONLY_COMPILER#include "dynloader.h"#else#include "port/dynloader/win32.h"#endif#include "miscadmin.h"#include "utils/dynamic_loader.h"#include "utils/hsearch.h"/* signatures for PostgreSQL-specific library init/fini functions */typedef void (*PG_init_t) (void);typedef void (*PG_fini_t) (void);/* hashtable entry for rendezvous variables */typedef struct{	char		varName[NAMEDATALEN];	/* hash key (must be first) */	void	   *varValue;} rendezvousHashEntry;/* * List of dynamically loaded files (kept in malloc'd memory). */typedef struct df_files{	struct df_files *next;		/* List link */	dev_t		device;			/* Device file is on */#ifndef WIN32					/* ensures we never again depend on this under								 * win32 */	ino_t		inode;			/* Inode number of file */#endif	void	   *handle;			/* a handle for pg_dl* functions */	char		filename[1];	/* Full pathname of file */	/*	 * we allocate the block big enough for actual length of pathname.	 * filename[] must be last item in struct!	 */} DynamicFileList;static DynamicFileList *file_list = NULL;static DynamicFileList *file_tail = NULL;/* stat() call under Win32 returns an st_ino field, but it has no meaning */#ifndef WIN32#define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)#else#define SAME_INODE(A,B) false#endifchar	   *Dynamic_library_path;static void *internal_load_library(const char *libname);static void internal_unload_library(const char *libname);static bool file_exists(const char *name);static char *expand_dynamic_library_name(const char *name);static void check_restricted_library_name(const char *name);static char *substitute_libpath_macro(const char *name);static char *find_in_dynamic_libpath(const char *basename);/* Magic structure that module needs to match to be accepted */static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;/* * Load the specified dynamic-link library file, and look for a function * named funcname in it. * * If the function is not found, we raise an error if signalNotFound is true, * else return (PGFunction) NULL.  Note that errors in loading the library * will provoke ereport() regardless of signalNotFound. * * If filehandle is not NULL, then *filehandle will be set to a handle * identifying the library file.  The filehandle can be used with * lookup_external_function to lookup additional functions in the same file * at less cost than repeating load_external_function. */PGFunctionload_external_function(char *filename, char *funcname,					   bool signalNotFound, void **filehandle){	char	   *fullname;	void	   *lib_handle;	PGFunction	retval;	/* Expand the possibly-abbreviated filename to an exact path name */	fullname = expand_dynamic_library_name(filename);	/* Load the shared library, unless we already did */	lib_handle = internal_load_library(fullname);	/* Return handle if caller wants it */	if (filehandle)		*filehandle = lib_handle;	/* Look up the function within the library */	retval = (PGFunction) pg_dlsym(lib_handle, funcname);	if (retval == NULL && signalNotFound)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("could not find function \"%s\" in file \"%s\"",						funcname, fullname)));	pfree(fullname);	return retval;}/* * This function loads a shlib file without looking up any particular * function in it.	If the same shlib has previously been loaded, * unload and reload it. * * When 'restricted' is true, only libraries in the presumed-secure * directory $libdir/plugins may be referenced. */voidload_file(const char *filename, bool restricted){	char	   *fullname;	/* Apply security restriction if requested */	if (restricted)		check_restricted_library_name(filename);	/* Expand the possibly-abbreviated filename to an exact path name */	fullname = expand_dynamic_library_name(filename);	/* Unload the library if currently loaded */	internal_unload_library(fullname);	/* Load the shared library */	(void) internal_load_library(fullname);	pfree(fullname);}/* * Lookup a function whose library file is already loaded. * Return (PGFunction) NULL if not found. */PGFunctionlookup_external_function(void *filehandle, char *funcname){	return (PGFunction) pg_dlsym(filehandle, funcname);}/* * Load the specified dynamic-link library file, unless it already is * loaded.	Return the pg_dl* handle for the file. * * Note: libname is expected to be an exact name for the library file. */static void *internal_load_library(const char *libname){	DynamicFileList *file_scanner;	PGModuleMagicFunction magic_func;	char	   *load_error;	struct stat stat_buf;	PG_init_t	PG_init;	/*	 * Scan the list of loaded FILES to see if the file has been loaded.	 */	for (file_scanner = file_list;		 file_scanner != NULL &&		 strcmp(libname, file_scanner->filename) != 0;		 file_scanner = file_scanner->next)		;	if (file_scanner == NULL)	{		/*		 * Check for same files - different paths (ie, symlink or link)		 */		if (stat(libname, &stat_buf) == -1)			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not access file \"%s\": %m",							libname)));		for (file_scanner = file_list;			 file_scanner != NULL &&			 !SAME_INODE(stat_buf, *file_scanner);			 file_scanner = file_scanner->next)			;	}	if (file_scanner == NULL)	{		/*		 * File not loaded yet.		 */		file_scanner = (DynamicFileList *)			malloc(sizeof(DynamicFileList) + strlen(libname));		if (file_scanner == NULL)			ereport(ERROR,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory")));		MemSet(file_scanner, 0, sizeof(DynamicFileList));		strcpy(file_scanner->filename, libname);		file_scanner->device = stat_buf.st_dev;#ifndef WIN32		file_scanner->inode = stat_buf.st_ino;#endif		file_scanner->next = NULL;		file_scanner->handle = pg_dlopen(file_scanner->filename);		if (file_scanner->handle == NULL)		{			load_error = (char *) pg_dlerror();			free((char *) file_scanner);			/* errcode_for_file_access might not be appropriate here? */			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not load library \"%s\": %s",							libname, load_error)));		}		/* Check the magic function to determine compatibility */		magic_func = (PGModuleMagicFunction)			pg_dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING);		if (magic_func)		{			const Pg_magic_struct *magic_data_ptr = (*magic_func) ();			if (magic_data_ptr->len != magic_data.len ||				memcmp(magic_data_ptr, &magic_data, magic_data.len) != 0)			{				/* copy data block before unlinking library */				Pg_magic_struct module_magic_data = *magic_data_ptr;				/* try to unlink library */				pg_dlclose(file_scanner->handle);				free((char *) file_scanner);				/*				 * Report suitable error.  It's probably not worth writing a				 * separate error message for each field; only the most common				 * case of wrong major version gets its own message.				 */				if (module_magic_data.version != magic_data.version)					ereport(ERROR,					 (errmsg("incompatible library \"%s\": version mismatch",							 libname),					  errdetail("Server is version %d.%d, library is version %d.%d.",								magic_data.version / 100,								magic_data.version % 100,								module_magic_data.version / 100,								module_magic_data.version % 100)));				ereport(ERROR,				 (errmsg("incompatible library \"%s\": magic block mismatch",						 libname)));			}		}		else		{			/* try to unlink library */			pg_dlclose(file_scanner->handle);			free((char *) file_scanner);			/* complain */			ereport(ERROR,				  (errmsg("incompatible library \"%s\": missing magic block",						  libname),				   errhint("Extension libraries are required to use the PG_MODULE_MAGIC macro.")));		}		/*		 * If the library has a _PG_init() function, call it.		 */		PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, "_PG_init");		if (PG_init)			(*PG_init) ();		/* OK to link it into list */		if (file_list == NULL)			file_list = file_scanner;		else			file_tail->next = file_scanner;		file_tail = file_scanner;	}	return file_scanner->handle;}/* * Unload the specified dynamic-link library file, if it is loaded. * * Note: libname is expected to be an exact name for the library file. */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?