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

Generated by: LCOV version 1.11