summaryrefslogtreecommitdiff
path: root/libexec/ld.so/prebind/sod.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/ld.so/prebind/sod.c')
-rw-r--r--libexec/ld.so/prebind/sod.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/libexec/ld.so/prebind/sod.c b/libexec/ld.so/prebind/sod.c
new file mode 100644
index 00000000000..f92213cf867
--- /dev/null
+++ b/libexec/ld.so/prebind/sod.c
@@ -0,0 +1,265 @@
+/* $OpenBSD: sod.c,v 1.1 2006/05/03 16:10:52 drahn Exp $ */
+
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/syslimits.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <nlist.h>
+#include <link.h>
+#include <limits.h>
+#include <machine/exec.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if 0
+#include "syscall.h"
+#include "archdep.h"
+#include "util.h"
+#endif
+#include "sod.h"
+
+int _dl_hinthash(char *cp, int vmajor, int vminor);
+void _dl_maphints(void);
+
+/*
+ * Populate sod struct for dlopen's call to map_object
+ */
+void
+_dl_build_sod(const char *name, struct sod *sodp)
+{
+ unsigned int tuplet;
+ int major, minor;
+ char *realname, *tok, *etok, *cp;
+
+ /* default is an absolute or relative path */
+ sodp->sod_name = (long)strdup(name); /* strtok is destructive */
+ sodp->sod_library = 0;
+ sodp->sod_major = sodp->sod_minor = 0;
+
+ /* does it look like /^lib/ ? */
+ if (strncmp((char *)sodp->sod_name, "lib", 3) != 0)
+ goto backout;
+
+ /* is this a filename? */
+ if (strchr((char *)sodp->sod_name, '/'))
+ goto backout;
+
+ /* skip over 'lib' */
+ cp = (char *)sodp->sod_name + 3;
+
+ realname = cp;
+
+ /* dot guardian */
+ if ((strchr(cp, '.') == NULL) || (*(cp+strlen(cp)-1) == '.'))
+ goto backout;
+
+ cp = strstr(cp, ".so");
+ if (cp == NULL)
+ goto backout;
+
+ /* default */
+ major = minor = -1;
+
+ /* loop through name - parse skipping name */
+ for (tuplet = 0; (tok = strsep(&cp, ".")) != NULL; tuplet++) {
+ switch (tuplet) {
+ case 0:
+ /* empty tok, we already skipped to "\.so.*" */
+ break;
+ case 1:
+ /* 'so' extension */
+ break;
+ case 2:
+ /* major version extension */
+ major = strtol(tok, &etok, 10);
+ if (*tok == '\0' || *etok != '\0')
+ goto backout;
+ break;
+ case 3:
+ /* minor version extension */
+ minor = strtol(tok, &etok, 10);
+ if (*tok == '\0' || *etok != '\0')
+ goto backout;
+ break;
+ /* if we get here, it must be weird */
+ default:
+ goto backout;
+ }
+ }
+ if (realname == NULL)
+ goto backout;
+ cp = (char *)sodp->sod_name;
+ sodp->sod_name = (long)strdup(realname);
+ free(cp);
+ sodp->sod_library = 1;
+ sodp->sod_major = major;
+ sodp->sod_minor = minor;
+ return;
+
+backout:
+ free((char *)sodp->sod_name);
+ sodp->sod_name = (long)strdup(name);
+}
+
+static struct hints_header *hheader = NULL;
+static struct hints_bucket *hbuckets;
+static char *hstrtab;
+char *_dl_hint_search_path = NULL;
+
+#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1)
+
+void
+_dl_maphints(void)
+{
+ struct stat sb;
+ caddr_t addr = MAP_FAILED;
+ long hsize = 0;
+ int hfd;
+
+ if ((hfd = open(_PATH_LD_HINTS, O_RDONLY)) < 0)
+ goto bad_hints;
+
+ if (fstat(hfd, &sb) != 0 || !S_ISREG(sb.st_mode) ||
+ sb.st_size < sizeof(struct hints_header) || sb.st_size > LONG_MAX)
+ goto bad_hints;
+
+ hsize = (long)sb.st_size;
+ addr = (void *)mmap(0, hsize, PROT_READ, MAP_PRIVATE, hfd, 0);
+ if (addr == MAP_FAILED)
+ goto bad_hints;
+
+ hheader = (struct hints_header *)addr;
+ if (HH_BADMAG(*hheader) || hheader->hh_ehints > hsize)
+ goto bad_hints;
+
+ if (hheader->hh_version != LD_HINTS_VERSION_1 &&
+ hheader->hh_version != LD_HINTS_VERSION_2)
+ goto bad_hints;
+
+ hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
+ hstrtab = (char *)(addr + hheader->hh_strtab);
+ if (hheader->hh_version >= LD_HINTS_VERSION_2)
+ _dl_hint_search_path = hstrtab + hheader->hh_dirlist;
+
+ /* close the file descriptor, leaving the hints mapped */
+ close(hfd);
+
+ return;
+
+bad_hints:
+ if (addr != MAP_FAILED)
+ munmap(addr, hsize);
+ if (hfd != -1)
+ close(hfd);
+ hheader = (struct hints_header *)-1;
+}
+
+char *
+_dl_findhint(char *name, int major, int minor, char *preferred_path)
+{
+ struct hints_bucket *bp;
+
+ /*
+ * If not mapped, and we have not tried before, try to map the
+ * hints, if previous attempts failed hheader is -1 and we
+ * do not wish to retry it.
+ */
+ if (hheader == NULL)
+ _dl_maphints();
+
+ /* if it failed to map, return failure */
+ if (!(HINTS_VALID))
+ return NULL;
+
+ bp = hbuckets + (_dl_hinthash(name, major, minor) % hheader->hh_nbucket);
+
+ while (1) {
+ /* Sanity check */
+ if (bp->hi_namex >= hheader->hh_strtab_sz) {
+ printf("Bad name index: %#x\n", bp->hi_namex);
+ exit(7);
+ break;
+ }
+ if (bp->hi_pathx >= hheader->hh_strtab_sz) {
+ printf("Bad path index: %#x\n", bp->hi_pathx);
+ exit(7);
+ break;
+ }
+
+ if (strcmp(name, hstrtab + bp->hi_namex) == 0) {
+ /* It's `name', check version numbers */
+ if (bp->hi_major == major &&
+ (bp->hi_ndewey < 2 || bp->hi_minor >= minor)) {
+ if (preferred_path == NULL) {
+ return hstrtab + bp->hi_pathx;
+ } else {
+ char *path = hstrtab + bp->hi_pathx;
+ char *edir = strrchr(path, '/');
+
+ if ((strncmp(preferred_path, path,
+ (edir - path)) == 0) &&
+ (preferred_path[edir - path] == '\0'))
+ return path;
+ }
+ }
+ }
+
+ if (bp->hi_next == -1)
+ break;
+
+ /* Move on to next in bucket */
+ bp = &hbuckets[bp->hi_next];
+ }
+
+ /* No hints available for name */
+ return NULL;
+}
+
+int
+_dl_hinthash(char *cp, int vmajor, int vminor)
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+ if (hheader->hh_version == LD_HINTS_VERSION_1)
+ k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
+
+ return k;
+}