LCOV - code coverage report
Current view: top level - src/backend/utils/fmgr - dfmgr.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12devel Lines: 144 214 67.3 %
Date: 2018-12-12 09:22:26 Functions: 13 15 86.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * dfmgr.c
       4             :  *    Dynamic function manager code.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/utils/fmgr/dfmgr.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include <sys/stat.h>
      18             : 
      19             : #ifdef HAVE_DLOPEN
      20             : #include <dlfcn.h>
      21             : 
      22             : /*
      23             :  * On macOS, <dlfcn.h> insists on including <stdbool.h>.  If we're not
      24             :  * using stdbool, undef bool to undo the damage.
      25             :  */
      26             : #ifndef USE_STDBOOL
      27             : #ifdef bool
      28             : #undef bool
      29             : #endif
      30             : #endif
      31             : #endif                          /* HAVE_DLOPEN */
      32             : 
      33             : #include "fmgr.h"
      34             : #include "lib/stringinfo.h"
      35             : #include "miscadmin.h"
      36             : #include "storage/shmem.h"
      37             : #include "utils/hsearch.h"
      38             : 
      39             : 
      40             : /* signatures for PostgreSQL-specific library init/fini functions */
      41             : typedef void (*PG_init_t) (void);
      42             : typedef void (*PG_fini_t) (void);
      43             : 
      44             : /* hashtable entry for rendezvous variables */
      45             : typedef struct
      46             : {
      47             :     char        varName[NAMEDATALEN];   /* hash key (must be first) */
      48             :     void       *varValue;
      49             : } rendezvousHashEntry;
      50             : 
      51             : /*
      52             :  * List of dynamically loaded files (kept in malloc'd memory).
      53             :  */
      54             : 
      55             : typedef struct df_files
      56             : {
      57             :     struct df_files *next;      /* List link */
      58             :     dev_t       device;         /* Device file is on */
      59             : #ifndef WIN32                   /* ensures we never again depend on this under
      60             :                                  * win32 */
      61             :     ino_t       inode;          /* Inode number of file */
      62             : #endif
      63             :     void       *handle;         /* a handle for pg_dl* functions */
      64             :     char        filename[FLEXIBLE_ARRAY_MEMBER];    /* Full pathname of file */
      65             : } DynamicFileList;
      66             : 
      67             : static DynamicFileList *file_list = NULL;
      68             : static DynamicFileList *file_tail = NULL;
      69             : 
      70             : /* stat() call under Win32 returns an st_ino field, but it has no meaning */
      71             : #ifndef WIN32
      72             : #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
      73             : #else
      74             : #define SAME_INODE(A,B) false
      75             : #endif
      76             : 
      77             : char       *Dynamic_library_path;
      78             : 
      79             : static void *internal_load_library(const char *libname);
      80             : static void incompatible_module_error(const char *libname,
      81             :                           const Pg_magic_struct *module_magic_data) pg_attribute_noreturn();
      82             : static void internal_unload_library(const char *libname);
      83             : static bool file_exists(const char *name);
      84             : static char *expand_dynamic_library_name(const char *name);
      85             : static void check_restricted_library_name(const char *name);
      86             : static char *substitute_libpath_macro(const char *name);
      87             : static char *find_in_dynamic_libpath(const char *basename);
      88             : 
      89             : /* Magic structure that module needs to match to be accepted */
      90             : static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
      91             : 
      92             : 
      93             : /*
      94             :  * Load the specified dynamic-link library file, and look for a function
      95             :  * named funcname in it.
      96             :  *
      97             :  * If the function is not found, we raise an error if signalNotFound is true,
      98             :  * else return (PGFunction) NULL.  Note that errors in loading the library
      99             :  * will provoke ereport() regardless of signalNotFound.
     100             :  *
     101             :  * If filehandle is not NULL, then *filehandle will be set to a handle
     102             :  * identifying the library file.  The filehandle can be used with
     103             :  * lookup_external_function to lookup additional functions in the same file
     104             :  * at less cost than repeating load_external_function.
     105             :  */
     106             : PGFunction
     107       85896 : load_external_function(const char *filename, const char *funcname,
     108             :                        bool signalNotFound, void **filehandle)
     109             : {
     110             :     char       *fullname;
     111             :     void       *lib_handle;
     112             :     PGFunction  retval;
     113             : 
     114             :     /* Expand the possibly-abbreviated filename to an exact path name */
     115       85896 :     fullname = expand_dynamic_library_name(filename);
     116             : 
     117             :     /* Load the shared library, unless we already did */
     118       85896 :     lib_handle = internal_load_library(fullname);
     119             : 
     120             :     /* Return handle if caller wants it */
     121       85890 :     if (filehandle)
     122       85302 :         *filehandle = lib_handle;
     123             : 
     124             :     /* Look up the function within the library. */
     125       85890 :     retval = (PGFunction) dlsym(lib_handle, funcname);
     126             : 
     127       85890 :     if (retval == NULL && signalNotFound)
     128           4 :         ereport(ERROR,
     129             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     130             :                  errmsg("could not find function \"%s\" in file \"%s\"",
     131             :                         funcname, fullname)));
     132             : 
     133       85886 :     pfree(fullname);
     134       85886 :     return retval;
     135             : }
     136             : 
     137             : /*
     138             :  * This function loads a shlib file without looking up any particular
     139             :  * function in it.  If the same shlib has previously been loaded,
     140             :  * unload and reload it.
     141             :  *
     142             :  * When 'restricted' is true, only libraries in the presumed-secure
     143             :  * directory $libdir/plugins may be referenced.
     144             :  */
     145             : void
     146         392 : load_file(const char *filename, bool restricted)
     147             : {
     148             :     char       *fullname;
     149             : 
     150             :     /* Apply security restriction if requested */
     151         392 :     if (restricted)
     152           0 :         check_restricted_library_name(filename);
     153             : 
     154             :     /* Expand the possibly-abbreviated filename to an exact path name */
     155         392 :     fullname = expand_dynamic_library_name(filename);
     156             : 
     157             :     /* Unload the library if currently loaded */
     158         392 :     internal_unload_library(fullname);
     159             : 
     160             :     /* Load the shared library */
     161         392 :     (void) internal_load_library(fullname);
     162             : 
     163         392 :     pfree(fullname);
     164         392 : }
     165             : 
     166             : /*
     167             :  * Lookup a function whose library file is already loaded.
     168             :  * Return (PGFunction) NULL if not found.
     169             :  */
     170             : PGFunction
     171       85298 : lookup_external_function(void *filehandle, const char *funcname)
     172             : {
     173       85298 :     return (PGFunction) dlsym(filehandle, funcname);
     174             : }
     175             : 
     176             : 
     177             : /*
     178             :  * Load the specified dynamic-link library file, unless it already is
     179             :  * loaded.  Return the pg_dl* handle for the file.
     180             :  *
     181             :  * Note: libname is expected to be an exact name for the library file.
     182             :  */
     183             : static void *
     184       87708 : internal_load_library(const char *libname)
     185             : {
     186             :     DynamicFileList *file_scanner;
     187             :     PGModuleMagicFunction magic_func;
     188             :     char       *load_error;
     189             :     struct stat stat_buf;
     190             :     PG_init_t   PG_init;
     191             : 
     192             :     /*
     193             :      * Scan the list of loaded FILES to see if the file has been loaded.
     194             :      */
     195     1055264 :     for (file_scanner = file_list;
     196      956236 :          file_scanner != NULL &&
     197      956236 :          strcmp(libname, file_scanner->filename) != 0;
     198      879848 :          file_scanner = file_scanner->next)
     199             :         ;
     200             : 
     201       87708 :     if (file_scanner == NULL)
     202             :     {
     203             :         /*
     204             :          * Check for same files - different paths (ie, symlink or link)
     205             :          */
     206       11320 :         if (stat(libname, &stat_buf) == -1)
     207           6 :             ereport(ERROR,
     208             :                     (errcode_for_file_access(),
     209             :                      errmsg("could not access file \"%s\": %m",
     210             :                             libname)));
     211             : 
     212      135190 :         for (file_scanner = file_list;
     213      112562 :              file_scanner != NULL &&
     214      112562 :              !SAME_INODE(stat_buf, *file_scanner);
     215      112562 :              file_scanner = file_scanner->next)
     216             :             ;
     217             :     }
     218             : 
     219       87702 :     if (file_scanner == NULL)
     220             :     {
     221             :         /*
     222             :          * File not loaded yet.
     223             :          */
     224       11314 :         file_scanner = (DynamicFileList *)
     225       11314 :             malloc(offsetof(DynamicFileList, filename) + strlen(libname) + 1);
     226       11314 :         if (file_scanner == NULL)
     227           0 :             ereport(ERROR,
     228             :                     (errcode(ERRCODE_OUT_OF_MEMORY),
     229             :                      errmsg("out of memory")));
     230             : 
     231       11314 :         MemSet(file_scanner, 0, offsetof(DynamicFileList, filename));
     232       11314 :         strcpy(file_scanner->filename, libname);
     233       11314 :         file_scanner->device = stat_buf.st_dev;
     234             : #ifndef WIN32
     235       11314 :         file_scanner->inode = stat_buf.st_ino;
     236             : #endif
     237       11314 :         file_scanner->next = NULL;
     238             : 
     239       11314 :         file_scanner->handle = dlopen(file_scanner->filename, RTLD_NOW | RTLD_GLOBAL);
     240       11314 :         if (file_scanner->handle == NULL)
     241             :         {
     242           0 :             load_error = dlerror();
     243           0 :             free((char *) file_scanner);
     244             :             /* errcode_for_file_access might not be appropriate here? */
     245           0 :             ereport(ERROR,
     246             :                     (errcode_for_file_access(),
     247             :                      errmsg("could not load library \"%s\": %s",
     248             :                             libname, load_error)));
     249             :         }
     250             : 
     251             :         /* Check the magic function to determine compatibility */
     252       11314 :         magic_func = (PGModuleMagicFunction)
     253       11314 :             dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING);
     254       11314 :         if (magic_func)
     255             :         {
     256       11314 :             const Pg_magic_struct *magic_data_ptr = (*magic_func) ();
     257             : 
     258       22628 :             if (magic_data_ptr->len != magic_data.len ||
     259       11314 :                 memcmp(magic_data_ptr, &magic_data, magic_data.len) != 0)
     260             :             {
     261             :                 /* copy data block before unlinking library */
     262           0 :                 Pg_magic_struct module_magic_data = *magic_data_ptr;
     263             : 
     264             :                 /* try to close library */
     265           0 :                 dlclose(file_scanner->handle);
     266           0 :                 free((char *) file_scanner);
     267             : 
     268             :                 /* issue suitable complaint */
     269           0 :                 incompatible_module_error(libname, &module_magic_data);
     270             :             }
     271             :         }
     272             :         else
     273             :         {
     274             :             /* try to close library */
     275           0 :             dlclose(file_scanner->handle);
     276           0 :             free((char *) file_scanner);
     277             :             /* complain */
     278           0 :             ereport(ERROR,
     279             :                     (errmsg("incompatible library \"%s\": missing magic block",
     280             :                             libname),
     281             :                      errhint("Extension libraries are required to use the PG_MODULE_MAGIC macro.")));
     282             :         }
     283             : 
     284             :         /*
     285             :          * If the library has a _PG_init() function, call it.
     286             :          */
     287       11314 :         PG_init = (PG_init_t) dlsym(file_scanner->handle, "_PG_init");
     288       11314 :         if (PG_init)
     289        2660 :             (*PG_init) ();
     290             : 
     291             :         /* OK to link it into list */
     292       11314 :         if (file_list == NULL)
     293        3094 :             file_list = file_scanner;
     294             :         else
     295        8220 :             file_tail->next = file_scanner;
     296       11314 :         file_tail = file_scanner;
     297             :     }
     298             : 
     299       87702 :     return file_scanner->handle;
     300             : }
     301             : 
     302             : /*
     303             :  * Report a suitable error for an incompatible magic block.
     304             :  */
     305             : static void
     306           0 : incompatible_module_error(const char *libname,
     307             :                           const Pg_magic_struct *module_magic_data)
     308             : {
     309             :     StringInfoData details;
     310             : 
     311             :     /*
     312             :      * If the version doesn't match, just report that, because the rest of the
     313             :      * block might not even have the fields we expect.
     314             :      */
     315           0 :     if (magic_data.version != module_magic_data->version)
     316             :     {
     317             :         char        library_version[32];
     318             : 
     319           0 :         if (module_magic_data->version >= 1000)
     320           0 :             snprintf(library_version, sizeof(library_version), "%d",
     321           0 :                      module_magic_data->version / 100);
     322             :         else
     323           0 :             snprintf(library_version, sizeof(library_version), "%d.%d",
     324           0 :                      module_magic_data->version / 100,
     325           0 :                      module_magic_data->version % 100);
     326           0 :         ereport(ERROR,
     327             :                 (errmsg("incompatible library \"%s\": version mismatch",
     328             :                         libname),
     329             :                  errdetail("Server is version %d, library is version %s.",
     330             :                            magic_data.version / 100, library_version)));
     331             :     }
     332             : 
     333             :     /*
     334             :      * Otherwise, spell out which fields don't agree.
     335             :      *
     336             :      * XXX this code has to be adjusted any time the set of fields in a magic
     337             :      * block change!
     338             :      */
     339           0 :     initStringInfo(&details);
     340             : 
     341           0 :     if (module_magic_data->funcmaxargs != magic_data.funcmaxargs)
     342             :     {
     343           0 :         if (details.len)
     344           0 :             appendStringInfoChar(&details, '\n');
     345           0 :         appendStringInfo(&details,
     346           0 :                          _("Server has FUNC_MAX_ARGS = %d, library has %d."),
     347             :                          magic_data.funcmaxargs,
     348             :                          module_magic_data->funcmaxargs);
     349             :     }
     350           0 :     if (module_magic_data->indexmaxkeys != magic_data.indexmaxkeys)
     351             :     {
     352           0 :         if (details.len)
     353           0 :             appendStringInfoChar(&details, '\n');
     354           0 :         appendStringInfo(&details,
     355           0 :                          _("Server has INDEX_MAX_KEYS = %d, library has %d."),
     356             :                          magic_data.indexmaxkeys,
     357             :                          module_magic_data->indexmaxkeys);
     358             :     }
     359           0 :     if (module_magic_data->namedatalen != magic_data.namedatalen)
     360             :     {
     361           0 :         if (details.len)
     362           0 :             appendStringInfoChar(&details, '\n');
     363           0 :         appendStringInfo(&details,
     364           0 :                          _("Server has NAMEDATALEN = %d, library has %d."),
     365             :                          magic_data.namedatalen,
     366             :                          module_magic_data->namedatalen);
     367             :     }
     368           0 :     if (module_magic_data->float4byval != magic_data.float4byval)
     369             :     {
     370           0 :         if (details.len)
     371           0 :             appendStringInfoChar(&details, '\n');
     372           0 :         appendStringInfo(&details,
     373           0 :                          _("Server has FLOAT4PASSBYVAL = %s, library has %s."),
     374           0 :                          magic_data.float4byval ? "true" : "false",
     375           0 :                          module_magic_data->float4byval ? "true" : "false");
     376             :     }
     377           0 :     if (module_magic_data->float8byval != magic_data.float8byval)
     378             :     {
     379           0 :         if (details.len)
     380           0 :             appendStringInfoChar(&details, '\n');
     381           0 :         appendStringInfo(&details,
     382           0 :                          _("Server has FLOAT8PASSBYVAL = %s, library has %s."),
     383           0 :                          magic_data.float8byval ? "true" : "false",
     384           0 :                          module_magic_data->float8byval ? "true" : "false");
     385             :     }
     386             : 
     387           0 :     if (details.len == 0)
     388           0 :         appendStringInfoString(&details,
     389           0 :                                _("Magic block has unexpected length or padding difference."));
     390             : 
     391           0 :     ereport(ERROR,
     392             :             (errmsg("incompatible library \"%s\": magic block mismatch",
     393             :                     libname),
     394             :              errdetail_internal("%s", details.data)));
     395             : }
     396             : 
     397             : /*
     398             :  * Unload the specified dynamic-link library file, if it is loaded.
     399             :  *
     400             :  * Note: libname is expected to be an exact name for the library file.
     401             :  *
     402             :  * XXX for the moment, this is disabled, resulting in LOAD of an already-loaded
     403             :  * library always being a no-op.  We might re-enable it someday if we can
     404             :  * convince ourselves we have safe protocols for un-hooking from hook function
     405             :  * pointers, releasing custom GUC variables, and perhaps other things that
     406             :  * are definitely unsafe currently.
     407             :  */
     408             : static void
     409         392 : internal_unload_library(const char *libname)
     410             : {
     411             : #ifdef NOT_USED
     412             :     DynamicFileList *file_scanner,
     413             :                *prv,
     414             :                *nxt;
     415             :     struct stat stat_buf;
     416             :     PG_fini_t   PG_fini;
     417             : 
     418             :     /*
     419             :      * We need to do stat() in order to determine whether this is the same
     420             :      * file as a previously loaded file; it's also handy so as to give a good
     421             :      * error message if bogus file name given.
     422             :      */
     423             :     if (stat(libname, &stat_buf) == -1)
     424             :         ereport(ERROR,
     425             :                 (errcode_for_file_access(),
     426             :                  errmsg("could not access file \"%s\": %m", libname)));
     427             : 
     428             :     /*
     429             :      * We have to zap all entries in the list that match on either filename or
     430             :      * inode, else internal_load_library() will still think it's present.
     431             :      */
     432             :     prv = NULL;
     433             :     for (file_scanner = file_list; file_scanner != NULL; file_scanner = nxt)
     434             :     {
     435             :         nxt = file_scanner->next;
     436             :         if (strcmp(libname, file_scanner->filename) == 0 ||
     437             :             SAME_INODE(stat_buf, *file_scanner))
     438             :         {
     439             :             if (prv)
     440             :                 prv->next = nxt;
     441             :             else
     442             :                 file_list = nxt;
     443             : 
     444             :             /*
     445             :              * If the library has a _PG_fini() function, call it.
     446             :              */
     447             :             PG_fini = (PG_fini_t) dlsym(file_scanner->handle, "_PG_fini");
     448             :             if (PG_fini)
     449             :                 (*PG_fini) ();
     450             : 
     451             :             clear_external_function_hash(file_scanner->handle);
     452             :             dlclose(file_scanner->handle);
     453             :             free((char *) file_scanner);
     454             :             /* prv does not change */
     455             :         }
     456             :         else
     457             :             prv = file_scanner;
     458             :     }
     459             : #endif                          /* NOT_USED */
     460         392 : }
     461             : 
     462             : static bool
     463      172380 : file_exists(const char *name)
     464             : {
     465             :     struct stat st;
     466             : 
     467             :     AssertArg(name != NULL);
     468             : 
     469      172380 :     if (stat(name, &st) == 0)
     470       86282 :         return S_ISDIR(st.st_mode) ? false : true;
     471       86098 :     else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES))
     472           0 :         ereport(ERROR,
     473             :                 (errcode_for_file_access(),
     474             :                  errmsg("could not access file \"%s\": %m", name)));
     475             : 
     476       86098 :     return false;
     477             : }
     478             : 
     479             : 
     480             : /* Example format: ".so" */
     481             : #ifndef DLSUFFIX
     482             : #error "DLSUFFIX must be defined to compile this file."
     483             : #endif
     484             : 
     485             : /*
     486             :  * If name contains a slash, check if the file exists, if so return
     487             :  * the name.  Else (no slash) try to expand using search path (see
     488             :  * find_in_dynamic_libpath below); if that works, return the fully
     489             :  * expanded file name.  If the previous failed, append DLSUFFIX and
     490             :  * try again.  If all fails, just return the original name.
     491             :  *
     492             :  * The result will always be freshly palloc'd.
     493             :  */
     494             : static char *
     495       86288 : expand_dynamic_library_name(const char *name)
     496             : {
     497             :     bool        have_slash;
     498             :     char       *new;
     499             :     char       *full;
     500             : 
     501             :     AssertArg(name);
     502             : 
     503       86288 :     have_slash = (first_dir_separator(name) != NULL);
     504             : 
     505       86288 :     if (!have_slash)
     506             :     {
     507         914 :         full = find_in_dynamic_libpath(name);
     508         914 :         if (full)
     509           0 :             return full;
     510             :     }
     511             :     else
     512             :     {
     513       85374 :         full = substitute_libpath_macro(name);
     514       85374 :         if (file_exists(full))
     515         196 :             return full;
     516       85178 :         pfree(full);
     517             :     }
     518             : 
     519       86092 :     new = psprintf("%s%s", name, DLSUFFIX);
     520             : 
     521       86092 :     if (!have_slash)
     522             :     {
     523         914 :         full = find_in_dynamic_libpath(new);
     524         914 :         pfree(new);
     525         914 :         if (full)
     526         908 :             return full;
     527             :     }
     528             :     else
     529             :     {
     530       85178 :         full = substitute_libpath_macro(new);
     531       85178 :         pfree(new);
     532       85178 :         if (file_exists(full))
     533       85178 :             return full;
     534           0 :         pfree(full);
     535             :     }
     536             : 
     537             :     /*
     538             :      * If we can't find the file, just return the string as-is. The ensuing
     539             :      * load attempt will fail and report a suitable message.
     540             :      */
     541           6 :     return pstrdup(name);
     542             : }
     543             : 
     544             : /*
     545             :  * Check a restricted library name.  It must begin with "$libdir/plugins/"
     546             :  * and there must not be any directory separators after that (this is
     547             :  * sufficient to prevent ".." style attacks).
     548             :  */
     549             : static void
     550           0 : check_restricted_library_name(const char *name)
     551             : {
     552           0 :     if (strncmp(name, "$libdir/plugins/", 16) != 0 ||
     553           0 :         first_dir_separator(name + 16) != NULL)
     554           0 :         ereport(ERROR,
     555             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     556             :                  errmsg("access to library \"%s\" is not allowed",
     557             :                         name)));
     558           0 : }
     559             : 
     560             : /*
     561             :  * Substitute for any macros appearing in the given string.
     562             :  * Result is always freshly palloc'd.
     563             :  */
     564             : static char *
     565      172380 : substitute_libpath_macro(const char *name)
     566             : {
     567             :     const char *sep_ptr;
     568             : 
     569             :     AssertArg(name != NULL);
     570             : 
     571             :     /* Currently, we only recognize $libdir at the start of the string */
     572      172380 :     if (name[0] != '$')
     573         196 :         return pstrdup(name);
     574             : 
     575      172184 :     if ((sep_ptr = first_dir_separator(name)) == NULL)
     576        1828 :         sep_ptr = name + strlen(name);
     577             : 
     578      344368 :     if (strlen("$libdir") != sep_ptr - name ||
     579      172184 :         strncmp(name, "$libdir", strlen("$libdir")) != 0)
     580           0 :         ereport(ERROR,
     581             :                 (errcode(ERRCODE_INVALID_NAME),
     582             :                  errmsg("invalid macro name in dynamic library path: %s",
     583             :                         name)));
     584             : 
     585      172184 :     return psprintf("%s%s", pkglib_path, sep_ptr);
     586             : }
     587             : 
     588             : 
     589             : /*
     590             :  * Search for a file called 'basename' in the colon-separated search
     591             :  * path Dynamic_library_path.  If the file is found, the full file name
     592             :  * is returned in freshly palloc'd memory.  If the file is not found,
     593             :  * return NULL.
     594             :  */
     595             : static char *
     596        1828 : find_in_dynamic_libpath(const char *basename)
     597             : {
     598             :     const char *p;
     599             :     size_t      baselen;
     600             : 
     601             :     AssertArg(basename != NULL);
     602             :     AssertArg(first_dir_separator(basename) == NULL);
     603             :     AssertState(Dynamic_library_path != NULL);
     604             : 
     605        1828 :     p = Dynamic_library_path;
     606        1828 :     if (strlen(p) == 0)
     607           0 :         return NULL;
     608             : 
     609        1828 :     baselen = strlen(basename);
     610             : 
     611             :     for (;;)
     612           0 :     {
     613             :         size_t      len;
     614             :         char       *piece;
     615             :         char       *mangled;
     616             :         char       *full;
     617             : 
     618        1828 :         piece = first_path_var_separator(p);
     619        1828 :         if (piece == p)
     620           0 :             ereport(ERROR,
     621             :                     (errcode(ERRCODE_INVALID_NAME),
     622             :                      errmsg("zero-length component in parameter \"dynamic_library_path\"")));
     623             : 
     624        1828 :         if (piece == NULL)
     625        1828 :             len = strlen(p);
     626             :         else
     627           0 :             len = piece - p;
     628             : 
     629        1828 :         piece = palloc(len + 1);
     630        1828 :         strlcpy(piece, p, len + 1);
     631             : 
     632        1828 :         mangled = substitute_libpath_macro(piece);
     633        1828 :         pfree(piece);
     634             : 
     635        1828 :         canonicalize_path(mangled);
     636             : 
     637             :         /* only absolute paths */
     638        1828 :         if (!is_absolute_path(mangled))
     639           0 :             ereport(ERROR,
     640             :                     (errcode(ERRCODE_INVALID_NAME),
     641             :                      errmsg("component in parameter \"dynamic_library_path\" is not an absolute path")));
     642             : 
     643        1828 :         full = palloc(strlen(mangled) + 1 + baselen + 1);
     644        1828 :         sprintf(full, "%s/%s", mangled, basename);
     645        1828 :         pfree(mangled);
     646             : 
     647        1828 :         elog(DEBUG3, "find_in_dynamic_libpath: trying \"%s\"", full);
     648             : 
     649        1828 :         if (file_exists(full))
     650         908 :             return full;
     651             : 
     652         920 :         pfree(full);
     653             : 
     654         920 :         if (p[len] == '\0')
     655         920 :             break;
     656             :         else
     657           0 :             p += len + 1;
     658             :     }
     659             : 
     660         920 :     return NULL;
     661             : }
     662             : 
     663             : 
     664             : /*
     665             :  * Find (or create) a rendezvous variable that one dynamically
     666             :  * loaded library can use to meet up with another.
     667             :  *
     668             :  * On the first call of this function for a particular varName,
     669             :  * a "rendezvous variable" is created with the given name.
     670             :  * The value of the variable is a void pointer (initially set to NULL).
     671             :  * Subsequent calls with the same varName just return the address of
     672             :  * the existing variable.  Once created, a rendezvous variable lasts
     673             :  * for the life of the process.
     674             :  *
     675             :  * Dynamically loaded libraries can use rendezvous variables
     676             :  * to find each other and share information: they just need to agree
     677             :  * on the variable name and the data it will point to.
     678             :  */
     679             : void      **
     680        2134 : find_rendezvous_variable(const char *varName)
     681             : {
     682             :     static HTAB *rendezvousHash = NULL;
     683             : 
     684             :     rendezvousHashEntry *hentry;
     685             :     bool        found;
     686             : 
     687             :     /* Create a hashtable if we haven't already done so in this process */
     688        2134 :     if (rendezvousHash == NULL)
     689             :     {
     690             :         HASHCTL     ctl;
     691             : 
     692        2130 :         MemSet(&ctl, 0, sizeof(ctl));
     693        2130 :         ctl.keysize = NAMEDATALEN;
     694        2130 :         ctl.entrysize = sizeof(rendezvousHashEntry);
     695        2130 :         rendezvousHash = hash_create("Rendezvous variable hash",
     696             :                                      16,
     697             :                                      &ctl,
     698             :                                      HASH_ELEM);
     699             :     }
     700             : 
     701             :     /* Find or create the hashtable entry for this varName */
     702        2134 :     hentry = (rendezvousHashEntry *) hash_search(rendezvousHash,
     703             :                                                  varName,
     704             :                                                  HASH_ENTER,
     705             :                                                  &found);
     706             : 
     707             :     /* Initialize to NULL if first time */
     708        2134 :     if (!found)
     709        2134 :         hentry->varValue = NULL;
     710             : 
     711        2134 :     return &hentry->varValue;
     712             : }
     713             : 
     714             : /*
     715             :  * Estimate the amount of space needed to serialize the list of libraries
     716             :  * we have loaded.
     717             :  */
     718             : Size
     719         472 : EstimateLibraryStateSpace(void)
     720             : {
     721             :     DynamicFileList *file_scanner;
     722         472 :     Size        size = 1;
     723             : 
     724        1348 :     for (file_scanner = file_list;
     725             :          file_scanner != NULL;
     726         404 :          file_scanner = file_scanner->next)
     727         404 :         size = add_size(size, strlen(file_scanner->filename) + 1);
     728             : 
     729         472 :     return size;
     730             : }
     731             : 
     732             : /*
     733             :  * Serialize the list of libraries we have loaded to a chunk of memory.
     734             :  */
     735             : void
     736         472 : SerializeLibraryState(Size maxsize, char *start_address)
     737             : {
     738             :     DynamicFileList *file_scanner;
     739             : 
     740        1348 :     for (file_scanner = file_list;
     741             :          file_scanner != NULL;
     742         404 :          file_scanner = file_scanner->next)
     743             :     {
     744             :         Size        len;
     745             : 
     746         404 :         len = strlcpy(start_address, file_scanner->filename, maxsize) + 1;
     747             :         Assert(len < maxsize);
     748         404 :         maxsize -= len;
     749         404 :         start_address += len;
     750             :     }
     751         472 :     start_address[0] = '\0';
     752         472 : }
     753             : 
     754             : /*
     755             :  * Load every library the serializing backend had loaded.
     756             :  */
     757             : void
     758        1576 : RestoreLibraryState(char *start_address)
     759             : {
     760        4572 :     while (*start_address != '\0')
     761             :     {
     762        1420 :         internal_load_library(start_address);
     763        1420 :         start_address += strlen(start_address) + 1;
     764             :     }
     765        1576 : }

Generated by: LCOV version 1.13