xref: /openbsd-src/libexec/ld.so/ldconfig/ldconfig.c (revision b7041c0781c8668129da8084451ded41b0c43954)
1*b7041c07Sderaadt /*	$OpenBSD: ldconfig.c,v 1.39 2021/10/24 21:24:20 deraadt Exp $	*/
289c547eeSrahnds 
389c547eeSrahnds /*
489c547eeSrahnds  * Copyright (c) 1993,1995 Paul Kranenburg
589c547eeSrahnds  * All rights reserved.
689c547eeSrahnds  *
789c547eeSrahnds  * Redistribution and use in source and binary forms, with or without
889c547eeSrahnds  * modification, are permitted provided that the following conditions
989c547eeSrahnds  * are met:
1089c547eeSrahnds  * 1. Redistributions of source code must retain the above copyright
1189c547eeSrahnds  *    notice, this list of conditions and the following disclaimer.
1289c547eeSrahnds  * 2. Redistributions in binary form must reproduce the above copyright
1389c547eeSrahnds  *    notice, this list of conditions and the following disclaimer in the
1489c547eeSrahnds  *    documentation and/or other materials provided with the distribution.
1589c547eeSrahnds  * 3. All advertising materials mentioning features or use of this software
1689c547eeSrahnds  *    must display the following acknowledgement:
1789c547eeSrahnds  *	This product includes software developed by Paul Kranenburg.
1889c547eeSrahnds  * 4. The name of the author may not be used to endorse or promote products
1989c547eeSrahnds  *    derived from this software without specific prior written permission
2089c547eeSrahnds  *
2189c547eeSrahnds  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2289c547eeSrahnds  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2389c547eeSrahnds  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2489c547eeSrahnds  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2589c547eeSrahnds  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2689c547eeSrahnds  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2789c547eeSrahnds  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2889c547eeSrahnds  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2989c547eeSrahnds  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3089c547eeSrahnds  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3189c547eeSrahnds  */
3289c547eeSrahnds 
3389c547eeSrahnds #include <sys/types.h>
3489c547eeSrahnds #include <sys/stat.h>
3589c547eeSrahnds #include <sys/mman.h>
36f4147939Sguenther 
3789c547eeSrahnds #include <dirent.h>
3889c547eeSrahnds #include <err.h>
3989c547eeSrahnds #include <errno.h>
4089c547eeSrahnds #include <fcntl.h>
4189c547eeSrahnds #include <ar.h>
4289c547eeSrahnds #include <ranlib.h>
4389c547eeSrahnds #include <stdio.h>
4489c547eeSrahnds #include <stdlib.h>
4589c547eeSrahnds #include <string.h>
4689c547eeSrahnds #include <unistd.h>
475b40abcfSderaadt #include <limits.h>
4889c547eeSrahnds 
4989c547eeSrahnds #include "ld.h"
5089c547eeSrahnds 
5189c547eeSrahnds #undef major
5289c547eeSrahnds #undef minor
5389c547eeSrahnds 
5489c547eeSrahnds extern char			*__progname;
5589c547eeSrahnds 
5610c6588aSderaadt int				verbose;
5789c547eeSrahnds static int			nostd;
5889c547eeSrahnds static int			justread;
5910c6588aSderaadt int				merge;
6089c547eeSrahnds static int			rescan;
61349c8928Sbrad static int			unconfig;
6289c547eeSrahnds 
6389c547eeSrahnds struct shlib_list {
6489c547eeSrahnds 	/* Internal list of shared libraries found */
6589c547eeSrahnds 	char			*name;
6689c547eeSrahnds 	char			*path;
6789c547eeSrahnds 	int			dewey[MAXDEWEY];
6889c547eeSrahnds 	int			ndewey;
6989c547eeSrahnds #define major dewey[0]
7089c547eeSrahnds #define minor dewey[1]
7189c547eeSrahnds 	struct shlib_list	*next;
7289c547eeSrahnds };
7389c547eeSrahnds 
7489c547eeSrahnds static struct shlib_list	*shlib_head = NULL, **shlib_tail = &shlib_head;
7589c547eeSrahnds static char			*dir_list;
7689c547eeSrahnds 
77c72b5b24Smillert static void	enter(char *, char *, char *, int *, int);
788318bad0Sdjm static int	dodir(char *, int);
798318bad0Sdjm static int	buildhints(void);
808318bad0Sdjm static int	readhints(void);
818318bad0Sdjm static void	listhints(void);
8289c547eeSrahnds 
832f86c0efSderaadt static void
usage(void)840adf9ddfSderaadt usage(void)
850adf9ddfSderaadt {
860adf9ddfSderaadt 	fprintf(stderr,
879b5c596eSkettenis 	    "usage: %s [-mRrsUv] [path ...]\n", __progname);
880adf9ddfSderaadt 	exit(1);
890adf9ddfSderaadt }
900adf9ddfSderaadt 
9189c547eeSrahnds int
main(int argc,char * argv[])92cffc06f4Sderaadt main(int argc, char *argv[])
9389c547eeSrahnds {
9489c547eeSrahnds 	int i, c;
9589c547eeSrahnds 	int rval = 0;
9689c547eeSrahnds 
974c60c5b9Sderaadt 	if (pledge("stdio rpath wpath cpath tmppath fattr", NULL) == -1)
984c60c5b9Sderaadt 		err(1, "pledge");
994c60c5b9Sderaadt 
1008aef0bb1Sdrahn 	while ((c = getopt(argc, argv, "DmPrRsSUv")) != -1) {
10189c547eeSrahnds 		switch (c) {
10289c547eeSrahnds 		case 'R':
10389c547eeSrahnds 			rescan = 1;
10489c547eeSrahnds 			break;
105349c8928Sbrad 		case 'U':
106349c8928Sbrad 			rescan = unconfig = 1;
107349c8928Sbrad 			break;
10889c547eeSrahnds 		case 'm':
10989c547eeSrahnds 			merge = 1;
11089c547eeSrahnds 			break;
11189c547eeSrahnds 		case 'r':
11289c547eeSrahnds 			justread = 1;
11389c547eeSrahnds 			break;
11489c547eeSrahnds 		case 's':
11589c547eeSrahnds 			nostd = 1;
11689c547eeSrahnds 			break;
11789c547eeSrahnds 		case 'v':
11889c547eeSrahnds 			verbose = 1;
11989c547eeSrahnds 			break;
12089c547eeSrahnds 		default:
1210adf9ddfSderaadt 			usage();
12289c547eeSrahnds 			break;
12389c547eeSrahnds 		}
12489c547eeSrahnds 	}
12589c547eeSrahnds 
126349c8928Sbrad 	if (unconfig && merge)
127349c8928Sbrad 		errx(1, "cannot use -U with -m");
128349c8928Sbrad 
12989c547eeSrahnds 	dir_list = xmalloc(1);
13089c547eeSrahnds 	*dir_list = '\0';
13189c547eeSrahnds 
13289c547eeSrahnds 	if (justread || merge || rescan) {
1338318bad0Sdjm 		if ((rval = readhints()) != 0)
13489c547eeSrahnds 			return rval;
13589c547eeSrahnds 		if (justread) {
1368318bad0Sdjm 			listhints();
13789c547eeSrahnds 			return 0;
13889c547eeSrahnds 		}
13989c547eeSrahnds 		add_search_path(dir_list);
140349c8928Sbrad 		dir_list = xrealloc(dir_list, 1);
141349c8928Sbrad 		*dir_list = '\0';
1420adf9ddfSderaadt 	} else if (!nostd)
143349c8928Sbrad 		std_search_path();
14489c547eeSrahnds 
145349c8928Sbrad 	if (unconfig) {
146349c8928Sbrad 		if (optind < argc)
147349c8928Sbrad 			for (i = optind; i < argc; i++)
148349c8928Sbrad 				remove_search_dir(argv[i]);
149349c8928Sbrad 		else {
150349c8928Sbrad 			i = 0;
151349c8928Sbrad 			while (i < n_search_dirs) {
152349c8928Sbrad 				if (access(search_dirs[i], R_OK) < 0)
153349c8928Sbrad 					remove_search_dir(search_dirs[i]);
154349c8928Sbrad 				else
155349c8928Sbrad 					i++;
156349c8928Sbrad 			}
157349c8928Sbrad 		}
158349c8928Sbrad 	} else
159349c8928Sbrad 		for (i = optind; i < argc; i++)
160349c8928Sbrad 			add_search_dir(argv[i]);
16189c547eeSrahnds 
162349c8928Sbrad 	for (i = 0; i < n_search_dirs; i++) {
163349c8928Sbrad 		char *cp = concat(dir_list, *dir_list?":":"", search_dirs[i]);
164cffc06f4Sderaadt 
16589c547eeSrahnds 		free(dir_list);
16689c547eeSrahnds 		dir_list = cp;
1678318bad0Sdjm 		rval |= dodir(search_dirs[i], 0);
16889c547eeSrahnds 	}
16989c547eeSrahnds 
1708318bad0Sdjm 	rval |= buildhints();
17189c547eeSrahnds 
17289c547eeSrahnds 	return rval;
17389c547eeSrahnds }
17489c547eeSrahnds 
17589c547eeSrahnds int
dodir(char * dir,int silent)1768318bad0Sdjm dodir(char *dir, int silent)
17789c547eeSrahnds {
17889c547eeSrahnds 	DIR		*dd;
17989c547eeSrahnds 	struct dirent	*dp;
1805b40abcfSderaadt 	char		name[PATH_MAX];
1818318bad0Sdjm 	int		dewey[MAXDEWEY], ndewey;
18289c547eeSrahnds 
18389c547eeSrahnds 	if ((dd = opendir(dir)) == NULL) {
18489c547eeSrahnds 		if (!silent || errno != ENOENT)
18589c547eeSrahnds 			warn("%s", dir);
18689c547eeSrahnds 		return -1;
18789c547eeSrahnds 	}
18889c547eeSrahnds 
18989c547eeSrahnds 	while ((dp = readdir(dd)) != NULL) {
190b0f83791Sderaadt 		size_t n;
19150d2b651Smpech 		char *cp;
19289c547eeSrahnds 
19389c547eeSrahnds 		/* Check for `lib' prefix */
19489c547eeSrahnds 		if (dp->d_name[0] != 'l' ||
19589c547eeSrahnds 		    dp->d_name[1] != 'i' ||
19689c547eeSrahnds 		    dp->d_name[2] != 'b')
19789c547eeSrahnds 			continue;
19889c547eeSrahnds 
19989c547eeSrahnds 		/* Copy the entry minus prefix */
20048f8891fSderaadt 		(void)strlcpy(name, dp->d_name + 3, sizeof name);
20189c547eeSrahnds 		n = strlen(name);
20289c547eeSrahnds 		if (n < 4)
20389c547eeSrahnds 			continue;
20489c547eeSrahnds 
20589c547eeSrahnds 		/* Find ".so." in name */
20689c547eeSrahnds 		for (cp = name + n - 4; cp > name; --cp) {
20789c547eeSrahnds 			if (cp[0] == '.' &&
20889c547eeSrahnds 			    cp[1] == 's' &&
20989c547eeSrahnds 			    cp[2] == 'o' &&
21089c547eeSrahnds 			    cp[3] == '.')
21189c547eeSrahnds 				break;
21289c547eeSrahnds 		}
21389c547eeSrahnds 		if (cp <= name)
21489c547eeSrahnds 			continue;
21589c547eeSrahnds 
21689c547eeSrahnds 		*cp = '\0';
21789c547eeSrahnds 
21889c547eeSrahnds 		bzero((caddr_t)dewey, sizeof(dewey));
219f6b06416Sespie 		ndewey = getdewey(dewey, cp + 3);
220f6b06416Sespie 		if (ndewey > 0)
2218318bad0Sdjm 			enter(dir, dp->d_name, name, dewey, ndewey);
22289c547eeSrahnds 	}
223ad0a2195Szinovik 	closedir(dd);
22489c547eeSrahnds 	return 0;
22589c547eeSrahnds }
22689c547eeSrahnds 
22789c547eeSrahnds static void
enter(char * dir,char * file,char * name,int dewey[],int ndewey)228cffc06f4Sderaadt enter(char *dir, char *file, char *name, int dewey[], int ndewey)
22989c547eeSrahnds {
23089c547eeSrahnds 	struct shlib_list	*shp;
23189c547eeSrahnds 
23289c547eeSrahnds 	for (shp = shlib_head; shp; shp = shp->next) {
23389c547eeSrahnds 		if (strcmp(name, shp->name) != 0 || major != shp->major)
23489c547eeSrahnds 			continue;
23589c547eeSrahnds 
23689c547eeSrahnds 		/* Name matches existing entry */
23789c547eeSrahnds 		if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) {
23889c547eeSrahnds 
23989c547eeSrahnds 			/* Update this entry with higher versioned lib */
24089c547eeSrahnds 			if (verbose)
24189c547eeSrahnds 				printf("Updating lib%s.%d.%d to %s/%s\n",
24289c547eeSrahnds 				    shp->name, shp->major, shp->minor,
24389c547eeSrahnds 				    dir, file);
24489c547eeSrahnds 
24589c547eeSrahnds 			free(shp->name);
246349c8928Sbrad 			shp->name = xstrdup(name);
24789c547eeSrahnds 			free(shp->path);
24889c547eeSrahnds 			shp->path = concat(dir, "/", file);
24989c547eeSrahnds 			bcopy(dewey, shp->dewey, sizeof(shp->dewey));
25089c547eeSrahnds 			shp->ndewey = ndewey;
25189c547eeSrahnds 		}
25289c547eeSrahnds 		break;
25389c547eeSrahnds 	}
25489c547eeSrahnds 
25589c547eeSrahnds 	if (shp)
25689c547eeSrahnds 		/* Name exists: older version or just updated */
25789c547eeSrahnds 		return;
25889c547eeSrahnds 
25989c547eeSrahnds 	/* Allocate new list element */
26089c547eeSrahnds 	if (verbose)
26189c547eeSrahnds 		printf("Adding %s/%s\n", dir, file);
26289c547eeSrahnds 
26389c547eeSrahnds 	shp = (struct shlib_list *)xmalloc(sizeof *shp);
264349c8928Sbrad 	shp->name = xstrdup(name);
26589c547eeSrahnds 	shp->path = concat(dir, "/", file);
26681bc4398Sbluhm 	bcopy(dewey, shp->dewey, sizeof(shp->dewey));
26789c547eeSrahnds 	shp->ndewey = ndewey;
26889c547eeSrahnds 	shp->next = NULL;
26989c547eeSrahnds 
27089c547eeSrahnds 	*shlib_tail = shp;
27189c547eeSrahnds 	shlib_tail = &shp->next;
27289c547eeSrahnds }
27389c547eeSrahnds 
2748318bad0Sdjm 
2758318bad0Sdjm #if DEBUG
2768318bad0Sdjm /* test */
2778318bad0Sdjm #undef _PATH_LD_HINTS
2788318bad0Sdjm #define _PATH_LD_HINTS		"./ld.so.hints"
2798318bad0Sdjm #endif
2808318bad0Sdjm 
2815b36bcefSderaadt static int
hinthash(char * cp,int vmajor,int vminor)282cffc06f4Sderaadt hinthash(char *cp, int vmajor, int vminor)
28389c547eeSrahnds {
28489c547eeSrahnds 	int	k = 0;
28589c547eeSrahnds 
28689c547eeSrahnds 	while (*cp)
28789c547eeSrahnds 		k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
28889c547eeSrahnds 
28989c547eeSrahnds 	k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
29089c547eeSrahnds #if 0
29189c547eeSrahnds 	k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
29289c547eeSrahnds #endif
29389c547eeSrahnds 
29489c547eeSrahnds 	return k;
29589c547eeSrahnds }
29689c547eeSrahnds 
29789c547eeSrahnds int
buildhints(void)2988318bad0Sdjm buildhints(void)
29989c547eeSrahnds {
3003edf6b2aSderaadt 	int strtab_sz = 0, nhints = 0, fd = -1, i, ret = -1, str_index = 0;
30189c547eeSrahnds 	struct hints_bucket *blist;
3025b36bcefSderaadt 	struct hints_header hdr;
30389c547eeSrahnds 	struct shlib_list *shp;
304b0f83791Sderaadt 	char *strtab, *tmpfilenam;
305b0f83791Sderaadt 	size_t n;
30689c547eeSrahnds 
30789c547eeSrahnds 	for (shp = shlib_head; shp; shp = shp->next) {
30889c547eeSrahnds 		strtab_sz += 1 + strlen(shp->name);
30989c547eeSrahnds 		strtab_sz += 1 + strlen(shp->path);
31089c547eeSrahnds 		nhints++;
31189c547eeSrahnds 	}
31289c547eeSrahnds 
31389c547eeSrahnds 	/* Fill hints file header */
31489c547eeSrahnds 	hdr.hh_magic = HH_MAGIC;
31589c547eeSrahnds 	hdr.hh_version = LD_HINTS_VERSION_2;
31689c547eeSrahnds 	hdr.hh_nbucket = 1 * nhints;
31789c547eeSrahnds 	n = hdr.hh_nbucket * sizeof(struct hints_bucket);
31889c547eeSrahnds 	hdr.hh_hashtab = sizeof(struct hints_header);
31989c547eeSrahnds 	hdr.hh_strtab = hdr.hh_hashtab + n;
32089c547eeSrahnds 	hdr.hh_dirlist = strtab_sz;
32189c547eeSrahnds 	strtab_sz += 1 + strlen(dir_list);
32289c547eeSrahnds 	hdr.hh_strtab_sz = strtab_sz;
32389c547eeSrahnds 	hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz;
32489c547eeSrahnds 
32589c547eeSrahnds 	if (verbose)
32689c547eeSrahnds 		printf("Totals: entries %d, buckets %ld, string size %d\n",
32789c547eeSrahnds 		    nhints, hdr.hh_nbucket, strtab_sz);
32889c547eeSrahnds 
32989c547eeSrahnds 	/* Allocate buckets and string table */
33089c547eeSrahnds 	blist = (struct hints_bucket *)xmalloc(n);
331b0f83791Sderaadt 	bzero(blist, n);
33289c547eeSrahnds 	for (i = 0; i < hdr.hh_nbucket; i++)
33389c547eeSrahnds 		/* Empty all buckets */
33489c547eeSrahnds 		blist[i].hi_next = -1;
33589c547eeSrahnds 
336b0f83791Sderaadt 	strtab = xmalloc(strtab_sz);
33789c547eeSrahnds 
33889c547eeSrahnds 	/* Enter all */
33989c547eeSrahnds 	for (shp = shlib_head; shp; shp = shp->next) {
34089c547eeSrahnds 		struct hints_bucket	*bp;
34189c547eeSrahnds 
34239b7d201Sderaadt 		bp = blist + (hinthash(shp->name, shp->major, shp->minor) %
34339b7d201Sderaadt 		    hdr.hh_nbucket);
34489c547eeSrahnds 
34589c547eeSrahnds 		if (bp->hi_pathx) {
346b0f83791Sderaadt 			int	j;
34789c547eeSrahnds 
348b0f83791Sderaadt 			for (j = 0; j < hdr.hh_nbucket; j++) {
349b0f83791Sderaadt 				if (blist[j].hi_pathx == 0)
35089c547eeSrahnds 					break;
35189c547eeSrahnds 			}
352b0f83791Sderaadt 			if (j == hdr.hh_nbucket) {
35389c547eeSrahnds 				warnx("Bummer!");
354f5e454e8Sray 				goto out;
35589c547eeSrahnds 			}
35689c547eeSrahnds 			while (bp->hi_next != -1)
35789c547eeSrahnds 				bp = &blist[bp->hi_next];
358b0f83791Sderaadt 			bp->hi_next = j;
359b0f83791Sderaadt 			bp = blist + j;
36089c547eeSrahnds 		}
36189c547eeSrahnds 
36289c547eeSrahnds 		/* Insert strings in string table */
36389c547eeSrahnds 		bp->hi_namex = str_index;
3640cd80e2bSdrahn 		strlcpy(strtab + str_index, shp->name, strtab_sz - str_index);
36589c547eeSrahnds 		str_index += 1 + strlen(shp->name);
36689c547eeSrahnds 
36789c547eeSrahnds 		bp->hi_pathx = str_index;
3680cd80e2bSdrahn 		strlcpy(strtab + str_index, shp->path, strtab_sz - str_index);
36989c547eeSrahnds 		str_index += 1 + strlen(shp->path);
37089c547eeSrahnds 
37189c547eeSrahnds 		/* Copy versions */
37289c547eeSrahnds 		bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey));
37389c547eeSrahnds 		bp->hi_ndewey = shp->ndewey;
37489c547eeSrahnds 	}
37589c547eeSrahnds 
37689c547eeSrahnds 	/* Copy search directories */
3770cd80e2bSdrahn 	strlcpy(strtab + str_index, dir_list, strtab_sz - str_index);
37889c547eeSrahnds 	str_index += 1 + strlen(dir_list);
37989c547eeSrahnds 
38089c547eeSrahnds 	/* Sanity check */
381b0f83791Sderaadt 	if (str_index != strtab_sz)
38289c547eeSrahnds 		errx(1, "str_index(%d) != strtab_sz(%d)", str_index, strtab_sz);
38389c547eeSrahnds 
384b0f83791Sderaadt 	tmpfilenam = concat(_PATH_LD_HINTS, ".XXXXXXXXXX", "");
385b0f83791Sderaadt 	if ((fd = mkstemp(tmpfilenam)) == -1) {
386b0f83791Sderaadt 		warn("%s", tmpfilenam);
387f5e454e8Sray 		goto out;
38889c547eeSrahnds 	}
38951e0f611Scheloha 	if (fchmod(fd, 0444) == -1) {
39051e0f611Scheloha 		warn("%s: failed to change mode", tmpfilenam);
39151e0f611Scheloha 		goto out;
39251e0f611Scheloha 	}
39389c547eeSrahnds 
39489c547eeSrahnds 	if (write(fd, &hdr, sizeof(struct hints_header)) !=
39589c547eeSrahnds 	    sizeof(struct hints_header)) {
3968318bad0Sdjm 		warn("%s", _PATH_LD_HINTS);
397f5e454e8Sray 		goto out;
39889c547eeSrahnds 	}
39989c547eeSrahnds 	if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) !=
40089c547eeSrahnds 	    hdr.hh_nbucket * sizeof(struct hints_bucket)) {
4018318bad0Sdjm 		warn("%s", _PATH_LD_HINTS);
402f5e454e8Sray 		goto out;
40389c547eeSrahnds 	}
40489c547eeSrahnds 	if (write(fd, strtab, strtab_sz) != strtab_sz) {
4058318bad0Sdjm 		warn("%s", _PATH_LD_HINTS);
406f5e454e8Sray 		goto out;
40789c547eeSrahnds 	}
40889c547eeSrahnds 
409b0f83791Sderaadt 	if (rename(tmpfilenam, _PATH_LD_HINTS) != 0) {
4108318bad0Sdjm 		warn("%s", _PATH_LD_HINTS);
411f5e454e8Sray 		goto out;
41289c547eeSrahnds 	}
41389c547eeSrahnds 
414f5e454e8Sray 	ret = 0;
415f5e454e8Sray out:
4163edf6b2aSderaadt 	if (fd != -1)
4173edf6b2aSderaadt 		close(fd);
418f5e454e8Sray 	free(blist);
419f5e454e8Sray 	free(strtab);
420f5e454e8Sray 	return (ret);
42189c547eeSrahnds }
42289c547eeSrahnds 
42389c547eeSrahnds static int
readhints(void)4248318bad0Sdjm readhints(void)
42589c547eeSrahnds {
426b2645b88Sdrahn 	struct stat sb;
42789c547eeSrahnds 	struct hints_bucket *blist;
4285b36bcefSderaadt 	struct hints_header *hdr;
42989c547eeSrahnds 	struct shlib_list *shp;
4305b36bcefSderaadt 	caddr_t addr;
4315b36bcefSderaadt 	char *strtab;
4325b36bcefSderaadt 	long msize;
4335b36bcefSderaadt 	int fd, i;
43489c547eeSrahnds 
435*b7041c07Sderaadt 	if ((fd = open(_PATH_LD_HINTS, O_RDONLY)) == -1) {
4368318bad0Sdjm 		warn("%s", _PATH_LD_HINTS);
43789c547eeSrahnds 		return -1;
43889c547eeSrahnds 	}
439b2645b88Sdrahn 	if (fstat(fd, &sb) != 0 || !S_ISREG(sb.st_mode) ||
440b2645b88Sdrahn 	    sb.st_size < sizeof(struct hints_header) || sb.st_size > LONG_MAX) {
441b2645b88Sdrahn 		warn("%s", _PATH_LD_HINTS);
442b2645b88Sdrahn 		return -1;
443b2645b88Sdrahn 	}
44489c547eeSrahnds 
445b2645b88Sdrahn 	msize = (long)sb.st_size;
4461507f10bSart 	addr = mmap(0, msize, PROT_READ, MAP_PRIVATE, fd, 0);
44789c547eeSrahnds 
44891915fb6Sart 	if (addr == MAP_FAILED) {
4498318bad0Sdjm 		warn("%s", _PATH_LD_HINTS);
45089c547eeSrahnds 		return -1;
45189c547eeSrahnds 	}
45289c547eeSrahnds 
45389c547eeSrahnds 	hdr = (struct hints_header *)addr;
45489c547eeSrahnds 	if (HH_BADMAG(*hdr)) {
45589c547eeSrahnds 		warnx("%s: Bad magic: %lo",
4568318bad0Sdjm 		    _PATH_LD_HINTS, hdr->hh_magic);
45789c547eeSrahnds 		return -1;
45889c547eeSrahnds 	}
45989c547eeSrahnds 
460b2645b88Sdrahn 	if (hdr->hh_ehints > msize) {
461f6a064e1Sdrahn 		warnx("%s: hintsize greater than filesize: 0x%lx > 0x%lx ",
462b2645b88Sdrahn 		    _PATH_LD_HINTS, hdr->hh_ehints, msize);
463b2645b88Sdrahn 		    return -1;
464b2645b88Sdrahn 	}
465b2645b88Sdrahn 
46689c547eeSrahnds 	if (hdr->hh_version != LD_HINTS_VERSION_2) {
46789c547eeSrahnds 		warnx("Unsupported version: %ld", hdr->hh_version);
46889c547eeSrahnds 		return -1;
46989c547eeSrahnds 	}
47089c547eeSrahnds 
47189c547eeSrahnds 	close(fd);
47289c547eeSrahnds 
47389c547eeSrahnds 	blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
47489c547eeSrahnds 	strtab = (char *)(addr + hdr->hh_strtab);
47589c547eeSrahnds 
476349c8928Sbrad 	dir_list = xstrdup(strtab + hdr->hh_dirlist);
477349c8928Sbrad 
478349c8928Sbrad 	if (rescan)
479349c8928Sbrad 		return (0);
480349c8928Sbrad 
48189c547eeSrahnds 	for (i = 0; i < hdr->hh_nbucket; i++) {
48289c547eeSrahnds 		struct hints_bucket	*bp = &blist[i];
48389c547eeSrahnds 
48489c547eeSrahnds 		/* Sanity check */
48589c547eeSrahnds 		if (bp->hi_namex >= hdr->hh_strtab_sz) {
48689c547eeSrahnds 			warnx("Bad name index: %#x", bp->hi_namex);
48789c547eeSrahnds 			return -1;
48889c547eeSrahnds 		}
48989c547eeSrahnds 		if (bp->hi_pathx >= hdr->hh_strtab_sz) {
49089c547eeSrahnds 			warnx("Bad path index: %#x", bp->hi_pathx);
49189c547eeSrahnds 			return -1;
49289c547eeSrahnds 		}
49389c547eeSrahnds 
49489c547eeSrahnds 		/* Allocate new list element */
49589c547eeSrahnds 		shp = (struct shlib_list *)xmalloc(sizeof *shp);
496349c8928Sbrad 		shp->name = xstrdup(strtab + bp->hi_namex);
497349c8928Sbrad 		shp->path = xstrdup(strtab + bp->hi_pathx);
49889c547eeSrahnds 		bcopy(bp->hi_dewey, shp->dewey, sizeof(shp->dewey));
49989c547eeSrahnds 		shp->ndewey = bp->hi_ndewey;
50089c547eeSrahnds 		shp->next = NULL;
50189c547eeSrahnds 
50289c547eeSrahnds 		*shlib_tail = shp;
50389c547eeSrahnds 		shlib_tail = &shp->next;
50489c547eeSrahnds 	}
50589c547eeSrahnds 	return 0;
50689c547eeSrahnds }
50789c547eeSrahnds 
50889c547eeSrahnds static void
listhints(void)5098318bad0Sdjm listhints(void)
51089c547eeSrahnds {
51189c547eeSrahnds 	struct shlib_list *shp;
51289c547eeSrahnds 	int i;
51389c547eeSrahnds 
5148318bad0Sdjm 	printf("%s:\n", _PATH_LD_HINTS);
51589c547eeSrahnds 	printf("\tsearch directories: %s\n", dir_list);
51689c547eeSrahnds 
51789c547eeSrahnds 	for (i = 0, shp = shlib_head; shp; i++, shp = shp->next)
51889c547eeSrahnds 		printf("\t%d:-l%s.%d.%d => %s\n",
51989c547eeSrahnds 		    i, shp->name, shp->major, shp->minor, shp->path);
52089c547eeSrahnds }
521