1 /* 2 * Copyright (c) 1993,1995 Paul Kranenburg 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Paul Kranenburg. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $Id: ldconfig.c,v 1.13 1996/01/09 00:04:35 pk Exp $ 31 */ 32 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <sys/file.h> 37 #include <sys/time.h> 38 #include <sys/mman.h> 39 #include <sys/resource.h> 40 #include <dirent.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <ar.h> 44 #include <ranlib.h> 45 #include <a.out.h> 46 #include <stab.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 52 #include "ld.h" 53 54 #undef major 55 #undef minor 56 57 extern char *__progname; 58 59 static int verbose; 60 static int nostd; 61 static int justread; 62 static int merge; 63 64 struct shlib_list { 65 /* Internal list of shared libraries found */ 66 char *name; 67 char *path; 68 int dewey[MAXDEWEY]; 69 int ndewey; 70 #define major dewey[0] 71 #define minor dewey[1] 72 struct shlib_list *next; 73 }; 74 75 static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head; 76 77 static void enter __P((char *, char *, char *, int *, int)); 78 static int dodir __P((char *, int)); 79 static int buildhints __P((void)); 80 static int readhints __P((void)); 81 static void listhints __P((void)); 82 83 int 84 main(argc, argv) 85 int argc; 86 char *argv[]; 87 { 88 int i, c; 89 int rval = 0; 90 91 while ((c = getopt(argc, argv, "mrsv")) != EOF) { 92 switch (c) { 93 case 'm': 94 merge = 1; 95 break; 96 case 'r': 97 justread = 1; 98 break; 99 case 's': 100 nostd = 1; 101 break; 102 case 'v': 103 verbose = 1; 104 break; 105 default: 106 errx(1, "Usage: %s [-m][-r][-s][-v][dir ...]", 107 __progname); 108 break; 109 } 110 } 111 112 if (justread || merge) { 113 if ((rval = readhints()) != 0) 114 return rval; 115 if (justread) { 116 listhints(); 117 return; 118 } 119 } 120 121 if (!nostd) 122 std_search_path(); 123 124 for (i = 0; i < n_search_dirs; i++) 125 rval |= dodir(search_dirs[i], 1); 126 127 for (i = optind; i < argc; i++) 128 rval |= dodir(argv[i], 0); 129 130 rval |= buildhints(); 131 132 return rval; 133 } 134 135 int 136 dodir(dir, silent) 137 char *dir; 138 int silent; 139 { 140 DIR *dd; 141 struct dirent *dp; 142 char name[MAXPATHLEN]; 143 int dewey[MAXDEWEY], ndewey; 144 145 if ((dd = opendir(dir)) == NULL) { 146 if (!silent || errno != ENOENT) 147 warn("%s", dir); 148 return -1; 149 } 150 151 while ((dp = readdir(dd)) != NULL) { 152 register int n; 153 register char *cp; 154 155 /* Check for `lib' prefix */ 156 if (dp->d_name[0] != 'l' || 157 dp->d_name[1] != 'i' || 158 dp->d_name[2] != 'b') 159 continue; 160 161 /* Copy the entry minus prefix */ 162 (void)strcpy(name, dp->d_name + 3); 163 n = strlen(name); 164 if (n < 4) 165 continue; 166 167 /* Find ".so." in name */ 168 for (cp = name + n - 4; cp > name; --cp) { 169 if (cp[0] == '.' && 170 cp[1] == 's' && 171 cp[2] == 'o' && 172 cp[3] == '.') 173 break; 174 } 175 if (cp <= name) 176 continue; 177 178 *cp = '\0'; 179 if (!isdigit(*(cp+4))) 180 continue; 181 182 bzero((caddr_t)dewey, sizeof(dewey)); 183 ndewey = getdewey(dewey, cp + 4); 184 enter(dir, dp->d_name, name, dewey, ndewey); 185 } 186 187 return 0; 188 } 189 190 static void 191 enter(dir, file, name, dewey, ndewey) 192 char *dir, *file, *name; 193 int dewey[], ndewey; 194 { 195 struct shlib_list *shp; 196 197 for (shp = shlib_head; shp; shp = shp->next) { 198 if (strcmp(name, shp->name) != 0 || major != shp->major) 199 continue; 200 201 /* Name matches existing entry */ 202 if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) { 203 204 /* Update this entry with higher versioned lib */ 205 if (verbose) 206 printf("Updating lib%s.%d.%d to %s/%s\n", 207 shp->name, shp->major, shp->minor, 208 dir, file); 209 210 free(shp->name); 211 shp->name = strdup(name); 212 free(shp->path); 213 shp->path = concat(dir, "/", file); 214 bcopy(dewey, shp->dewey, sizeof(shp->dewey)); 215 shp->ndewey = ndewey; 216 } 217 break; 218 } 219 220 if (shp) 221 /* Name exists: older version or just updated */ 222 return; 223 224 /* Allocate new list element */ 225 if (verbose) 226 printf("Adding %s/%s\n", dir, file); 227 228 shp = (struct shlib_list *)xmalloc(sizeof *shp); 229 shp->name = strdup(name); 230 shp->path = concat(dir, "/", file); 231 bcopy(dewey, shp->dewey, MAXDEWEY); 232 shp->ndewey = ndewey; 233 shp->next = NULL; 234 235 *shlib_tail = shp; 236 shlib_tail = &shp->next; 237 } 238 239 240 #if DEBUG 241 /* test */ 242 #undef _PATH_LD_HINTS 243 #define _PATH_LD_HINTS "./ld.so.hints" 244 #endif 245 246 int 247 hinthash(cp, vmajor) 248 char *cp; 249 int vmajor; 250 { 251 int k = 0; 252 253 while (*cp) 254 k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; 255 256 k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff; 257 258 return k; 259 } 260 261 int 262 buildhints() 263 { 264 struct hints_header hdr; 265 struct hints_bucket *blist; 266 struct shlib_list *shp; 267 char *strtab; 268 int i, n, str_index = 0; 269 int strtab_sz = 0; /* Total length of strings */ 270 int nhints = 0; /* Total number of hints */ 271 int fd; 272 char *tmpfile; 273 274 for (shp = shlib_head; shp; shp = shp->next) { 275 strtab_sz += 1 + strlen(shp->name); 276 strtab_sz += 1 + strlen(shp->path); 277 nhints++; 278 } 279 280 /* Fill hints file header */ 281 hdr.hh_magic = HH_MAGIC; 282 hdr.hh_version = LD_HINTS_VERSION_1; 283 hdr.hh_nbucket = 1 * nhints; 284 n = hdr.hh_nbucket * sizeof(struct hints_bucket); 285 hdr.hh_hashtab = sizeof(struct hints_header); 286 hdr.hh_strtab = hdr.hh_hashtab + n; 287 hdr.hh_strtab_sz = strtab_sz; 288 hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz; 289 290 if (verbose) 291 printf("Totals: entries %d, buckets %d, string size %d\n", 292 nhints, hdr.hh_nbucket, strtab_sz); 293 294 /* Allocate buckets and string table */ 295 blist = (struct hints_bucket *)xmalloc(n); 296 bzero((char *)blist, n); 297 for (i = 0; i < hdr.hh_nbucket; i++) 298 /* Empty all buckets */ 299 blist[i].hi_next = -1; 300 301 strtab = (char *)xmalloc(strtab_sz); 302 303 /* Enter all */ 304 for (shp = shlib_head; shp; shp = shp->next) { 305 struct hints_bucket *bp; 306 307 bp = blist + 308 (hinthash(shp->name, shp->major) % hdr.hh_nbucket); 309 310 if (bp->hi_pathx) { 311 int i; 312 313 for (i = 0; i < hdr.hh_nbucket; i++) { 314 if (blist[i].hi_pathx == 0) 315 break; 316 } 317 if (i == hdr.hh_nbucket) { 318 warnx("Bummer!"); 319 return -1; 320 } 321 while (bp->hi_next != -1) 322 bp = &blist[bp->hi_next]; 323 bp->hi_next = i; 324 bp = blist + i; 325 } 326 327 /* Insert strings in string table */ 328 bp->hi_namex = str_index; 329 strcpy(strtab + str_index, shp->name); 330 str_index += 1 + strlen(shp->name); 331 332 bp->hi_pathx = str_index; 333 strcpy(strtab + str_index, shp->path); 334 str_index += 1 + strlen(shp->path); 335 336 /* Copy versions */ 337 bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey)); 338 bp->hi_ndewey = shp->ndewey; 339 } 340 341 umask(022); /* ensure the file will be worl-readable */ 342 tmpfile = concat(_PATH_LD_HINTS, "+", ""); 343 if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) { 344 warn("%s", _PATH_LD_HINTS); 345 return -1; 346 } 347 348 if (write(fd, &hdr, sizeof(struct hints_header)) != 349 sizeof(struct hints_header)) { 350 warn("%s", _PATH_LD_HINTS); 351 return -1; 352 } 353 if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) != 354 hdr.hh_nbucket * sizeof(struct hints_bucket)) { 355 warn("%s", _PATH_LD_HINTS); 356 return -1; 357 } 358 if (write(fd, strtab, strtab_sz) != strtab_sz) { 359 warn("%s", _PATH_LD_HINTS); 360 return -1; 361 } 362 if (close(fd) != 0) { 363 warn("%s", _PATH_LD_HINTS); 364 return -1; 365 } 366 367 /* Install it */ 368 if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) { 369 warn("%s", _PATH_LD_HINTS); 370 return -1; 371 } 372 373 if (rename(tmpfile, _PATH_LD_HINTS) != 0) { 374 warn("%s", _PATH_LD_HINTS); 375 return -1; 376 } 377 378 return 0; 379 } 380 381 static int 382 readhints() 383 { 384 int fd; 385 caddr_t addr; 386 long msize; 387 struct hints_header *hdr; 388 struct hints_bucket *blist; 389 char *strtab; 390 struct shlib_list *shp; 391 int i; 392 393 if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) { 394 warn("%s", _PATH_LD_HINTS); 395 return -1; 396 } 397 398 msize = PAGSIZ; 399 addr = mmap(0, msize, PROT_READ, MAP_COPY, fd, 0); 400 401 if (addr == (caddr_t)-1) { 402 warn("%s", _PATH_LD_HINTS); 403 return -1; 404 } 405 406 hdr = (struct hints_header *)addr; 407 if (HH_BADMAG(*hdr)) { 408 warnx("%s: Bad magic: %o", 409 _PATH_LD_HINTS, hdr->hh_magic); 410 return -1; 411 } 412 413 if (hdr->hh_version != LD_HINTS_VERSION_1) { 414 warnx("Unsupported version: %d", hdr->hh_version); 415 return -1; 416 } 417 418 if (hdr->hh_ehints > msize) { 419 if (mmap(addr+msize, hdr->hh_ehints - msize, 420 PROT_READ, MAP_COPY|MAP_FIXED, 421 fd, msize) != (caddr_t)(addr+msize)) { 422 423 warn("%s", _PATH_LD_HINTS); 424 return -1; 425 } 426 } 427 close(fd); 428 429 blist = (struct hints_bucket *)(addr + hdr->hh_hashtab); 430 strtab = (char *)(addr + hdr->hh_strtab); 431 432 for (i = 0; i < hdr->hh_nbucket; i++) { 433 struct hints_bucket *bp = &blist[i]; 434 435 /* Sanity check */ 436 if (bp->hi_namex >= hdr->hh_strtab_sz) { 437 warnx("Bad name index: %#x", bp->hi_namex); 438 return -1; 439 } 440 if (bp->hi_pathx >= hdr->hh_strtab_sz) { 441 warnx("Bad path index: %#x", bp->hi_pathx); 442 return -1; 443 } 444 445 /* Allocate new list element */ 446 shp = (struct shlib_list *)xmalloc(sizeof *shp); 447 shp->name = strdup(strtab + bp->hi_namex); 448 shp->path = strdup(strtab + bp->hi_pathx); 449 bcopy(bp->hi_dewey, shp->dewey, sizeof(shp->dewey)); 450 shp->ndewey = bp->hi_ndewey; 451 shp->next = NULL; 452 453 *shlib_tail = shp; 454 shlib_tail = &shp->next; 455 } 456 457 return 0; 458 } 459 460 static void 461 listhints() 462 { 463 struct shlib_list *shp; 464 int i; 465 466 printf("%s:\n", _PATH_LD_HINTS); 467 468 for (i = 0, shp = shlib_head; shp; i++, shp = shp->next) 469 printf("\t%d:-l%s.%d.%d => %s\n", 470 i, shp->name, shp->major, shp->minor, shp->path); 471 472 return; 473 } 474