CUBRID Engine  latest
dynamic_load.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * dynamic_load.c - Dynamic loader for run-time inclusion of object code
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #if !defined(SOLARIS) && !defined(LINUX)
28 #include <a.out.h>
29 #if defined(sun) || defined(sparc)
30 #include <sys/mman.h> /* for mprotect() */
31 #include <malloc.h> /* for valloc() */
32 #endif /* defined(sun) || defined(sparc) */
33 #endif /* !(SOLARIS) && !(LINUX) */
34 #include <sys/types.h>
35 #include <signal.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <ar.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <sys/stat.h>
44 #ifdef HAVE_VFORK
45 #include <vfork.h>
46 #endif /* HAVE_VFORK */
47 #include <assert.h>
48 
49 #include "porting.h"
50 
51 #include "intl_support.h"
52 #include "dynamic_load.h"
53 #include "error_manager.h"
54 #include "memory_alloc.h"
55 #include "environment_variable.h"
56 #include "system_parameter.h"
57 #include "util_func.h"
58 
59 #if defined(_AIX)
60 #define N_BADMAG(x) \
61  ((x).magic != 0x107 && (x).magic != 0x108 && (x).magic != 0x10b)
62 #elif defined(HPUX)
63 #define N_BADMAG(x) \
64  ((x).a_magic != RELOC_MAGIC && /* relocatable only */ \
65  (x).a_magic != EXEC_MAGIC && /* normal executable */ \
66  (x).a_magic != SHARE_MAGIC && /* shared executable */ \
67  (x).a_magic != DL_MAGIC) /* dynamic load library */
68 #endif /* _AIX */
69 
70 #define FNAME_TBL_SIZE 127
71 
72 #define DEBUG
73 #ifdef DEBUG
74 #define TEMPNAM(d,p) dl_get_temporary_name((d), (p), __LINE__)
75 #define OPEN(fn, m) dl_open_object_file((fn), (m), __LINE__)
76 #define CLOSE(fd) dl_close_object_file((fd), __LINE__)
77 #define PIPE(fd) dl_open_pipe((fd), __LINE__)
78 #endif /* DEBUG */
79 
80 #ifndef TEMPNAM
81 #define TEMPNAM tempnam
82 #endif /* TEMPNAM */
83 #ifndef OPEN
84 #define OPEN open
85 #endif /* OPEN */
86 #ifndef CLOSE
87 #define CLOSE close
88 #endif /* CLOSE */
89 #ifndef PIPE
90 #define PIPE pipe
91 #endif /* PIPE */
92 
93 #ifndef FORK
94 #ifdef HAVE_VFORK
95 #define FORK vfork
96 #else /* HAVE_VFORK */
97 #define FORK fork
98 #endif /* HAVE_VFORK */
99 #endif /* FORK */
100 
101 #define DL_SET_ERROR_WITH_CODE(code) \
102  er_set(ER_ERROR_SEVERITY, \
103  ARG_FILE_LINE, \
104  dl_Errno = (code), \
105  0)
106 
107 #define DL_SET_ERROR_WITH_CODE_ONE_ARG(code, arg) \
108  er_set(ER_ERROR_SEVERITY, \
109  ARG_FILE_LINE, \
110  dl_Errno = (code), \
111  1, \
112  (arg))
113 
114 #define DL_SET_ERROR_SYSTEM_MSG() \
115  er_set(ER_ERROR_SEVERITY, \
116  ARG_FILE_LINE, \
117  dl_Errno = ER_DL_ESYS, \
118  1, \
119  dl_get_system_error_message(errno))
120 
121 #define DL_SET_ERROR_SYSTEM_FILENAME(fn) \
122  er_set(ER_ERROR_SEVERITY, \
123  ARG_FILE_LINE, \
124  dl_Errno = ER_DL_EFILE, \
125  2, \
126  (fn), \
127  dl_get_system_error_message(errno))
128 
129 
130 typedef void (*FUNCTION_POINTER_TYPE) (void);
131 typedef struct tbl_link TBL_LINK;
132 typedef struct file_entry FILE_ENTRY;
134 
135 struct tbl_link
136 {
137  char *filename;
138  const TBL_LINK *link;
139 };
140 
142 {
143  char *filename;
144  bool valid;
145  bool archive;
146  bool duplicate;
147  size_t size;
148 };
149 
151 {
152  bool virgin; /* true if the loader has ever been used */
153  struct
154  {
155  FILE_ENTRY *entries; /* descriptors for each file to be loaded */
156  int num; /* size of candidates */
157  } candidates;
158  int num_need_load; /* files that haven't already been loaded */
159  TBL_LINK *loaded[FNAME_TBL_SIZE]; /* names of loaded object files. */
160  pid_t (*fork_function_p) (); /* forking function to use (fork or vfork) */
161  struct
162  {
163  int daemon_fd; /* The file descriptor of the pipe used to communicate with the daemon. -1 for
164  * unspawned daemon, -2 for broken daemon, greater than 0 for operating daemon. */
165 
166  char daemon_name[PATH_MAX]; /* The name of the process to be exec'ed as the daemon to scavenge tmpfiles. */
167  } daemon;
168 
169 #if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
170  struct
171  {
172  void **handles; /* An array of handles to the shared objects */
173  int top; /* the next handle to be allocated */
174  int num; /* the total number of handles in the array */
175  } handler;
176 #endif /* SOLARIS || HPUX || LINUX */
177 
178  struct
179  {
180  const char *cmd; /* The pathname of the ld command to be used to link the object files. */
181 
182  caddr_t *ptr; /* pointers to chunks VALLOC'ed to hold the text and data loaded int num; */
183  int num;
184  } loader;
185 
186  const char *image_file; /* The name of the file that holds the up-to-date symbol table info */
187 };
188 
190 
191 /* There should only be one loader extant at any one time; */
193 
194 /* set DL_DEBUG for debugging actions. */
195 static int dl_Debug = 0;
196 
197 #if (defined(sun) || defined(sparc))&& !defined(SOLARIS)
198 static const char *dl_Default_libs[] = {
199  "-lm",
200  "-lc",
201  NULL
202 };
203 #endif /* ((sun) || (sparc))&& !(SOLARIS) */
204 
205 static const int MAX_UNLINK_RETRY = 15;
206 
207 static const int DAEMON_NOT_SPAWNED = -1;
208 static const int DAEMON_NOT_AVAILABLE = -2;
209 
210 static const char DAEMON_NAME[] = "dl_daemon";
211 
212 /* number of handles to allocate per extent */
213 static const int HANDLES_PER_EXTENT = 10;
214 
215 #if defined(sun) || defined(sparc)
216 static const char DEFAULT_LD_NAME[] = "/bin/ld";
217 #elif defined(_AIX)
218 /* this space intentionally blank */
219 #elif defined(HPUX)
220 /* this space intentionally blank */
221 #elif defined(SOLARIS)
222 /* this space intentionally blank */
223 #elif defined(LINUX)
224 /* this space intentionally blank */
225 #endif /* (sun) || (sparc) */
226 
227 #ifdef DEBUG
228 static int dl_open_object_file (const char *filename, int mode, int lineno);
229 static int dl_close_object_file (int fd, int lineno);
230 #endif /* DEBUG */
231 
232 static void dl_destroy_candidates (DYNAMIC_LOADER *);
233 static int dl_validate_file_entry (FILE_ENTRY *, const char *);
234 static int dl_initiate_dynamic_loader (DYNAMIC_LOADER *, const char *);
236 static int dl_validate_candidates (DYNAMIC_LOADER *, const char **);
237 static void dl_find_daemon (DYNAMIC_LOADER *);
238 static void dl_record_files (DYNAMIC_LOADER *);
240 static int dl_resolve_symbol (DYNAMIC_LOADER *, struct nlist *);
241 
242 #if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
243 static void dl_notify_daemon (DYNAMIC_LOADER *);
244 static void dl_spawn_daemon (DYNAMIC_LOADER *);
245 static void dl_set_pipe_handler (void);
246 static void dl_set_new_image_file (DYNAMIC_LOADER *, const char *);
247 static int dl_set_new_load_points (DYNAMIC_LOADER * this_, const caddr_t);
248 static int dl_load_object_image (caddr_t, const char *);
249 static const char **dl_parse_extra_options (int *num_options, char *option_string);
250 static void dl_decipher_waitval (int waitval);
251 #ifdef DEBUG
252 static char *dl_get_temporary_name (const char *dir, const char *prefix, int lineno);
253 static int dl_open_pipe (int *fd, int lineno);
254 #endif /* DEBUG */
255 #endif /* !(SOLARIS) && !(HPUX) && !(LINUX) && !(AIX) */
256 
257 #if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
258 static size_t dl_get_image_file_size (const char *);
259 static int dl_link_file (DYNAMIC_LOADER *, const char *, caddr_t, const char **);
260 static int dl_load_objects (DYNAMIC_LOADER *, size_t *, const char **, const char **, const size_t,
261  enum dl_estimate_mode);
262 #elif defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
263 static int dl_load_objects (DYNAMIC_LOADER *, const char **);
264 #else /* ((sun) || (sparc)) && !(SOLARIS) */
265 #error "Unknown machine type."
266 #endif /* ((sun) || (sparc)) && !(SOLARIS) */
267 
268 static const char *
270 {
271  return (strerror (n));
272 }
273 
274 #ifdef DEBUG
275 #if ((defined(sun) || defined(sparc))&& !defined(SOLARIS))
276 static char *
277 dl_get_temporary_name (const char *dir, const char *prefix, int lineno)
278 {
279  char *result;
280 
281  result = tempnam (dir, prefix);
282  if (dl_Debug)
283  {
284  fprintf (stderr, "%s[%d]: tempnam(", __FILE__, lineno);
285  if (dir)
286  {
287  fprintf (stderr, "\"%s\", ", dir);
288  }
289  else
290  {
291  fputs ("NULL, ", stderr);
292  }
293  if (prefix)
294  {
295  fprintf (stderr, "\"%s\") => ", prefix);
296  }
297  else
298  {
299  fputs ("NULL) => ", stderr);
300  }
301  fprintf (stderr, "\"%s\" (0x%p)\n", result, result);
302  fflush (stderr);
303  }
304  return result;
305 }
306 #endif /* (((sun) || (sparc))&& !(SOLARIS)) */
307 
308 static int
309 dl_open_object_file (const char *filename, int mode, int lineno)
310 {
311  int fd;
312 
313  if (dl_Debug)
314  {
315  fprintf (stderr, "%s[%d]: attempting to open %s...", __FILE__, lineno, filename);
316  }
317 
318  fd = open (filename, mode, 0111);
319  if (dl_Debug)
320  {
321  if (fd == -1)
322  {
323  fputs ("failed\n", stderr);
324  }
325  else
326  {
327  fprintf (stderr, "succeeded on fd %d\n", fd);
328  }
329  }
330  return fd;
331 }
332 
333 
334 static int
335 dl_close_object_file (int fd, int lineno)
336 {
337  if (dl_Debug)
338  {
339  fprintf (stderr, "%s[%d]: closing fd %d\n", __FILE__, lineno, fd);
340  }
341  return close (fd);
342 }
343 #endif /* DEBUG */
344 
345 
346 #if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
347 /*
348  * dl_decipher_waitval() - decipher exit status
349  * return: none
350  * waitval(in): exit status
351  */
352 static void
353 dl_decipher_waitval (int waitval)
354 {
355 #ifdef __GNUG__
356  /* Because of some idiocy in the GNU header files, we have to recreate some stupid overriding #define before
357  * WIFEXITED and friends will work. Who thinks of this stuff? */
358 #define wait WaitStatus
359 #endif /* __GNUG__ */
360 
361  if (WIFEXITED (waitval))
362  {
363  if (WEXITSTATUS (waitval))
364  {
365  DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_LDEXIT, WEXITSTATUS (waitval));
366  }
367  else
368  {
369  dl_Errno = NO_ERROR;
370  }
371  }
372  else if (WIFSIGNALED (waitval))
373  {
374  /*
375  * Child terminated by signal.
376  */
377  DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_LDTERM, WTERMSIG (waitval));
378  }
379  else
380  {
381  if (dl_Debug)
382  {
383  fprintf (stderr, "dynamic loader: unknown wait status = 0x%x\n", waitval);
384  }
386  }
387 
388 #ifdef __GNUG__
389 #undef wait
390 #endif /* __GNUG__ */
391 }
392 #endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
393 
394 /*
395  * dl_destroy_candidates()
396  * return: none
397  * this_(in): DYNAMIC_LOADER structure pointer
398  *
399  * Note: If it has been put in the FILE_ENTRY table, we leave the responsibility
400  * of freeing the string to the table.
401  */
402 static void
404 {
405  int i;
406 
407  assert (this_ != NULL);
408 
409  for (i = 0; i < this_->candidates.num; ++i)
410  {
411  FILE_ENTRY *fe = &this_->candidates.entries[i];
412 
413  if (fe->filename)
414  {
415  if (!fe->valid || fe->duplicate || fe->archive)
416  {
417  free_and_init (fe->filename);
418  }
419  }
420 
421  }
422 
423  if (this_->candidates.entries)
424  {
426  }
427 
428  this_->candidates.entries = NULL;
429  this_->candidates.num = 0;
430  this_->num_need_load = 0;
431 }
432 
433 /*
434  * dl_validate_file_entry() - Make sure that the file is usable
435  * return: Zero on valid, non-zero on invalid
436  * this_(out): save validation result
437  * filename(in): file name to validate
438  */
439 static int
441 {
442  static char pathbuf[PATH_MAX];
443 #if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
444 #define AR_MAGIC_STR ARMAG
445 #define AR_MAGIC_STR_SIZ SARMAG
446  char ar_magic[AR_MAGIC_STRING_SIZ];
447  struct exec hdr;
448 #elif defined(_AIX)
449 #define AR_MAGIC_STR AIAMAG
450 #define AR_MAGIC_STR_SIZ SAIAMAG
451  char ar_magic[AR_MAGIC_STR_SIZ];
452  struct aouthdr hdr;
453 #endif /* ((sun) || (sparc)) && !(SOLARIS) */
454  int fd;
455 
456  assert (this_ != NULL);
457 
458  dl_Errno = NO_ERROR;
459 
460  fd = OPEN (filename, O_RDONLY);
461  if (fd == -1)
462  {
463  DL_SET_ERROR_SYSTEM_FILENAME (filename);
464  }
465  else
466  {
467  if (realpath ((char *) filename, pathbuf) == NULL)
468  {
470  }
471  else if ((this_->filename = strdup ((char *) filename)) == NULL)
472  {
474  }
475  else
476  {
477 #if defined (SOLARIS) || defined (HPUX) || defined(LINUX)
478  this_->archive = false;
479  this_->size = 0; /* we rely on dlopen to catch any errors. */
480 #else /* SOLARIS || HPUX || LINUX */
481 
482 #if defined(sun) || defined(sparc) || defined(_AIX)
483 #if defined(_AIX)
484  if (lseek (fd, sizeof (struct filehdr), SEEK_SET) < 0)
485  { /* See <xcoff.h> for the layout of the file. */
487  }
488  else
489 #endif /* _AIX */
490  if (read (fd, (char *) &hdr, sizeof (hdr)) == sizeof (hdr) && !N_BADMAG (hdr))
491  {
492  this_->archive = false;
493 #if defined(sun) || defined(sparc)
494  this_->size = hdr.a_text + hdr.a_data + hdr.a_bss;
495 #endif /* sun || sparc */
496  }
497  else
498  {
499  (void) lseek (fd, 0, 0);
500  if (read (fd, ar_magic, AR_MAGIC_STR_SIZ) == AR_MAGIC_STR_SIZ)
501  {
502  if (strncmp (ar_magic, AR_MAGIC_STR, AR_MAGIC_STR_SIZ) == 0)
503  {
504  this_->archive = true;
505  this_->size = 0;
506  }
507  }
508  else
509  {
510 #if defined(_AIX) && defined(gcc)
511  this_->archive = false;
512 #else
514 #endif /* _AIX && gcc */
515  }
516  }
517 #endif /* sun || sparc || _AIX */
518 
519 #endif /* SOLARIS || HPUX || LINUX || _AIX */
520  }
521 
522  CLOSE (fd);
523  }
524 
525  this_->valid = (dl_Errno == NO_ERROR);
526 
527  if (this_->valid)
528  return NO_ERROR;
529 
530  return ER_FAILED;
531 }
532 
533 
534 /*
535  * dl_initiate_dynamic_loader() - builds up dynamic loader
536  * return: Zero on success, non-zero on failure
537  * this_(out): information structure of dynamic loader
538  * original(in): original image file
539  */
540 static int
541 dl_initiate_dynamic_loader (DYNAMIC_LOADER * this_, const char *original)
542 {
543  int i;
544 
545  assert (this_ != NULL);
546 
547  if (dl_Debug)
548  {
549  fprintf (stderr, "%s[%d]: dynamic loader being built\n", __FILE__, __LINE__);
550  }
551 
552  this_->virgin = true;
553  this_->candidates.entries = NULL;
554  this_->candidates.num = 0;
555  this_->num_need_load = 0;
556  for (i = 0; i < FNAME_TBL_SIZE; i++)
557  {
558  this_->loaded[i] = NULL;
559  }
560 
562  {
563  if (strcmp (prm_get_string_value (PRM_ID_DL_FORK), "fork") == 0)
564  {
565  this_->fork_function_p = &fork;
566  }
567 #if defined(HAVE_VFORK)
568  else if (strcmp (prm_get_string_value (PRM_ID_DL_FORK), "vfork") == 0)
569  {
570  this_->fork_function_p = &vfork;
571  }
572 #endif /* HAVE_VFORK */
573  else
574  {
575  this_->fork_function_p = (pid_t (*)())NULL;
576  }
577  }
578  else
579  {
580  this_->fork_function_p = &FORK;
581  }
582 
584 
585 #if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
586  this_->handler.handles = (void **) malloc (HANDLES_PER_EXTENT * sizeof (void *));
587  if (this_->handler.handles == NULL)
588  {
590  return ER_FAILED;
591  }
592  this_->handler.top = 0;
593  this_->handler.num = HANDLES_PER_EXTENT;
594  for (i = 0; i < this_->handler.num; i++)
595  {
596  this_->handler.handles[i] = 0;
597  }
598 #endif /* SOLARIS || HPUX || LINUX || AIX */
599 
600  this_->loader.cmd = NULL;
601  this_->loader.ptr = NULL;
602  this_->loader.num = 0;
603 
604  this_->image_file = original;
605 
606 #if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
607  this_->loader.cmd = DEFAULT_LD_NAME; /* use the default name. */
608 #endif /* !(SOLARIS) && !(HPUX) && !(LINUX) && !(AIX) */
609 
610  if (dl_Errno == NO_ERROR)
611  {
612  dl_find_daemon (this_);
613  }
614 
615  return dl_Errno;
616 }
617 
618 
619 static void
621 {
622  int i, tbl_size;
623 
624  assert (this_ != NULL);
625 
626 #if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
627  for (i = 0; i < this_->handler.top; i++)
628  {
629 #if defined(HPUX)
630  shl_unload (this_->handler.handles[i]);
631 #else /* HPUX */
632  (void) dlclose (this_->handler.handles[i]);
633 #endif /* HPUX */
634  }
635  free_and_init (this_->handler.handles);
636  this_->handler.top = this_->handler.num = 0;
637 #endif /* SOLARIS || HPUX || LINUX */
638 
639  for (i = 0, tbl_size = FNAME_TBL_SIZE; i < tbl_size; i++)
640  {
641  TBL_LINK *tp, *next_tp;
642  for (tp = this_->loaded[i]; tp; tp = next_tp)
643  {
644  next_tp = (TBL_LINK *) tp->link;
645  free_and_init (tp->filename);
646  free_and_init (tp);
647  }
648  }
649 
650  if (this_->loader.ptr)
651  {
652  for (i = 0, tbl_size = this_->loader.num; i < tbl_size; ++i)
653  {
654 #if (defined(sun) || defined(sparc) ) && !defined(SOLARIS)
655  free (this_->loader.ptr[i]); /* Use free because the storage was allocated by VALLOC */
656 #endif /* ((sun) || (sparc)) && !(SOLARIS) */
657  }
658  free_and_init (this_->loader.ptr);
659  }
660 
661 #if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
662  if (!this_->virgin)
663  {
664  (void) unlink (this_->image_file);
665  }
666 
667  free ((char *) this_->image_file); /* Don't use free_and_init(), image_file came from exec_path */
668 #endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
669 
670  if (this_->daemon.daemon_fd >= 0)
671  {
672  CLOSE (this_->daemon.daemon_fd);
673  }
674 
675  if (dl_Debug)
676  {
677  fprintf (stderr, "%s[%d]: dynamic loader torn down\n", __FILE__, __LINE__);
678  }
679 }
680 
681 
682 /*
683  * dl_validate_candidates() - initiate and validate file entry
684  * return: Zero on success, non-zero on failure
685  * filenames(in): file names of candidates
686  * this_(in): DYNAMIC_LOADER structure pointer
687  */
688 static int
689 dl_validate_candidates (DYNAMIC_LOADER * this_, const char **filenames)
690 {
691  int i;
692  const char **fname;
693 
694  assert (filenames != NULL);
695 
696  this_->num_need_load = 0;
697 
698  for (fname = filenames, this_->candidates.num = 0; *fname; ++fname)
699  {
700  /* how many candidates we're considering. */
701  ++this_->candidates.num;
702  }
703 
704  if (dl_Debug)
705  {
706  fprintf (stderr, "Number of candidates = %d\n", this_->candidates.num);
707  }
708 
709  if (this_->candidates.num == 0)
710  {
711  return NO_ERROR;
712  }
713 
714  this_->candidates.entries = (FILE_ENTRY *) malloc (this_->candidates.num * sizeof (FILE_ENTRY));
715  if (this_->candidates.entries == NULL)
716  {
718  goto cleanup;
719  }
720 
721  for (i = 0; i < this_->candidates.num; i++)
722  {
723  memset (&this_->candidates.entries[i], 0, sizeof (FILE_ENTRY));
724  }
725 
726  for (i = 0; i < this_->candidates.num; ++i)
727  {
728  if (dl_validate_file_entry (&this_->candidates.entries[i], filenames[i]))
729  {
730  /* Perform individual validation on each. Give up if any fail. */
731  if (dl_Debug)
732  {
733  fprintf (stderr, "dl_validate_file_entry failed on %s\n", filenames[i]);
734  }
735 
736  goto cleanup;
737  }
738  }
739 
740  for (i = 0; i < this_->candidates.num; ++i)
741  {
742  if (!this_->candidates.entries[i].archive)
743  {
744  const char *path;
745  const TBL_LINK *tbl_p;
746  int j;
747 
748  path = this_->candidates.entries[i].filename;
749  tbl_p = this_->loaded[hashpjw (path) % FNAME_TBL_SIZE];
750  for (; tbl_p; tbl_p = tbl_p->link)
751  {
752  /* look in the table of already-loaded files */
753  if (strcmp (tbl_p->filename, path) == 0)
754  {
755  this_->candidates.entries[i].duplicate = true;
756  if (dl_Debug)
757  {
758  fprintf (stderr, "Duplicate: %s\n", path);
759  }
760  continue;
761  }
762  }
763 
764  for (j = 0; j < i; ++j)
765  {
766  /* make sure that it hasn't already appeared in the current list of candidates */
767  if (strcmp (this_->candidates.entries[j].filename, path) == 0)
768  {
769  this_->candidates.entries[i].duplicate = true;
770  if (dl_Debug)
771  {
772  fprintf (stderr, "Duplicate: %s\n", path);
773  }
774  continue;
775  }
776  }
777 
778  /* we record the fact that we need to load it. */
779  ++this_->num_need_load;
780  }
781  }
782 
783 cleanup:
784 
785  if (dl_Debug)
786  {
787  fprintf (stderr, "Number needed to load (nneed) = %d\n", this_->num_need_load);
788  }
789 
790  if (dl_Errno == NO_ERROR)
791  return NO_ERROR;
792 
793  return ER_FAILED;
794 }
795 
796 
797 #if (defined(sun) || defined(sparc) ) && !defined(SOLARIS)
798 /*
799  * dl_get_image_file_size() - get static size requirements
800  * return: Returns -1 if anything goes wrong.
801  * filename(in): image file name
802  */
803 static size_t
804 dl_get_image_file_size (const char *filename)
805 {
806  struct exec hdr;
807  int fd;
808  size_t size = (size_t) - 1;
809 
810  assert (filename != NULL);
811 
812  fd = OPEN (filename, O_RDONLY);
813  if (fd == -1)
814  {
815  DL_SET_ERROR_SYSTEM_FILENAME (filename);
816  }
817  else
818  {
819  if (read (fd, (char *) &hdr, sizeof (hdr)) != sizeof (hdr) || N_BADMAG (hdr))
820  {
822  }
823  else
824  {
825  size = hdr.a_text + hdr.a_data + hdr.a_bss;
826  }
827 
828  if (dl_Debug)
829  {
830  fprintf (stderr, "%s[%d]: closing fd %d\n", __FILE__, __LINE__, fd);
831  }
832 
833  CLOSE (fd);
834  }
835 
836  return size;
837 }
838 #endif /* ((sun) || (sparc)) && !(SOLARIS) */
839 
840 
841 /*
842  * dl_find_daemon() - Discover the pathname for the daemon process.
843  * return: none
844  *
845  * Note: DL_DAEMON env-variable is used.
846  * If we can't find the daemon, we simply set daemon_fd to DAEMON_NOT_AVAILABLE.
847  */
848 static void
850 {
851  char *path;
852 
853  assert (this_ != NULL);
854 
855  path = this_->daemon.daemon_name;
856  if (path != NULL)
857  {
858  envvar_bindir_file (path, PATH_MAX, DAEMON_NAME);
859 
860  if (path[0] != '\0')
861  {
862  if (access (path, X_OK) == 0)
863  {
864  return;
865  }
866  }
867 
868  this_->daemon.daemon_name[0] = '\0';
869  }
871 
872  if (dl_Debug)
873  {
875  }
876 }
877 
878 #if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
879 /*
880  * dl_parse_extra_options() - Break up a string of options into a vector
881  * return: options vector
882  * returns a NULL pointer and sets *noptions to -1 if a problem arises
883  * num_options(out): number of options
884  * option_string(in): string of options
885  */
886 static const char **
887 dl_parse_extra_options (int *num_options, char *option_string)
888 {
889  const char **option_vec = NULL;
890  const char *option = NULL;
891  char *save;
892  int i = 0, opt_cnt = 0;
893 
894 
895  for (option = (const char *) strtok_r (option_string, " \t", &save); option;
896  option = (const char *) strtok_r ((char *) NULL, " \t", &save))
897  {
898  const char **new_vec = NULL;
899 
900  opt_cnt += sizeof (const char *);
901  if (option_vec)
902  {
903  new_vec = realloc (option_vec, opt_cnt);
904  }
905  else
906  {
907  new_vec = malloc (opt_cnt);
908  }
909 
910  if (new_vec == NULL)
911  {
913  if (option_vec)
914  {
915  free_and_init (option_vec);
916  }
917  *num_options = -1;
918  return NULL;
919  }
920 
921  option_vec = new_vec;
922  option_vec[i++] = option;
923  }
924 
925  *num_options = i;
926  return option_vec;
927 }
928 #endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
929 
930 #if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
931 /*
932  * dl_link_file() - Builds up a "command line" which is then forked via execv()
933  * return: Zero on success, non-zero on failure
934  * this_(in): DYNAMIC_LOADER structure pointer
935  * tmp_file(in): temporary file name to be passed to ld
936  * load_point(in): load point to be passed to ld
937  * syms(in): symbols to be used as Export and Import lists(AIX)
938  * libs(in): array of arguments to be passed to ld
939  * Note : You can pass extra parameters to ld with DL_LD_OPTIONS env-variable
940  */
941 #if defined(sun) || defined(sparc)
942 static int
943 dl_link_file (DYNAMIC_LOADER * this_, const char *tmp_file, caddr_t load_point, const char **libs)
944 #endif /* (sun) || (sparc) */
945 {
946  int num_libs = 0;
947  const char **p;
949  const char **option_vec = (const char **) NULL;
950  int num_options = 0;
951  int argc = 0;
952  const char **argv, **argvp;
953  char load_point_buf[16];
954  int i;
955  pid_t pid = 0;
956 
957  extra_options = (char *) getenv ("DL_LD_OPTIONS"); /* to be passed to ld */
958  if (extra_options)
959  {
960  extra_options = strdup (extra_options);
961  if (extra_options == NULL)
962  {
964  }
965  option_vec = dl_parse_extra_options (&num_options, extra_options);
966  }
967 
968  for (p = libs; *p; p++)
969  {
970  num_libs++; /* count libray parameters */
971  }
972 
973 #if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
974  /* ld -N -A <image_file> -T <load_point> -o <tmp_file> <...obj_files...> <...libs...> */
975  argc = 8 + this_->candidates.num + num_libs + num_options;
976 #endif /* ((sun) || (sparc)) && !(SOLARIS) */
977 
978  argv = malloc (sizeof (const char *) * (argc + 1));
979  if (argv == NULL)
980  {
982  goto end_link_file;
983  }
984  argvp = argv;
985 
986  *argvp++ = this_->loader.cmd;
987 #if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
988  *argvp++ = "-N";
989  *argvp++ = "-A";
990  *argvp++ = this_->image_file;
991  *argvp++ = "-T";
992  /* TODO : consider LP64 */
993  (void) sprintf (load_point_buf, "%p", load_point);
994  *argvp++ = load_point_buf;
995  *argvp++ = "-o";
996  *argvp++ = tmp_file;
997 #endif /* ((sun) || (sparc)) && !(SOLARIS) */
998  for (i = 0; i < this_->candidates.num; ++i)
999  {
1000  if (this_->candidates.entries[i].valid && !this_->candidates.entries[i].duplicate)
1001  {
1002  *argvp++ = this_->candidates.entries[i].filename;
1003  }
1004  }
1005  for (i = 0; i < num_options; ++i)
1006  {
1007  *argvp++ = option_vec[i];
1008  }
1009  for (p = libs; *p;)
1010  {
1011  *argvp++ = *p++;
1012  }
1013  *argvp++ = NULL;
1014 
1016  {
1017  const char **p;
1018  fprintf (stderr, "%s[%d]: ", __FILE__, __LINE__);
1019  for (p = argv; *p; ++p)
1020  {
1021  fputs (*p, stderr);
1022  fputc (' ', stderr);
1023  }
1024  fputc ('\n', stderr);
1025  fflush (stderr);
1026  }
1027 
1028  pid = (pid_t) (*this_->fork_function_p) ();
1029  if (pid)
1030  {
1031  /* This is the parent process, pid is the child */
1032  int waitval;
1033  if (pid == -1 || waitpid (pid, &waitval, 0) == -1)
1034  {
1036  }
1037  else
1038  {
1039  dl_decipher_waitval (waitval);
1040  }
1041  }
1042  else
1043  {
1044  /* This is the child process - do the exec */
1045  execv ((char *) argv[0], (char **) &argv[0]);
1047  _exit (1);
1048  }
1049 
1050 end_link_file:
1051  if (extra_options)
1052  free_and_init (extra_options);
1053  if (option_vec)
1054  free_and_init (option_vec);
1055  free_and_init (argv);
1056 
1057  return dl_Errno;
1058 }
1059 #endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
1060 
1061 
1062 #if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
1063 /*
1064  * dl_load_object_image()
1065  * return: Zero on success, non-zero on failure
1066  * load_point(out): buffer to receive object image
1067  * image_file(in): image file name
1068  */
1069 static int
1070 dl_load_object_image (caddr_t load_point, const char *image_file)
1071 {
1072  struct exec hdr;
1073  size_t size = 0;
1074 
1075  int fd = OPEN (image_file, O_RDONLY);
1076 
1077  dl_Errno = NO_ERROR;
1078 
1079  if (fd == -1)
1080  {
1081  DL_SET_ERROR_SYSTEM_FILENAME (image_file);
1082  goto cleanup;
1083  }
1084 
1085  if (read (fd, (char *) &hdr, sizeof (hdr)) != sizeof (hdr))
1086  {
1087  DL_SET_ERROR_SYSTEM_FILENAME (image_file);
1088  goto cleanup;
1089  }
1090 
1091  if (N_BADMAG (hdr))
1092  {
1094  goto cleanup;
1095  }
1096 
1097  if (lseek (fd, N_TXTOFF (hdr), 0) == -1)
1098  {
1099  DL_SET_ERROR_SYSTEM_FILENAME (image_file);
1100  goto cleanup;
1101  }
1102 
1103  size = hdr.a_text + hdr.a_data;
1104  if (read (fd, load_point, size) != size)
1105  {
1106  DL_SET_ERROR_SYSTEM_FILENAME (image_file);
1107  goto cleanup;
1108  }
1109 
1110 cleanup:
1111 
1112  if (fd != -1)
1113  {
1114  CLOSE (fd);
1115  }
1116 
1117  if (dl_Errno == NO_ERROR)
1118  return NO_ERROR;
1119 
1120  return ER_FAILED;
1121 }
1122 #endif /* ((sun) || (sparc)) && !(SOLARIS) */
1123 
1124 
1125 #if ((defined(sun) || defined(sparc)) && !defined(SOLARIS))
1126 #if defined(DEBUG)
1127 static int
1128 dl_open_pipe (int *fd, int lineno)
1129 {
1130  int result = pipe (fd);
1131  if (dl_Debug)
1132  {
1133  if (result == -1)
1134  {
1135  fprintf (stderr, "%s[%d]: pipe creation failed\n", __FILE__, lineno);
1136  }
1137  else
1138  {
1139  fprintf (stderr, "%s[%d]: pipe created on fds %d and %d\n", __FILE__, lineno, fd[0], fd[1]);
1140  }
1141  }
1142  return result;
1143 }
1144 #endif /* DEBUG */
1145 
1146 static void
1147 dl_set_pipe_handler (void)
1148 {
1149  void (*old_handler) () = signal (SIGPIPE, SIG_IGN);
1150 
1151  if (old_handler != SIG_DFL && old_handler != SIG_IGN)
1152  {
1153  signal (SIGPIPE, old_handler); /* restore old handler */
1154  }
1155 }
1156 
1157 /*
1158  * dl_spawn_daemon() - Forks a separate process that waits around to clean up
1159  * any tmpfiles that we fail to close(because we abort, for example)
1160  */
1161 static void
1163 {
1164  int fd[2];
1165  int daemon_pid;
1166 
1167  assert (this_ != NULL);
1168 
1169  if (this_->daemon.daemon_fd != DAEMON_NOT_SPAWNED)
1170  {
1171  return;
1172  }
1173 
1174  if (PIPE (fd) == -1)
1175  { /* pipe creation failed */
1178  return;
1179  }
1180 
1181  if (dl_Debug)
1182  {
1183  fprintf (stderr, "%s[%d]: spawning %s on fds %d and %d\n", __FILE__, __LINE__, this_->daemon.daemon_name, fd[0],
1184  fd[1]);
1185  fflush (stderr);
1186  }
1187 
1188  daemon_pid = (*this_->fork_function_p) ();
1189  if (daemon_pid)
1190  {
1191  /* This is the parent process. */
1192  if (daemon_pid == -1)
1193  {
1195  CLOSE (fd[0]);
1196  CLOSE (fd[1]);
1198  return;
1199  }
1201  CLOSE (fd[0]);
1202  this_->daemon.daemon_fd = fd[1]; /* write side of the pipe */
1203  }
1204  else
1205  {
1206  /* This is the child process. */
1207  int i;
1208  if (dup2 (fd[0], 0) == -1) /* read side of the pipe */
1209  {
1210  _exit (1);
1211  }
1212  for (i = 1; i < NOFILE; ++i)
1213  {
1214  close (i); /* Close all file descriptors except stdin */
1215  }
1216  execl (this_->daemon.daemon_name, (char *) 0);
1217  _exit (1);
1218  }
1219 }
1220 
1221 /*
1222  * dl_notify_daemon() - Let the daemon know that we have let loose of
1223  * the current tmpfile and are now using a new one.
1224  */
1225 static void
1227 {
1228  int num_chars;
1229 
1230  assert (this_ != NULL);
1231 
1232  num_chars = strlen (this_->image_file) + 1; /* include null */
1233 
1234  if (this_->daemon.daemon_fd == DAEMON_NOT_SPAWNED)
1235  {
1236  /* Start a daemon if we haven't tried already. */
1237  dl_spawn_daemon (this_);
1238  }
1239 
1240  if (this_->daemon.daemon_fd >= 0)
1241  {
1242  if (write (this_->daemon.daemon_fd, this_->image_file, num_chars) != num_chars)
1243  {
1244  if (dl_Debug)
1245  {
1247  }
1249  }
1250  }
1251 }
1252 
1253 /*
1254  * dl_set_new_image_file()
1255  * return: none
1256  * this_(in): DYNAMIC_LOADER * structure pointer
1257  * new_image(in): Short description of the param3
1258  */
1259 static void
1260 dl_set_new_image_file (DYNAMIC_LOADER * this_, const char *new_image)
1261 {
1262  if (!this_->virgin)
1263  {
1264  (void) unlink (this_->image_file); /* temporary old one */
1265  }
1266 
1267  /* don't use free_and_init(), it came from exec_path() */
1268  free ((char *) this_->image_file);
1269 
1270  this_->image_file = new_image;
1271  this_->virgin = false;
1272 
1273  dl_notify_daemon (this_);
1274 }
1275 
1276 /*
1277  * dl_set_new_load_points() - Add new load point
1278  * return: Zero on success, non-zero on failure
1279  * this_(in): DYNAMIC_LOADER structure pointer
1280  * load_point(in): load point to be added
1281  */
1282 static int
1283 dl_set_new_load_points (DYNAMIC_LOADER * this_, const caddr_t load_point)
1284 {
1285  caddr_t *new_load_points;
1286 
1287  if (this_->loader.ptr)
1288  {
1289  new_load_points = (caddr_t *) realloc (this_->loader.ptr, (this_->loader.num + 1) * sizeof (caddr_t));
1290  }
1291  else
1292  {
1293  new_load_points = (caddr_t *) malloc (sizeof (caddr_t));
1294  }
1295 
1296  if (new_load_points)
1297  {
1298  this_->loader.ptr = new_load_points;
1299  this_->loader.ptr[this_->loader.num++] = load_point;
1300  }
1301  else
1302  {
1304  return ER_FAILED;
1305  }
1306 }
1307 #endif /* ((sun || sparc) && !SOLARIS) || _AIX */
1308 
1309 /*
1310  * dl_record_files() - Record the names of the files that we have loaded.
1311  * this_(in): DYNAMIC_LOADER * structure pointer
1312  */
1313 static void
1315 {
1316  int i;
1317 
1318  for (i = 0; i < this_->candidates.num; ++i)
1319  {
1320  FILE_ENTRY *fe = &this_->candidates.entries[i];
1321  if (fe->valid && !fe->archive && !fe->duplicate)
1322  {
1323  TBL_LINK *tl;
1324  int index = hashpjw (fe->filename) % FNAME_TBL_SIZE;
1325 
1326  tl = (TBL_LINK *) malloc (sizeof (TBL_LINK));
1327  if (tl)
1328  {
1329  tl->filename = fe->filename;
1330  tl->link = this_->loaded[index];
1331  this_->loaded[index] = tl;
1332  }
1333  else
1334  {
1335  fe->valid = false;
1336  }
1337  }
1338  }
1339 }
1340 
1341 static int
1343 {
1344 #if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
1345  return 1;
1346 #else /* SOLARIS || HPUX || LINUX || AIX */
1347  assert (this_ != NULL);
1348  return this_->image_file != NULL;
1349 #endif /* SOLARIS || HPUX || LINUX || AIX */
1350 }
1351 
1352 
1353 #if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
1354 /*
1355  * dl_load_objects() - Validate and load object files
1356  * return: Zero on success, non-zero on failure
1357  * this_(in): DYNAMIC_LOADER structure pointer
1358  * actual(out): pointer to receive information
1359  * obj_files(in): array of object file names
1360  * libs(in): array of library
1361  * estimate(in): fudge factor for modifying estimate of size required
1362  * to load files
1363  * mode(in) : if mode == DL_RELATIVE, estimated_size is an extra value to be
1364  * added to the loader's estimate;
1365  * if mode == DL_ABSOLUTE, estimated_size is used as the estimate.
1366  */
1367 static int
1368 dl_load_objects (DYNAMIC_LOADER * this_, size_t * actual, const char **obj_files, const char **libs,
1369  const size_t estimate, enum dl_estimate_mode mode)
1370 {
1371  size_t estimated_size = 0;
1372  size_t actual_size = 0;
1373  caddr_t load_point = NULL, old_load_point = NULL;
1374  const char *tmp_file = NULL;
1375  int first_time = true;
1376  int i;
1377 
1378  dl_Errno = NO_ERROR;
1379 
1380  if (dl_validate_candidates (this_, obj_files) || (this_->num_need_load == 0))
1381  goto cleanup;
1382 
1383  tmp_file = TEMPNAM (NULL, "dynld");
1384  if (tmp_file == NULL)
1385  {
1387  goto cleanup;
1388  }
1389 
1390  if (mode == DL_RELATIVE || (mode == DL_ABSOLUTE && estimate == 0))
1391  {
1392  for (i = 0; i < this_->candidates.num; ++i)
1393  {
1394  if (this_->candidates.entries[i].valid && !this_->candidates.entries[i].duplicate)
1395  {
1396  estimated_size += this_->candidates.entries[i].size;
1397  }
1398  }
1399  }
1400  else
1401  {
1402  estimated_size = estimate;
1403  }
1404 
1405  if (mode == DL_RELATIVE)
1406  {
1407  estimated_size += estimate;
1408  }
1409 
1410  for (first_time = true;; first_time = false)
1411  {
1412  /* allocate > link > check estimated size > free the space and try again. */
1413  load_point = VALLOC (estimated_size);
1414  if (load_point == NULL)
1415  {
1417  goto cleanup;
1418  }
1419 
1420  if (load_point != old_load_point)
1421  {
1422  if (dl_link_file (tmp_file, load_point, libs == NULL ? dl_Default_libs : libs))
1423  goto cleanup;
1424  actual_size = dl_get_image_file_size (tmp_file);
1425  if (actual_size == -1)
1426  goto cleanup;
1427  if (first_time && actual)
1428  {
1429  if (mode == DL_RELATIVE)
1430  {
1431  *actual = actual_size - estimated_size;
1432  }
1433  else
1434  {
1435  *actual = actual_size;
1436  }
1437  }
1438  }
1439 
1440  if (estimated_size >= actual_size)
1441  {
1442  break;
1443  }
1444 
1445  estimated_size = actual_size; /* update the estimate and try again. */
1446  old_load_point = load_point;
1447 
1448  free (load_point); /* don't use free_and_init, they come from VALLOC() */
1449  }
1450 
1451  if (dl_load_object_image (load_point, tmp_file))
1452  goto cleanup;
1453 
1454  if (mprotect (load_point, actual_size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) /* Add all permissions to this
1455  * new chunk of memory */
1456  {
1458  goto cleanup;
1459  }
1460 
1461  dl_set_new_image_file (this_, tmp_file);
1462  tmp_file = NULL;
1463 
1464  if (dl_set_new_load_points (this_, load_point))
1465  goto cleanup;
1466 
1467  dl_record_files (this_);
1468 
1469 cleanup:
1470 
1471  if (dl_Errno)
1472  {
1473  for (i = 0; i < this_->candidates.num; ++i)
1474  {
1475  this_->candidates.entries[i].valid = false;
1476  }
1477 
1478  if (load_point)
1479  free (load_point); /* don't use free_and_init, they come from VALLOC() */
1480 
1481  if (tmp_file)
1482  {
1483  int rc;
1484  int max_retry = 0;
1485 
1486  while (((rc = unlink (tmp_file)) != 0) && (max_retry < MAX_UNLINK_RETRY))
1487  {
1488  if (rc < 0)
1489  {
1490  if (dl_Debug)
1491  {
1492  fprintf (stderr, "%s[%d]: retrying unlink: errno = %d\n", __FILE__, __LINE__, errno);
1493  }
1494  max_retry++;
1495  (void) sleep (3);
1496  continue;
1497  }
1498  }
1499 
1500  if (dl_Debug)
1501  {
1502  if (max_retry < MAX_UNLINK_RETRY)
1503  {
1504  fprintf (stderr, "%s[%d]: successful unlink: %s\n", __FILE__, __LINE__, tmp_file);
1505  }
1506  else
1507  {
1508  fprintf (stderr, "%s[%d]: hit retry max for unlink: %s\n", __FILE__, __LINE__, tmp_file);
1509  }
1510  }
1511 
1512  /*
1513  * Don't use free_and_init on tmp_file; it came to us via tempnam().
1514  */
1515  free ((char *) tmp_file);
1516  }
1517  }
1518 
1519  dl_destroy_candidates (this_);
1520 
1521  if (dl_Errno == NO_ERROR)
1522  return NO_ERROR;
1523 
1524  return ER_FAILED;
1525 }
1526 
1527 #elif defined(SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
1528 /*
1529  * dl_load_objects() - Validate and load object files
1530  * return: Zero on success, non-zero on failure
1531  * this_(in): DYNAMIC_LOADER * structure pointer
1532  * obj_files(in): array of object file names
1533  */
1534 static int
1535 dl_load_objects (DYNAMIC_LOADER * this_, const char **obj_files)
1536 {
1537  int i;
1538 
1539  dl_Errno = NO_ERROR;
1540 
1541  if (dl_validate_candidates (this_, obj_files) || (this_->num_need_load == 0))
1542  {
1543  /* validation failed or All of the candidates were already loaded */
1544  goto cleanup;
1545  }
1546 
1547  for (i = 0; i < this_->candidates.num; i++)
1548  {
1549  if (!this_->candidates.entries[i].duplicate)
1550  {
1551  if (dl_Debug)
1552  {
1553  fprintf (stderr, "Opening file: %s as handle: %d\n", obj_files[i], this_->handler.top);
1554  }
1555 
1556  /* first see if we need to extend the handle array */
1557  if (this_->handler.top == this_->handler.num)
1558  {
1559  int new_handles_num;
1560  void **new_handles;
1561 
1562  new_handles_num = this_->handler.num + HANDLES_PER_EXTENT;
1563  if (dl_Debug)
1564  {
1565  fprintf (stderr, "Extending handle arrary to %d handles\n", new_handles_num);
1566  }
1567  new_handles = (void **) malloc (new_handles_num * sizeof (void *));
1568  if (new_handles == NULL)
1569  {
1571  "Memory allocation failed for handle extension");
1572  dl_Errno = ER_FAILED;
1573  goto cleanup;
1574  }
1575  memcpy (new_handles, this_->handler.handles, (this_->handler.num * sizeof (void *)));
1576  free_and_init (this_->handler.handles);
1577  this_->handler.handles = new_handles;
1578  this_->handler.num = new_handles_num;
1579  }
1580 
1581 #if defined(HPUX)
1582  this_->handler.handles[this_->handler.top] =
1583  (void *) shl_load (obj_files[i], BIND_IMMEDIATE | BIND_NONFATAL, 0);
1584 #else /* HPUX */
1585  this_->handler.handles[this_->handler.top] = dlopen (obj_files[i], RTLD_LAZY);
1586 #endif /* HPUX */
1587  if (this_->handler.handles[this_->handler.top] == NULL)
1588  {
1589 #if defined(HPUX)
1590  char dl_msg[1024];
1591  sprintf (dl_msg, "Error shl_load'ing file: %s, with error code: %d", obj_files[i], errno);
1592  if (dl_Debug)
1593  {
1594  fprintf (stderr, "%s\n", dl_msg);
1595  }
1596 #else /* HPUX */
1597  char *dl_msg;
1598  dl_msg = dlerror ();
1599  if (dl_Debug)
1600  {
1601  fprintf (stderr, "Error opening file: %s, with error \"%s\"\n", obj_files[i], dl_msg);
1602  }
1603 #endif /* HPUX */
1605  dl_Errno = ER_FAILED;
1606  goto cleanup;
1607  }
1608  else
1609  {
1610  if (dl_Debug)
1611  {
1612  fprintf (stderr, "dl_open for handle: %d succeeded, value = %p\n", this_->handler.top,
1613  this_->handler.handles[this_->handler.top]);
1614  }
1615  this_->handler.top++;
1616  }
1617  }
1618  }
1619 
1620  dl_record_files (this_); /* Record the names of the files that we have loaded, so that we don't ever load them
1621  * again. */
1622 
1623 cleanup:
1624 
1625  if (dl_Errno)
1626  {
1627  for (i = 0; i < this_->candidates.num; ++i)
1628  {
1629  this_->candidates.entries[i].valid = false; /* to free filename */
1630  }
1631  }
1632 
1633  dl_destroy_candidates (this_);
1634 
1635  if (dl_Errno == NO_ERROR)
1636  return NO_ERROR;
1637 
1638  return ER_FAILED;
1639 }
1640 #endif /* (SOLARIS) || (HPUX) || (LINUX) || (AIX) */
1641 
1642 /*
1643  * dl_resolve_symbol() - obtain the address of a symbol from a object
1644  * return: Zero on success, non-zero on failure
1645  * this_(in): DYNAMIC_LOADER * structure pointer
1646  * syms(in): symbols to resolve
1647  */
1648 static int
1649 dl_resolve_symbol (DYNAMIC_LOADER * this_, struct nlist *syms)
1650 {
1651 #if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
1652 
1653 #if defined(HPUX)
1654 #define SYMS_NTYPE_NULL ST_NULL
1655 #define SYMS_NTYPE_ENTRY ST_ENTRY
1656 #else /* HPUX */ /* LINUX code is same with SOLARIS */
1657 #define SYMS_NTYPE_NULL N_UNDF
1658 #define SYMS_NTYPE_ENTRY (N_TEXT | N_EXT)
1659 #endif
1660 
1661  int i, j, num_resolutions;
1662  void *resolution;
1663 
1664  for (i = 0; syms[i].n_name != NULL; i++)
1665  {
1666  syms[i].n_type = SYMS_NTYPE_NULL;
1667 
1668  if (dl_Debug)
1669  {
1670  fprintf (stderr, "Resolving symbol: %s\n", syms[i].n_name);
1671  }
1672 
1673  for (j = 0, num_resolutions = 0; j < this_->handler.top; j++)
1674  {
1675  if (dl_Debug)
1676  {
1677  fprintf (stderr, "resolving symbols with handle: %d, value = %p\n", j, this_->handler.handles[j]);
1678  }
1679 #if defined(HPUX)
1680  if (shl_findsym ((shl_t *) (&this_->handler.handles[j]), syms[i].n_name, TYPE_PROCEDURE, &resolution) ==
1681  NO_ERROR)
1682 #else /* HPUX */
1683  if ((resolution = dlsym (this_->handler.handles[j], syms[i].n_name)))
1684 #endif
1685  {
1686  num_resolutions++;
1687  syms[i].n_value = (long) resolution; /* TODO: consider: LP64 */
1688  syms[i].n_type = SYMS_NTYPE_ENTRY;
1689  }
1690  else if (dl_Debug)
1691  {
1692  fprintf (stderr, "Error resolving: %s, from handle: %d: Error code %d\n", syms[i].n_name, j, errno);
1693  }
1694 
1695  }
1696 
1697  if (dl_Debug)
1698  {
1699  fprintf (stderr, "Number of resolutions found for symbol: %s is: %d\n", syms[i].n_name, num_resolutions);
1700  }
1701 
1702  if (num_resolutions > 1)
1703  {
1704  /* set an error and return */
1706  syms[i].n_type = SYMS_NTYPE_NULL;
1707  return -1;
1708  }
1709  }
1710 
1711  return NO_ERROR;
1712 #else /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
1713  return nlist ((char *) this_->image_file, syms);
1714 #endif /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
1715 }
1716 
1717 /*
1718  * dl_initiate_module() - initialize the dynamic loader
1719  * return: Zero on success, non-zero on failure.
1720  * module_name(in): name of the file whose symbol table should be used
1721  * as the starting point for dynamic loading
1722  */
1723 #if !defined (SOLARIS) && !defined(LINUX) && !defined(AIX)
1724 int
1725 dl_initiate_module (const char *module_name)
1726 #else /* !(SOLARIS) && !(LINUX) && !(AIX) */
1727 int
1728 dl_initiate_module (void)
1729 #endif /* !(SOLARIS) && !(LINUX) && !(AIX) */
1730 {
1731  const char *image_name = NULL;
1732 
1733  if (dl_Loader)
1734  {
1736  return ER_FAILED;
1737  }
1738 
1739 #if !defined (SOLARIS) && !defined(LINUX) && !defined(AIX)
1740  image_name = exec_path (module_name);
1741  if (image_name == NULL)
1742  {
1744  return ER_FAILED;
1745  }
1746 #endif /* !SOLARIS && !LINUX && !AIX */
1747 
1748  dl_Debug = (getenv ("DL_DEBUG") != NULL);
1749 
1750  dl_Loader = (DYNAMIC_LOADER *) malloc (sizeof (DYNAMIC_LOADER));
1751  if (dl_Loader == NULL)
1752  {
1754  return ER_FAILED;
1755  }
1756 
1757  if (dl_initiate_dynamic_loader (dl_Loader, image_name))
1758  {
1759  return ER_FAILED;
1760  }
1761 
1762  if (!dl_is_valid_image_file (dl_Loader))
1763  {
1765  return ER_FAILED;
1766  }
1767 
1768  return NO_ERROR;
1769 }
1770 
1771 /*
1772  * dl_destroy_module() - ear down the dynamic loader
1773  * return: Zero on success, non-zero on failure.
1774  */
1775 int
1777 {
1778  dl_Errno = NO_ERROR;
1779 
1780  if (dl_Loader == NULL)
1781  {
1783  return ER_FAILED;
1784  }
1785 
1786  if (!dl_is_valid_image_file (dl_Loader))
1787  {
1789  return ER_FAILED;
1790  }
1791 
1792  dl_destroy_dynamic_loader (dl_Loader);
1793 
1794  free_and_init (dl_Loader);
1795  dl_Debug = false;
1796 
1797  return dl_Errno;
1798 }
1799 
1800 #if defined(sun) || defined(sparc) || defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
1801 /*
1802  * dl_load_object_module() - loads the named files
1803  * return: Zero on success, non-zero on failure.
1804  * obj_files(in): array of filenames to be loaded
1805  * msgp(in): not used
1806  * libs(in): array of arguments to be passed to ld
1807  *
1808  * Note: If you feel the need
1809  */
1810 #if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
1811 int
1812 dl_load_object_module (const char **obj_files, const char **msgp)
1813 #else /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
1814 int
1815 dl_load_object_module (const char **obj_files, const char **msgp, const char **libs)
1816 #endif /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
1817 {
1818  dl_Errno = NO_ERROR;
1819 
1820  if (msgp)
1821  {
1822  *msgp = "obsolete interface; use standard error interface instead";
1823  }
1824 
1825  if (dl_Loader == NULL)
1826  {
1828  return ER_FAILED;
1829  }
1830 
1831  if (!dl_is_valid_image_file (dl_Loader))
1832  {
1834  return ER_FAILED;
1835  }
1836 #if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
1837  return dl_load_objects (dl_Loader, obj_files);
1838 #else /* HPUX */
1839  return dl_load_objects (dl_Loader, obj_files, libs, 0, NULL, DL_RELATIVE);
1840 #endif /* HPUX */
1841 }
1842 
1843 /*
1844  * dl_resolve_object_symbol() - obtain the address of a symbol from a object
1845  * return: Zero on success, non-zero on failure
1846  * syms(in): symbols to resolve
1847  *
1848  * Note: For each entry in syms, if the named symbol is present in the
1849  * process's current symbol table, its value and type are placed
1850  * in the n_value and n_type fields.
1851  */
1852 int
1853 dl_resolve_object_symbol (struct nlist *syms)
1854 {
1855  if (dl_Loader == NULL)
1856  {
1858  return ER_FAILED;
1859  }
1860 
1861  if (!dl_is_valid_image_file (dl_Loader))
1862  {
1864  return ER_FAILED;
1865  }
1866 
1867  return dl_resolve_symbol (dl_Loader, syms);
1868 }
1869 
1870 #if defined (ENABLE_UNUSED_FUNCTION)
1871 /*
1872  * dl_load_object_with_estimate() - run dl_load_object_module and accepts extra
1873  * information to try to refine size estimates for loading the files
1874  * return: Zero on success, non-zero on failure
1875  * actual_size(out): pointer to receive information
1876  * obj_files(in): array of object file names
1877  * libs(in): array of arguments to be passed to ld
1878  * msgp(in): not used
1879  * estimated_size(in): fudge factor for modifying estimate of size required
1880  * to load files
1881  * mode(in) : if mode == DL_RELATIVE, estimated_size is an extra value to be
1882  * added to the loader's estimate;
1883  * if mode == DL_ABSOLUTE, estimated_size is used as the estimate.
1884  */
1885 #if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
1886 int
1887 dl_load_object_with_estimate (const char **obj_files, const char **msgp)
1888 #elif (defined(sun) || defined(sparc)) && !defined(SOLARIS)
1889 int
1890 dl_load_object_with_estimate (size_t * actual_size, const char **obj_files, const char **msgp, const char **libs,
1891  const size_t estimated_size, enum dl_estimate_mode mode)
1892 #endif /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
1893 {
1894  dl_Errno = NO_ERROR;
1895 
1896  if (msgp)
1897  {
1898  *msgp = "obsolete interface; use standard error interface instead";
1899  }
1900 
1901  if (dl_Loader == NULL)
1902  {
1904  return ER_FAILED;
1905  }
1906 
1907  if (!dl_is_valid_image_file (dl_Loader))
1908  {
1910  return ER_FAILED;
1911  }
1912 #if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
1913  return dl_load_objects (dl_Loader, obj_files);
1914 #else /* HPUX || SOLARIS || LINUX || AIX */
1915  return dl_load_objects (dl_Loader, obj_files, libs, estimated_size, actual_size, mode);
1916 #endif /* HPUX || SOLARIS || LINUX || AIX */
1917 }
1918 #endif /* ENABLE_UNUSED_FUNCTION */
1919 #endif
caddr_t * ptr
Definition: dynamic_load.c:182
bool duplicate
Definition: dynamic_load.c:146
#define ER_DL_MULTIPLY_DEFINED
Definition: error_code.h:719
char daemon_name[PATH_MAX]
Definition: dynamic_load.c:166
#define NO_ERROR
Definition: error_code.h:46
#define FORK
Definition: dynamic_load.c:97
static char * dl_get_temporary_name(const char *dir, const char *prefix, int lineno)
static int dl_initiate_dynamic_loader(DYNAMIC_LOADER *, const char *)
Definition: dynamic_load.c:541
int dl_destroy_module(void)
static void dl_set_new_image_file(DYNAMIC_LOADER *, const char *)
static int dl_close_object_file(int fd, int lineno)
Definition: dynamic_load.c:335
int argc
Definition: dynamic_load.c:951
struct dynamic_loader::@6 loader
#define ER_FAILED
Definition: error_code.h:47
int num_options
Definition: dynamic_load.c:950
static const int DAEMON_NOT_AVAILABLE
Definition: dynamic_load.c:208
size_t size
Definition: dynamic_load.c:147
static int dl_set_new_load_points(DYNAMIC_LOADER *this_, const caddr_t)
char * extra_options
Definition: dynamic_load.c:948
#define ER_DL_LOAD_ERR
Definition: error_code.h:718
bool valid
Definition: dynamic_load.c:144
static int dl_load_object_image(caddr_t, const char *)
void(* FUNCTION_POINTER_TYPE)(void)
Definition: dynamic_load.c:130
static void dl_destroy_candidates(DYNAMIC_LOADER *)
Definition: dynamic_load.c:403
static void dl_set_pipe_handler(void)
const char ** option_vec
Definition: dynamic_load.c:949
char load_point_buf[16]
Definition: dynamic_load.c:953
#define ER_DL_DAEMON_DISAPPEARED
Definition: error_code.h:467
const char * cmd
Definition: dynamic_load.c:180
static DYNAMIC_LOADER * dl_Loader
Definition: dynamic_load.c:192
struct dynamic_loader::@5 daemon
#define OPEN(fn, m)
Definition: dynamic_load.c:75
static const int MAX_UNLINK_RETRY
Definition: dynamic_load.c:205
static int dl_Debug
Definition: dynamic_load.c:195
unsigned int hashpjw(const char *s)
Definition: util_func.c:83
static int dl_open_pipe(int *fd, int lineno)
static void dl_destroy_dynamic_loader(DYNAMIC_LOADER *)
Definition: dynamic_load.c:620
#define PIPE(fd)
Definition: dynamic_load.c:77
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
static const char ** dl_parse_extra_options(int *num_options, char *option_string)
Definition: dynamic_load.c:887
#define assert(x)
pid_t(* fork_function_p)()
Definition: dynamic_load.c:160
Definition: dynamic_load.c:141
TBL_LINK * loaded[FNAME_TBL_SIZE]
Definition: dynamic_load.c:159
#define ER_DL_INVALID
Definition: error_code.h:456
static void dl_spawn_daemon(DYNAMIC_LOADER *)
static void dl_find_daemon(DYNAMIC_LOADER *)
Definition: dynamic_load.c:849
static const int HANDLES_PER_EXTENT
Definition: dynamic_load.c:213
static enum scanner_mode mode
#define ER_DL_DAEMON_MISSING
Definition: error_code.h:466
char * envvar_bindir_file(char *path, size_t size, const char *filename)
#define DL_SET_ERROR_WITH_CODE_ONE_ARG(code, arg)
Definition: dynamic_load.c:107
static void dl_notify_daemon(DYNAMIC_LOADER *)
static void cleanup(int signo)
Definition: broker.c:717
const char ** argvp
Definition: dynamic_load.c:952
#define NULL
Definition: freelistheap.h:34
static const char * dl_get_system_error_message(int n)
Definition: dynamic_load.c:269
dl_estimate_mode
Definition: dynamic_load.h:75
pid_t pid
Definition: dynamic_load.c:955
static const int DAEMON_NOT_SPAWNED
Definition: dynamic_load.c:207
static void dl_decipher_waitval(int waitval)
Definition: dynamic_load.c:353
#define ER_DL_EXISTS
Definition: error_code.h:454
static int dl_resolve_symbol(DYNAMIC_LOADER *, struct nlist *)
bool archive
Definition: dynamic_load.c:145
static const char DAEMON_NAME[]
Definition: dynamic_load.c:210
int dl_Errno
Definition: dynamic_load.c:189
#define CLOSE(fd)
Definition: dynamic_load.c:76
#define ER_DL_IMAGE
Definition: error_code.h:462
#define ER_DL_BADHDR
Definition: error_code.h:457
static int dl_open_object_file(const char *filename, int mode, int lineno)
Definition: dynamic_load.c:309
static int rc
Definition: serial.c:50
char * filename
Definition: dynamic_load.c:143
#define ER_DL_LDWAIT
Definition: error_code.h:461
#define ARG_FILE_LINE
Definition: error_manager.h:44
int dl_initiate_module(const char *module_name)
static int dl_validate_candidates(DYNAMIC_LOADER *, const char **)
Definition: dynamic_load.c:689
static int dl_validate_file_entry(FILE_ENTRY *, const char *)
Definition: dynamic_load.c:440
const char * image_file
Definition: dynamic_load.c:186
static int dl_is_valid_image_file(DYNAMIC_LOADER *)
struct dynamic_loader::@4 candidates
int nlist(char *, struct nlist *)
const char ** argv
Definition: dynamic_load.c:952
#define ER_DL_PATH
Definition: error_code.h:458
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define strlen(s1)
Definition: intl_support.c:43
char * prm_get_string_value(PARAM_ID prm_id)
#define DL_SET_ERROR_SYSTEM_MSG()
Definition: dynamic_load.c:114
#define ER_DL_LDTERM
Definition: error_code.h:460
FILE_ENTRY * entries
Definition: dynamic_load.c:155
int i
Definition: dynamic_load.c:954
#define DL_SET_ERROR_WITH_CODE(code)
Definition: dynamic_load.c:101
#define TEMPNAM(d, p)
Definition: dynamic_load.c:74
char * strdup(const char *str)
Definition: porting.c:901
_exit(1)
static void dl_record_files(DYNAMIC_LOADER *)
#define FNAME_TBL_SIZE
Definition: dynamic_load.c:70
#define DL_SET_ERROR_SYSTEM_FILENAME(fn)
Definition: dynamic_load.c:121
#define ER_DL_LDEXIT
Definition: error_code.h:459
const char ** p
Definition: dynamic_load.c:945
#define ER_DL_ABSENT
Definition: error_code.h:455