sod.c revision 1.15
1343171Sdim/* $OpenBSD: sod.c,v 1.15 2002/07/29 22:43:36 art Exp $ */ 2343171Sdim 3353358Sdim/* 4353358Sdim * Copyright (c) 1993 Paul Kranenburg 5353358Sdim * All rights reserved. 6343171Sdim * 7343171Sdim * Redistribution and use in source and binary forms, with or without 8343171Sdim * modification, are permitted provided that the following conditions 9343171Sdim * are met: 10343171Sdim * 1. Redistributions of source code must retain the above copyright 11343171Sdim * notice, this list of conditions and the following disclaimer. 12343171Sdim * 2. Redistributions in binary form must reproduce the above copyright 13343171Sdim * notice, this list of conditions and the following disclaimer in the 14343171Sdim * documentation and/or other materials provided with the distribution. 15343171Sdim * 3. All advertising materials mentioning features or use of this software 16343171Sdim * must display the following acknowledgement: 17343171Sdim * This product includes software developed by Paul Kranenburg. 18343171Sdim * 4. The name of the author may not be used to endorse or promote products 19343171Sdim * derived from this software without specific prior written permission 20343171Sdim * 21343171Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22343171Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23343171Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24343171Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25343171Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26343171Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27343171Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28343171Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29343171Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30343171Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31343171Sdim * 32343171Sdim */ 33343171Sdim 34343171Sdim#include <sys/types.h> 35343171Sdim#include <sys/syslimits.h> 36343171Sdim#include <stdio.h> 37343171Sdim#include <fcntl.h> 38343171Sdim#include <nlist.h> 39343171Sdim#include <link.h> 40343171Sdim#include <machine/exec.h> 41343171Sdim#include <sys/mman.h> 42343171Sdim#include <string.h> 43343171Sdim#include <stdlib.h> 44343171Sdim#include <unistd.h> 45343171Sdim#include <syscall.h> 46343171Sdim 47343171Sdim#include "archdep.h" 48343171Sdim#include "util.h" 49343171Sdim#include "sod.h" 50343171Sdim 51343171Sdim#define PAGSIZ __LDPGSZ 52343171Sdimint _dl_hinthash(char *cp, int vmajor, int vminor); 53343171Sdim 54343171Sdim/* 55343171Sdim * Populate sod struct for dlopen's call to map_object 56343171Sdim */ 57343171Sdimvoid 58343171Sdim_dl_build_sod(name, sodp) 59343171Sdim const char *name; 60343171Sdim struct sod *sodp; 61343171Sdim{ 62343171Sdim unsigned int tuplet; 63343171Sdim int major, minor; 64343171Sdim char *realname, *tok, *etok, *cp; 65343171Sdim 66343171Sdim /* default is an absolute or relative path */ 67343171Sdim sodp->sod_name = (long)_dl_strdup(name); /* strtok is destructive */ 68343171Sdim sodp->sod_library = 0; 69343171Sdim sodp->sod_major = sodp->sod_minor = 0; 70343171Sdim 71343171Sdim /* does it look like /^lib/ ? */ 72343171Sdim if (_dl_strncmp((char *)sodp->sod_name, "lib", 3) != 0) 73343171Sdim return; 74343171Sdim 75343171Sdim /* is this a filename? */ 76343171Sdim if (_dl_strchr((char *)sodp->sod_name, '/')) 77343171Sdim return; 78343171Sdim 79343171Sdim /* skip over 'lib' */ 80343171Sdim cp = (char *)sodp->sod_name + 3; 81343171Sdim 82343171Sdim /* dot guardian */ 83343171Sdim if ((_dl_strchr(cp, '.') == NULL) || (*(cp+_dl_strlen(cp)-1) == '.')) 84353358Sdim return; 85343171Sdim 86343171Sdim /* default */ 87343171Sdim major = minor = -1; 88343171Sdim 89343171Sdim realname = NULL; 90343171Sdim /* loop through name - parse skipping name */ 91343171Sdim for (tuplet = 0; (tok = strsep(&cp, ".")) != NULL; tuplet++) { 92343171Sdim switch (tuplet) { 93343171Sdim case 0: 94343171Sdim /* removed 'lib' and extensions from name */ 95343171Sdim realname = tok; 96343171Sdim break; 97343171Sdim case 1: 98343171Sdim /* 'so' extension */ 99343171Sdim if (_dl_strcmp(tok, "so") != 0) 100343171Sdim goto backout; 101343171Sdim break; 102343171Sdim case 2: 103343171Sdim /* major version extension */ 104343171Sdim major = strtol(tok, &etok, 10); 105343171Sdim if (*tok == '\0' || *etok != '\0') 106343171Sdim goto backout; 107343171Sdim break; 108343171Sdim case 3: 109343171Sdim /* minor version extension */ 110343171Sdim minor = strtol(tok, &etok, 10); 111343171Sdim if (*tok == '\0' || *etok != '\0') 112343171Sdim goto backout; 113343171Sdim break; 114343171Sdim /* if we get here, it must be weird */ 115343171Sdim default: 116343171Sdim goto backout; 117343171Sdim } 118343171Sdim } 119343171Sdim if (realname == NULL) { 120343171Sdim goto backout; 121343171Sdim } 122343171Sdim cp = (char *)sodp->sod_name; 123343171Sdim sodp->sod_name = (long)_dl_strdup(realname); 124343171Sdim _dl_free(cp); 125343171Sdim sodp->sod_library = 1; 126343171Sdim sodp->sod_major = major; 127343171Sdim sodp->sod_minor = minor; 128343171Sdim return; 129343171Sdim 130343171Sdimbackout: 131343171Sdim _dl_free((char *)sodp->sod_name); 132343171Sdim sodp->sod_name = (long)_dl_strdup(name); 133343171Sdim} 134343171Sdim 135343171Sdimstatic int hfd; 136343171Sdimstatic long hsize; 137343171Sdimstatic struct hints_header *hheader = NULL; 138343171Sdimstatic struct hints_bucket *hbuckets; 139343171Sdimstatic char *hstrtab; 140343171Sdimchar *_dl_hint_search_path = NULL; 141343171Sdim 142343171Sdim#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1) 143343171Sdim 144343171Sdimvoid 145343171Sdim_dl_maphints() 146343171Sdim{ 147343171Sdim caddr_t addr; 148343171Sdim 149343171Sdim if ((hfd = _dl_open(_PATH_LD_HINTS, O_RDONLY)) < 0) { 150343171Sdim hheader = (struct hints_header *)-1; 151343171Sdim return; 152343171Sdim } 153343171Sdim 154343171Sdim hsize = PAGSIZ; 155343171Sdim addr = (void *) _dl_mmap(0, hsize, PROT_READ, MAP_PRIVATE, hfd, 0); 156343171Sdim 157343171Sdim if (addr == MAP_FAILED) { 158343171Sdim _dl_close(hfd); 159353358Sdim hheader = (struct hints_header *)-1; 160343171Sdim return; 161343171Sdim } 162353358Sdim 163343171Sdim hheader = (struct hints_header *)addr; 164343171Sdim if (HH_BADMAG(*hheader)) { 165343171Sdim _dl_munmap(addr, hsize); 166343171Sdim _dl_close(hfd); 167343171Sdim hheader = (struct hints_header *)-1; 168343171Sdim return; 169360784Sdim } 170360784Sdim 171343171Sdim if (hheader->hh_version != LD_HINTS_VERSION_1 && 172343171Sdim hheader->hh_version != LD_HINTS_VERSION_2) { 173343171Sdim _dl_munmap(addr, hsize); 174353358Sdim _dl_close(hfd); 175343171Sdim hheader = (struct hints_header *)-1; 176343171Sdim return; 177343171Sdim } 178343171Sdim 179343171Sdim if (hheader->hh_ehints > hsize) { 180343171Sdim if ((caddr_t)_dl_mmap(addr+hsize, hheader->hh_ehints - hsize, 181343171Sdim PROT_READ, MAP_PRIVATE|MAP_FIXED, 182343171Sdim hfd, hsize) != (caddr_t)(addr+hsize)) { 183343171Sdim _dl_munmap((caddr_t)hheader, hsize); 184353358Sdim _dl_close(hfd); 185343171Sdim hheader = (struct hints_header *)-1; 186343171Sdim return; 187360784Sdim } 188360784Sdim } 189353358Sdim 190343171Sdim hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab); 191343171Sdim hstrtab = (char *)(addr + hheader->hh_strtab); 192343171Sdim if (hheader->hh_version >= LD_HINTS_VERSION_2) 193343171Sdim _dl_hint_search_path = hstrtab + hheader->hh_dirlist; 194343171Sdim 195343171Sdim /* close the file descriptor, leaving the hints mapped */ 196343171Sdim _dl_close(hfd); 197343171Sdim} 198343171Sdim 199343171Sdimchar * 200343171Sdim_dl_findhint(name, major, minor, prefered_path) 201343171Sdim char *name; 202343171Sdim int major, minor; 203343171Sdim char *prefered_path; 204353358Sdim{ 205353358Sdim struct hints_bucket *bp; 206343171Sdim 207343171Sdim /* 208343171Sdim * If not mapped, and we have not tried before, try to map the 209343171Sdim * hints, if previous attempts failed hheader is -1 and we 210343171Sdim * do not wish to retry it. 211343171Sdim */ 212343171Sdim if (hheader == NULL) 213 _dl_maphints(); 214 215 /* if it failed to map, return failure */ 216 if (!(HINTS_VALID)) 217 return NULL; 218 219 bp = hbuckets + (_dl_hinthash(name, major, minor) % hheader->hh_nbucket); 220 221 while (1) { 222 /* Sanity check */ 223 if (bp->hi_namex >= hheader->hh_strtab_sz) { 224 _dl_printf("Bad name index: %#x\n", bp->hi_namex); 225 _dl_exit(7); 226 break; 227 } 228 if (bp->hi_pathx >= hheader->hh_strtab_sz) { 229 _dl_printf("Bad path index: %#x\n", bp->hi_pathx); 230 _dl_exit(7); 231 break; 232 } 233 234 if (_dl_strcmp(name, hstrtab + bp->hi_namex) == 0) { 235 /* It's `name', check version numbers */ 236 if (bp->hi_major == major && 237 (bp->hi_ndewey < 2 || bp->hi_minor >= minor)) { 238 if (prefered_path == NULL || 239 _dl_strncmp(prefered_path, 240 hstrtab + bp->hi_pathx, 241 _dl_strlen(prefered_path)) == 0) 242 return hstrtab + bp->hi_pathx; 243 } 244 } 245 246 if (bp->hi_next == -1) 247 break; 248 249 /* Move on to next in bucket */ 250 bp = &hbuckets[bp->hi_next]; 251 } 252 253 /* No hints available for name */ 254 return NULL; 255} 256int 257_dl_hinthash(cp, vmajor, vminor) 258 char *cp; 259 int vmajor, vminor; 260{ 261 int k = 0; 262 263 while (*cp) 264 k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; 265 266 k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff; 267 if (hheader->hh_version == LD_HINTS_VERSION_1) 268 k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff; 269 270 return k; 271} 272