Index: head/libexec/rtld-elf/malloc.c =================================================================== --- head/libexec/rtld-elf/malloc.c (revision 325133) +++ head/libexec/rtld-elf/malloc.c (revision 325134) @@ -1,490 +1,490 @@ /*- * Copyright (c) 1983 Regents of the University of California. * 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. */ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/ static char *rcsid = "$FreeBSD$"; #endif /* LIBC_SCCS and not lint */ /* * malloc.c (Caltech) 2/21/82 * Chris Kingsley, kingsley@cit-20. * * This is a very fast storage allocator. It allocates blocks of a small * number of different sizes, and keeps free lists of each size. Blocks that * don't exactly fit are passed up to the next larger size. In this * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long. * This is designed for use in a virtual memory environment. */ #include #include #include #include #include #include #include #include #include #include #include "rtld_printf.h" static void morecore(); static int findbucket(); /* * Pre-allocate mmap'ed pages */ #define NPOOLPAGES (32*1024/pagesz) static caddr_t pagepool_start, pagepool_end; static int morepages(); /* * The overhead on a block is at least 4 bytes. When free, this space * contains a pointer to the next free block, and the bottom two bits must * be zero. When in use, the first byte is set to MAGIC, and the second * byte is the size index. The remaining bytes are for alignment. * If range checking is enabled then a second word holds the size of the * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). * The order of elements is critical: ov_magic must overlay the low order * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. */ union overhead { union overhead *ov_next; /* when free */ struct { u_char ovu_magic; /* magic number */ u_char ovu_index; /* bucket # */ #ifdef RCHECK u_short ovu_rmagic; /* range magic number */ u_int ovu_size; /* actual block size */ #endif } ovu; #define ov_magic ovu.ovu_magic #define ov_index ovu.ovu_index #define ov_rmagic ovu.ovu_rmagic #define ov_size ovu.ovu_size }; #define MAGIC 0xef /* magic # on accounting info */ #define RMAGIC 0x5555 /* magic # on range info */ #ifdef RCHECK #define RSLOP sizeof (u_short) #else #define RSLOP 0 #endif /* * nextf[i] is the pointer to the next free block of size 2^(i+3). The * smallest allocatable block is 8 bytes. The overhead information * precedes the data area returned to the user. */ #define NBUCKETS 30 static union overhead *nextf[NBUCKETS]; static int pagesz; /* page size */ static int pagebucket; /* page size bucket */ #ifdef MSTATS /* * nmalloc[i] is the difference between the number of mallocs and frees * for a given block size. */ static u_int nmalloc[NBUCKETS]; #include #endif #if defined(MALLOC_DEBUG) || defined(RCHECK) #define ASSERT(p) if (!(p)) botch("p") #include static void botch(s) char *s; { fprintf(stderr, "\r\nassertion botched: %s\r\n", s); (void) fflush(stderr); /* just in case user buffered it */ abort(); } #else #define ASSERT(p) #endif /* Debugging stuff */ #define TRACE() rtld_printf("TRACE %s:%d\n", __FILE__, __LINE__) /* * The array of supported page sizes is provided by the user, i.e., the * program that calls this storage allocator. That program must initialize * the array before making its first call to allocate storage. The array * must contain at least one page size. The page sizes must be stored in * increasing order. */ extern size_t *pagesizes; void * malloc(nbytes) size_t nbytes; { register union overhead *op; register int bucket; register long n; register unsigned amt; /* * First time malloc is called, setup page size and * align break pointer so all data will be page aligned. */ if (pagesz == 0) { pagesz = n = pagesizes[0]; if (morepages(NPOOLPAGES) == 0) return NULL; op = (union overhead *)(pagepool_start); n = n - sizeof (*op) - ((long)op & (n - 1)); if (n < 0) n += pagesz; if (n) { pagepool_start += n; } bucket = 0; amt = 8; while ((unsigned)pagesz > amt) { amt <<= 1; bucket++; } pagebucket = bucket; } /* * Convert amount of memory requested into closest block size * stored in hash buckets which satisfies request. * Account for space used per block for accounting. */ if (nbytes <= (unsigned long)(n = pagesz - sizeof (*op) - RSLOP)) { #ifndef RCHECK amt = 8; /* size of first bucket */ bucket = 0; #else amt = 16; /* size of first bucket */ bucket = 1; #endif n = -(sizeof (*op) + RSLOP); } else { amt = pagesz; bucket = pagebucket; } while (nbytes > amt + n) { amt <<= 1; if (amt == 0) return (NULL); bucket++; } /* * If nothing in hash bucket right now, * request more memory from the system. */ if ((op = nextf[bucket]) == NULL) { morecore(bucket); if ((op = nextf[bucket]) == NULL) return (NULL); } /* remove from linked list */ nextf[bucket] = op->ov_next; op->ov_magic = MAGIC; op->ov_index = bucket; #ifdef MSTATS nmalloc[bucket]++; #endif #ifdef RCHECK /* * Record allocated size of block and * bound space with magic numbers. */ op->ov_size = roundup2(nbytes, RSLOP); op->ov_rmagic = RMAGIC; *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif return ((char *)(op + 1)); } void * calloc(size_t num, size_t size) { void *ret; if (size != 0 && (num * size) / size != num) { /* size_t overflow. */ return (NULL); } if ((ret = malloc(num * size)) != NULL) memset(ret, 0, num * size); return (ret); } /* * Allocate more memory to the indicated bucket. */ static void morecore(bucket) int bucket; { register union overhead *op; register int sz; /* size of desired block */ int amt; /* amount to allocate */ int nblks; /* how many blocks we get */ /* * sbrk_size <= 0 only for big, FLUFFY, requests (about * 2^30 bytes on a VAX, I think) or for a negative arg. */ sz = 1 << (bucket + 3); #ifdef MALLOC_DEBUG ASSERT(sz > 0); #else if (sz <= 0) return; #endif if (sz < pagesz) { amt = pagesz; nblks = amt / sz; } else { amt = sz + pagesz; nblks = 1; } if (amt > pagepool_end - pagepool_start) if (morepages(amt/pagesz + NPOOLPAGES) == 0) return; op = (union overhead *)pagepool_start; pagepool_start += amt; /* * Add new memory allocated to that on * free list for this hash bucket. */ nextf[bucket] = op; while (--nblks > 0) { op->ov_next = (union overhead *)((caddr_t)op + sz); op = (union overhead *)((caddr_t)op + sz); } } void free(cp) void *cp; { register int size; register union overhead *op; if (cp == NULL) return; op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); #ifdef MALLOC_DEBUG ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */ #else if (op->ov_magic != MAGIC) return; /* sanity */ #endif #ifdef RCHECK ASSERT(op->ov_rmagic == RMAGIC); ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC); #endif size = op->ov_index; ASSERT(size < NBUCKETS); op->ov_next = nextf[size]; /* also clobbers ov_magic */ nextf[size] = op; #ifdef MSTATS nmalloc[size]--; #endif } /* * When a program attempts "storage compaction" as mentioned in the * old malloc man page, it realloc's an already freed block. Usually * this is the last block it freed; occasionally it might be farther * back. We have to search all the free lists for the block in order * to determine its bucket: 1st we make one pass through the lists * checking only the first block in each; if that fails we search * ``realloc_srchlen'' blocks in each list for a match (the variable * is extern so the caller can modify it). If that fails we just copy * however many bytes was given to realloc() and hope it's not huge. */ int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */ void * realloc(cp, nbytes) void *cp; size_t nbytes; { register u_int onb; register int i; union overhead *op; char *res; int was_alloced = 0; if (cp == NULL) return (malloc(nbytes)); op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); if (op->ov_magic == MAGIC) { was_alloced++; i = op->ov_index; } else { /* * Already free, doing "compaction". * * Search for the old block of memory on the * free list. First, check the most common * case (last element free'd), then (this failing) * the last ``realloc_srchlen'' items free'd. * If all lookups fail, then assume the size of * the memory block being realloc'd is the * largest possible (so that all "nbytes" of new * memory are copied into). Note that this could cause * a memory fault if the old area was tiny, and the moon * is gibbous. However, that is very unlikely. */ if ((i = findbucket(op, 1)) < 0 && (i = findbucket(op, realloc_srchlen)) < 0) i = NBUCKETS; } onb = 1 << (i + 3); if (onb < (u_int)pagesz) onb -= sizeof (*op) + RSLOP; else onb += pagesz - sizeof (*op) - RSLOP; /* avoid the copy if same size block */ if (was_alloced) { if (i) { i = 1 << (i + 2); if (i < pagesz) i -= sizeof (*op) + RSLOP; else i += pagesz - sizeof (*op) - RSLOP; } if (nbytes <= onb && nbytes > (size_t)i) { #ifdef RCHECK op->ov_size = roundup2(nbytes, RSLOP); *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif return(cp); } else free(cp); } if ((res = malloc(nbytes)) == NULL) return (NULL); if (cp != res) /* common optimization if "compacting" */ bcopy(cp, res, (nbytes < onb) ? nbytes : onb); return (res); } /* * Search ``srchlen'' elements of each free list for a block whose * header starts at ``freep''. If srchlen is -1 search the whole list. * Return bucket number, or -1 if not found. */ static int findbucket(freep, srchlen) union overhead *freep; int srchlen; { register union overhead *p; register int i, j; for (i = 0; i < NBUCKETS; i++) { j = 0; for (p = nextf[i]; p && j != srchlen; p = p->ov_next) { if (p == freep) return (i); j++; } } return (-1); } #ifdef MSTATS /* * mstats - print out statistics about malloc * * Prints two lines of numbers, one showing the length of the free list * for each size category, the second showing the number of mallocs - * frees for each size category. */ mstats(s) char *s; { register int i, j; register union overhead *p; int totfree = 0, totused = 0; fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s); for (i = 0; i < NBUCKETS; i++) { for (j = 0, p = nextf[i]; p; p = p->ov_next, j++) ; fprintf(stderr, " %d", j); totfree += j * (1 << (i + 3)); } fprintf(stderr, "\nused:\t"); for (i = 0; i < NBUCKETS; i++) { fprintf(stderr, " %d", nmalloc[i]); totused += nmalloc[i] * (1 << (i + 3)); } fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n", totused, totfree); } #endif static int morepages(n) int n; { int fd = -1; int offset; if (pagepool_end - pagepool_start > pagesz) { caddr_t addr = (caddr_t) (((long)pagepool_start + pagesz - 1) & ~(pagesz - 1)); if (munmap(addr, pagepool_end - addr) != 0) rtld_fdprintf(STDERR_FILENO, "morepages: munmap %p", addr); } offset = (long)pagepool_start - ((long)pagepool_start & ~(pagesz - 1)); if ((pagepool_start = mmap(0, n * pagesz, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) { + MAP_ANON|MAP_PRIVATE, fd, 0)) == (caddr_t)-1) { rtld_printf("Cannot map anonymous memory\n"); return 0; } pagepool_end = pagepool_start + n * pagesz; pagepool_start += offset; return n; } Index: head/sbin/ldconfig/ldconfig.c =================================================================== --- head/sbin/ldconfig/ldconfig.c (revision 325133) +++ head/sbin/ldconfig/ldconfig.c (revision 325134) @@ -1,648 +1,648 @@ /* * Copyright (c) 1993,1995 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. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ldconfig.h" #include "shlib.h" #include "support.h" #if DEBUG /* test */ #undef _PATH_LD_HINTS #define _PATH_LD_HINTS "./ld.so.hints" #undef _PATH_ELF_HINTS #define _PATH_ELF_HINTS "./ld-elf.so.hints" #endif #define _PATH_LD32_HINTS "/var/run/ld32.so.hints" #define _PATH_ELF32_HINTS "/var/run/ld-elf32.so.hints" #define _PATH_ELFSOFT_HINTS "/var/run/ld-elf-soft.so.hints" #undef major #undef minor static int verbose; static int nostd; static int justread; static int merge; static int rescan; static const char *hints_file; struct shlib_list { /* Internal list of shared libraries found */ char *name; char *path; int dewey[MAXDEWEY]; int ndewey; #define major dewey[0] #define minor dewey[1] struct shlib_list *next; }; static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head; static char *dir_list; static int buildhints(void); static int dodir(char *, int); int dofile(char *, int); static void enter(char *, char *, char *, int *, int); static void listhints(void); static int readhints(void); static void usage(void); /* * Note on aout/a.out support. * To properly support shared libraries for compat2x, which are a.out, we need * to support a.out here. As of 2013, bug reports are still coming in for this * feature (on amd64 no less), so we know it is still in use. */ int main(int argc, char **argv) { int i, c; int rval = 0; int is_aout = 0; int is_32 = 0; int is_soft = 0; while (argc > 1) { if (strcmp(argv[1], "-aout") == 0) { is_aout = 1; argc--; argv++; } else if (strcmp(argv[1], "-elf") == 0) { is_aout = 0; argc--; argv++; } else if (strcmp(argv[1], "-32") == 0) { is_32 = 1; argc--; argv++; } else if (strcmp(argv[1], "-soft") == 0) { is_soft = 1; argc--; argv++; } else { break; } } if (is_soft) hints_file = _PATH_ELFSOFT_HINTS; /* Never will have a.out softfloat */ else if (is_32) hints_file = is_aout ? _PATH_LD32_HINTS : _PATH_ELF32_HINTS; else hints_file = is_aout ? _PATH_LD_HINTS : _PATH_ELF_HINTS; if (argc == 1) rescan = 1; else while((c = getopt(argc, argv, "Rf:imrsv")) != -1) { switch (c) { case 'R': rescan = 1; break; case 'f': hints_file = optarg; break; case 'i': insecure = 1; break; case 'm': merge = 1; break; case 'r': justread = 1; break; case 's': nostd = 1; break; case 'v': verbose = 1; break; default: usage(); break; } } if (!is_aout) { if (justread) list_elf_hints(hints_file); else update_elf_hints(hints_file, argc - optind, argv + optind, merge || rescan); return 0; } /* Here begins the aout libs processing */ dir_list = strdup(""); if (justread || merge || rescan) { if ((rval = readhints()) != 0) return rval; } if (!nostd && !merge && !rescan) std_search_path(); /* Add any directories/files from the command line */ if (!justread) { for (i = optind; i < argc; i++) { struct stat stbuf; if (stat(argv[i], &stbuf) == -1) { warn("%s", argv[i]); rval = -1; } else if (strcmp(argv[i], "/usr/lib") == 0) { warnx("WARNING! '%s' can not be used", argv[i]); rval = -1; } else { /* * See if this is a directory-containing * file instead of a directory */ if (S_ISREG(stbuf.st_mode)) rval |= dofile(argv[i], 0); else add_search_path(argv[i]); } } } for (i = 0; i < n_search_dirs; i++) { char *cp = concat(dir_list, *dir_list?":":"", search_dirs[i]); free(dir_list); dir_list = cp; } if (justread) { listhints(); return 0; } for (i = 0; i < n_search_dirs; i++) rval |= dodir(search_dirs[i], 1); rval |= buildhints(); return rval; } static void usage(void) { fprintf(stderr, "usage: ldconfig [-32] [-aout | -elf] [-Rimrsv] [-f hints_file] [directory | file ...]\n"); exit(1); } int dofile(char *fname, int silent) { FILE *hfp; char buf[MAXPATHLEN]; int rval = 0; char *cp, *sp; if ((hfp = fopen(fname, "r")) == NULL) { warn("%s", fname); return -1; } while (fgets(buf, sizeof(buf), hfp)) { cp = buf; while (isspace(*cp)) cp++; if (*cp == '#' || *cp == '\0') continue; sp = cp; while (!isspace(*cp) && *cp != '\0') cp++; if (*cp != '\n') { *cp = '\0'; warnx("%s: trailing characters ignored", sp); } *cp = '\0'; rval |= dodir(sp, silent); } (void)fclose(hfp); return rval; } int dodir(char *dir, int silent) { DIR *dd; struct dirent *dp; char name[MAXPATHLEN]; int dewey[MAXDEWEY], ndewey; if ((dd = opendir(dir)) == NULL) { if (silent && errno == ENOENT) /* Ignore the error */ return 0; warn("%s", dir); return -1; } while ((dp = readdir(dd)) != NULL) { int n; char *cp; /* Check for `lib' prefix */ if (dp->d_name[0] != 'l' || dp->d_name[1] != 'i' || dp->d_name[2] != 'b') continue; /* Copy the entry minus prefix */ (void)strcpy(name, dp->d_name + 3); n = strlen(name); if (n < 4) continue; /* Find ".so." in name */ for (cp = name + n - 4; cp > name; --cp) { if (cp[0] == '.' && cp[1] == 's' && cp[2] == 'o' && cp[3] == '.') break; } if (cp <= name) continue; *cp = '\0'; if (!isdigit(*(cp+4))) continue; bzero((caddr_t)dewey, sizeof(dewey)); ndewey = getdewey(dewey, cp + 4); if (ndewey < 2) continue; enter(dir, dp->d_name, name, dewey, ndewey); } closedir(dd); return 0; } static void enter(char *dir, char *file, char *name, int dewey[], int ndewey) { struct shlib_list *shp; for (shp = shlib_head; shp; shp = shp->next) { if (strcmp(name, shp->name) != 0 || major != shp->major) continue; /* Name matches existing entry */ if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) { /* Update this entry with higher versioned lib */ if (verbose) printf("Updating lib%s.%d.%d to %s/%s\n", shp->name, shp->major, shp->minor, dir, file); free(shp->name); shp->name = strdup(name); free(shp->path); shp->path = concat(dir, "/", file); bcopy(dewey, shp->dewey, sizeof(shp->dewey)); shp->ndewey = ndewey; } break; } if (shp) /* Name exists: older version or just updated */ return; /* Allocate new list element */ if (verbose) printf("Adding %s/%s\n", dir, file); shp = (struct shlib_list *)xmalloc(sizeof *shp); shp->name = strdup(name); shp->path = concat(dir, "/", file); bcopy(dewey, shp->dewey, sizeof(shp->dewey)); shp->ndewey = ndewey; shp->next = NULL; *shlib_tail = shp; shlib_tail = &shp->next; } static int hinthash(char *cp, int vmajor) { int k = 0; while (*cp) k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff; return k; } int buildhints(void) { struct hints_header hdr; struct hints_bucket *blist; struct shlib_list *shp; char *strtab; int i, n, str_index = 0; int strtab_sz = 0; /* Total length of strings */ int nhints = 0; /* Total number of hints */ int fd; char *tmpfilename; for (shp = shlib_head; shp; shp = shp->next) { strtab_sz += 1 + strlen(shp->name); strtab_sz += 1 + strlen(shp->path); nhints++; } /* Fill hints file header */ hdr.hh_magic = HH_MAGIC; hdr.hh_version = LD_HINTS_VERSION_2; hdr.hh_nbucket = 1 * nhints; n = hdr.hh_nbucket * sizeof(struct hints_bucket); hdr.hh_hashtab = sizeof(struct hints_header); hdr.hh_strtab = hdr.hh_hashtab + n; hdr.hh_dirlist = strtab_sz; strtab_sz += 1 + strlen(dir_list); hdr.hh_strtab_sz = strtab_sz; hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz; if (verbose) printf("Totals: entries %d, buckets %ld, string size %d\n", nhints, (long)hdr.hh_nbucket, strtab_sz); /* Allocate buckets and string table */ blist = (struct hints_bucket *)xmalloc(n); bzero((char *)blist, n); for (i = 0; i < hdr.hh_nbucket; i++) /* Empty all buckets */ blist[i].hi_next = -1; strtab = (char *)xmalloc(strtab_sz); /* Enter all */ for (shp = shlib_head; shp; shp = shp->next) { struct hints_bucket *bp; bp = blist + (hinthash(shp->name, shp->major) % hdr.hh_nbucket); if (bp->hi_pathx) { int j; for (j = 0; j < hdr.hh_nbucket; j++) { if (blist[j].hi_pathx == 0) break; } if (j == hdr.hh_nbucket) { warnx("bummer!"); return -1; } while (bp->hi_next != -1) bp = &blist[bp->hi_next]; bp->hi_next = j; bp = blist + j; } /* Insert strings in string table */ bp->hi_namex = str_index; strcpy(strtab + str_index, shp->name); str_index += 1 + strlen(shp->name); bp->hi_pathx = str_index; strcpy(strtab + str_index, shp->path); str_index += 1 + strlen(shp->path); /* Copy versions */ bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey)); bp->hi_ndewey = shp->ndewey; } /* Copy search directories */ strcpy(strtab + str_index, dir_list); str_index += 1 + strlen(dir_list); /* Sanity check */ if (str_index != strtab_sz) { errx(1, "str_index(%d) != strtab_sz(%d)", str_index, strtab_sz); } tmpfilename = concat(hints_file, ".XXXXXXXXXX", ""); umask(0); /* Create with exact permissions */ if ((fd = mkstemp(tmpfilename)) == -1) { warn("%s", tmpfilename); return -1; } fchmod(fd, 0444); if (write(fd, &hdr, sizeof(struct hints_header)) != sizeof(struct hints_header)) { warn("%s", hints_file); return -1; } if (write(fd, blist, hdr.hh_nbucket * sizeof(*blist)) != (ssize_t)(hdr.hh_nbucket * sizeof(*blist))) { warn("%s", hints_file); return -1; } if (write(fd, strtab, strtab_sz) != strtab_sz) { warn("%s", hints_file); return -1; } if (close(fd) != 0) { warn("%s", hints_file); return -1; } /* Install it */ if (unlink(hints_file) != 0 && errno != ENOENT) { warn("%s", hints_file); return -1; } if (rename(tmpfilename, hints_file) != 0) { warn("%s", hints_file); return -1; } return 0; } static int readhints(void) { int fd; void *addr; long fsize; long msize; struct hints_header *hdr; struct hints_bucket *blist; char *strtab; struct shlib_list *shp; int i; if ((fd = open(hints_file, O_RDONLY, 0)) == -1) { warn("%s", hints_file); return -1; } msize = PAGE_SIZE; - addr = mmap(0, msize, PROT_READ, MAP_COPY, fd, 0); + addr = mmap(0, msize, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { warn("%s", hints_file); return -1; } hdr = (struct hints_header *)addr; if (HH_BADMAG(*hdr)) { warnx("%s: bad magic: %lo", hints_file, (unsigned long)hdr->hh_magic); return -1; } if (hdr->hh_version != LD_HINTS_VERSION_1 && hdr->hh_version != LD_HINTS_VERSION_2) { warnx("unsupported version: %ld", (long)hdr->hh_version); return -1; } if (hdr->hh_ehints > msize) { fsize = hdr->hh_ehints; munmap(addr, msize); - addr = mmap(0, fsize, PROT_READ, MAP_COPY, fd, 0); + addr = mmap(0, fsize, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { warn("%s", hints_file); return -1; } hdr = (struct hints_header *)addr; } close(fd); strtab = (char *)addr + hdr->hh_strtab; if (hdr->hh_version >= LD_HINTS_VERSION_2) add_search_path(strtab + hdr->hh_dirlist); else if (rescan) errx(1, "%s too old and does not contain the search path", hints_file); if (rescan) return 0; blist = malloc(sizeof(*blist) * hdr->hh_nbucket); if (blist == NULL) err(1, "readhints"); memcpy(blist, (char *)addr + hdr->hh_hashtab, sizeof(*blist) * hdr->hh_nbucket); for (i = 0; i < hdr->hh_nbucket; i++) { struct hints_bucket *bp = &blist[i]; /* Sanity check */ if (bp->hi_namex >= hdr->hh_strtab_sz) { warnx("bad name index: %#x", bp->hi_namex); free(blist); return -1; } if (bp->hi_pathx >= hdr->hh_strtab_sz) { warnx("bad path index: %#x", bp->hi_pathx); free(blist); return -1; } /* Allocate new list element */ shp = (struct shlib_list *)xmalloc(sizeof *shp); shp->name = strdup(strtab + bp->hi_namex); shp->path = strdup(strtab + bp->hi_pathx); bcopy(bp->hi_dewey, shp->dewey, sizeof(shp->dewey)); shp->ndewey = bp->hi_ndewey; shp->next = NULL; *shlib_tail = shp; shlib_tail = &shp->next; } free(blist); return 0; } static void listhints(void) { struct shlib_list *shp; int i; printf("%s:\n", hints_file); printf("\tsearch directories: %s\n", dir_list); for (i = 0, shp = shlib_head; shp; i++, shp = shp->next) printf("\t%d:-l%s.%d.%d => %s\n", i, shp->name, shp->major, shp->minor, shp->path); return; }