Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / port / dynloader / aix.c
bloba0c047972dc56b4a9e5b1d7b414e2c1aa943de5c
1 /*
2 * $PostgreSQL:$
5 * @(#)dlfcn.c 1.7 revision of 95/08/14 19:08:38
6 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
7 * 30159 Hannover, Germany
8 */
10 #include "postgres.h"
12 #include "sys/ldr.h"
13 #include <a.out.h>
14 #include "ldfcn.h"
16 #include "dynloader.h"
18 #ifndef HAVE_DLOPEN
21 * AIX 4.3 and up has dlopen() and friends in -ldl.
22 * A la long, the homebrewn dl*() functions below should be obsolete.
26 * We simulate dlopen() et al. through a call to load. Because AIX has
27 * no call to find an exported symbol we read the loader section of the
28 * loaded module and build a list of exported symbols and their virtual
29 * address.
32 typedef struct
34 char *name; /* the symbols's name */
35 void *addr; /* its relocated virtual address */
36 } Export, *ExportPtr;
39 * xlC uses the following structure to list its constructors and
40 * destructors. This is gleaned from the output of munch.
42 typedef struct
44 void (*init) (void); /* call static constructors */
45 void (*term) (void); /* call static destructors */
46 } Cdtor, *CdtorPtr;
49 * The void * handle returned from dlopen is actually a ModulePtr.
51 typedef struct Module
53 struct Module *next;
54 char *name; /* module name for refcounting */
55 int refCnt; /* the number of references */
56 void *entry; /* entry point from load */
57 struct dl_info *info; /* optional init/terminate functions */
58 CdtorPtr cdtors; /* optional C++ constructors */
59 int nExports; /* the number of exports found */
60 ExportPtr exports; /* the array of exports */
61 } Module, *ModulePtr;
64 * We keep a list of all loaded modules to be able to call the fini
65 * handlers and destructors at atexit() time.
67 static ModulePtr modList;
70 * The last error from one of the dl* routines is kept in static
71 * variables here. Each error is returned only once to the caller.
73 static char errbuf[BUFSIZ];
74 static int errvalid;
76 extern char *strdup(const char *);
77 static void caterr(char *);
78 static int readExports(ModulePtr);
79 static void terminate(void);
80 static void *findMain(void);
82 void *
83 dlopen(const char *path, int mode)
85 ModulePtr mp;
86 static void *mainModule;
89 * Upon the first call register a terminate handler that will close all
90 * libraries. Also get a reference to the main module for use with
91 * loadbind.
93 if (!mainModule)
95 if ((mainModule = findMain()) == NULL)
96 return NULL;
97 atexit(terminate);
101 * Scan the list of modules if we have the module already loaded.
103 for (mp = modList; mp; mp = mp->next)
104 if (strcmp(mp->name, path) == 0)
106 mp->refCnt++;
107 return mp;
109 if ((mp = (ModulePtr) calloc(1, sizeof(*mp))) == NULL)
111 errvalid++;
112 strcpy(errbuf, "calloc: ");
113 strcat(errbuf, strerror(errno));
114 return NULL;
116 if ((mp->name = strdup(path)) == NULL)
118 errvalid++;
119 strcpy(errbuf, "strdup: ");
120 strcat(errbuf, strerror(errno));
121 free(mp);
122 return NULL;
126 * load should be declared load(const char *...). Thus we cast the path to
127 * a normal char *. Ugly.
129 if ((mp->entry = (void *) load((char *) path, L_NOAUTODEFER, NULL)) == NULL)
131 free(mp->name);
132 free(mp);
133 errvalid++;
134 strcpy(errbuf, "dlopen: ");
135 strcat(errbuf, path);
136 strcat(errbuf, ": ");
139 * If AIX says the file is not executable, the error can be further
140 * described by querying the loader about the last error.
142 if (errno == ENOEXEC)
144 char *tmp[BUFSIZ / sizeof(char *)];
146 if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
147 strcpy(errbuf, strerror(errno));
148 else
150 char **p;
152 for (p = tmp; *p; p++)
153 caterr(*p);
156 else
157 strcat(errbuf, strerror(errno));
158 return NULL;
160 mp->refCnt = 1;
161 mp->next = modList;
162 modList = mp;
163 if (loadbind(0, mainModule, mp->entry) == -1)
165 dlclose(mp);
166 errvalid++;
167 strcpy(errbuf, "loadbind: ");
168 strcat(errbuf, strerror(errno));
169 return NULL;
173 * If the user wants global binding, loadbind against all other loaded
174 * modules.
176 if (mode & RTLD_GLOBAL)
178 ModulePtr mp1;
180 for (mp1 = mp->next; mp1; mp1 = mp1->next)
181 if (loadbind(0, mp1->entry, mp->entry) == -1)
183 dlclose(mp);
184 errvalid++;
185 strcpy(errbuf, "loadbind: ");
186 strcat(errbuf, strerror(errno));
187 return NULL;
190 if (readExports(mp) == -1)
192 dlclose(mp);
193 return NULL;
197 * If there is a dl_info structure, call the init function.
199 if (mp->info = (struct dl_info *) dlsym(mp, "dl_info"))
201 if (mp->info->init)
202 (*mp->info->init) ();
204 else
205 errvalid = 0;
208 * If the shared object was compiled using xlC we will need to call static
209 * constructors (and later on dlclose destructors).
211 if (mp->cdtors = (CdtorPtr) dlsym(mp, "__cdtors"))
213 while (mp->cdtors->init)
215 (*mp->cdtors->init) ();
216 mp->cdtors++;
219 else
220 errvalid = 0;
221 return mp;
225 * Attempt to decipher an AIX loader error message and append it
226 * to our static error message buffer.
228 static void
229 caterr(char *s)
231 char *p = s;
233 while (*p >= '0' && *p <= '9')
234 p++;
235 switch (atoi(s))
237 case L_ERROR_TOOMANY:
238 strcat(errbuf, "to many errors");
239 break;
240 case L_ERROR_NOLIB:
241 strcat(errbuf, "cannot load library");
242 strcat(errbuf, p);
243 break;
244 case L_ERROR_UNDEF:
245 strcat(errbuf, "cannot find symbol");
246 strcat(errbuf, p);
247 break;
248 case L_ERROR_RLDBAD:
249 strcat(errbuf, "bad RLD");
250 strcat(errbuf, p);
251 break;
252 case L_ERROR_FORMAT:
253 strcat(errbuf, "bad exec format in");
254 strcat(errbuf, p);
255 break;
256 case L_ERROR_ERRNO:
257 strcat(errbuf, strerror(atoi(++p)));
258 break;
259 default:
260 strcat(errbuf, s);
261 break;
265 void *
266 dlsym(void *handle, const char *symbol)
268 ModulePtr mp = (ModulePtr) handle;
269 ExportPtr ep;
270 int i;
273 * Could speed up the search, but I assume that one assigns the result to
274 * function pointers anyways.
276 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
277 if (strcmp(ep->name, symbol) == 0)
278 return ep->addr;
279 errvalid++;
280 strcpy(errbuf, "dlsym: undefined symbol ");
281 strcat(errbuf, symbol);
282 return NULL;
285 char *
286 dlerror(void)
288 if (errvalid)
290 errvalid = 0;
291 return errbuf;
293 return NULL;
297 dlclose(void *handle)
299 ModulePtr mp = (ModulePtr) handle;
300 int result;
301 ModulePtr mp1;
303 if (--mp->refCnt > 0)
304 return 0;
305 if (mp->info && mp->info->fini)
306 (*mp->info->fini) ();
307 if (mp->cdtors)
308 while (mp->cdtors->term)
310 (*mp->cdtors->term) ();
311 mp->cdtors++;
313 result = unload(mp->entry);
314 if (result == -1)
316 errvalid++;
317 strcpy(errbuf, strerror(errno));
319 if (mp->exports)
321 ExportPtr ep;
322 int i;
324 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
325 if (ep->name)
326 free(ep->name);
327 free(mp->exports);
329 if (mp == modList)
330 modList = mp->next;
331 else
333 for (mp1 = modList; mp1; mp1 = mp1->next)
334 if (mp1->next == mp)
336 mp1->next = mp->next;
337 break;
340 free(mp->name);
341 free(mp);
342 return result;
345 static void
346 terminate(void)
348 while (modList)
349 dlclose(modList);
353 * Build the export table from the XCOFF .loader section.
355 static int
356 readExports(ModulePtr mp)
358 LDFILE *ldp = NULL;
359 SCNHDR sh,
360 shdata;
361 LDHDR *lhp;
362 char *ldbuf;
363 LDSYM *ls;
364 int i;
365 ExportPtr ep;
367 if ((ldp = ldopen(mp->name, ldp)) == NULL)
369 struct ld_info *lp;
370 char *buf;
371 int size = 4 * 1024;
373 if (errno != ENOENT)
375 errvalid++;
376 strcpy(errbuf, "readExports: ");
377 strcat(errbuf, strerror(errno));
378 return -1;
382 * The module might be loaded due to the LIBPATH environment variable.
383 * Search for the loaded module using L_GETINFO.
385 if ((buf = malloc(size)) == NULL)
387 errvalid++;
388 strcpy(errbuf, "readExports: ");
389 strcat(errbuf, strerror(errno));
390 return -1;
392 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM)
394 free(buf);
395 size += 4 * 1024;
396 if ((buf = malloc(size)) == NULL)
398 errvalid++;
399 strcpy(errbuf, "readExports: ");
400 strcat(errbuf, strerror(errno));
401 return -1;
404 if (i == -1)
406 errvalid++;
407 strcpy(errbuf, "readExports: ");
408 strcat(errbuf, strerror(errno));
409 free(buf);
410 return -1;
414 * Traverse the list of loaded modules. The entry point returned by
415 * load() does actually point to the data segment origin.
417 lp = (struct ld_info *) buf;
418 while (lp)
420 if (lp->ldinfo_dataorg == mp->entry)
422 ldp = ldopen(lp->ldinfo_filename, ldp);
423 break;
425 if (lp->ldinfo_next == 0)
426 lp = NULL;
427 else
428 lp = (struct ld_info *) ((char *) lp + lp->ldinfo_next);
430 free(buf);
431 if (!ldp)
433 errvalid++;
434 strcpy(errbuf, "readExports: ");
435 strcat(errbuf, strerror(errno));
436 return -1;
439 if (TYPE(ldp) != U802TOCMAGIC)
441 errvalid++;
442 strcpy(errbuf, "readExports: bad magic");
443 while (ldclose(ldp) == FAILURE)
445 return -1;
449 * Get the padding for the data section. This is needed for AIX 4.1
450 * compilers. This is used when building the final function pointer to the
451 * exported symbol.
453 if (ldnshread(ldp, _DATA, &shdata) != SUCCESS)
455 errvalid++;
456 strcpy(errbuf, "readExports: cannot read data section header");
457 while (ldclose(ldp) == FAILURE)
459 return -1;
461 if (ldnshread(ldp, _LOADER, &sh) != SUCCESS)
463 errvalid++;
464 strcpy(errbuf, "readExports: cannot read loader section header");
465 while (ldclose(ldp) == FAILURE)
467 return -1;
471 * We read the complete loader section in one chunk, this makes finding
472 * long symbol names residing in the string table easier.
474 if ((ldbuf = (char *) malloc(sh.s_size)) == NULL)
476 errvalid++;
477 strcpy(errbuf, "readExports: ");
478 strcat(errbuf, strerror(errno));
479 while (ldclose(ldp) == FAILURE)
481 return -1;
483 if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK)
485 errvalid++;
486 strcpy(errbuf, "readExports: cannot seek to loader section");
487 free(ldbuf);
488 while (ldclose(ldp) == FAILURE)
490 return -1;
492 if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1)
494 errvalid++;
495 strcpy(errbuf, "readExports: cannot read loader section");
496 free(ldbuf);
497 while (ldclose(ldp) == FAILURE)
499 return -1;
501 lhp = (LDHDR *) ldbuf;
502 ls = (LDSYM *) (ldbuf + LDHDRSZ);
505 * Count the number of exports to include in our export table.
507 for (i = lhp->l_nsyms; i; i--, ls++)
509 if (!LDR_EXPORT(*ls))
510 continue;
511 mp->nExports++;
513 if ((mp->exports = (ExportPtr) calloc(mp->nExports, sizeof(*mp->exports))) == NULL)
515 errvalid++;
516 strcpy(errbuf, "readExports: ");
517 strcat(errbuf, strerror(errno));
518 free(ldbuf);
519 while (ldclose(ldp) == FAILURE)
521 return -1;
525 * Fill in the export table. All entries are relative to the entry point
526 * we got from load.
528 ep = mp->exports;
529 ls = (LDSYM *) (ldbuf + LDHDRSZ);
530 for (i = lhp->l_nsyms; i; i--, ls++)
532 char *symname;
533 char tmpsym[SYMNMLEN + 1];
535 if (!LDR_EXPORT(*ls))
536 continue;
537 if (ls->l_zeroes == 0)
538 symname = ls->l_offset + lhp->l_stoff + ldbuf;
539 else
542 * The l_name member is not zero terminated, we must copy the
543 * first SYMNMLEN chars and make sure we have a zero byte at the
544 * end.
546 strncpy(tmpsym, ls->l_name, SYMNMLEN);
547 tmpsym[SYMNMLEN] = '\0';
548 symname = tmpsym;
550 ep->name = strdup(symname);
551 ep->addr = (void *) ((unsigned long) mp->entry +
552 ls->l_value - shdata.s_vaddr);
553 ep++;
555 free(ldbuf);
556 while (ldclose(ldp) == FAILURE)
558 return 0;
562 * Find the main modules entry point. This is used as export pointer
563 * for loadbind() to be able to resolve references to the main part.
565 static void *
566 findMain(void)
568 struct ld_info *lp;
569 char *buf;
570 int size = 4 * 1024;
571 int i;
572 void *ret;
574 if ((buf = malloc(size)) == NULL)
576 errvalid++;
577 strcpy(errbuf, "findMain: ");
578 strcat(errbuf, strerror(errno));
579 return NULL;
581 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM)
583 free(buf);
584 size += 4 * 1024;
585 if ((buf = malloc(size)) == NULL)
587 errvalid++;
588 strcpy(errbuf, "findMain: ");
589 strcat(errbuf, strerror(errno));
590 return NULL;
593 if (i == -1)
595 errvalid++;
596 strcpy(errbuf, "findMain: ");
597 strcat(errbuf, strerror(errno));
598 free(buf);
599 return NULL;
603 * The first entry is the main module. The entry point returned by load()
604 * does actually point to the data segment origin.
606 lp = (struct ld_info *) buf;
607 ret = lp->ldinfo_dataorg;
608 free(buf);
609 return ret;
612 #endif /* HAVE_DLOPEN */