Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * dfmgr.c
4 : * Dynamic function manager code.
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 : #ifndef WIN32
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 PG_USE_STDBOOL
27 : #ifdef bool
28 : #undef bool
29 : #endif
30 : #endif
31 : #endif /* !WIN32 */
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 : /* signature for PostgreSQL-specific library init function */
41 : typedef void (*PG_init_t) (void);
42 :
43 : /* hashtable entry for rendezvous variables */
44 : typedef struct
45 : {
46 : char varName[NAMEDATALEN]; /* hash key (must be first) */
47 : void *varValue;
48 : } rendezvousHashEntry;
49 :
50 : /*
51 : * List of dynamically loaded files (kept in malloc'd memory).
52 : */
53 :
54 : typedef struct df_files
55 : {
56 : struct df_files *next; /* List link */
57 : dev_t device; /* Device file is on */
58 : #ifndef WIN32 /* ensures we never again depend on this under
59 : * win32 */
60 : ino_t inode; /* Inode number of file */
61 : #endif
62 : void *handle; /* a handle for pg_dl* functions */
63 : char filename[FLEXIBLE_ARRAY_MEMBER]; /* Full pathname of file */
64 : } DynamicFileList;
65 :
66 : static DynamicFileList *file_list = NULL;
67 : static DynamicFileList *file_tail = NULL;
68 :
69 : /* stat() call under Win32 returns an st_ino field, but it has no meaning */
70 : #ifndef WIN32
71 : #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
72 : #else
73 : #define SAME_INODE(A,B) false
74 : #endif
75 :
76 : char *Dynamic_library_path;
77 :
78 : static void *internal_load_library(const char *libname);
79 : static void incompatible_module_error(const char *libname,
80 : const Pg_magic_struct *module_magic_data) pg_attribute_noreturn();
81 : static bool file_exists(const char *name);
82 : static char *expand_dynamic_library_name(const char *name);
83 : static void check_restricted_library_name(const char *name);
84 : static char *substitute_libpath_macro(const char *name);
85 : static char *find_in_dynamic_libpath(const char *basename);
86 :
87 : /* Magic structure that module needs to match to be accepted */
88 : static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
89 :
90 :
91 : /*
92 : * Load the specified dynamic-link library file, and look for a function
93 : * named funcname in it.
94 : *
95 : * If the function is not found, we raise an error if signalNotFound is true,
96 : * else return NULL. Note that errors in loading the library
97 : * will provoke ereport() regardless of signalNotFound.
98 : *
99 : * If filehandle is not NULL, then *filehandle will be set to a handle
100 : * identifying the library file. The filehandle can be used with
101 : * lookup_external_function to lookup additional functions in the same file
102 : * at less cost than repeating load_external_function.
103 : */
104 : void *
2186 tgl 105 CBC 7575 : load_external_function(const char *filename, const char *funcname,
106 : bool signalNotFound, void **filehandle)
107 : {
108 : char *fullname;
109 : void *lib_handle;
110 : void *retval;
111 :
112 : /* Expand the possibly-abbreviated filename to an exact path name */
6081 113 7575 : fullname = expand_dynamic_library_name(filename);
114 :
115 : /* Load the shared library, unless we already did */
116 7575 : lib_handle = internal_load_library(fullname);
117 :
118 : /* Return handle if caller wants it */
119 7571 : if (filehandle)
120 6311 : *filehandle = lib_handle;
121 :
122 : /* Look up the function within the library. */
999 peter 123 7571 : retval = dlsym(lib_handle, funcname);
124 :
6081 tgl 125 7571 : if (retval == NULL && signalNotFound)
126 3 : ereport(ERROR,
127 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
128 : errmsg("could not find function \"%s\" in file \"%s\"",
129 : funcname, fullname)));
130 :
131 7568 : pfree(fullname);
132 7568 : return retval;
133 : }
134 :
135 : /*
136 : * This function loads a shlib file without looking up any particular
137 : * function in it. If the same shlib has previously been loaded,
138 : * unload and reload it.
139 : *
140 : * When 'restricted' is true, only libraries in the presumed-secure
141 : * directory $libdir/plugins may be referenced.
142 : */
143 : void
6080 144 930 : load_file(const char *filename, bool restricted)
145 : {
146 : char *fullname;
147 :
148 : /* Apply security restriction if requested */
149 930 : if (restricted)
6081 tgl 150 UBC 0 : check_restricted_library_name(filename);
151 :
152 : /* Expand the possibly-abbreviated filename to an exact path name */
6081 tgl 153 CBC 930 : fullname = expand_dynamic_library_name(filename);
154 :
155 : /* Load the shared library */
156 930 : (void) internal_load_library(fullname);
157 :
158 930 : pfree(fullname);
159 930 : }
160 :
161 : /*
162 : * Lookup a function whose library file is already loaded.
163 : * Return NULL if not found.
164 : */
165 : void *
2186 166 6308 : lookup_external_function(void *filehandle, const char *funcname)
167 : {
999 peter 168 6308 : return dlsym(filehandle, funcname);
169 : }
170 :
171 :
172 : /*
173 : * Load the specified dynamic-link library file, unless it already is
174 : * loaded. Return the pg_dl* handle for the file.
175 : *
176 : * Note: libname is expected to be an exact name for the library file.
177 : *
178 : * NB: There is presently no way to unload a dynamically loaded file. We might
179 : * add one someday if we can convince ourselves we have safe protocols for un-
180 : * hooking from hook function pointers, releasing custom GUC variables, and
181 : * perhaps other things that are definitely unsafe currently.
182 : */
183 : static void *
6081 tgl 184 10860 : 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 : */
8351 195 10860 : for (file_scanner = file_list;
7032 neilc 196 17361 : file_scanner != NULL &&
6081 tgl 197 12162 : strcmp(libname, file_scanner->filename) != 0;
8351 198 6501 : file_scanner = file_scanner->next)
199 : ;
200 :
7032 neilc 201 10860 : if (file_scanner == NULL)
202 : {
203 : /*
204 : * Check for same files - different paths (ie, symlink or link)
205 : */
6081 tgl 206 5199 : if (stat(libname, &stat_buf) == -1)
7205 207 4 : ereport(ERROR,
208 : (errcode_for_file_access(),
209 : errmsg("could not access file \"%s\": %m",
210 : libname)));
211 :
9345 bruce 212 5195 : for (file_scanner = file_list;
7032 neilc 213 8633 : file_scanner != NULL &&
8053 bruce 214 3438 : !SAME_INODE(stat_buf, *file_scanner);
9345 215 3438 : file_scanner = file_scanner->next)
216 : ;
217 : }
218 :
7032 neilc 219 10856 : if (file_scanner == NULL)
220 : {
221 : /*
222 : * File not loaded yet.
223 : */
224 : file_scanner = (DynamicFileList *)
2118 tgl 225 5195 : malloc(offsetof(DynamicFileList, filename) + strlen(libname) + 1);
8351 226 5195 : if (file_scanner == NULL)
7205 tgl 227 UBC 0 : ereport(ERROR,
228 : (errcode(ERRCODE_OUT_OF_MEMORY),
229 : errmsg("out of memory")));
230 :
2969 tgl 231 CBC 25975 : MemSet(file_scanner, 0, offsetof(DynamicFileList, filename));
6081 232 5195 : strcpy(file_scanner->filename, libname);
9345 bruce 233 5195 : file_scanner->device = stat_buf.st_dev;
234 : #ifndef WIN32
235 5195 : file_scanner->inode = stat_buf.st_ino;
236 : #endif
7032 neilc 237 5195 : file_scanner->next = NULL;
238 :
1676 peter_e 239 5195 : file_scanner->handle = dlopen(file_scanner->filename, RTLD_NOW | RTLD_GLOBAL);
7032 neilc 240 5195 : if (file_scanner->handle == NULL)
241 : {
1676 peter_e 242 UBC 0 : load_error = dlerror();
226 peter 243 UNC 0 : free(file_scanner);
244 : /* errcode_for_file_access might not be appropriate here? */
7205 tgl 245 UBC 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 */
6158 tgl 252 CBC 5195 : magic_func = (PGModuleMagicFunction)
1676 peter_e 253 5195 : dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING);
6158 tgl 254 5195 : if (magic_func)
255 : {
256 5195 : const Pg_magic_struct *magic_data_ptr = (*magic_func) ();
257 :
258 5195 : if (magic_data_ptr->len != magic_data.len ||
6031 bruce 259 5195 : memcmp(magic_data_ptr, &magic_data, magic_data.len) != 0)
260 : {
261 : /* copy data block before unlinking library */
6158 tgl 262 UBC 0 : Pg_magic_struct module_magic_data = *magic_data_ptr;
263 :
264 : /* try to close library */
1676 peter_e 265 0 : dlclose(file_scanner->handle);
226 peter 266 UNC 0 : free(file_scanner);
267 :
268 : /* issue suitable complaint */
5331 tgl 269 UBC 0 : incompatible_module_error(libname, &module_magic_data);
270 : }
271 : }
272 : else
273 : {
274 : /* try to close library */
1676 peter_e 275 0 : dlclose(file_scanner->handle);
226 peter 276 UNC 0 : free(file_scanner);
277 : /* complain */
6157 tgl 278 UBC 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 : */
1676 peter_e 287 CBC 5195 : PG_init = (PG_init_t) dlsym(file_scanner->handle, "_PG_init");
6088 tgl 288 5195 : if (PG_init)
6031 bruce 289 2706 : (*PG_init) ();
290 :
291 : /* OK to link it into list */
7032 neilc 292 5195 : if (file_list == NULL)
8351 tgl 293 3245 : file_list = file_scanner;
294 : else
295 1950 : file_tail->next = file_scanner;
9345 bruce 296 5195 : file_tail = file_scanner;
297 : }
298 :
6081 tgl 299 10856 : return file_scanner->handle;
300 : }
301 :
302 : /*
303 : * Report a suitable error for an incompatible magic block.
304 : */
305 : static void
5331 tgl 306 UBC 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 :
2427 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);
5331 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 : * Similarly, if the ABI extra field doesn't match, error out. Other
335 : * fields below might also mismatch, but that isn't useful information if
336 : * you're using the wrong product altogether.
337 : */
503 peter 338 0 : if (strcmp(module_magic_data->abi_extra, magic_data.abi_extra) != 0)
339 : {
340 0 : ereport(ERROR,
341 : (errmsg("incompatible library \"%s\": ABI mismatch",
342 : libname),
343 : errdetail("Server has ABI \"%s\", library has \"%s\".",
344 : magic_data.abi_extra,
345 : module_magic_data->abi_extra)));
346 : }
347 :
348 : /*
349 : * Otherwise, spell out which fields don't agree.
350 : *
351 : * XXX this code has to be adjusted any time the set of fields in a magic
352 : * block change!
353 : */
5331 tgl 354 0 : initStringInfo(&details);
355 :
356 0 : if (module_magic_data->funcmaxargs != magic_data.funcmaxargs)
357 : {
358 0 : if (details.len)
359 0 : appendStringInfoChar(&details, '\n');
360 0 : appendStringInfo(&details,
361 0 : _("Server has FUNC_MAX_ARGS = %d, library has %d."),
362 0 : magic_data.funcmaxargs,
363 0 : module_magic_data->funcmaxargs);
364 : }
365 0 : if (module_magic_data->indexmaxkeys != magic_data.indexmaxkeys)
366 : {
367 0 : if (details.len)
368 0 : appendStringInfoChar(&details, '\n');
369 0 : appendStringInfo(&details,
370 0 : _("Server has INDEX_MAX_KEYS = %d, library has %d."),
371 0 : magic_data.indexmaxkeys,
372 0 : module_magic_data->indexmaxkeys);
373 : }
374 0 : if (module_magic_data->namedatalen != magic_data.namedatalen)
375 : {
376 0 : if (details.len)
377 0 : appendStringInfoChar(&details, '\n');
378 0 : appendStringInfo(&details,
379 0 : _("Server has NAMEDATALEN = %d, library has %d."),
380 0 : magic_data.namedatalen,
381 0 : module_magic_data->namedatalen);
382 : }
383 0 : if (module_magic_data->float8byval != magic_data.float8byval)
384 : {
385 0 : if (details.len)
386 0 : appendStringInfoChar(&details, '\n');
387 0 : appendStringInfo(&details,
2118 388 0 : _("Server has FLOAT8PASSBYVAL = %s, library has %s."),
5331 389 0 : magic_data.float8byval ? "true" : "false",
390 0 : module_magic_data->float8byval ? "true" : "false");
391 : }
392 :
393 0 : if (details.len == 0)
3447 rhaas 394 0 : appendStringInfoString(&details,
2118 tgl 395 0 : _("Magic block has unexpected length or padding difference."));
396 :
5331 397 0 : ereport(ERROR,
398 : (errmsg("incompatible library \"%s\": magic block mismatch",
399 : libname),
400 : errdetail_internal("%s", details.data)));
401 : }
402 :
403 : static bool
7997 peter_e 404 CBC 16441 : file_exists(const char *name)
405 : {
406 : struct stat st;
407 :
163 peter 408 GNC 16441 : Assert(name != NULL);
409 :
7997 peter_e 410 CBC 16441 : if (stat(name, &st) == 0)
578 michael 411 8501 : return !S_ISDIR(st.st_mode);
7997 peter_e 412 7940 : else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES))
7205 tgl 413 UBC 0 : ereport(ERROR,
414 : (errcode_for_file_access(),
415 : errmsg("could not access file \"%s\": %m", name)));
416 :
7997 peter_e 417 CBC 7940 : return false;
418 : }
419 :
420 :
421 : /*
422 : * If name contains a slash, check if the file exists, if so return
423 : * the name. Else (no slash) try to expand using search path (see
424 : * find_in_dynamic_libpath below); if that works, return the fully
425 : * expanded file name. If the previous failed, append DLSUFFIX and
426 : * try again. If all fails, just return the original name.
427 : *
428 : * The result will always be freshly palloc'd.
429 : */
430 : static char *
431 8505 : expand_dynamic_library_name(const char *name)
432 : {
433 : bool have_slash;
434 : char *new;
435 : char *full;
436 :
163 peter 437 GNC 8505 : Assert(name);
438 :
6877 bruce 439 CBC 8505 : have_slash = (first_dir_separator(name) != NULL);
440 :
7997 peter_e 441 8505 : if (!have_slash)
442 : {
443 1758 : full = find_in_dynamic_libpath(name);
444 1758 : if (full)
7997 peter_e 445 UBC 0 : return full;
446 : }
447 : else
448 : {
7995 peter_e 449 CBC 6747 : full = substitute_libpath_macro(name);
450 6747 : if (file_exists(full))
451 569 : return full;
7857 tgl 452 6178 : pfree(full);
453 : }
454 :
3465 peter_e 455 7936 : new = psprintf("%s%s", name, DLSUFFIX);
456 :
7997 457 7936 : if (!have_slash)
458 : {
459 1758 : full = find_in_dynamic_libpath(new);
460 1758 : pfree(new);
461 1758 : if (full)
462 1754 : return full;
463 : }
464 : else
465 : {
7995 466 6178 : full = substitute_libpath_macro(new);
7857 tgl 467 6178 : pfree(new);
7995 peter_e 468 6178 : if (file_exists(full))
469 6178 : return full;
7857 tgl 470 UBC 0 : pfree(full);
471 : }
472 :
473 : /*
474 : * If we can't find the file, just return the string as-is. The ensuing
475 : * load attempt will fail and report a suitable message.
476 : */
6081 tgl 477 CBC 4 : return pstrdup(name);
478 : }
479 :
480 : /*
481 : * Check a restricted library name. It must begin with "$libdir/plugins/"
482 : * and there must not be any directory separators after that (this is
483 : * sufficient to prevent ".." style attacks).
484 : */
485 : static void
6081 tgl 486 UBC 0 : check_restricted_library_name(const char *name)
487 : {
488 0 : if (strncmp(name, "$libdir/plugins/", 16) != 0 ||
489 0 : first_dir_separator(name + 16) != NULL)
490 0 : ereport(ERROR,
491 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
492 : errmsg("access to library \"%s\" is not allowed",
493 : name)));
494 0 : }
495 :
496 : /*
497 : * Substitute for any macros appearing in the given string.
498 : * Result is always freshly palloc'd.
499 : */
500 : static char *
7836 bruce 501 CBC 16441 : substitute_libpath_macro(const char *name)
502 : {
503 : const char *sep_ptr;
504 :
163 peter 505 GNC 16441 : Assert(name != NULL);
506 :
507 : /* Currently, we only recognize $libdir at the start of the string */
7855 tgl 508 CBC 16441 : if (name[0] != '$')
7995 peter_e 509 569 : return pstrdup(name);
510 :
6877 bruce 511 15872 : if ((sep_ptr = first_dir_separator(name)) == NULL)
6901 512 3516 : sep_ptr = name + strlen(name);
513 :
514 15872 : if (strlen("$libdir") != sep_ptr - name ||
515 15872 : strncmp(name, "$libdir", strlen("$libdir")) != 0)
7205 tgl 516 UBC 0 : ereport(ERROR,
517 : (errcode(ERRCODE_INVALID_NAME),
518 : errmsg("invalid macro name in dynamic library path: %s",
519 : name)));
520 :
3465 peter_e 521 CBC 15872 : return psprintf("%s%s", pkglib_path, sep_ptr);
522 : }
523 :
524 :
525 : /*
526 : * Search for a file called 'basename' in the colon-separated search
527 : * path Dynamic_library_path. If the file is found, the full file name
528 : * is returned in freshly palloc'd memory. If the file is not found,
529 : * return NULL.
530 : */
531 : static char *
7836 bruce 532 3516 : find_in_dynamic_libpath(const char *basename)
533 : {
534 : const char *p;
535 : size_t baselen;
536 :
163 peter 537 GNC 3516 : Assert(basename != NULL);
538 3516 : Assert(first_dir_separator(basename) == NULL);
539 3516 : Assert(Dynamic_library_path != NULL);
540 :
7997 peter_e 541 CBC 3516 : p = Dynamic_library_path;
542 3516 : if (strlen(p) == 0)
7997 peter_e 543 UBC 0 : return NULL;
544 :
7997 peter_e 545 CBC 3516 : baselen = strlen(basename);
546 :
547 : for (;;)
7857 tgl 548 UBC 0 : {
549 : size_t len;
550 : char *piece;
551 : char *mangled;
552 : char *full;
553 :
4449 bruce 554 CBC 3516 : piece = first_path_var_separator(p);
6797 555 3516 : if (piece == p)
7205 tgl 556 UBC 0 : ereport(ERROR,
557 : (errcode(ERRCODE_INVALID_NAME),
558 : errmsg("zero-length component in parameter \"dynamic_library_path\"")));
559 :
4545 tgl 560 CBC 3516 : if (piece == NULL)
6797 bruce 561 3516 : len = strlen(p);
562 : else
6797 bruce 563 UBC 0 : len = piece - p;
564 :
7995 peter_e 565 CBC 3516 : piece = palloc(len + 1);
5905 566 3516 : strlcpy(piece, p, len + 1);
567 :
7995 568 3516 : mangled = substitute_libpath_macro(piece);
7857 tgl 569 3516 : pfree(piece);
570 :
6813 571 3516 : canonicalize_path(mangled);
572 :
573 : /* only absolute paths */
7310 bruce 574 3516 : if (!is_absolute_path(mangled))
7205 tgl 575 UBC 0 : ereport(ERROR,
576 : (errcode(ERRCODE_INVALID_NAME),
577 : errmsg("component in parameter \"dynamic_library_path\" is not an absolute path")));
578 :
7995 peter_e 579 CBC 3516 : full = palloc(strlen(mangled) + 1 + baselen + 1);
580 3516 : sprintf(full, "%s/%s", mangled, basename);
7857 tgl 581 3516 : pfree(mangled);
582 :
7205 583 3516 : elog(DEBUG3, "find_in_dynamic_libpath: trying \"%s\"", full);
584 :
7997 peter_e 585 3516 : if (file_exists(full))
586 1754 : return full;
587 :
588 1762 : pfree(full);
589 :
590 1762 : if (p[len] == '\0')
591 1762 : break;
592 : else
7997 peter_e 593 UBC 0 : p += len + 1;
594 : }
595 :
7997 peter_e 596 CBC 1762 : return NULL;
597 : }
598 :
599 :
600 : /*
601 : * Find (or create) a rendezvous variable that one dynamically
602 : * loaded library can use to meet up with another.
603 : *
604 : * On the first call of this function for a particular varName,
605 : * a "rendezvous variable" is created with the given name.
606 : * The value of the variable is a void pointer (initially set to NULL).
607 : * Subsequent calls with the same varName just return the address of
608 : * the existing variable. Once created, a rendezvous variable lasts
609 : * for the life of the process.
610 : *
611 : * Dynamically loaded libraries can use rendezvous variables
612 : * to find each other and share information: they just need to agree
613 : * on the variable name and the data it will point to.
614 : */
615 : void **
6081 tgl 616 1792 : find_rendezvous_variable(const char *varName)
617 : {
618 : static HTAB *rendezvousHash = NULL;
619 :
620 : rendezvousHashEntry *hentry;
621 : bool found;
622 :
623 : /* Create a hashtable if we haven't already done so in this process */
624 1792 : if (rendezvousHash == NULL)
625 : {
626 : HASHCTL ctl;
627 :
6031 bruce 628 1789 : ctl.keysize = NAMEDATALEN;
629 1789 : ctl.entrysize = sizeof(rendezvousHashEntry);
6081 tgl 630 1789 : rendezvousHash = hash_create("Rendezvous variable hash",
631 : 16,
632 : &ctl,
633 : HASH_ELEM | HASH_STRINGS);
634 : }
635 :
636 : /* Find or create the hashtable entry for this varName */
637 1792 : hentry = (rendezvousHashEntry *) hash_search(rendezvousHash,
638 : varName,
639 : HASH_ENTER,
640 : &found);
641 :
642 : /* Initialize to NULL if first time */
643 1792 : if (!found)
644 1792 : hentry->varValue = NULL;
645 :
646 1792 : return &hentry->varValue;
647 : }
648 :
649 : /*
650 : * Estimate the amount of space needed to serialize the list of libraries
651 : * we have loaded.
652 : */
653 : Size
2901 rhaas 654 403 : EstimateLibraryStateSpace(void)
655 : {
656 : DynamicFileList *file_scanner;
2878 bruce 657 403 : Size size = 1;
658 :
2901 rhaas 659 403 : for (file_scanner = file_list;
660 1006 : file_scanner != NULL;
661 603 : file_scanner = file_scanner->next)
662 603 : size = add_size(size, strlen(file_scanner->filename) + 1);
663 :
664 403 : return size;
665 : }
666 :
667 : /*
668 : * Serialize the list of libraries we have loaded to a chunk of memory.
669 : */
670 : void
671 403 : SerializeLibraryState(Size maxsize, char *start_address)
672 : {
673 : DynamicFileList *file_scanner;
674 :
675 403 : for (file_scanner = file_list;
676 1006 : file_scanner != NULL;
677 603 : file_scanner = file_scanner->next)
678 : {
679 : Size len;
680 :
681 603 : len = strlcpy(start_address, file_scanner->filename, maxsize) + 1;
682 603 : Assert(len < maxsize);
683 603 : maxsize -= len;
684 603 : start_address += len;
685 : }
686 403 : start_address[0] = '\0';
687 403 : }
688 :
689 : /*
690 : * Load every library the serializing backend had loaded.
691 : */
692 : void
693 1298 : RestoreLibraryState(char *start_address)
694 : {
695 3653 : while (*start_address != '\0')
696 : {
697 2355 : internal_load_library(start_address);
698 2355 : start_address += strlen(start_address) + 1;
699 : }
700 1298 : }
|