ldconfig.c revision 9290
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 * 309290Sasami * $Id: ldconfig.c,v 1.8 1994/06/16 13:38:32 pk 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 575205Snateextern char *__progname; 585205Snate 59696Spaulstatic int verbose; 60696Spaulstatic int nostd; 61696Spaulstatic int justread; 629290Sasamistatic int merge; 63696Spaul 64696Spaulstruct shlib_list { 65696Spaul /* Internal list of shared libraries found */ 66696Spaul char *name; 67696Spaul char *path; 68696Spaul int dewey[MAXDEWEY]; 69696Spaul int ndewey; 70696Spaul#define major dewey[0] 71696Spaul#define minor dewey[1] 72696Spaul struct shlib_list *next; 73696Spaul}; 74696Spaul 75696Spaulstatic struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head; 76696Spaul 77696Spaulstatic void enter __P((char *, char *, char *, int *, int)); 781153Sjkhstatic int dodir __P((char *, int)); 799290Sasamistatic int buildhints __P((void)); 809290Sasamistatic int readhints __P((void)); 819290Sasamistatic void listhints __P((void)); 82696Spaul 83696Spaulint 84696Spaulmain(argc, argv) 85696Spaulint argc; 86696Spaulchar *argv[]; 87696Spaul{ 88696Spaul int i, c; 89696Spaul int rval = 0; 90696Spaul 919290Sasami while ((c = getopt(argc, argv, "mrsv")) != EOF) { 92696Spaul switch (c) { 939290Sasami case 'm': 949290Sasami merge = 1; 95696Spaul break; 969290Sasami case 'r': 979290Sasami justread = 1; 989290Sasami break; 99696Spaul case 's': 100696Spaul nostd = 1; 101696Spaul break; 1029290Sasami case 'v': 1039290Sasami verbose = 1; 104696Spaul break; 105696Spaul default: 1069290Sasami errx(1, "Usage: %s [-m][-r][-s][-v][dir ...]", 1075205Snate __progname); 108696Spaul break; 109696Spaul } 110696Spaul } 111696Spaul 1129290Sasami if (justread || merge) { 1139290Sasami if ((rval = readhints()) != 0) 1149290Sasami return rval; 1159290Sasami if (justread) { 1169290Sasami listhints(); 1179290Sasami return; 1189290Sasami } 1199290Sasami } 120696Spaul 121696Spaul if (!nostd) 1221741Srich std_search_path(); 123696Spaul 124696Spaul for (i = 0; i < n_search_dirs; i++) 1251153Sjkh rval |= dodir(search_dirs[i], 1); 126696Spaul 127696Spaul for (i = optind; i < argc; i++) 1281153Sjkh rval |= dodir(argv[i], 0); 129696Spaul 1309290Sasami rval |= buildhints(); 131696Spaul 132696Spaul return rval; 133696Spaul} 134696Spaul 135696Spaulint 1361153Sjkhdodir(dir, silent) 137696Spaulchar *dir; 1381153Sjkhint silent; 139696Spaul{ 140696Spaul DIR *dd; 141696Spaul struct dirent *dp; 142696Spaul char name[MAXPATHLEN], rest[MAXPATHLEN]; 143696Spaul int dewey[MAXDEWEY], ndewey; 144696Spaul 145696Spaul if ((dd = opendir(dir)) == NULL) { 1461153Sjkh if (!silent || errno != ENOENT) 1479290Sasami warn("%s", dir); 148696Spaul return -1; 149696Spaul } 150696Spaul 151696Spaul while ((dp = readdir(dd)) != NULL) { 152696Spaul int n; 153696Spaul 154696Spaul name[0] = rest[0] = '\0'; 155696Spaul 156696Spaul n = sscanf(dp->d_name, "lib%[^.].so.%s", 157696Spaul name, rest); 158696Spaul 159696Spaul if (n < 2 || rest[0] == '\0') 160696Spaul continue; 161696Spaul 162696Spaul ndewey = getdewey(dewey, rest); 163696Spaul enter(dir, dp->d_name, name, dewey, ndewey); 164696Spaul } 165696Spaul 166696Spaul return 0; 167696Spaul} 168696Spaul 169696Spaulstatic void 170696Spaulenter(dir, file, name, dewey, ndewey) 171696Spaulchar *dir, *file, *name; 172696Spaulint dewey[], ndewey; 173696Spaul{ 174696Spaul struct shlib_list *shp; 175696Spaul 176696Spaul for (shp = shlib_head; shp; shp = shp->next) { 177696Spaul if (strcmp(name, shp->name) != 0 || major != shp->major) 178696Spaul continue; 179696Spaul 180696Spaul /* Name matches existing entry */ 181696Spaul if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) { 182696Spaul 183696Spaul /* Update this entry with higher versioned lib */ 184696Spaul if (verbose) 185696Spaul printf("Updating lib%s.%d.%d to %s/%s\n", 186696Spaul shp->name, shp->major, shp->minor, 187696Spaul dir, file); 188696Spaul 189696Spaul free(shp->name); 190696Spaul shp->name = strdup(name); 191696Spaul free(shp->path); 192696Spaul shp->path = concat(dir, "/", file); 193696Spaul bcopy(dewey, shp->dewey, sizeof(shp->dewey)); 194696Spaul shp->ndewey = ndewey; 195696Spaul } 196696Spaul break; 197696Spaul } 198696Spaul 199696Spaul if (shp) 200696Spaul /* Name exists: older version or just updated */ 201696Spaul return; 202696Spaul 203696Spaul /* Allocate new list element */ 204696Spaul if (verbose) 205696Spaul printf("Adding %s/%s\n", dir, file); 206696Spaul 207696Spaul shp = (struct shlib_list *)xmalloc(sizeof *shp); 208696Spaul shp->name = strdup(name); 209696Spaul shp->path = concat(dir, "/", file); 210696Spaul bcopy(dewey, shp->dewey, MAXDEWEY); 211696Spaul shp->ndewey = ndewey; 212696Spaul shp->next = NULL; 213696Spaul 214696Spaul *shlib_tail = shp; 215696Spaul shlib_tail = &shp->next; 216696Spaul} 217696Spaul 218696Spaul 219696Spaul#if DEBUG 220696Spaul/* test */ 221696Spaul#undef _PATH_LD_HINTS 222696Spaul#define _PATH_LD_HINTS "./ld.so.hints" 223696Spaul#endif 224696Spaul 225696Spaulint 2265551Sjoerghinthash(cp, vmajor) 227696Spaulchar *cp; 2285551Sjoergint vmajor; 229696Spaul{ 230696Spaul int k = 0; 231696Spaul 232696Spaul while (*cp) 233696Spaul k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; 234696Spaul 235696Spaul k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff; 236696Spaul 237696Spaul return k; 238696Spaul} 239696Spaul 240696Spaulint 2419290Sasamibuildhints() 242696Spaul{ 243696Spaul struct hints_header hdr; 244696Spaul struct hints_bucket *blist; 245696Spaul struct shlib_list *shp; 246696Spaul char *strtab; 247696Spaul int i, n, str_index = 0; 248696Spaul int strtab_sz = 0; /* Total length of strings */ 249696Spaul int nhints = 0; /* Total number of hints */ 250696Spaul int fd; 251696Spaul char *tmpfile; 252696Spaul 253696Spaul for (shp = shlib_head; shp; shp = shp->next) { 254696Spaul strtab_sz += 1 + strlen(shp->name); 255696Spaul strtab_sz += 1 + strlen(shp->path); 256696Spaul nhints++; 257696Spaul } 258696Spaul 259696Spaul /* Fill hints file header */ 260696Spaul hdr.hh_magic = HH_MAGIC; 261696Spaul hdr.hh_version = LD_HINTS_VERSION_1; 262696Spaul hdr.hh_nbucket = 1 * nhints; 263696Spaul n = hdr.hh_nbucket * sizeof(struct hints_bucket); 264696Spaul hdr.hh_hashtab = sizeof(struct hints_header); 265696Spaul hdr.hh_strtab = hdr.hh_hashtab + n; 266696Spaul hdr.hh_strtab_sz = strtab_sz; 267696Spaul hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz; 268696Spaul 269696Spaul if (verbose) 270696Spaul printf("Totals: entries %d, buckets %d, string size %d\n", 271696Spaul nhints, hdr.hh_nbucket, strtab_sz); 272696Spaul 273696Spaul /* Allocate buckets and string table */ 274696Spaul blist = (struct hints_bucket *)xmalloc(n); 275696Spaul bzero((char *)blist, n); 276696Spaul for (i = 0; i < hdr.hh_nbucket; i++) 277696Spaul /* Empty all buckets */ 278696Spaul blist[i].hi_next = -1; 279696Spaul 280696Spaul strtab = (char *)xmalloc(strtab_sz); 281696Spaul 282696Spaul /* Enter all */ 283696Spaul for (shp = shlib_head; shp; shp = shp->next) { 284696Spaul struct hints_bucket *bp; 285696Spaul 286696Spaul bp = blist + 2875551Sjoerg (hinthash(shp->name, shp->major) % hdr.hh_nbucket); 288696Spaul 289696Spaul if (bp->hi_pathx) { 290696Spaul int i; 291696Spaul 292696Spaul for (i = 0; i < hdr.hh_nbucket; i++) { 293696Spaul if (blist[i].hi_pathx == 0) 294696Spaul break; 295696Spaul } 296696Spaul if (i == hdr.hh_nbucket) { 2979290Sasami warnx("Bummer!"); 298696Spaul return -1; 299696Spaul } 300696Spaul while (bp->hi_next != -1) 301696Spaul bp = &blist[bp->hi_next]; 302696Spaul bp->hi_next = i; 303696Spaul bp = blist + i; 304696Spaul } 305696Spaul 306696Spaul /* Insert strings in string table */ 307696Spaul bp->hi_namex = str_index; 308696Spaul strcpy(strtab + str_index, shp->name); 309696Spaul str_index += 1 + strlen(shp->name); 310696Spaul 311696Spaul bp->hi_pathx = str_index; 312696Spaul strcpy(strtab + str_index, shp->path); 313696Spaul str_index += 1 + strlen(shp->path); 314696Spaul 315696Spaul /* Copy versions */ 316696Spaul bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey)); 317696Spaul bp->hi_ndewey = shp->ndewey; 318696Spaul } 319696Spaul 320696Spaul tmpfile = concat(_PATH_LD_HINTS, "+", ""); 321696Spaul if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) { 3229290Sasami warn("%s", _PATH_LD_HINTS); 323696Spaul return -1; 324696Spaul } 325696Spaul 3261153Sjkh if (write(fd, &hdr, sizeof(struct hints_header)) != 3271153Sjkh sizeof(struct hints_header)) { 3289290Sasami warn("%s", _PATH_LD_HINTS); 3291153Sjkh return -1; 3301153Sjkh } 3311153Sjkh if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) != 3321153Sjkh hdr.hh_nbucket * sizeof(struct hints_bucket)) { 3339290Sasami warn("%s", _PATH_LD_HINTS); 3341153Sjkh return -1; 3351153Sjkh } 3361153Sjkh if (write(fd, strtab, strtab_sz) != strtab_sz) { 3379290Sasami warn("%s", _PATH_LD_HINTS); 3381153Sjkh return -1; 3391153Sjkh } 340696Spaul if (close(fd) != 0) { 3419290Sasami warn("%s", _PATH_LD_HINTS); 342696Spaul return -1; 343696Spaul } 344696Spaul 3451153Sjkh /* Install it */ 346696Spaul if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) { 3479290Sasami warn("%s", _PATH_LD_HINTS); 348696Spaul return -1; 349696Spaul } 350696Spaul 351696Spaul if (rename(tmpfile, _PATH_LD_HINTS) != 0) { 3529290Sasami warn("%s", _PATH_LD_HINTS); 353696Spaul return -1; 354696Spaul } 355696Spaul 356696Spaul return 0; 357696Spaul} 358696Spaul 3591741Srichstatic int 3609290Sasamireadhints() 361696Spaul{ 362696Spaul int fd; 363696Spaul caddr_t addr; 364696Spaul long msize; 365696Spaul struct hints_header *hdr; 366696Spaul struct hints_bucket *blist; 367696Spaul char *strtab; 3689290Sasami struct shlib_list *shp; 369696Spaul int i; 370696Spaul 371696Spaul if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) { 3729290Sasami warn("%s", _PATH_LD_HINTS); 373696Spaul return -1; 374696Spaul } 375696Spaul 376696Spaul msize = PAGSIZ; 3775205Snate addr = mmap(0, msize, PROT_READ, MAP_COPY, fd, 0); 378696Spaul 379696Spaul if (addr == (caddr_t)-1) { 3809290Sasami warn("%s", _PATH_LD_HINTS); 381696Spaul return -1; 382696Spaul } 383696Spaul 384696Spaul hdr = (struct hints_header *)addr; 385696Spaul if (HH_BADMAG(*hdr)) { 3869290Sasami warnx("%s: Bad magic: %o", 3871741Srich _PATH_LD_HINTS, hdr->hh_magic); 388696Spaul return -1; 389696Spaul } 390696Spaul 391696Spaul if (hdr->hh_version != LD_HINTS_VERSION_1) { 3929290Sasami warnx("Unsupported version: %d", hdr->hh_version); 393696Spaul return -1; 394696Spaul } 395696Spaul 396696Spaul if (hdr->hh_ehints > msize) { 397696Spaul if (mmap(addr+msize, hdr->hh_ehints - msize, 3985205Snate PROT_READ, MAP_COPY|MAP_FIXED, 399696Spaul fd, msize) != (caddr_t)(addr+msize)) { 400696Spaul 4019290Sasami warn("%s", _PATH_LD_HINTS); 402696Spaul return -1; 403696Spaul } 404696Spaul } 405696Spaul close(fd); 406696Spaul 407696Spaul blist = (struct hints_bucket *)(addr + hdr->hh_hashtab); 408696Spaul strtab = (char *)(addr + hdr->hh_strtab); 409696Spaul 410696Spaul for (i = 0; i < hdr->hh_nbucket; i++) { 411696Spaul struct hints_bucket *bp = &blist[i]; 412696Spaul 413696Spaul /* Sanity check */ 414696Spaul if (bp->hi_namex >= hdr->hh_strtab_sz) { 4159290Sasami warnx("Bad name index: %#x", bp->hi_namex); 416696Spaul return -1; 417696Spaul } 418696Spaul if (bp->hi_pathx >= hdr->hh_strtab_sz) { 4199290Sasami warnx("Bad path index: %#x", bp->hi_pathx); 420696Spaul return -1; 421696Spaul } 422696Spaul 4239290Sasami /* Allocate new list element */ 4249290Sasami shp = (struct shlib_list *)xmalloc(sizeof *shp); 4259290Sasami shp->name = strdup(strtab + bp->hi_namex); 4269290Sasami shp->path = strdup(strtab + bp->hi_pathx); 4279290Sasami bcopy(bp->hi_dewey, shp->dewey, sizeof(shp->dewey)); 4289290Sasami shp->ndewey = bp->hi_ndewey; 4299290Sasami shp->next = NULL; 4309290Sasami 4319290Sasami *shlib_tail = shp; 4329290Sasami shlib_tail = &shp->next; 433696Spaul } 434696Spaul 435696Spaul return 0; 436696Spaul} 437696Spaul 4389290Sasamistatic void 4399290Sasamilisthints() 4409290Sasami{ 4419290Sasami struct shlib_list *shp; 4429290Sasami int i; 4439290Sasami 4449290Sasami printf("%s:\n", _PATH_LD_HINTS); 4459290Sasami 4469290Sasami for (i = 0, shp = shlib_head; shp; i++, shp = shp->next) 4479290Sasami printf("\t%d:-l%s.%d.%d => %s\n", 4489290Sasami i, shp->name, shp->major, shp->minor, shp->path); 4499290Sasami 4509290Sasami return; 4519290Sasami} 4529290Sasami 453