Header And Logo

PostgreSQL
| The world's most advanced open source database.

dfmgr.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * dfmgr.c
00004  *    Dynamic function manager code.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/fmgr/dfmgr.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include <sys/stat.h>
00018 
00019 #ifndef WIN32_ONLY_COMPILER
00020 #include "dynloader.h"
00021 #else
00022 #include "port/dynloader/win32.h"
00023 #endif
00024 #include "lib/stringinfo.h"
00025 #include "miscadmin.h"
00026 #include "utils/dynamic_loader.h"
00027 #include "utils/hsearch.h"
00028 
00029 
00030 /* signatures for PostgreSQL-specific library init/fini functions */
00031 typedef void (*PG_init_t) (void);
00032 typedef void (*PG_fini_t) (void);
00033 
00034 /* hashtable entry for rendezvous variables */
00035 typedef struct
00036 {
00037     char        varName[NAMEDATALEN];   /* hash key (must be first) */
00038     void       *varValue;
00039 } rendezvousHashEntry;
00040 
00041 /*
00042  * List of dynamically loaded files (kept in malloc'd memory).
00043  */
00044 
00045 typedef struct df_files
00046 {
00047     struct df_files *next;      /* List link */
00048     dev_t       device;         /* Device file is on */
00049 #ifndef WIN32                   /* ensures we never again depend on this under
00050                                  * win32 */
00051     ino_t       inode;          /* Inode number of file */
00052 #endif
00053     void       *handle;         /* a handle for pg_dl* functions */
00054     char        filename[1];    /* Full pathname of file */
00055 
00056     /*
00057      * we allocate the block big enough for actual length of pathname.
00058      * filename[] must be last item in struct!
00059      */
00060 } DynamicFileList;
00061 
00062 static DynamicFileList *file_list = NULL;
00063 static DynamicFileList *file_tail = NULL;
00064 
00065 /* stat() call under Win32 returns an st_ino field, but it has no meaning */
00066 #ifndef WIN32
00067 #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
00068 #else
00069 #define SAME_INODE(A,B) false
00070 #endif
00071 
00072 char       *Dynamic_library_path;
00073 
00074 static void *internal_load_library(const char *libname);
00075 static void incompatible_module_error(const char *libname,
00076                           const Pg_magic_struct *module_magic_data);
00077 static void internal_unload_library(const char *libname);
00078 static bool file_exists(const char *name);
00079 static char *expand_dynamic_library_name(const char *name);
00080 static void check_restricted_library_name(const char *name);
00081 static char *substitute_libpath_macro(const char *name);
00082 static char *find_in_dynamic_libpath(const char *basename);
00083 
00084 /* Magic structure that module needs to match to be accepted */
00085 static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
00086 
00087 
00088 /*
00089  * Load the specified dynamic-link library file, and look for a function
00090  * named funcname in it.
00091  *
00092  * If the function is not found, we raise an error if signalNotFound is true,
00093  * else return (PGFunction) NULL.  Note that errors in loading the library
00094  * will provoke ereport() regardless of signalNotFound.
00095  *
00096  * If filehandle is not NULL, then *filehandle will be set to a handle
00097  * identifying the library file.  The filehandle can be used with
00098  * lookup_external_function to lookup additional functions in the same file
00099  * at less cost than repeating load_external_function.
00100  */
00101 PGFunction
00102 load_external_function(char *filename, char *funcname,
00103                        bool signalNotFound, void **filehandle)
00104 {
00105     char       *fullname;
00106     void       *lib_handle;
00107     PGFunction  retval;
00108 
00109     /* Expand the possibly-abbreviated filename to an exact path name */
00110     fullname = expand_dynamic_library_name(filename);
00111 
00112     /* Load the shared library, unless we already did */
00113     lib_handle = internal_load_library(fullname);
00114 
00115     /* Return handle if caller wants it */
00116     if (filehandle)
00117         *filehandle = lib_handle;
00118 
00119     /* Look up the function within the library */
00120     retval = (PGFunction) pg_dlsym(lib_handle, funcname);
00121 
00122     if (retval == NULL && signalNotFound)
00123         ereport(ERROR,
00124                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00125                  errmsg("could not find function \"%s\" in file \"%s\"",
00126                         funcname, fullname)));
00127 
00128     pfree(fullname);
00129     return retval;
00130 }
00131 
00132 /*
00133  * This function loads a shlib file without looking up any particular
00134  * function in it.  If the same shlib has previously been loaded,
00135  * unload and reload it.
00136  *
00137  * When 'restricted' is true, only libraries in the presumed-secure
00138  * directory $libdir/plugins may be referenced.
00139  */
00140 void
00141 load_file(const char *filename, bool restricted)
00142 {
00143     char       *fullname;
00144 
00145     /* Apply security restriction if requested */
00146     if (restricted)
00147         check_restricted_library_name(filename);
00148 
00149     /* Expand the possibly-abbreviated filename to an exact path name */
00150     fullname = expand_dynamic_library_name(filename);
00151 
00152     /* Unload the library if currently loaded */
00153     internal_unload_library(fullname);
00154 
00155     /* Load the shared library */
00156     (void) internal_load_library(fullname);
00157 
00158     pfree(fullname);
00159 }
00160 
00161 /*
00162  * Lookup a function whose library file is already loaded.
00163  * Return (PGFunction) NULL if not found.
00164  */
00165 PGFunction
00166 lookup_external_function(void *filehandle, char *funcname)
00167 {
00168     return (PGFunction) pg_dlsym(filehandle, funcname);
00169 }
00170 
00171 
00172 /*
00173  * Load the specified dynamic-link library file, unless it already is
00174  * loaded.  Return the pg_dl* handle for the file.
00175  *
00176  * Note: libname is expected to be an exact name for the library file.
00177  */
00178 static void *
00179 internal_load_library(const char *libname)
00180 {
00181     DynamicFileList *file_scanner;
00182     PGModuleMagicFunction magic_func;
00183     char       *load_error;
00184     struct stat stat_buf;
00185     PG_init_t   PG_init;
00186 
00187     /*
00188      * Scan the list of loaded FILES to see if the file has been loaded.
00189      */
00190     for (file_scanner = file_list;
00191          file_scanner != NULL &&
00192          strcmp(libname, file_scanner->filename) != 0;
00193          file_scanner = file_scanner->next)
00194         ;
00195 
00196     if (file_scanner == NULL)
00197     {
00198         /*
00199          * Check for same files - different paths (ie, symlink or link)
00200          */
00201         if (stat(libname, &stat_buf) == -1)
00202             ereport(ERROR,
00203                     (errcode_for_file_access(),
00204                      errmsg("could not access file \"%s\": %m",
00205                             libname)));
00206 
00207         for (file_scanner = file_list;
00208              file_scanner != NULL &&
00209              !SAME_INODE(stat_buf, *file_scanner);
00210              file_scanner = file_scanner->next)
00211             ;
00212     }
00213 
00214     if (file_scanner == NULL)
00215     {
00216         /*
00217          * File not loaded yet.
00218          */
00219         file_scanner = (DynamicFileList *)
00220             malloc(sizeof(DynamicFileList) + strlen(libname));
00221         if (file_scanner == NULL)
00222             ereport(ERROR,
00223                     (errcode(ERRCODE_OUT_OF_MEMORY),
00224                      errmsg("out of memory")));
00225 
00226         MemSet(file_scanner, 0, sizeof(DynamicFileList));
00227         strcpy(file_scanner->filename, libname);
00228         file_scanner->device = stat_buf.st_dev;
00229 #ifndef WIN32
00230         file_scanner->inode = stat_buf.st_ino;
00231 #endif
00232         file_scanner->next = NULL;
00233 
00234         file_scanner->handle = pg_dlopen(file_scanner->filename);
00235         if (file_scanner->handle == NULL)
00236         {
00237             load_error = (char *) pg_dlerror();
00238             free((char *) file_scanner);
00239             /* errcode_for_file_access might not be appropriate here? */
00240             ereport(ERROR,
00241                     (errcode_for_file_access(),
00242                      errmsg("could not load library \"%s\": %s",
00243                             libname, load_error)));
00244         }
00245 
00246         /* Check the magic function to determine compatibility */
00247         magic_func = (PGModuleMagicFunction)
00248             pg_dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING);
00249         if (magic_func)
00250         {
00251             const Pg_magic_struct *magic_data_ptr = (*magic_func) ();
00252 
00253             if (magic_data_ptr->len != magic_data.len ||
00254                 memcmp(magic_data_ptr, &magic_data, magic_data.len) != 0)
00255             {
00256                 /* copy data block before unlinking library */
00257                 Pg_magic_struct module_magic_data = *magic_data_ptr;
00258 
00259                 /* try to unlink library */
00260                 pg_dlclose(file_scanner->handle);
00261                 free((char *) file_scanner);
00262 
00263                 /* issue suitable complaint */
00264                 incompatible_module_error(libname, &module_magic_data);
00265             }
00266         }
00267         else
00268         {
00269             /* try to unlink library */
00270             pg_dlclose(file_scanner->handle);
00271             free((char *) file_scanner);
00272             /* complain */
00273             ereport(ERROR,
00274                   (errmsg("incompatible library \"%s\": missing magic block",
00275                           libname),
00276                    errhint("Extension libraries are required to use the PG_MODULE_MAGIC macro.")));
00277         }
00278 
00279         /*
00280          * If the library has a _PG_init() function, call it.
00281          */
00282         PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, "_PG_init");
00283         if (PG_init)
00284             (*PG_init) ();
00285 
00286         /* OK to link it into list */
00287         if (file_list == NULL)
00288             file_list = file_scanner;
00289         else
00290             file_tail->next = file_scanner;
00291         file_tail = file_scanner;
00292     }
00293 
00294     return file_scanner->handle;
00295 }
00296 
00297 /*
00298  * Report a suitable error for an incompatible magic block.
00299  */
00300 static void
00301 incompatible_module_error(const char *libname,
00302                           const Pg_magic_struct *module_magic_data)
00303 {
00304     StringInfoData details;
00305 
00306     /*
00307      * If the version doesn't match, just report that, because the rest of the
00308      * block might not even have the fields we expect.
00309      */
00310     if (magic_data.version != module_magic_data->version)
00311         ereport(ERROR,
00312                 (errmsg("incompatible library \"%s\": version mismatch",
00313                         libname),
00314               errdetail("Server is version %d.%d, library is version %d.%d.",
00315                         magic_data.version / 100,
00316                         magic_data.version % 100,
00317                         module_magic_data->version / 100,
00318                         module_magic_data->version % 100)));
00319 
00320     /*
00321      * Otherwise, spell out which fields don't agree.
00322      *
00323      * XXX this code has to be adjusted any time the set of fields in a magic
00324      * block change!
00325      */
00326     initStringInfo(&details);
00327 
00328     if (module_magic_data->funcmaxargs != magic_data.funcmaxargs)
00329     {
00330         if (details.len)
00331             appendStringInfoChar(&details, '\n');
00332         appendStringInfo(&details,
00333                          _("Server has FUNC_MAX_ARGS = %d, library has %d."),
00334                          magic_data.funcmaxargs,
00335                          module_magic_data->funcmaxargs);
00336     }
00337     if (module_magic_data->indexmaxkeys != magic_data.indexmaxkeys)
00338     {
00339         if (details.len)
00340             appendStringInfoChar(&details, '\n');
00341         appendStringInfo(&details,
00342                          _("Server has INDEX_MAX_KEYS = %d, library has %d."),
00343                          magic_data.indexmaxkeys,
00344                          module_magic_data->indexmaxkeys);
00345     }
00346     if (module_magic_data->namedatalen != magic_data.namedatalen)
00347     {
00348         if (details.len)
00349             appendStringInfoChar(&details, '\n');
00350         appendStringInfo(&details,
00351                          _("Server has NAMEDATALEN = %d, library has %d."),
00352                          magic_data.namedatalen,
00353                          module_magic_data->namedatalen);
00354     }
00355     if (module_magic_data->float4byval != magic_data.float4byval)
00356     {
00357         if (details.len)
00358             appendStringInfoChar(&details, '\n');
00359         appendStringInfo(&details,
00360                        _("Server has FLOAT4PASSBYVAL = %s, library has %s."),
00361                          magic_data.float4byval ? "true" : "false",
00362                          module_magic_data->float4byval ? "true" : "false");
00363     }
00364     if (module_magic_data->float8byval != magic_data.float8byval)
00365     {
00366         if (details.len)
00367             appendStringInfoChar(&details, '\n');
00368         appendStringInfo(&details,
00369                        _("Server has FLOAT8PASSBYVAL = %s, library has %s."),
00370                          magic_data.float8byval ? "true" : "false",
00371                          module_magic_data->float8byval ? "true" : "false");
00372     }
00373 
00374     if (details.len == 0)
00375         appendStringInfo(&details,
00376               _("Magic block has unexpected length or padding difference."));
00377 
00378     ereport(ERROR,
00379             (errmsg("incompatible library \"%s\": magic block mismatch",
00380                     libname),
00381              errdetail_internal("%s", details.data)));
00382 }
00383 
00384 /*
00385  * Unload the specified dynamic-link library file, if it is loaded.
00386  *
00387  * Note: libname is expected to be an exact name for the library file.
00388  *
00389  * XXX for the moment, this is disabled, resulting in LOAD of an already-loaded
00390  * library always being a no-op.  We might re-enable it someday if we can
00391  * convince ourselves we have safe protocols for un-hooking from hook function
00392  * pointers, releasing custom GUC variables, and perhaps other things that
00393  * are definitely unsafe currently.
00394  */
00395 static void
00396 internal_unload_library(const char *libname)
00397 {
00398 #ifdef NOT_USED
00399     DynamicFileList *file_scanner,
00400                *prv,
00401                *nxt;
00402     struct stat stat_buf;
00403     PG_fini_t   PG_fini;
00404 
00405     /*
00406      * We need to do stat() in order to determine whether this is the same
00407      * file as a previously loaded file; it's also handy so as to give a good
00408      * error message if bogus file name given.
00409      */
00410     if (stat(libname, &stat_buf) == -1)
00411         ereport(ERROR,
00412                 (errcode_for_file_access(),
00413                  errmsg("could not access file \"%s\": %m", libname)));
00414 
00415     /*
00416      * We have to zap all entries in the list that match on either filename or
00417      * inode, else internal_load_library() will still think it's present.
00418      */
00419     prv = NULL;
00420     for (file_scanner = file_list; file_scanner != NULL; file_scanner = nxt)
00421     {
00422         nxt = file_scanner->next;
00423         if (strcmp(libname, file_scanner->filename) == 0 ||
00424             SAME_INODE(stat_buf, *file_scanner))
00425         {
00426             if (prv)
00427                 prv->next = nxt;
00428             else
00429                 file_list = nxt;
00430 
00431             /*
00432              * If the library has a _PG_fini() function, call it.
00433              */
00434             PG_fini = (PG_fini_t) pg_dlsym(file_scanner->handle, "_PG_fini");
00435             if (PG_fini)
00436                 (*PG_fini) ();
00437 
00438             clear_external_function_hash(file_scanner->handle);
00439             pg_dlclose(file_scanner->handle);
00440             free((char *) file_scanner);
00441             /* prv does not change */
00442         }
00443         else
00444             prv = file_scanner;
00445     }
00446 #endif   /* NOT_USED */
00447 }
00448 
00449 static bool
00450 file_exists(const char *name)
00451 {
00452     struct stat st;
00453 
00454     AssertArg(name != NULL);
00455 
00456     if (stat(name, &st) == 0)
00457         return S_ISDIR(st.st_mode) ? false : true;
00458     else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES))
00459         ereport(ERROR,
00460                 (errcode_for_file_access(),
00461                  errmsg("could not access file \"%s\": %m", name)));
00462 
00463     return false;
00464 }
00465 
00466 
00467 /* Example format: ".so" */
00468 #ifndef DLSUFFIX
00469 #error "DLSUFFIX must be defined to compile this file."
00470 #endif
00471 
00472 /*
00473  * If name contains a slash, check if the file exists, if so return
00474  * the name.  Else (no slash) try to expand using search path (see
00475  * find_in_dynamic_libpath below); if that works, return the fully
00476  * expanded file name.  If the previous failed, append DLSUFFIX and
00477  * try again.  If all fails, just return the original name.
00478  *
00479  * The result will always be freshly palloc'd.
00480  */
00481 static char *
00482 expand_dynamic_library_name(const char *name)
00483 {
00484     bool        have_slash;
00485     char       *new;
00486     char       *full;
00487 
00488     AssertArg(name);
00489 
00490     have_slash = (first_dir_separator(name) != NULL);
00491 
00492     if (!have_slash)
00493     {
00494         full = find_in_dynamic_libpath(name);
00495         if (full)
00496             return full;
00497     }
00498     else
00499     {
00500         full = substitute_libpath_macro(name);
00501         if (file_exists(full))
00502             return full;
00503         pfree(full);
00504     }
00505 
00506     new = palloc(strlen(name) + strlen(DLSUFFIX) + 1);
00507     strcpy(new, name);
00508     strcat(new, DLSUFFIX);
00509 
00510     if (!have_slash)
00511     {
00512         full = find_in_dynamic_libpath(new);
00513         pfree(new);
00514         if (full)
00515             return full;
00516     }
00517     else
00518     {
00519         full = substitute_libpath_macro(new);
00520         pfree(new);
00521         if (file_exists(full))
00522             return full;
00523         pfree(full);
00524     }
00525 
00526     /*
00527      * If we can't find the file, just return the string as-is. The ensuing
00528      * load attempt will fail and report a suitable message.
00529      */
00530     return pstrdup(name);
00531 }
00532 
00533 /*
00534  * Check a restricted library name.  It must begin with "$libdir/plugins/"
00535  * and there must not be any directory separators after that (this is
00536  * sufficient to prevent ".." style attacks).
00537  */
00538 static void
00539 check_restricted_library_name(const char *name)
00540 {
00541     if (strncmp(name, "$libdir/plugins/", 16) != 0 ||
00542         first_dir_separator(name + 16) != NULL)
00543         ereport(ERROR,
00544                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00545                  errmsg("access to library \"%s\" is not allowed",
00546                         name)));
00547 }
00548 
00549 /*
00550  * Substitute for any macros appearing in the given string.
00551  * Result is always freshly palloc'd.
00552  */
00553 static char *
00554 substitute_libpath_macro(const char *name)
00555 {
00556     const char *sep_ptr;
00557     char       *ret;
00558 
00559     AssertArg(name != NULL);
00560 
00561     /* Currently, we only recognize $libdir at the start of the string */
00562     if (name[0] != '$')
00563         return pstrdup(name);
00564 
00565     if ((sep_ptr = first_dir_separator(name)) == NULL)
00566         sep_ptr = name + strlen(name);
00567 
00568     if (strlen("$libdir") != sep_ptr - name ||
00569         strncmp(name, "$libdir", strlen("$libdir")) != 0)
00570         ereport(ERROR,
00571                 (errcode(ERRCODE_INVALID_NAME),
00572                  errmsg("invalid macro name in dynamic library path: %s",
00573                         name)));
00574 
00575     ret = palloc(strlen(pkglib_path) + strlen(sep_ptr) + 1);
00576 
00577     strcpy(ret, pkglib_path);
00578     strcat(ret, sep_ptr);
00579 
00580     return ret;
00581 }
00582 
00583 
00584 /*
00585  * Search for a file called 'basename' in the colon-separated search
00586  * path Dynamic_library_path.  If the file is found, the full file name
00587  * is returned in freshly palloc'd memory.  If the file is not found,
00588  * return NULL.
00589  */
00590 static char *
00591 find_in_dynamic_libpath(const char *basename)
00592 {
00593     const char *p;
00594     size_t      baselen;
00595 
00596     AssertArg(basename != NULL);
00597     AssertArg(first_dir_separator(basename) == NULL);
00598     AssertState(Dynamic_library_path != NULL);
00599 
00600     p = Dynamic_library_path;
00601     if (strlen(p) == 0)
00602         return NULL;
00603 
00604     baselen = strlen(basename);
00605 
00606     for (;;)
00607     {
00608         size_t      len;
00609         char       *piece;
00610         char       *mangled;
00611         char       *full;
00612 
00613         piece = first_path_var_separator(p);
00614         if (piece == p)
00615             ereport(ERROR,
00616                     (errcode(ERRCODE_INVALID_NAME),
00617                      errmsg("zero-length component in parameter \"dynamic_library_path\"")));
00618 
00619         if (piece == NULL)
00620             len = strlen(p);
00621         else
00622             len = piece - p;
00623 
00624         piece = palloc(len + 1);
00625         strlcpy(piece, p, len + 1);
00626 
00627         mangled = substitute_libpath_macro(piece);
00628         pfree(piece);
00629 
00630         canonicalize_path(mangled);
00631 
00632         /* only absolute paths */
00633         if (!is_absolute_path(mangled))
00634             ereport(ERROR,
00635                     (errcode(ERRCODE_INVALID_NAME),
00636                      errmsg("component in parameter \"dynamic_library_path\" is not an absolute path")));
00637 
00638         full = palloc(strlen(mangled) + 1 + baselen + 1);
00639         sprintf(full, "%s/%s", mangled, basename);
00640         pfree(mangled);
00641 
00642         elog(DEBUG3, "find_in_dynamic_libpath: trying \"%s\"", full);
00643 
00644         if (file_exists(full))
00645             return full;
00646 
00647         pfree(full);
00648 
00649         if (p[len] == '\0')
00650             break;
00651         else
00652             p += len + 1;
00653     }
00654 
00655     return NULL;
00656 }
00657 
00658 
00659 /*
00660  * Find (or create) a rendezvous variable that one dynamically
00661  * loaded library can use to meet up with another.
00662  *
00663  * On the first call of this function for a particular varName,
00664  * a "rendezvous variable" is created with the given name.
00665  * The value of the variable is a void pointer (initially set to NULL).
00666  * Subsequent calls with the same varName just return the address of
00667  * the existing variable.  Once created, a rendezvous variable lasts
00668  * for the life of the process.
00669  *
00670  * Dynamically loaded libraries can use rendezvous variables
00671  * to find each other and share information: they just need to agree
00672  * on the variable name and the data it will point to.
00673  */
00674 void      **
00675 find_rendezvous_variable(const char *varName)
00676 {
00677     static HTAB *rendezvousHash = NULL;
00678 
00679     rendezvousHashEntry *hentry;
00680     bool        found;
00681 
00682     /* Create a hashtable if we haven't already done so in this process */
00683     if (rendezvousHash == NULL)
00684     {
00685         HASHCTL     ctl;
00686 
00687         MemSet(&ctl, 0, sizeof(ctl));
00688         ctl.keysize = NAMEDATALEN;
00689         ctl.entrysize = sizeof(rendezvousHashEntry);
00690         rendezvousHash = hash_create("Rendezvous variable hash",
00691                                      16,
00692                                      &ctl,
00693                                      HASH_ELEM);
00694     }
00695 
00696     /* Find or create the hashtable entry for this varName */
00697     hentry = (rendezvousHashEntry *) hash_search(rendezvousHash,
00698                                                  varName,
00699                                                  HASH_ENTER,
00700                                                  &found);
00701 
00702     /* Initialize to NULL if first time */
00703     if (!found)
00704         hentry->varValue = NULL;
00705 
00706     return &hentry->varValue;
00707 }