00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00031 typedef void (*PG_init_t) (void);
00032 typedef void (*PG_fini_t) (void);
00033
00034
00035 typedef struct
00036 {
00037 char varName[NAMEDATALEN];
00038 void *varValue;
00039 } rendezvousHashEntry;
00040
00041
00042
00043
00044
00045 typedef struct df_files
00046 {
00047 struct df_files *next;
00048 dev_t device;
00049 #ifndef WIN32
00050
00051 ino_t inode;
00052 #endif
00053 void *handle;
00054 char filename[1];
00055
00056
00057
00058
00059
00060 } DynamicFileList;
00061
00062 static DynamicFileList *file_list = NULL;
00063 static DynamicFileList *file_tail = NULL;
00064
00065
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
00085 static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
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
00110 fullname = expand_dynamic_library_name(filename);
00111
00112
00113 lib_handle = internal_load_library(fullname);
00114
00115
00116 if (filehandle)
00117 *filehandle = lib_handle;
00118
00119
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
00134
00135
00136
00137
00138
00139
00140 void
00141 load_file(const char *filename, bool restricted)
00142 {
00143 char *fullname;
00144
00145
00146 if (restricted)
00147 check_restricted_library_name(filename);
00148
00149
00150 fullname = expand_dynamic_library_name(filename);
00151
00152
00153 internal_unload_library(fullname);
00154
00155
00156 (void) internal_load_library(fullname);
00157
00158 pfree(fullname);
00159 }
00160
00161
00162
00163
00164
00165 PGFunction
00166 lookup_external_function(void *filehandle, char *funcname)
00167 {
00168 return (PGFunction) pg_dlsym(filehandle, funcname);
00169 }
00170
00171
00172
00173
00174
00175
00176
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
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
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
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
00240 ereport(ERROR,
00241 (errcode_for_file_access(),
00242 errmsg("could not load library \"%s\": %s",
00243 libname, load_error)));
00244 }
00245
00246
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
00257 Pg_magic_struct module_magic_data = *magic_data_ptr;
00258
00259
00260 pg_dlclose(file_scanner->handle);
00261 free((char *) file_scanner);
00262
00263
00264 incompatible_module_error(libname, &module_magic_data);
00265 }
00266 }
00267 else
00268 {
00269
00270 pg_dlclose(file_scanner->handle);
00271 free((char *) file_scanner);
00272
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
00281
00282 PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, "_PG_init");
00283 if (PG_init)
00284 (*PG_init) ();
00285
00286
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
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
00308
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
00322
00323
00324
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
00386
00387
00388
00389
00390
00391
00392
00393
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
00407
00408
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
00417
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
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
00442 }
00443 else
00444 prv = file_scanner;
00445 }
00446 #endif
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
00468 #ifndef DLSUFFIX
00469 #error "DLSUFFIX must be defined to compile this file."
00470 #endif
00471
00472
00473
00474
00475
00476
00477
00478
00479
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
00528
00529
00530 return pstrdup(name);
00531 }
00532
00533
00534
00535
00536
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
00551
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
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
00586
00587
00588
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
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
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
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
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
00697 hentry = (rendezvousHashEntry *) hash_search(rendezvousHash,
00698 varName,
00699 HASH_ENTER,
00700 &found);
00701
00702
00703 if (!found)
00704 hentry->varValue = NULL;
00705
00706 return &hentry->varValue;
00707 }