ldconfig.c revision 1741
1696Spaul/* 2696Spaul * Copyright (c) 1993 Paul Kranenburg 3696Spaul * All rights reserved. 4696Spaul * 5696Spaul * Redistribution and use in source and binary forms, with or without 6696Spaul * modification, are permitted provided that the following conditions 7696Spaul * are met: 8696Spaul * 1. Redistributions of source code must retain the above copyright 9696Spaul * notice, this list of conditions and the following disclaimer. 10696Spaul * 2. Redistributions in binary form must reproduce the above copyright 11696Spaul * notice, this list of conditions and the following disclaimer in the 12696Spaul * documentation and/or other materials provided with the distribution. 13696Spaul * 3. All advertising materials mentioning features or use of this software 14696Spaul * must display the following acknowledgement: 15696Spaul * This product includes software developed by Paul Kranenburg. 16696Spaul * 4. The name of the author may not be used to endorse or promote products 171153Sjkh * derived from this software without specific prior written permission 18696Spaul * 19696Spaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20696Spaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21696Spaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22696Spaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23696Spaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24696Spaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25696Spaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26696Spaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27696Spaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28696Spaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29696Spaul * 301741Srich * $Id: ldconfig.c,v 1.6 1994/06/05 19:04:11 ats Exp $ 31696Spaul */ 32696Spaul 33696Spaul#include <sys/param.h> 34696Spaul#include <sys/types.h> 35696Spaul#include <sys/stat.h> 36696Spaul#include <sys/file.h> 37696Spaul#include <sys/time.h> 38696Spaul#include <sys/mman.h> 39696Spaul#include <sys/resource.h> 401741Srich#include <dirent.h> 411741Srich#include <errno.h> 42696Spaul#include <fcntl.h> 43696Spaul#include <ar.h> 44696Spaul#include <ranlib.h> 45696Spaul#include <a.out.h> 46696Spaul#include <stab.h> 471741Srich#include <stdio.h> 481741Srich#include <stdlib.h> 49696Spaul#include <string.h> 501741Srich#include <unistd.h> 51696Spaul 52696Spaul#include "ld.h" 53696Spaul 54696Spaul#undef major 55696Spaul#undef minor 56696Spaul 57696Spaulchar *progname; 58696Spaulstatic int verbose; 59696Spaulstatic int nostd; 60696Spaulstatic int justread; 61696Spaul 62696Spaulstruct shlib_list { 63696Spaul /* Internal list of shared libraries found */ 64696Spaul char *name; 65696Spaul char *path; 66696Spaul int dewey[MAXDEWEY]; 67696Spaul int ndewey; 68696Spaul#define major dewey[0] 69696Spaul#define minor dewey[1] 70696Spaul struct shlib_list *next; 71696Spaul}; 72696Spaul 73696Spaulstatic struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head; 74696Spaul 75696Spaulstatic void enter __P((char *, char *, char *, int *, int)); 761153Sjkhstatic int dodir __P((char *, int)); 77696Spaulstatic int build_hints __P((void)); 781741Srichstatic int listhints __P((void)); 79696Spaul 80696Spaulint 81696Spaulmain(argc, argv) 82696Spaulint argc; 83696Spaulchar *argv[]; 84696Spaul{ 85696Spaul int i, c; 86696Spaul int rval = 0; 87696Spaul extern int optind; 88696Spaul 89696Spaul if ((progname = strrchr(argv[0], '/')) == NULL) 90696Spaul progname = argv[0]; 91696Spaul else 92696Spaul progname++; 93696Spaul 94696Spaul while ((c = getopt(argc, argv, "rsv")) != EOF) { 95696Spaul switch (c) { 96696Spaul case 'v': 97696Spaul verbose = 1; 98696Spaul break; 99696Spaul case 's': 100696Spaul nostd = 1; 101696Spaul break; 102696Spaul case 'r': 103696Spaul justread = 1; 104696Spaul break; 105696Spaul default: 1061683Sats fprintf(stderr, "Usage: %s [-r] [-s] [-v] [dir ...]\n", progname); 107696Spaul exit(1); 108696Spaul break; 109696Spaul } 110696Spaul } 111696Spaul 112696Spaul if (justread) 113696Spaul return listhints(); 114696Spaul 115696Spaul if (!nostd) 1161741Srich std_search_path(); 117696Spaul 118696Spaul for (i = 0; i < n_search_dirs; i++) 1191153Sjkh rval |= dodir(search_dirs[i], 1); 120696Spaul 121696Spaul for (i = optind; i < argc; i++) 1221153Sjkh rval |= dodir(argv[i], 0); 123696Spaul 124696Spaul rval |= build_hints(); 125696Spaul 126696Spaul return rval; 127696Spaul} 128696Spaul 129696Spaulint 1301153Sjkhdodir(dir, silent) 131696Spaulchar *dir; 1321153Sjkhint silent; 133696Spaul{ 134696Spaul DIR *dd; 135696Spaul struct dirent *dp; 136696Spaul char name[MAXPATHLEN], rest[MAXPATHLEN]; 137696Spaul int dewey[MAXDEWEY], ndewey; 138696Spaul 139696Spaul if ((dd = opendir(dir)) == NULL) { 1401153Sjkh if (!silent || errno != ENOENT) 1411153Sjkh perror(dir); 142696Spaul return -1; 143696Spaul } 144696Spaul 145696Spaul while ((dp = readdir(dd)) != NULL) { 146696Spaul int n; 147696Spaul 148696Spaul name[0] = rest[0] = '\0'; 149696Spaul 150696Spaul n = sscanf(dp->d_name, "lib%[^.].so.%s", 151696Spaul name, rest); 152696Spaul 153696Spaul if (n < 2 || rest[0] == '\0') 154696Spaul continue; 155696Spaul 156696Spaul ndewey = getdewey(dewey, rest); 157696Spaul enter(dir, dp->d_name, name, dewey, ndewey); 158696Spaul } 159696Spaul 160696Spaul return 0; 161696Spaul} 162696Spaul 163696Spaulstatic void 164696Spaulenter(dir, file, name, dewey, ndewey) 165696Spaulchar *dir, *file, *name; 166696Spaulint dewey[], ndewey; 167696Spaul{ 168696Spaul struct shlib_list *shp; 169696Spaul 170696Spaul for (shp = shlib_head; shp; shp = shp->next) { 171696Spaul if (strcmp(name, shp->name) != 0 || major != shp->major) 172696Spaul continue; 173696Spaul 174696Spaul /* Name matches existing entry */ 175696Spaul if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) { 176696Spaul 177696Spaul /* Update this entry with higher versioned lib */ 178696Spaul if (verbose) 179696Spaul printf("Updating lib%s.%d.%d to %s/%s\n", 180696Spaul shp->name, shp->major, shp->minor, 181696Spaul dir, file); 182696Spaul 183696Spaul free(shp->name); 184696Spaul shp->name = strdup(name); 185696Spaul free(shp->path); 186696Spaul shp->path = concat(dir, "/", file); 187696Spaul bcopy(dewey, shp->dewey, sizeof(shp->dewey)); 188696Spaul shp->ndewey = ndewey; 189696Spaul } 190696Spaul break; 191696Spaul } 192696Spaul 193696Spaul if (shp) 194696Spaul /* Name exists: older version or just updated */ 195696Spaul return; 196696Spaul 197696Spaul /* Allocate new list element */ 198696Spaul if (verbose) 199696Spaul printf("Adding %s/%s\n", dir, file); 200696Spaul 201696Spaul shp = (struct shlib_list *)xmalloc(sizeof *shp); 202696Spaul shp->name = strdup(name); 203696Spaul shp->path = concat(dir, "/", file); 204696Spaul bcopy(dewey, shp->dewey, MAXDEWEY); 205696Spaul shp->ndewey = ndewey; 206696Spaul shp->next = NULL; 207696Spaul 208696Spaul *shlib_tail = shp; 209696Spaul shlib_tail = &shp->next; 210696Spaul} 211696Spaul 212696Spaul 213696Spaul#if DEBUG 214696Spaul/* test */ 215696Spaul#undef _PATH_LD_HINTS 216696Spaul#define _PATH_LD_HINTS "./ld.so.hints" 217696Spaul#endif 218696Spaul 219696Spaulint 220696Spaulhinthash(cp, vmajor, vminor) 221696Spaulchar *cp; 222696Spaulint vmajor, vminor; 223696Spaul{ 224696Spaul int k = 0; 225696Spaul 226696Spaul while (*cp) 227696Spaul k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; 228696Spaul 229696Spaul k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff; 230696Spaul k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff; 231696Spaul 232696Spaul return k; 233696Spaul} 234696Spaul 235696Spaulint 236696Spaulbuild_hints() 237696Spaul{ 238696Spaul struct hints_header hdr; 239696Spaul struct hints_bucket *blist; 240696Spaul struct shlib_list *shp; 241696Spaul char *strtab; 242696Spaul int i, n, str_index = 0; 243696Spaul int strtab_sz = 0; /* Total length of strings */ 244696Spaul int nhints = 0; /* Total number of hints */ 245696Spaul int fd; 246696Spaul char *tmpfile; 247696Spaul 248696Spaul for (shp = shlib_head; shp; shp = shp->next) { 249696Spaul strtab_sz += 1 + strlen(shp->name); 250696Spaul strtab_sz += 1 + strlen(shp->path); 251696Spaul nhints++; 252696Spaul } 253696Spaul 254696Spaul /* Fill hints file header */ 255696Spaul hdr.hh_magic = HH_MAGIC; 256696Spaul hdr.hh_version = LD_HINTS_VERSION_1; 257696Spaul hdr.hh_nbucket = 1 * nhints; 258696Spaul n = hdr.hh_nbucket * sizeof(struct hints_bucket); 259696Spaul hdr.hh_hashtab = sizeof(struct hints_header); 260696Spaul hdr.hh_strtab = hdr.hh_hashtab + n; 261696Spaul hdr.hh_strtab_sz = strtab_sz; 262696Spaul hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz; 263696Spaul 264696Spaul if (verbose) 265696Spaul printf("Totals: entries %d, buckets %d, string size %d\n", 266696Spaul nhints, hdr.hh_nbucket, strtab_sz); 267696Spaul 268696Spaul /* Allocate buckets and string table */ 269696Spaul blist = (struct hints_bucket *)xmalloc(n); 270696Spaul bzero((char *)blist, n); 271696Spaul for (i = 0; i < hdr.hh_nbucket; i++) 272696Spaul /* Empty all buckets */ 273696Spaul blist[i].hi_next = -1; 274696Spaul 275696Spaul strtab = (char *)xmalloc(strtab_sz); 276696Spaul 277696Spaul /* Enter all */ 278696Spaul for (shp = shlib_head; shp; shp = shp->next) { 279696Spaul struct hints_bucket *bp; 280696Spaul 281696Spaul bp = blist + 282696Spaul (hinthash(shp->name, shp->major, shp->minor) % hdr.hh_nbucket); 283696Spaul 284696Spaul if (bp->hi_pathx) { 285696Spaul int i; 286696Spaul 287696Spaul for (i = 0; i < hdr.hh_nbucket; i++) { 288696Spaul if (blist[i].hi_pathx == 0) 289696Spaul break; 290696Spaul } 291696Spaul if (i == hdr.hh_nbucket) { 292696Spaul fprintf(stderr, "Bummer!\n"); 293696Spaul return -1; 294696Spaul } 295696Spaul while (bp->hi_next != -1) 296696Spaul bp = &blist[bp->hi_next]; 297696Spaul bp->hi_next = i; 298696Spaul bp = blist + i; 299696Spaul } 300696Spaul 301696Spaul /* Insert strings in string table */ 302696Spaul bp->hi_namex = str_index; 303696Spaul strcpy(strtab + str_index, shp->name); 304696Spaul str_index += 1 + strlen(shp->name); 305696Spaul 306696Spaul bp->hi_pathx = str_index; 307696Spaul strcpy(strtab + str_index, shp->path); 308696Spaul str_index += 1 + strlen(shp->path); 309696Spaul 310696Spaul /* Copy versions */ 311696Spaul bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey)); 312696Spaul bp->hi_ndewey = shp->ndewey; 313696Spaul } 314696Spaul 315696Spaul tmpfile = concat(_PATH_LD_HINTS, "+", ""); 316696Spaul if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) { 317696Spaul perror(_PATH_LD_HINTS); 318696Spaul return -1; 319696Spaul } 320696Spaul 3211153Sjkh if (write(fd, &hdr, sizeof(struct hints_header)) != 3221153Sjkh sizeof(struct hints_header)) { 3231153Sjkh perror(_PATH_LD_HINTS); 3241153Sjkh return -1; 3251153Sjkh } 3261153Sjkh if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) != 3271153Sjkh hdr.hh_nbucket * sizeof(struct hints_bucket)) { 3281153Sjkh perror(_PATH_LD_HINTS); 3291153Sjkh return -1; 3301153Sjkh } 3311153Sjkh if (write(fd, strtab, strtab_sz) != strtab_sz) { 3321153Sjkh perror(_PATH_LD_HINTS); 3331153Sjkh return -1; 3341153Sjkh } 335696Spaul if (close(fd) != 0) { 336696Spaul perror(_PATH_LD_HINTS); 337696Spaul return -1; 338696Spaul } 339696Spaul 3401153Sjkh /* Install it */ 341696Spaul if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) { 342696Spaul perror(_PATH_LD_HINTS); 343696Spaul return -1; 344696Spaul } 345696Spaul 346696Spaul if (rename(tmpfile, _PATH_LD_HINTS) != 0) { 347696Spaul perror(_PATH_LD_HINTS); 348696Spaul return -1; 349696Spaul } 350696Spaul 351696Spaul return 0; 352696Spaul} 353696Spaul 3541741Srichstatic int 355696Spaullisthints() 356696Spaul{ 357696Spaul int fd; 358696Spaul caddr_t addr; 359696Spaul long msize; 360696Spaul struct hints_header *hdr; 361696Spaul struct hints_bucket *blist; 362696Spaul char *strtab; 363696Spaul int i; 364696Spaul 365696Spaul if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) { 366696Spaul perror(_PATH_LD_HINTS); 367696Spaul return -1; 368696Spaul } 369696Spaul 370696Spaul msize = PAGSIZ; 371696Spaul addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0); 372696Spaul 373696Spaul if (addr == (caddr_t)-1) { 374696Spaul perror(_PATH_LD_HINTS); 375696Spaul return -1; 376696Spaul } 377696Spaul 378696Spaul hdr = (struct hints_header *)addr; 379696Spaul if (HH_BADMAG(*hdr)) { 3801741Srich fprintf(stderr, "%s: Bad magic: %o\n", 3811741Srich _PATH_LD_HINTS, hdr->hh_magic); 382696Spaul return -1; 383696Spaul } 384696Spaul 385696Spaul if (hdr->hh_version != LD_HINTS_VERSION_1) { 386696Spaul fprintf(stderr, "Unsupported version: %d\n", hdr->hh_version); 387696Spaul return -1; 388696Spaul } 389696Spaul 390696Spaul if (hdr->hh_ehints > msize) { 391696Spaul if (mmap(addr+msize, hdr->hh_ehints - msize, 392696Spaul PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED, 393696Spaul fd, msize) != (caddr_t)(addr+msize)) { 394696Spaul 395696Spaul perror(_PATH_LD_HINTS); 396696Spaul return -1; 397696Spaul } 398696Spaul } 399696Spaul close(fd); 400696Spaul 401696Spaul blist = (struct hints_bucket *)(addr + hdr->hh_hashtab); 402696Spaul strtab = (char *)(addr + hdr->hh_strtab); 403696Spaul 404696Spaul printf("%s:\n", _PATH_LD_HINTS); 405696Spaul for (i = 0; i < hdr->hh_nbucket; i++) { 406696Spaul struct hints_bucket *bp = &blist[i]; 407696Spaul 408696Spaul /* Sanity check */ 409696Spaul if (bp->hi_namex >= hdr->hh_strtab_sz) { 410696Spaul fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex); 411696Spaul return -1; 412696Spaul } 413696Spaul if (bp->hi_pathx >= hdr->hh_strtab_sz) { 414696Spaul fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx); 415696Spaul return -1; 416696Spaul } 417696Spaul 418811Sjkh printf("\t%d:-l%s.%d.%d => %s (%d -> %d)\n", 419811Sjkh i, 420696Spaul strtab + bp->hi_namex, bp->hi_major, bp->hi_minor, 421811Sjkh strtab + bp->hi_pathx, 422811Sjkh hinthash(strtab+bp->hi_namex, bp->hi_major, bp->hi_minor) 423811Sjkh % hdr->hh_nbucket, 424811Sjkh bp->hi_next); 425696Spaul } 426696Spaul 427696Spaul return 0; 428696Spaul} 429696Spaul 430