00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "ruby.h"
00014 #include "dln.h"
00015
00016 #ifdef HAVE_STDLIB_H
00017 # include <stdlib.h>
00018 #endif
00019
00020 #ifdef __CHECKER__
00021 #undef HAVE_DLOPEN
00022 #undef USE_DLN_A_OUT
00023 #undef USE_DLN_DLOPEN
00024 #endif
00025
00026 #ifdef USE_DLN_A_OUT
00027 char *dln_argv0;
00028 #endif
00029
00030 #ifdef _AIX
00031 #pragma alloca
00032 #endif
00033
00034 #if defined(HAVE_ALLOCA_H)
00035 #include <alloca.h>
00036 #endif
00037
00038 #ifdef HAVE_STRING_H
00039 # include <string.h>
00040 #else
00041 # include <strings.h>
00042 #endif
00043
00044 #ifndef xmalloc
00045 void *xmalloc();
00046 void *xcalloc();
00047 void *xrealloc();
00048 #endif
00049
00050 #include <stdio.h>
00051 #if defined(_WIN32) || defined(__VMS)
00052 #include "missing/file.h"
00053 #endif
00054 #include <sys/types.h>
00055 #include <sys/stat.h>
00056
00057 #ifndef S_ISDIR
00058 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
00059 #endif
00060
00061 #ifdef HAVE_SYS_PARAM_H
00062 # include <sys/param.h>
00063 #endif
00064 #ifndef MAXPATHLEN
00065 # define MAXPATHLEN 1024
00066 #endif
00067
00068 #ifdef HAVE_UNISTD_H
00069 # include <unistd.h>
00070 #endif
00071
00072 #ifndef _WIN32
00073 char *getenv();
00074 #endif
00075
00076 #if defined(__VMS)
00077 #pragma builtins
00078 #include <dlfcn.h>
00079 #endif
00080
00081 #ifdef __MACOS__
00082 # include <TextUtils.h>
00083 # include <CodeFragments.h>
00084 # include <Aliases.h>
00085 # include "macruby_private.h"
00086 #endif
00087
00088 #ifdef __BEOS__
00089 # include <image.h>
00090 #endif
00091
00092 int eaccess();
00093
00094 #ifndef NO_DLN_LOAD
00095
00096 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(__APPLE__) && !defined(_UNICOSMP)
00097
00098 # define USE_DLN_DLOPEN
00099 #endif
00100
00101 #ifndef FUNCNAME_PATTERN
00102 # if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__)
00103 # define FUNCNAME_PATTERN "_Init_%s"
00104 # else
00105 # define FUNCNAME_PATTERN "Init_%s"
00106 # endif
00107 #endif
00108
00109 static int
00110 init_funcname_len(buf, file)
00111 char **buf;
00112 const char *file;
00113 {
00114 char *p;
00115 const char *slash;
00116 int len;
00117
00118
00119 for (slash = file-1; *file; file++)
00120 #ifdef __MACOS__
00121 if (*file == ':') slash = file;
00122 #else
00123 if (*file == '/') slash = file;
00124 #endif
00125
00126 len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1);
00127 *buf = xmalloc(len);
00128 snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1);
00129 for (p = *buf; *p; p++) {
00130 if (*p == '.') {
00131 *p = '\0'; break;
00132 }
00133 }
00134 return p - *buf;
00135 }
00136
00137 #define init_funcname(buf, file) do {\
00138 int len = init_funcname_len(buf, file);\
00139 char *tmp = ALLOCA_N(char, len+1);\
00140 if (!tmp) {\
00141 free(*buf);\
00142 rb_memerror();\
00143 }\
00144 strcpy(tmp, *buf);\
00145 free(*buf);\
00146 *buf = tmp;\
00147 } while (0)
00148
00149 #ifdef USE_DLN_A_OUT
00150
00151 #ifndef LIBC_NAME
00152 # define LIBC_NAME "libc.a"
00153 #endif
00154
00155 #ifndef DLN_DEFAULT_LIB_PATH
00156 # define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
00157 #endif
00158
00159 #include <errno.h>
00160
00161 static int dln_errno;
00162
00163 #define DLN_ENOEXEC ENOEXEC
00164 #define DLN_ECONFL 1201
00165 #define DLN_ENOINIT 1202
00166 #define DLN_EUNDEF 1203
00167 #define DLN_ENOTLIB 1204
00168 #define DLN_EBADLIB 1205
00169 #define DLN_EINIT 1206
00170
00171 static int dln_init_p = 0;
00172
00173 #include <ar.h>
00174 #include <a.out.h>
00175 #ifndef N_COMM
00176 # define N_COMM 0x12
00177 #endif
00178 #ifndef N_MAGIC
00179 # define N_MAGIC(x) (x).a_magic
00180 #endif
00181
00182 #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
00183
00184 #include "util.h"
00185 #include "st.h"
00186
00187 static st_table *sym_tbl;
00188 static st_table *undef_tbl;
00189
00190 static int load_lib();
00191
00192 static int
00193 load_header(fd, hdrp, disp)
00194 int fd;
00195 struct exec *hdrp;
00196 long disp;
00197 {
00198 int size;
00199
00200 lseek(fd, disp, 0);
00201 size = read(fd, hdrp, sizeof(struct exec));
00202 if (size == -1) {
00203 dln_errno = errno;
00204 return -1;
00205 }
00206 if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
00207 dln_errno = DLN_ENOEXEC;
00208 return -1;
00209 }
00210 return 0;
00211 }
00212
00213 #if defined(sequent)
00214 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
00215 #define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr)
00216 #define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr)
00217 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
00218 #endif
00219
00220
00221 #ifndef RELOC_ADDRESS
00222 #define RELOC_ADDRESS(r) ((r)->r_address)
00223 #define RELOC_EXTERN_P(r) ((r)->r_extern)
00224 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
00225 #define RELOC_MEMORY_SUB_P(r) 0
00226 #define RELOC_PCREL_P(r) ((r)->r_pcrel)
00227 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
00228 #endif
00229
00230 #if defined(sun) && defined(sparc)
00231
00232 # undef relocation_info
00233 # define relocation_info reloc_info_sparc
00234 # define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type])
00235 # define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type])
00236 # define R_LENGTH(r) (reloc_r_length[(r)->r_type])
00237 static int reloc_r_rightshift[] = {
00238 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
00239 };
00240 static int reloc_r_bitsize[] = {
00241 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
00242 };
00243 static int reloc_r_length[] = {
00244 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
00245 };
00246 # define R_PCREL(r) \
00247 ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
00248 # define R_SYMBOL(r) ((r)->r_index)
00249 #endif
00250
00251 #if defined(sequent)
00252 #define R_SYMBOL(r) ((r)->r_symbolnum)
00253 #define R_MEMORY_SUB(r) ((r)->r_bsr)
00254 #define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr)
00255 #define R_LENGTH(r) ((r)->r_length)
00256 #endif
00257
00258 #ifndef R_SYMBOL
00259 # define R_SYMBOL(r) ((r)->r_symbolnum)
00260 # define R_MEMORY_SUB(r) 0
00261 # define R_PCREL(r) ((r)->r_pcrel)
00262 # define R_LENGTH(r) ((r)->r_length)
00263 #endif
00264
00265 static struct relocation_info *
00266 load_reloc(fd, hdrp, disp)
00267 int fd;
00268 struct exec *hdrp;
00269 long disp;
00270 {
00271 struct relocation_info *reloc;
00272 int size;
00273
00274 lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
00275 size = hdrp->a_trsize + hdrp->a_drsize;
00276 reloc = (struct relocation_info*)xmalloc(size);
00277 if (reloc == NULL) {
00278 dln_errno = errno;
00279 return NULL;
00280 }
00281
00282 if (read(fd, reloc, size) != size) {
00283 dln_errno = errno;
00284 free(reloc);
00285 return NULL;
00286 }
00287
00288 return reloc;
00289 }
00290
00291 static struct nlist *
00292 load_sym(fd, hdrp, disp)
00293 int fd;
00294 struct exec *hdrp;
00295 long disp;
00296 {
00297 struct nlist * buffer;
00298 struct nlist * sym;
00299 struct nlist * end;
00300 long displ;
00301 int size;
00302
00303 lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
00304 if (read(fd, &size, sizeof(int)) != sizeof(int)) {
00305 goto err_noexec;
00306 }
00307
00308 buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
00309 if (buffer == NULL) {
00310 dln_errno = errno;
00311 return NULL;
00312 }
00313
00314 lseek(fd, disp + N_SYMOFF(*hdrp), 0);
00315 if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
00316 free(buffer);
00317 goto err_noexec;
00318 }
00319
00320 sym = buffer;
00321 end = sym + hdrp->a_syms / sizeof(struct nlist);
00322 displ = (long)buffer + (long)(hdrp->a_syms);
00323
00324 while (sym < end) {
00325 sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
00326 sym++;
00327 }
00328 return buffer;
00329
00330 err_noexec:
00331 dln_errno = DLN_ENOEXEC;
00332 return NULL;
00333 }
00334
00335 static st_table *
00336 sym_hash(hdrp, syms)
00337 struct exec *hdrp;
00338 struct nlist *syms;
00339 {
00340 st_table *tbl;
00341 struct nlist *sym = syms;
00342 struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
00343
00344 tbl = st_init_strtable();
00345 if (tbl == NULL) {
00346 dln_errno = errno;
00347 return NULL;
00348 }
00349
00350 while (sym < end) {
00351 st_insert(tbl, sym->n_un.n_name, sym);
00352 sym++;
00353 }
00354 return tbl;
00355 }
00356
00357 static int
00358 dln_init(prog)
00359 const char *prog;
00360 {
00361 char *file;
00362 int fd;
00363 struct exec hdr;
00364 struct nlist *syms;
00365
00366 if (dln_init_p == 1) return 0;
00367
00368 file = dln_find_exe(prog, NULL);
00369 if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
00370 dln_errno = errno;
00371 return -1;
00372 }
00373
00374 if (load_header(fd, &hdr, 0) == -1) return -1;
00375 syms = load_sym(fd, &hdr, 0);
00376 if (syms == NULL) {
00377 close(fd);
00378 return -1;
00379 }
00380 sym_tbl = sym_hash(&hdr, syms);
00381 if (sym_tbl == NULL) {
00382 char c = '\0';
00383 char buf[MAXPATHLEN];
00384 char *p;
00385
00386 free(syms);
00387 lseek(fd, 0L, 0);
00388 if (read(fd, &c, 1) == -1) {
00389 dln_errno = errno;
00390 return -1;
00391 }
00392 if (c != '#') goto err_noexec;
00393 if (read(fd, &c, 1) == -1) {
00394 dln_errno = errno;
00395 return -1;
00396 }
00397 if (c != '!') goto err_noexec;
00398
00399 p = buf;
00400
00401 while (read(fd, &c, 1) == 1) {
00402 if (c == '\n') goto err_noexec;
00403 if (c != '\t' && c != ' ') {
00404 *p++ = c;
00405 break;
00406 }
00407 }
00408
00409 while (read(fd, p, 1) == 1) {
00410 if (*p == '\n' || *p == '\t' || *p == ' ') break;
00411 p++;
00412 if (p-buf >= MAXPATHLEN) {
00413 dln_errno = ENAMETOOLONG;
00414 return -1;
00415 }
00416 }
00417 *p = '\0';
00418
00419 return dln_init(buf);
00420 }
00421 dln_init_p = 1;
00422 undef_tbl = st_init_strtable();
00423 close(fd);
00424 return 0;
00425
00426 err_noexec:
00427 close(fd);
00428 dln_errno = DLN_ENOEXEC;
00429 return -1;
00430 }
00431
00432 static long
00433 load_text_data(fd, hdrp, bss, disp)
00434 int fd;
00435 struct exec *hdrp;
00436 int bss;
00437 long disp;
00438 {
00439 int size;
00440 unsigned char* addr;
00441
00442 lseek(fd, disp + N_TXTOFF(*hdrp), 0);
00443 size = hdrp->a_text + hdrp->a_data;
00444
00445 if (bss == -1) size += hdrp->a_bss;
00446 else if (bss > 1) size += bss;
00447
00448 addr = (unsigned char*)xmalloc(size);
00449 if (addr == NULL) {
00450 dln_errno = errno;
00451 return 0;
00452 }
00453
00454 if (read(fd, addr, size) != size) {
00455 dln_errno = errno;
00456 free(addr);
00457 return 0;
00458 }
00459
00460 if (bss == -1) {
00461 memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
00462 }
00463 else if (bss > 0) {
00464 memset(addr + hdrp->a_text + hdrp->a_data, 0, bss);
00465 }
00466
00467 return (long)addr;
00468 }
00469
00470 static int
00471 undef_print(key, value)
00472 char *key, *value;
00473 {
00474 fprintf(stderr, " %s\n", key);
00475 return ST_CONTINUE;
00476 }
00477
00478 static void
00479 dln_print_undef()
00480 {
00481 fprintf(stderr, " Undefined symbols:\n");
00482 st_foreach(undef_tbl, undef_print, NULL);
00483 }
00484
00485 static void
00486 dln_undefined()
00487 {
00488 if (undef_tbl->num_entries > 0) {
00489 fprintf(stderr, "dln: Calling undefined function\n");
00490 dln_print_undef();
00491 rb_exit(1);
00492 }
00493 }
00494
00495 struct undef {
00496 char *name;
00497 struct relocation_info reloc;
00498 long base;
00499 char *addr;
00500 union {
00501 char c;
00502 short s;
00503 long l;
00504 } u;
00505 };
00506
00507 static st_table *reloc_tbl = NULL;
00508 static void
00509 link_undef(name, base, reloc)
00510 const char *name;
00511 long base;
00512 struct relocation_info *reloc;
00513 {
00514 static int u_no = 0;
00515 struct undef *obj;
00516 char *addr = (char*)(reloc->r_address + base);
00517
00518 obj = (struct undef*)xmalloc(sizeof(struct undef));
00519 obj->name = strdup(name);
00520 obj->reloc = *reloc;
00521 obj->base = base;
00522 switch (R_LENGTH(reloc)) {
00523 case 0:
00524 obj->u.c = *addr;
00525 break;
00526 case 1:
00527 obj->u.s = *(short*)addr;
00528 break;
00529 case 2:
00530 obj->u.l = *(long*)addr;
00531 break;
00532 }
00533 if (reloc_tbl == NULL) {
00534 reloc_tbl = st_init_numtable();
00535 }
00536 st_insert(reloc_tbl, u_no++, obj);
00537 }
00538
00539 struct reloc_arg {
00540 const char *name;
00541 long value;
00542 };
00543
00544 static int
00545 reloc_undef(no, undef, arg)
00546 int no;
00547 struct undef *undef;
00548 struct reloc_arg *arg;
00549 {
00550 int datum;
00551 char *address;
00552 #if defined(sun) && defined(sparc)
00553 unsigned int mask = 0;
00554 #endif
00555
00556 if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
00557 address = (char*)(undef->base + undef->reloc.r_address);
00558 datum = arg->value;
00559
00560 if (R_PCREL(&(undef->reloc))) datum -= undef->base;
00561 #if defined(sun) && defined(sparc)
00562 datum += undef->reloc.r_addend;
00563 datum >>= R_RIGHTSHIFT(&(undef->reloc));
00564 mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
00565 mask |= mask -1;
00566 datum &= mask;
00567 switch (R_LENGTH(&(undef->reloc))) {
00568 case 0:
00569 *address = undef->u.c;
00570 *address &= ~mask;
00571 *address |= datum;
00572 break;
00573 case 1:
00574 *(short *)address = undef->u.s;
00575 *(short *)address &= ~mask;
00576 *(short *)address |= datum;
00577 break;
00578 case 2:
00579 *(long *)address = undef->u.l;
00580 *(long *)address &= ~mask;
00581 *(long *)address |= datum;
00582 break;
00583 }
00584 #else
00585 switch (R_LENGTH(&(undef->reloc))) {
00586 case 0:
00587 if (R_MEMORY_SUB(&(undef->reloc)))
00588 *address = datum - *address;
00589 else *address = undef->u.c + datum;
00590 break;
00591 case 1:
00592 if (R_MEMORY_SUB(&(undef->reloc)))
00593 *(short*)address = datum - *(short*)address;
00594 else *(short*)address = undef->u.s + datum;
00595 break;
00596 case 2:
00597 if (R_MEMORY_SUB(&(undef->reloc)))
00598 *(long*)address = datum - *(long*)address;
00599 else *(long*)address = undef->u.l + datum;
00600 break;
00601 }
00602 #endif
00603 free(undef->name);
00604 free(undef);
00605 return ST_DELETE;
00606 }
00607
00608 static void
00609 unlink_undef(name, value)
00610 const char *name;
00611 long value;
00612 {
00613 struct reloc_arg arg;
00614
00615 arg.name = name;
00616 arg.value = value;
00617 st_foreach(reloc_tbl, reloc_undef, &arg);
00618 }
00619
00620 #ifdef N_INDR
00621 struct indr_data {
00622 char *name0, *name1;
00623 };
00624
00625 static int
00626 reloc_repl(no, undef, data)
00627 int no;
00628 struct undef *undef;
00629 struct indr_data *data;
00630 {
00631 if (strcmp(data->name0, undef->name) == 0) {
00632 free(undef->name);
00633 undef->name = strdup(data->name1);
00634 }
00635 return ST_CONTINUE;
00636 }
00637 #endif
00638
00639 static int
00640 load_1(fd, disp, need_init)
00641 int fd;
00642 long disp;
00643 const char *need_init;
00644 {
00645 static char *libc = LIBC_NAME;
00646 struct exec hdr;
00647 struct relocation_info *reloc = NULL;
00648 long block = 0;
00649 long new_common = 0;
00650 struct nlist *syms = NULL;
00651 struct nlist *sym;
00652 struct nlist *end;
00653 int init_p = 0;
00654
00655 if (load_header(fd, &hdr, disp) == -1) return -1;
00656 if (INVALID_OBJECT(hdr)) {
00657 dln_errno = DLN_ENOEXEC;
00658 return -1;
00659 }
00660 reloc = load_reloc(fd, &hdr, disp);
00661 if (reloc == NULL) return -1;
00662
00663 syms = load_sym(fd, &hdr, disp);
00664 if (syms == NULL) {
00665 free(reloc);
00666 return -1;
00667 }
00668
00669 sym = syms;
00670 end = syms + (hdr.a_syms / sizeof(struct nlist));
00671 while (sym < end) {
00672 struct nlist *old_sym;
00673 int value = sym->n_value;
00674
00675 #ifdef N_INDR
00676 if (sym->n_type == (N_INDR | N_EXT)) {
00677 char *key = sym->n_un.n_name;
00678
00679 if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
00680 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
00681 unlink_undef(key, old_sym->n_value);
00682 free(key);
00683 }
00684 }
00685 else {
00686 struct indr_data data;
00687
00688 data.name0 = sym->n_un.n_name;
00689 data.name1 = sym[1].n_un.n_name;
00690 st_foreach(reloc_tbl, reloc_repl, &data);
00691
00692 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
00693 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
00694 free(key);
00695 }
00696 }
00697 sym += 2;
00698 continue;
00699 }
00700 #endif
00701 if (sym->n_type == (N_UNDF | N_EXT)) {
00702 if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
00703 old_sym = NULL;
00704 }
00705
00706 if (value) {
00707 if (old_sym) {
00708 sym->n_type = N_EXT | N_COMM;
00709 sym->n_value = old_sym->n_value;
00710 }
00711 else {
00712 int rnd =
00713 value >= sizeof(double) ? sizeof(double) - 1
00714 : value >= sizeof(long) ? sizeof(long) - 1
00715 : sizeof(short) - 1;
00716
00717 sym->n_type = N_COMM;
00718 new_common += rnd;
00719 new_common &= ~(long)rnd;
00720 sym->n_value = new_common;
00721 new_common += value;
00722 }
00723 }
00724 else {
00725 if (old_sym) {
00726 sym->n_type = N_EXT | N_COMM;
00727 sym->n_value = old_sym->n_value;
00728 }
00729 else {
00730 sym->n_value = (long)dln_undefined;
00731 st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
00732 }
00733 }
00734 }
00735 sym++;
00736 }
00737
00738 block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
00739 if (block == 0) goto err_exit;
00740
00741 sym = syms;
00742 while (sym < end) {
00743 struct nlist *new_sym;
00744 char *key;
00745
00746 switch (sym->n_type) {
00747 case N_COMM:
00748 sym->n_value += hdr.a_text + hdr.a_data;
00749 case N_TEXT|N_EXT:
00750 case N_DATA|N_EXT:
00751
00752 sym->n_value += block;
00753
00754 if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
00755 && new_sym->n_value != (long)dln_undefined) {
00756 dln_errno = DLN_ECONFL;
00757 goto err_exit;
00758 }
00759
00760 key = sym->n_un.n_name;
00761 if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) {
00762 unlink_undef(key, sym->n_value);
00763 free(key);
00764 }
00765
00766 new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
00767 *new_sym = *sym;
00768 new_sym->n_un.n_name = strdup(sym->n_un.n_name);
00769 st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
00770 break;
00771
00772 case N_TEXT:
00773 case N_DATA:
00774 sym->n_value += block;
00775 break;
00776 }
00777 sym++;
00778 }
00779
00780
00781
00782
00783 {
00784 struct relocation_info * rel = reloc;
00785 struct relocation_info * rel_beg = reloc +
00786 (hdr.a_trsize/sizeof(struct relocation_info));
00787 struct relocation_info * rel_end = reloc +
00788 (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
00789
00790 while (rel < rel_end) {
00791 char *address = (char*)(rel->r_address + block);
00792 long datum = 0;
00793 #if defined(sun) && defined(sparc)
00794 unsigned int mask = 0;
00795 #endif
00796
00797 if(rel >= rel_beg)
00798 address += hdr.a_text;
00799
00800 if (rel->r_extern) {
00801 sym = &(syms[R_SYMBOL(rel)]);
00802 switch (sym->n_type) {
00803 case N_EXT|N_UNDF:
00804 link_undef(sym->n_un.n_name, block, rel);
00805 case N_EXT|N_COMM:
00806 case N_COMM:
00807 datum = sym->n_value;
00808 break;
00809 default:
00810 goto err_exit;
00811 }
00812 }
00813 else {
00814 switch (R_SYMBOL(rel)) {
00815 case N_TEXT:
00816 case N_DATA:
00817 datum = block;
00818 break;
00819 case N_BSS:
00820 datum = block + new_common;
00821 break;
00822 case N_ABS:
00823 break;
00824 }
00825 }
00826 if (R_PCREL(rel)) datum -= block;
00827
00828 #if defined(sun) && defined(sparc)
00829 datum += rel->r_addend;
00830 datum >>= R_RIGHTSHIFT(rel);
00831 mask = (1 << R_BITSIZE(rel)) - 1;
00832 mask |= mask -1;
00833 datum &= mask;
00834
00835 switch (R_LENGTH(rel)) {
00836 case 0:
00837 *address &= ~mask;
00838 *address |= datum;
00839 break;
00840 case 1:
00841 *(short *)address &= ~mask;
00842 *(short *)address |= datum;
00843 break;
00844 case 2:
00845 *(long *)address &= ~mask;
00846 *(long *)address |= datum;
00847 break;
00848 }
00849 #else
00850 switch (R_LENGTH(rel)) {
00851 case 0:
00852 if (datum < -128 || datum > 127) goto err_exit;
00853 *address += datum;
00854 break;
00855 case 1:
00856 *(short *)address += datum;
00857 break;
00858 case 2:
00859 *(long *)address += datum;
00860 break;
00861 }
00862 #endif
00863 rel++;
00864 }
00865 }
00866
00867 if (need_init) {
00868 int len;
00869 char **libs_to_be_linked = 0;
00870 char *buf;
00871
00872 if (undef_tbl->num_entries > 0) {
00873 if (load_lib(libc) == -1) goto err_exit;
00874 }
00875
00876 init_funcname(&buf, need_init);
00877 len = strlen(buf);
00878
00879 for (sym = syms; sym<end; sym++) {
00880 char *name = sym->n_un.n_name;
00881 if (name[0] == '_' && sym->n_value >= block) {
00882 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
00883 libs_to_be_linked = (char**)sym->n_value;
00884 }
00885 else if (strcmp(name+1, buf) == 0) {
00886 init_p = 1;
00887 ((int (*)())sym->n_value)();
00888 }
00889 }
00890 }
00891 if (libs_to_be_linked && undef_tbl->num_entries > 0) {
00892 while (*libs_to_be_linked) {
00893 load_lib(*libs_to_be_linked);
00894 libs_to_be_linked++;
00895 }
00896 }
00897 }
00898 free(reloc);
00899 free(syms);
00900 if (need_init) {
00901 if (init_p == 0) {
00902 dln_errno = DLN_ENOINIT;
00903 return -1;
00904 }
00905 if (undef_tbl->num_entries > 0) {
00906 if (load_lib(libc) == -1) goto err_exit;
00907 if (undef_tbl->num_entries > 0) {
00908 dln_errno = DLN_EUNDEF;
00909 return -1;
00910 }
00911 }
00912 }
00913 return 0;
00914
00915 err_exit:
00916 if (syms) free(syms);
00917 if (reloc) free(reloc);
00918 if (block) free((char*)block);
00919 return -1;
00920 }
00921
00922 static int target_offset;
00923 static int
00924 search_undef(key, value, lib_tbl)
00925 const char *key;
00926 int value;
00927 st_table *lib_tbl;
00928 {
00929 long offset;
00930
00931 if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
00932 target_offset = offset;
00933 return ST_STOP;
00934 }
00935
00936 struct symdef {
00937 int rb_str_index;
00938 int lib_offset;
00939 };
00940
00941 char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
00942
00943 static int
00944 load_lib(lib)
00945 const char *lib;
00946 {
00947 char *path, *file;
00948 char armagic[SARMAG];
00949 int fd, size;
00950 struct ar_hdr ahdr;
00951 st_table *lib_tbl = NULL;
00952 int *data, nsym;
00953 struct symdef *base;
00954 char *name_base;
00955
00956 if (dln_init_p == 0) {
00957 dln_errno = DLN_ENOINIT;
00958 return -1;
00959 }
00960
00961 if (undef_tbl->num_entries == 0) return 0;
00962 dln_errno = DLN_EBADLIB;
00963
00964 if (lib[0] == '-' && lib[1] == 'l') {
00965 long len = strlen(lib) + 4;
00966 char *p = alloca(len);
00967 snprintf(p, len, "lib%s.a", lib+2);
00968 lib = p;
00969 }
00970
00971
00972
00973
00974
00975 path = getenv("DLN_LIBRARY_PATH");
00976 if (path == NULL) path = dln_librrb_ary_path;
00977
00978 file = dln_find_file(lib, path);
00979 fd = open(file, O_RDONLY);
00980 if (fd == -1) goto syserr;
00981 size = read(fd, armagic, SARMAG);
00982 if (size == -1) goto syserr;
00983
00984 if (size != SARMAG) {
00985 dln_errno = DLN_ENOTLIB;
00986 goto badlib;
00987 }
00988 size = read(fd, &ahdr, sizeof(ahdr));
00989 if (size == -1) goto syserr;
00990 if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
00991 goto badlib;
00992 }
00993
00994 if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
00995
00996
00997 lib_tbl = st_init_strtable();
00998 data = (int*)xmalloc(size);
00999 if (data == NULL) goto syserr;
01000 size = read(fd, data, size);
01001 nsym = *data / sizeof(struct symdef);
01002 base = (struct symdef*)(data + 1);
01003 name_base = (char*)(base + nsym) + sizeof(int);
01004 while (nsym > 0) {
01005 char *name = name_base + base->rb_str_index;
01006
01007 st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
01008 nsym--;
01009 base++;
01010 }
01011 for (;;) {
01012 target_offset = -1;
01013 st_foreach(undef_tbl, search_undef, lib_tbl);
01014 if (target_offset == -1) break;
01015 if (load_1(fd, target_offset, 0) == -1) {
01016 st_free_table(lib_tbl);
01017 free(data);
01018 goto badlib;
01019 }
01020 if (undef_tbl->num_entries == 0) break;
01021 }
01022 free(data);
01023 st_free_table(lib_tbl);
01024 }
01025 else {
01026
01027
01028 for (;;) {
01029 int offset = SARMAG;
01030 int found = 0;
01031 struct exec hdr;
01032 struct nlist *syms, *sym, *end;
01033
01034 while (undef_tbl->num_entries > 0) {
01035 found = 0;
01036 lseek(fd, offset, 0);
01037 size = read(fd, &ahdr, sizeof(ahdr));
01038 if (size == -1) goto syserr;
01039 if (size == 0) break;
01040 if (size != sizeof(ahdr)
01041 || sscanf(ahdr.ar_size, "%d", &size) != 1) {
01042 goto badlib;
01043 }
01044 offset += sizeof(ahdr);
01045 if (load_header(fd, &hdr, offset) == -1)
01046 goto badlib;
01047 syms = load_sym(fd, &hdr, offset);
01048 if (syms == NULL) goto badlib;
01049 sym = syms;
01050 end = syms + (hdr.a_syms / sizeof(struct nlist));
01051 while (sym < end) {
01052 if (sym->n_type == N_EXT|N_TEXT
01053 && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
01054 break;
01055 }
01056 sym++;
01057 }
01058 if (sym < end) {
01059 found++;
01060 free(syms);
01061 if (load_1(fd, offset, 0) == -1) {
01062 goto badlib;
01063 }
01064 }
01065 offset += size;
01066 if (offset & 1) offset++;
01067 }
01068 if (found) break;
01069 }
01070 }
01071 close(fd);
01072 return 0;
01073
01074 syserr:
01075 dln_errno = errno;
01076 badlib:
01077 if (fd >= 0) close(fd);
01078 return -1;
01079 }
01080
01081 static int
01082 load(file)
01083 const char *file;
01084 {
01085 int fd;
01086 int result;
01087
01088 if (dln_init_p == 0) {
01089 if (dln_init(dln_argv0) == -1) return -1;
01090 }
01091 result = strlen(file);
01092 if (file[result-1] == 'a') {
01093 return load_lib(file);
01094 }
01095
01096 fd = open(file, O_RDONLY);
01097 if (fd == -1) {
01098 dln_errno = errno;
01099 return -1;
01100 }
01101 result = load_1(fd, 0, file);
01102 close(fd);
01103
01104 return result;
01105 }
01106
01107 void*
01108 dln_sym(name)
01109 const char *name;
01110 {
01111 struct nlist *sym;
01112
01113 if (st_lookup(sym_tbl, name, &sym))
01114 return (void*)sym->n_value;
01115 return NULL;
01116 }
01117
01118 #endif
01119
01120 #ifdef USE_DLN_DLOPEN
01121 # if defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ < 105000000
01122 # include <nlist.h>
01123 # include <link.h>
01124 # else
01125 # include <dlfcn.h>
01126 # endif
01127 #endif
01128
01129 #ifdef __hpux
01130 #include <errno.h>
01131 #include "dl.h"
01132 #endif
01133
01134 #if defined(_AIX)
01135 #include <ctype.h>
01136 #include <errno.h>
01137 #include <sys/ldr.h>
01138 #endif
01139
01140 #ifdef NeXT
01141 #if NS_TARGET_MAJOR < 4
01142 #include <mach-o/rld.h>
01143 #else
01144 #include <mach-o/dyld.h>
01145 #ifndef NSLINKMODULE_OPTION_BINDNOW
01146 #define NSLINKMODULE_OPTION_BINDNOW 1
01147 #endif
01148 #endif
01149 #else
01150 #ifdef __APPLE__
01151 #include <mach-o/dyld.h>
01152 #endif
01153 #endif
01154
01155 #if defined _WIN32 && !defined __CYGWIN__
01156 #include <windows.h>
01157 #endif
01158
01159 #ifdef _WIN32_WCE
01160 #undef FormatMessage
01161 #define FormatMessage FormatMessageA
01162 #undef LoadLibrary
01163 #define LoadLibrary LoadLibraryA
01164 #undef GetProcAddress
01165 #define GetProcAddress GetProcAddressA
01166 #endif
01167
01168 static const char *
01169 dln_strerror()
01170 {
01171 #ifdef USE_DLN_A_OUT
01172 char *strerror();
01173
01174 switch (dln_errno) {
01175 case DLN_ECONFL:
01176 return "Symbol name conflict";
01177 case DLN_ENOINIT:
01178 return "No initializer given";
01179 case DLN_EUNDEF:
01180 return "Unresolved symbols";
01181 case DLN_ENOTLIB:
01182 return "Not a library file";
01183 case DLN_EBADLIB:
01184 return "Malformed library file";
01185 case DLN_EINIT:
01186 return "Not initialized";
01187 default:
01188 return strerror(dln_errno);
01189 }
01190 #endif
01191
01192 #ifdef USE_DLN_DLOPEN
01193 return (char*)dlerror();
01194 #endif
01195
01196 #if defined _WIN32 && !defined __CYGWIN__
01197 static char message[1024];
01198 int error = GetLastError();
01199 char *p = message;
01200 p += sprintf(message, "%d: ", error);
01201 FormatMessage(
01202 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
01203 NULL,
01204 error,
01205 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
01206 p,
01207 sizeof message - strlen(message),
01208 NULL);
01209
01210 for (p = message; *p; p++) {
01211 if (*p == '\n' || *p == '\r')
01212 *p = ' ';
01213 }
01214 return message;
01215 #endif
01216 }
01217
01218
01219 #if defined(_AIX) && ! defined(_IA64)
01220 static void
01221 aix_loaderror(const char *pathname)
01222 {
01223 char *message[8], errbuf[1024];
01224 int i,j;
01225
01226 struct errtab {
01227 int errnum;
01228 char *errstr;
01229 } load_errtab[] = {
01230 {L_ERROR_TOOMANY, "too many errors, rest skipped."},
01231 {L_ERROR_NOLIB, "can't load library:"},
01232 {L_ERROR_UNDEF, "can't find symbol in library:"},
01233 {L_ERROR_RLDBAD,
01234 "RLD index out of range or bad relocation type:"},
01235 {L_ERROR_FORMAT, "not a valid, executable xcoff file:"},
01236 {L_ERROR_MEMBER,
01237 "file not an archive or does not contain requested member:"},
01238 {L_ERROR_TYPE, "symbol table mismatch:"},
01239 {L_ERROR_ALIGN, "text alignment in file is wrong."},
01240 {L_ERROR_SYSTEM, "System error:"},
01241 {L_ERROR_ERRNO, NULL}
01242 };
01243
01244 #define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0]))
01245 #define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1)
01246
01247 snprintf(errbuf, 1024, "load failed - %s ", pathname);
01248
01249 if (!loadquery(1, &message[0], sizeof(message)))
01250 ERRBUF_APPEND(strerror(errno));
01251 for(i = 0; message[i] && *message[i]; i++) {
01252 int nerr = atoi(message[i]);
01253 for (j=0; j<LOAD_ERRTAB_LEN; j++) {
01254 if (nerr == load_errtab[i].errnum && load_errtab[i].errstr)
01255 ERRBUF_APPEND(load_errtab[i].errstr);
01256 }
01257 while (isdigit(*message[i])) message[i]++;
01258 ERRBUF_APPEND(message[i]);
01259 ERRBUF_APPEND("\n");
01260 }
01261 errbuf[strlen(errbuf)-1] = '\0';
01262 rb_loaderror(errbuf);
01263 return;
01264 }
01265 #endif
01266
01267 #if defined(__VMS)
01268 #include <starlet.h>
01269 #include <rms.h>
01270 #include <stsdef.h>
01271 #include <unixlib.h>
01272 #include <descrip.h>
01273 #include <lib$routines.h>
01274
01275 static char *vms_filespec;
01276 static int vms_fileact(char *filespec, int type);
01277 static long vms_fisexh(long *sigarr, long *mecarr);
01278 #endif
01279
01280 #endif
01281
01282 void*
01283 dln_load(file)
01284 const char *file;
01285 {
01286 #ifdef NO_DLN_LOAD
01287 rb_raise(rb_eLoadError, "this executable file can't load extension libraries");
01288 #else
01289
01290 #if !defined(_AIX) && !defined(NeXT)
01291 const char *error = 0;
01292 #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
01293 #endif
01294
01295 #if defined _WIN32 && !defined __CYGWIN__
01296 HINSTANCE handle;
01297 char winfile[MAXPATHLEN];
01298 void (*init_fct)();
01299 char *buf;
01300
01301 if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long");
01302
01303
01304 init_funcname(&buf, file);
01305
01306 strcpy(winfile, file);
01307
01308
01309 if ((handle = LoadLibrary(winfile)) == NULL) {
01310 error = dln_strerror();
01311 goto failed;
01312 }
01313
01314 if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
01315 rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
01316 }
01317
01318
01319 (*init_fct)();
01320 return handle;
01321 #else
01322 #ifdef USE_DLN_A_OUT
01323 if (load(file) == -1) {
01324 error = dln_strerror();
01325 goto failed;
01326 }
01327 return 0;
01328 #else
01329
01330 char *buf;
01331
01332 init_funcname(&buf, file);
01333
01334 #ifdef USE_DLN_DLOPEN
01335 #define DLN_DEFINED
01336 {
01337 void *handle;
01338 void (*init_fct)();
01339
01340 #ifndef RTLD_LAZY
01341 # define RTLD_LAZY 1
01342 #endif
01343 #ifdef __INTERIX
01344 # undef RTLD_GLOBAL
01345 #endif
01346 #ifndef RTLD_GLOBAL
01347 # define RTLD_GLOBAL 0
01348 #endif
01349
01350
01351 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
01352 error = dln_strerror();
01353 goto failed;
01354 }
01355
01356 init_fct = (void(*)())dlsym(handle, buf);
01357 if (init_fct == NULL) {
01358 error = DLN_ERROR();
01359 dlclose(handle);
01360 goto failed;
01361 }
01362
01363 (*init_fct)();
01364
01365 return handle;
01366 }
01367 #endif
01368
01369 #ifdef __hpux
01370 #define DLN_DEFINED
01371 {
01372 shl_t lib = NULL;
01373 int flags;
01374 void (*init_fct)();
01375
01376 flags = BIND_DEFERRED;
01377 lib = shl_load(file, flags, 0);
01378 if (lib == NULL) {
01379 extern int errno;
01380 rb_loaderror("%s - %s", strerror(errno), file);
01381 }
01382 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
01383 if (init_fct == NULL) {
01384 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
01385 if (init_fct == NULL) {
01386 errno = ENOSYM;
01387 rb_loaderror("%s - %s", strerror(ENOSYM), file);
01388 }
01389 }
01390 (*init_fct)();
01391 return (void*)lib;
01392 }
01393 #endif
01394
01395 #if defined(_AIX) && ! defined(_IA64)
01396 #define DLN_DEFINED
01397 {
01398 void (*init_fct)();
01399
01400 init_fct = (void(*)())load((char*)file, 1, 0);
01401 if (init_fct == NULL) {
01402 aix_loaderror(file);
01403 }
01404 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
01405 aix_loaderror(file);
01406 }
01407 (*init_fct)();
01408 return (void*)init_fct;
01409 }
01410 #endif
01411
01412 #if defined(NeXT) || defined(__APPLE__)
01413 #define DLN_DEFINED
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423 #if defined(NeXT) && (NS_TARGET_MAJOR < 4)
01424
01425 {
01426 NXStream* s;
01427 unsigned long init_address;
01428 char *object_files[2] = {NULL, NULL};
01429
01430 void (*init_fct)();
01431
01432 object_files[0] = (char*)file;
01433
01434 s = NXOpenFile(2,NX_WRITEONLY);
01435
01436
01437 if(rld_load(s, NULL, object_files, NULL) == 0) {
01438 NXFlush(s);
01439 NXClose(s);
01440 rb_loaderror("Failed to load %.200s", file);
01441 }
01442
01443
01444 if(rld_lookup(s, buf, &init_address) == 0) {
01445 NXFlush(s);
01446 NXClose(s);
01447 rb_loaderror("Failed to lookup Init function %.200s", file);
01448 }
01449
01450 NXFlush(s);
01451 NXClose(s);
01452
01453
01454
01455 init_fct = (void(*)())init_address;
01456 (*init_fct)();
01457 return (void*)init_address;
01458 }
01459 #else
01460 {
01461 int dyld_result;
01462 NSObjectFileImage obj_file;
01463
01464
01465
01466 void (*init_fct)();
01467
01468
01469 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
01470
01471 if (dyld_result != NSObjectFileImageSuccess) {
01472 rb_loaderror("Failed to load %.200s", file);
01473 }
01474
01475 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
01476
01477
01478 if(!NSIsSymbolNameDefined(buf)) {
01479 rb_loaderror("Failed to lookup Init function %.200s",file);
01480 }
01481 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
01482 (*init_fct)();
01483
01484 return (void*)init_fct;
01485 }
01486 #endif
01487 #endif
01488
01489 #ifdef __BEOS__
01490 # define DLN_DEFINED
01491 {
01492 status_t err_stat;
01493 image_id img_id;
01494 void (*init_fct)();
01495
01496
01497 img_id = load_add_on(file);
01498 if (img_id <= 0) {
01499 rb_loaderror("Failed to load %.200s", file);
01500 }
01501
01502
01503
01504
01505
01506
01507
01508 err_stat = get_image_symbol(img_id, buf,
01509 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01510
01511 if (err_stat != B_NO_ERROR) {
01512 char real_name[MAXPATHLEN];
01513
01514 strcpy(real_name, buf);
01515 strcat(real_name, "__Fv");
01516 err_stat = get_image_symbol(img_id, real_name,
01517 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01518 }
01519
01520 if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
01521 unload_add_on(img_id);
01522 rb_loaderror("Failed to lookup Init function %.200s", file);
01523 }
01524 else if (B_NO_ERROR != err_stat) {
01525 char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
01526 unload_add_on(img_id);
01527 rb_loaderror(errmsg, strerror(err_stat), buf);
01528 }
01529
01530
01531 (*init_fct)();
01532 return (void*)img_id;
01533 }
01534 #endif
01535
01536 #ifdef __MACOS__
01537 # define DLN_DEFINED
01538 {
01539 OSErr err;
01540 FSSpec libspec;
01541 CFragConnectionID connID;
01542 Ptr mainAddr;
01543 char errMessage[1024];
01544 Boolean isfolder, didsomething;
01545 Str63 fragname;
01546 Ptr symAddr;
01547 CFragSymbolClass class;
01548 void (*init_fct)();
01549 char fullpath[MAXPATHLEN];
01550
01551 strcpy(fullpath, file);
01552
01553
01554 c2pstr(fullpath);
01555 (void)FSMakeFSSpec(0, 0, fullpath, &libspec);
01556 err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething);
01557 if (err) {
01558 rb_loaderror("Unresolved Alias - %s", file);
01559 }
01560
01561
01562 fragname[0] = 0;
01563 err = GetDiskFragment(&libspec, 0, 0, fragname,
01564 kLoadCFrag, &connID, &mainAddr,
01565 errMessage);
01566 if (err) {
01567 p2cstr(errMessage);
01568 rb_loaderror("%s - %s",errMessage , file);
01569 }
01570
01571
01572 c2pstr(buf);
01573 err = FindSymbol(connID, buf, &symAddr, &class);
01574 if (err) {
01575 rb_loaderror("Unresolved symbols - %s" , file);
01576 }
01577 init_fct = (void (*)())symAddr;
01578 (*init_fct)();
01579 return (void*)init_fct;
01580 }
01581 #endif
01582
01583 #if defined(__VMS)
01584 #define DLN_DEFINED
01585 {
01586 long status;
01587 void (*init_fct)();
01588 char *fname, *p1, *p2;
01589
01590 $DESCRIPTOR(fname_d, "");
01591 $DESCRIPTOR(image_d, "");
01592 $DESCRIPTOR(buf_d, "");
01593
01594 decc$to_vms(file, vms_fileact, 0, 0);
01595
01596 fname = (char *)__alloca(strlen(file)+1);
01597 strcpy(fname,file);
01598 if (p1 = strrchr(fname,'/'))
01599 fname = p1 + 1;
01600 if (p2 = strrchr(fname,'.'))
01601 *p2 = '\0';
01602
01603 fname_d.dsc$w_length = strlen(fname);
01604 fname_d.dsc$a_pointer = fname;
01605 image_d.dsc$w_length = strlen(vms_filespec);
01606 image_d.dsc$a_pointer = vms_filespec;
01607 buf_d.dsc$w_length = strlen(buf);
01608 buf_d.dsc$a_pointer = buf;
01609
01610 lib$establish(vms_fisexh);
01611
01612 status = lib$find_image_symbol (
01613 &fname_d,
01614 &buf_d,
01615 &init_fct,
01616 &image_d);
01617
01618 lib$establish(0);
01619
01620 if (status == RMS$_FNF) {
01621 error = dln_strerror();
01622 goto failed;
01623 } else if (!$VMS_STATUS_SUCCESS(status)) {
01624 error = DLN_ERROR();
01625 goto failed;
01626 }
01627
01628
01629 (*init_fct)();
01630
01631 return 1;
01632 }
01633 #endif
01634
01635 #ifndef DLN_DEFINED
01636 rb_notimplement();
01637 #endif
01638
01639 #endif
01640 #endif
01641 #if !defined(_AIX) && !defined(NeXT)
01642 failed:
01643 rb_loaderror("%s - %s", error, file);
01644 #endif
01645
01646 #endif
01647 return 0;
01648 }
01649
01650 static char *dln_find_1();
01651
01652 char *
01653 dln_find_exe(fname, path)
01654 const char *fname;
01655 const char *path;
01656 {
01657 if (!path) {
01658 path = getenv(PATH_ENV);
01659 }
01660
01661 if (!path) {
01662 #if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__MACOS__)
01663 path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
01664 #else
01665 path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
01666 #endif
01667 }
01668 return dln_find_1(fname, path, 1);
01669 }
01670
01671 char *
01672 dln_find_file(fname, path)
01673 const char *fname;
01674 const char *path;
01675 {
01676 #ifndef __MACOS__
01677 if (!path) path = ".";
01678 return dln_find_1(fname, path, 0);
01679 #else
01680 if (!path) path = ".";
01681 return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0));
01682 #endif
01683 }
01684
01685 #if defined(__CYGWIN32__)
01686 const char *
01687 conv_to_posix_path(win32, posix, len)
01688 char *win32;
01689 char *posix;
01690 int len;
01691 {
01692 char *first = win32;
01693 char *p = win32;
01694 char *dst = posix;
01695
01696 posix[0] = '\0';
01697 for (p = win32; *p; p++)
01698 if (*p == ';') {
01699 *p = 0;
01700 cygwin32_conv_to_posix_path(first, posix);
01701 posix += strlen(posix);
01702 *posix++ = ':';
01703 first = p + 1;
01704 *p = ';';
01705 }
01706 if (len < strlen(first))
01707 fprintf(stderr, "PATH length too long: %s\n", first);
01708 else
01709 cygwin32_conv_to_posix_path(first, posix);
01710 return dst;
01711 }
01712 #endif
01713
01714 static char fbuf[MAXPATHLEN];
01715
01716 static char *
01717 dln_find_1(fname, path, exe_flag)
01718 char *fname;
01719 char *path;
01720 int exe_flag;
01721 {
01722 register char *dp;
01723 register char *ep;
01724 register char *bp;
01725 struct stat st;
01726 #ifdef __MACOS__
01727 const char* mac_fullpath;
01728 #endif
01729
01730 if (!fname) return fname;
01731 if (fname[0] == '/') return fname;
01732 if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
01733 return fname;
01734 if (exe_flag && strchr(fname, '/')) return fname;
01735 #ifdef DOSISH
01736 if (fname[0] == '\\') return fname;
01737 # ifdef DOSISH_DRIVE_LETTER
01738 if (strlen(fname) > 2 && fname[1] == ':') return fname;
01739 # endif
01740 if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
01741 return fname;
01742 if (exe_flag && strchr(fname, '\\')) return fname;
01743 #endif
01744
01745 for (dp = path;; dp = ++ep) {
01746 register int l;
01747 int i;
01748 int fspace;
01749
01750
01751 ep = strchr(dp, PATH_SEP[0]);
01752 if (ep == NULL)
01753 ep = dp+strlen(dp);
01754
01755
01756 l = ep - dp;
01757 bp = fbuf;
01758 fspace = sizeof fbuf - 2;
01759 if (l > 0) {
01760
01761
01762
01763
01764
01765
01766
01767
01768 if (*dp == '~' && (l == 1 ||
01769 #if defined(DOSISH)
01770 dp[1] == '\\' ||
01771 #endif
01772 dp[1] == '/')) {
01773 char *home;
01774
01775 home = getenv("HOME");
01776 if (home != NULL) {
01777 i = strlen(home);
01778 if ((fspace -= i) < 0)
01779 goto toolong;
01780 memcpy(bp, home, i);
01781 bp += i;
01782 }
01783 dp++;
01784 l--;
01785 }
01786 if (l > 0) {
01787 if ((fspace -= l) < 0)
01788 goto toolong;
01789 memcpy(bp, dp, l);
01790 bp += l;
01791 }
01792
01793
01794 if (ep[-1] != '/')
01795 *bp++ = '/';
01796 }
01797
01798
01799 i = strlen(fname);
01800 if ((fspace -= i) < 0) {
01801 toolong:
01802 fprintf(stderr, "openpath: pathname too long (ignored)\n");
01803 *bp = '\0';
01804 fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
01805 fprintf(stderr, "\tFile \"%s\"\n", fname);
01806 goto next;
01807 }
01808 memcpy(bp, fname, i + 1);
01809
01810 #ifndef __MACOS__
01811 if (stat(fbuf, &st) == 0) {
01812 if (exe_flag == 0) return fbuf;
01813
01814 if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
01815 return fbuf;
01816 }
01817 #else
01818 if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
01819 if (exe_flag == 0) return mac_fullpath;
01820
01821 if (stat(mac_fullpath, &st) == 0) {
01822 if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
01823 return mac_fullpath;
01824 }
01825 }
01826 #endif
01827 #if defined(DOSISH)
01828 if (exe_flag) {
01829 static const char *extension[] = {
01830 #if defined(MSDOS)
01831 ".com", ".exe", ".bat",
01832 #if defined(DJGPP)
01833 ".btm", ".sh", ".ksh", ".pl", ".sed",
01834 #endif
01835 #elif defined(__EMX__) || defined(_WIN32)
01836 ".exe", ".com", ".cmd", ".bat",
01837
01838 #else
01839 ".r", ".R", ".x", ".X", ".bat", ".BAT",
01840
01841 #endif
01842 (char *) NULL
01843 };
01844 int j;
01845
01846 for (j = 0; extension[j]; j++) {
01847 if (fspace < strlen(extension[j])) {
01848 fprintf(stderr, "openpath: pathname too long (ignored)\n");
01849 fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
01850 fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
01851 continue;
01852 }
01853 strcpy(bp + i, extension[j]);
01854 #ifndef __MACOS__
01855 if (stat(fbuf, &st) == 0)
01856 return fbuf;
01857 #else
01858 if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf))
01859 return mac_fullpath;
01860
01861 #endif
01862 }
01863 }
01864 #endif
01865
01866 next:
01867
01868 if (*ep == '\0') {
01869 return NULL;
01870 }
01871
01872
01873 }
01874 }
01875
01876 #if defined(__VMS)
01877
01878
01879 static int vms_fileact(char *filespec, int type)
01880 {
01881 if (vms_filespec)
01882 free(vms_filespec);
01883 vms_filespec = malloc(strlen(filespec)+1);
01884 strcpy(vms_filespec, filespec);
01885 return 1;
01886 }
01887
01888
01889 static long vms_fisexh(long *sigarr, long *mecarr)
01890 {
01891 sys$unwind(1, 0);
01892 return 1;
01893 }
01894
01895 #endif
01896