xref: /titanic_50/usr/src/cmd/sgs/rtld/common/cache_a.out.c (revision cb511613a15cb3949eadffd67b37d3c665b4ef22)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
237257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245aefb655Srie  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267257d1b4Sraf 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * 4.x ld.so directory caching: run-time link-editor specific functions.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include	<dirent.h>
327c478bd9Sstevel@tonic-gate #include	<string.h>
337c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
347c478bd9Sstevel@tonic-gate #include	<fcntl.h>
357c478bd9Sstevel@tonic-gate #include	<unistd.h>
367c478bd9Sstevel@tonic-gate #include	"_a.out.h"
377c478bd9Sstevel@tonic-gate #include	"cache_a.out.h"
387c478bd9Sstevel@tonic-gate #include	"_rtld.h"
397c478bd9Sstevel@tonic-gate #include	"msg.h"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate static int	stol();
427c478bd9Sstevel@tonic-gate static int	rest_ok();
437c478bd9Sstevel@tonic-gate static int	verscmp();
447c478bd9Sstevel@tonic-gate static void	fix_lo();
457c478bd9Sstevel@tonic-gate static int	extract_name();
467c478bd9Sstevel@tonic-gate static int	hash();
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static struct link_object *get_lo();
497c478bd9Sstevel@tonic-gate static struct dbd *new_dbd();
507c478bd9Sstevel@tonic-gate static struct db *find_so();
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define	SKIP_DOT(str)	((*str == '.')  ? ++str : str)
537c478bd9Sstevel@tonic-gate #define	EMPTY(str)	((str == NULL) || (*str == '\0'))
547c478bd9Sstevel@tonic-gate #define	isdigit(c)	(((c) >= '0') && ((c) <= '9') ? 1:0)
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static struct dbd *dbd_head = NULL;	/* head of data bases */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * Given a db - find the highest shared versioned object. The
617c478bd9Sstevel@tonic-gate  * highest versioned object is the .so  with a matching major number
627c478bd9Sstevel@tonic-gate  * but the highest minor number
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate char *
ask_db(dbp,file)657c478bd9Sstevel@tonic-gate ask_db(dbp, file)
667c478bd9Sstevel@tonic-gate 	struct db *dbp;
677c478bd9Sstevel@tonic-gate 	const char *file;
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	char *libname, *n;
707c478bd9Sstevel@tonic-gate 	char *mnp;
717c478bd9Sstevel@tonic-gate 	char *mjp;
727c478bd9Sstevel@tonic-gate 	int liblen;
737c478bd9Sstevel@tonic-gate 	int major = 0;
747c478bd9Sstevel@tonic-gate 	int to_min;
757c478bd9Sstevel@tonic-gate 	struct dbe *ep;
767c478bd9Sstevel@tonic-gate 	struct link_object *tlop;
777c478bd9Sstevel@tonic-gate 	int index;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	n = (char *)file;
807c478bd9Sstevel@tonic-gate 	if ((liblen = extract_name(&n)) == -1)
817c478bd9Sstevel@tonic-gate 		return (NULL);
827c478bd9Sstevel@tonic-gate 	if ((libname = malloc(liblen + 1)) == 0)
837c478bd9Sstevel@tonic-gate 		return (NULL);
847c478bd9Sstevel@tonic-gate 	(void) strncpy(libname, n, liblen);
857c478bd9Sstevel@tonic-gate 	libname[liblen] = NULL;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	if (strncmp(MSG_ORIG(MSG_FIL_DOTSODOT), (n + liblen),
887c478bd9Sstevel@tonic-gate 	    MSG_FIL_DOTSODOT_SIZE))
897c478bd9Sstevel@tonic-gate 		return (NULL);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	mnp = mjp = ((char *)file + MSG_FIL_LIB_SIZE + liblen +
927c478bd9Sstevel@tonic-gate 	    MSG_FIL_DOTSODOT_SIZE);
937c478bd9Sstevel@tonic-gate 	if (!(stol(mjp, '.', &mnp, &major) && (*mnp == '.') &&
947c478bd9Sstevel@tonic-gate 	    rest_ok(mnp + 1)))
957c478bd9Sstevel@tonic-gate 		return (NULL);
967c478bd9Sstevel@tonic-gate 	to_min = mnp - file + 1;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	/*
997c478bd9Sstevel@tonic-gate 	 * Search appropriate hash bucket for a matching entry.
1007c478bd9Sstevel@tonic-gate 	 */
1017c478bd9Sstevel@tonic-gate 	index = hash(libname, liblen, major);
1027c478bd9Sstevel@tonic-gate 	for (ep = (struct dbe *)&(dbp->db_hash[index]); (ep && ep->dbe_lop);
1037c478bd9Sstevel@tonic-gate 	    ep = ep->dbe_next == 0 ? NULL :
1047c478bd9Sstevel@tonic-gate 	    /* LINTED */
1057c478bd9Sstevel@tonic-gate 	    (struct dbe *)&AP(dbp)[ep->dbe_next]) {
1067c478bd9Sstevel@tonic-gate 		/* LINTED */
1077c478bd9Sstevel@tonic-gate 		tlop = (struct link_object *)&AP(dbp)[ep->dbe_lop];
1087c478bd9Sstevel@tonic-gate 		if (tlop->lo_major == major)
1097c478bd9Sstevel@tonic-gate 			if (strcmp((char *)&AP(dbp)[tlop->lo_name],
1107c478bd9Sstevel@tonic-gate 			    libname) == 0)
1117c478bd9Sstevel@tonic-gate 				break;
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	/*
1157c478bd9Sstevel@tonic-gate 	 * If no entry was found, we've lost.
1167c478bd9Sstevel@tonic-gate 	 */
1177c478bd9Sstevel@tonic-gate 	if (!(ep && ep->dbe_lop))
1187c478bd9Sstevel@tonic-gate 		return (NULL);
1197c478bd9Sstevel@tonic-gate 	if (verscmp(file + to_min,
1207c478bd9Sstevel@tonic-gate 	    &AP(dbp)[ep->dbe_name] + tlop->lo_minor) > 0)
1215aefb655Srie 		eprintf(&lml_main, ERR_WARNING, MSG_INTL(MSG_GEN_OLDREV),
1227c478bd9Sstevel@tonic-gate 		    &AP(dbp)[ep->dbe_name], file + to_min);
1237c478bd9Sstevel@tonic-gate 	return (&AP(dbp)[ep->dbe_name]);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * Given a directory name - give back a data base. The data base may have
1287c478bd9Sstevel@tonic-gate  * orginated from the mmapped file or temporarily created
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate struct db *
lo_cache(const char * ds)1317c478bd9Sstevel@tonic-gate lo_cache(const char *ds)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	struct db *dbp;			/* database pointer */
1347c478bd9Sstevel@tonic-gate 	struct dbd *dbdp;		/* working database descriptor */
1357c478bd9Sstevel@tonic-gate 	struct dbd **dbdpp;		/* insertion pointer */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	dbdpp = &dbd_head;
1387c478bd9Sstevel@tonic-gate 	for (dbdp = dbd_head; dbdp; dbdp = dbdp->dbd_next) {
1397c478bd9Sstevel@tonic-gate 		if (strcmp(ds, &AP(dbdp->dbd_db)[dbdp->dbd_db->db_name]) == 0)
1407c478bd9Sstevel@tonic-gate 			return (dbdp->dbd_db);
1417c478bd9Sstevel@tonic-gate 		dbdpp = &dbdp->dbd_next;
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	if (dbp = find_so(ds)) {
1447c478bd9Sstevel@tonic-gate 		(void) new_dbd(dbdpp, dbp);
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 	return (dbp);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Build a database for the directory "ds".
1517c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate static struct db *
find_so(const char * ds)1537c478bd9Sstevel@tonic-gate find_so(const char *ds)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	int fd;				/* descriptor on directory */
1567c478bd9Sstevel@tonic-gate 	int n;				/* bytes from getdents */
1577c478bd9Sstevel@tonic-gate 	char *cp;			/* working char * */
158*cb511613SAli Bahrami 	rtld_stat_t sb;			/* buffer for stat'ing directory */
1597c478bd9Sstevel@tonic-gate 	struct db *dbp;			/* database */
1607c478bd9Sstevel@tonic-gate 	static caddr_t buf = NULL;	/* buffer for doing getdents */
1617c478bd9Sstevel@tonic-gate 	static long bs;			/* cached blocksize for getdents */
1627c478bd9Sstevel@tonic-gate 	struct link_object *tlop;	/* working link object ptr. */
1637c478bd9Sstevel@tonic-gate 	struct dirent *dp;		/* directory entry ptr. */
1647c478bd9Sstevel@tonic-gate 	struct dbe *ep;			/* working db_entry ptr. */
1657c478bd9Sstevel@tonic-gate 	char *mnp;			/* where minor version begins */
1667c478bd9Sstevel@tonic-gate 	char *mjp;			/* where major version begins */
1677c478bd9Sstevel@tonic-gate 	int m;				/* the major number */
1687c478bd9Sstevel@tonic-gate 	int to_min;			/* index into string of minor */
1697c478bd9Sstevel@tonic-gate 	int cplen;			/* length of X */
1707c478bd9Sstevel@tonic-gate 	int index;			/* the hash value */
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/*
1737c478bd9Sstevel@tonic-gate 	 * Try to open directory.  Failing that, just return silently.
1747c478bd9Sstevel@tonic-gate 	 */
1757c478bd9Sstevel@tonic-gate 	if ((fd = open(ds, O_RDONLY)) == -1)
1767c478bd9Sstevel@tonic-gate 		return ((struct db *)NULL);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/*
1797c478bd9Sstevel@tonic-gate 	 * If we have not yet gotten a buffer for reading directories,
1807c478bd9Sstevel@tonic-gate 	 * allocate it now.  Size it according to the most efficient size
1817c478bd9Sstevel@tonic-gate 	 * for the first directory we open successfully.
1827c478bd9Sstevel@tonic-gate 	 */
1837c478bd9Sstevel@tonic-gate 	if (!buf) {
184*cb511613SAli Bahrami 		if (rtld_fstat(fd, &sb) == -1) {
1857c478bd9Sstevel@tonic-gate 			(void) close(fd);
1867c478bd9Sstevel@tonic-gate 			return ((struct db *)NULL);
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 		bs = sb.st_blksize;
1897c478bd9Sstevel@tonic-gate 		buf = calloc(bs, 1);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/*
1937c478bd9Sstevel@tonic-gate 	 * Have a directory, have a buffer.  Allocate up a database
1947c478bd9Sstevel@tonic-gate 	 * and initialize it.
1957c478bd9Sstevel@tonic-gate 	 */
1967c478bd9Sstevel@tonic-gate 	dbp = calloc(sizeof (struct db), 1);
1977c478bd9Sstevel@tonic-gate 	dbp->db_name = RELPTR(dbp, calloc((strlen(ds) + 1), 1));
1987c478bd9Sstevel@tonic-gate 	(void) strcpy((char *)&AP(dbp)[dbp->db_name], ds);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/*
2017c478bd9Sstevel@tonic-gate 	 * Scan the directory looking for shared libraries.  getdents()
2027c478bd9Sstevel@tonic-gate 	 * failures are silently ignored and terminate the scan.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	/* LINTED */
2057c478bd9Sstevel@tonic-gate 	while ((n = getdents(fd, (struct dirent *)buf, bs)) > 0)
2067c478bd9Sstevel@tonic-gate 		/* LINTED */
2077c478bd9Sstevel@tonic-gate 		for (dp = (struct dirent *)buf;
2087c478bd9Sstevel@tonic-gate 		    /* LINTED */
2097c478bd9Sstevel@tonic-gate 		    dp && (dp < (struct dirent *)(buf + n));
2107c478bd9Sstevel@tonic-gate 		    /* LINTED */
2117c478bd9Sstevel@tonic-gate 		    dp = (struct dirent *)((dp->d_reclen == 0) ?
2127c478bd9Sstevel@tonic-gate 		    NULL : (char *)dp + dp->d_reclen)) {
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 			/*
2157c478bd9Sstevel@tonic-gate 			 * If file starts with a "lib", then extract the X
2167c478bd9Sstevel@tonic-gate 			 * from libX.
2177c478bd9Sstevel@tonic-gate 			 */
2187c478bd9Sstevel@tonic-gate 			cp = dp->d_name;
2197c478bd9Sstevel@tonic-gate 			if ((cplen = extract_name(&cp)) == -1)
2207c478bd9Sstevel@tonic-gate 				continue;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 			/*
2237c478bd9Sstevel@tonic-gate 			 * Is the next component ".so."?
2247c478bd9Sstevel@tonic-gate 			 */
2257c478bd9Sstevel@tonic-gate 			if (strncmp(MSG_ORIG(MSG_FIL_DOTSODOT), (cp + cplen),
2267c478bd9Sstevel@tonic-gate 			    MSG_FIL_DOTSODOT_SIZE))
2277c478bd9Sstevel@tonic-gate 				continue;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 			/*
2307c478bd9Sstevel@tonic-gate 			 * Check if next component is the major number and
2317c478bd9Sstevel@tonic-gate 			 * whether following components are legal.
2327c478bd9Sstevel@tonic-gate 			 */
2337c478bd9Sstevel@tonic-gate 			mnp = mjp = (dp->d_name + MSG_FIL_LIB_SIZE + cplen +
2347c478bd9Sstevel@tonic-gate 			    MSG_FIL_DOTSODOT_SIZE);
2357c478bd9Sstevel@tonic-gate 			if (!(stol(mjp, '.', &mnp, &m) && (*mnp == '.') &&
2367c478bd9Sstevel@tonic-gate 			    rest_ok(mnp + 1)))
2377c478bd9Sstevel@tonic-gate 				continue;
2387c478bd9Sstevel@tonic-gate 			to_min = mnp - dp->d_name + 1;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 			/*
2417c478bd9Sstevel@tonic-gate 			 * Have libX.so.major.minor - attempt to add it to the
2427c478bd9Sstevel@tonic-gate 			 * cache. If there is another with the same major
2437c478bd9Sstevel@tonic-gate 			 * number then the chose the object with the highest
2447c478bd9Sstevel@tonic-gate 			 * minor number
2457c478bd9Sstevel@tonic-gate 			 */
2467c478bd9Sstevel@tonic-gate 			index = hash(cp, cplen, m);
2477c478bd9Sstevel@tonic-gate 			ep = &(dbp->db_hash[index]);
2487c478bd9Sstevel@tonic-gate 			if (ep->dbe_lop == NULL) {
2497c478bd9Sstevel@tonic-gate 				ep->dbe_lop = (long)get_lo(dbp, cp,
2507c478bd9Sstevel@tonic-gate 				    cplen, m, to_min);
2517c478bd9Sstevel@tonic-gate 				/* LINTED */
2527c478bd9Sstevel@tonic-gate 				tlop = (struct link_object *)
2537c478bd9Sstevel@tonic-gate 				    &AP(dbp)[ep->dbe_lop];
2547c478bd9Sstevel@tonic-gate 				(void) strcpy(&AP(dbp)[tlop->lo_next],
2557c478bd9Sstevel@tonic-gate 				    dp->d_name);
2567c478bd9Sstevel@tonic-gate 				continue;
2577c478bd9Sstevel@tonic-gate 			}
2587c478bd9Sstevel@tonic-gate 			for (ep = &(dbp->db_hash[index]); ep;
2597c478bd9Sstevel@tonic-gate 			    /* LINTED */
2607c478bd9Sstevel@tonic-gate 			    ep = (struct dbe *)&AP(dbp)[ep->dbe_next]) {
2617c478bd9Sstevel@tonic-gate 				/* LINTED */
2627c478bd9Sstevel@tonic-gate 				tlop = (struct link_object *)
2637c478bd9Sstevel@tonic-gate 				    &AP(dbp)[ep->dbe_lop];
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 				/*
2667c478bd9Sstevel@tonic-gate 				 * Choose the highest minor version
2677c478bd9Sstevel@tonic-gate 				 */
2687c478bd9Sstevel@tonic-gate 				if ((tlop->lo_major == m) &&
2697c478bd9Sstevel@tonic-gate 				    (strncmp(&AP(dbp)[tlop->lo_name],
2707c478bd9Sstevel@tonic-gate 				    cp, cplen) == 0) &&
2717c478bd9Sstevel@tonic-gate 				    (*(&AP(dbp)[tlop->lo_name +
2727c478bd9Sstevel@tonic-gate 				    cplen]) == '\0')) {
2737c478bd9Sstevel@tonic-gate 					if (verscmp(dp->d_name + to_min,
2747c478bd9Sstevel@tonic-gate 					    (char *)(&AP(dbp)[tlop->lo_next]
2757c478bd9Sstevel@tonic-gate 					    + to_min)) > 0)
2767c478bd9Sstevel@tonic-gate 						(void) strcpy(&AP(dbp)
2777c478bd9Sstevel@tonic-gate 						    [tlop->lo_next],
2787c478bd9Sstevel@tonic-gate 						    dp->d_name);
2797c478bd9Sstevel@tonic-gate 					break;
2807c478bd9Sstevel@tonic-gate 				}
2817c478bd9Sstevel@tonic-gate 				if (ep->dbe_next == NULL) {
2827c478bd9Sstevel@tonic-gate 					ep->dbe_next = RELPTR(dbp,
2837c478bd9Sstevel@tonic-gate 					    calloc(sizeof (struct dbe), 1));
2847c478bd9Sstevel@tonic-gate 					/* LINTED */
2857c478bd9Sstevel@tonic-gate 					ep  = (struct dbe *)
2867c478bd9Sstevel@tonic-gate 					    &AP(dbp)[ep->dbe_next];
2877c478bd9Sstevel@tonic-gate 					ep->dbe_lop = (long)get_lo(dbp,
2887c478bd9Sstevel@tonic-gate 					    cp, cplen, m, to_min);
2897c478bd9Sstevel@tonic-gate 					/* LINTED */
2907c478bd9Sstevel@tonic-gate 					tlop = (struct link_object *)
2917c478bd9Sstevel@tonic-gate 					    &AP(dbp)[ep->dbe_lop];
2927c478bd9Sstevel@tonic-gate 					(void) strcpy(&AP(dbp)[tlop->lo_next],
2937c478bd9Sstevel@tonic-gate 					    dp->d_name);
2947c478bd9Sstevel@tonic-gate 					break;
2957c478bd9Sstevel@tonic-gate 				}
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 	fix_lo(dbp);
2997c478bd9Sstevel@tonic-gate 	(void) close(fd);
3007c478bd9Sstevel@tonic-gate 	return (dbp);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * Allocate and fill in the fields for a link_object
3057c478bd9Sstevel@tonic-gate  */
3067c478bd9Sstevel@tonic-gate static struct link_object *
get_lo(dbp,cp,cplen,m,n)3077c478bd9Sstevel@tonic-gate get_lo(dbp, cp, cplen, m, n)
3087c478bd9Sstevel@tonic-gate 	struct db *dbp;			/* data base */
3097c478bd9Sstevel@tonic-gate 	char *cp;			/* ptr. to X of libX */
3107c478bd9Sstevel@tonic-gate 	int cplen;			/* length of X */
3117c478bd9Sstevel@tonic-gate 	int m;				/* major version */
3127c478bd9Sstevel@tonic-gate 	int n;				/* index to minor version */
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	struct link_object *lop;	/* link_object to be returned */
3157c478bd9Sstevel@tonic-gate 	struct link_object *tlop;	/* working copy of the above */
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	/*
3187c478bd9Sstevel@tonic-gate 	 * Allocate a link object prototype in the database heap.
3197c478bd9Sstevel@tonic-gate 	 * Store the numeric major (interface) number, but the minor
3207c478bd9Sstevel@tonic-gate 	 * number is stored in the database as an index to the string
3217c478bd9Sstevel@tonic-gate 	 * representing the minor version.  By keeping the minor version
3227c478bd9Sstevel@tonic-gate 	 * as a string, "subfields" (i.e., major.minor[.other.fields. etc.])
3237c478bd9Sstevel@tonic-gate 	 * are permitted.  Although not meaningful to the link editor, this
3247c478bd9Sstevel@tonic-gate 	 * permits run-time substitution of arbitrary customer revisions,
3257c478bd9Sstevel@tonic-gate 	 * although introducing the confusion of overloading the lo_minor
3267c478bd9Sstevel@tonic-gate 	 * field in the database (!)
3277c478bd9Sstevel@tonic-gate 	 */
3287c478bd9Sstevel@tonic-gate 	lop = (struct link_object *)RELPTR(dbp,
3297c478bd9Sstevel@tonic-gate 	    calloc(sizeof (struct link_object), 1));
3307c478bd9Sstevel@tonic-gate 	/* LINTED */
3317c478bd9Sstevel@tonic-gate 	tlop = (struct link_object *)&AP(dbp)[(long)lop];
3327c478bd9Sstevel@tonic-gate 	tlop->lo_major = m;
3337c478bd9Sstevel@tonic-gate 	tlop->lo_minor = n;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * Allocate space for the complete path name on the host program's
3377c478bd9Sstevel@tonic-gate 	 * heap -- as we have to save it from the directory buffer which
3387c478bd9Sstevel@tonic-gate 	 * might otherwise get re-used on us.  Note that this space
3397c478bd9Sstevel@tonic-gate 	 * is wasted -- we can not assume that it can be reclaimed.
3407c478bd9Sstevel@tonic-gate 	 */
3417c478bd9Sstevel@tonic-gate 	tlop->lo_next = (long)RELPTR(dbp, calloc(MAXNAMLEN, 1));
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * Store the prototype name in the link object in the database.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	tlop->lo_name = (long)RELPTR(dbp, calloc((cplen + 1), 1));
3477c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)&AP(dbp)[tlop->lo_name], cp, cplen);
3487c478bd9Sstevel@tonic-gate 	return (lop);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate /*
3527c478bd9Sstevel@tonic-gate  * Pull the "X" from libX, set name to X and return the
3537c478bd9Sstevel@tonic-gate  * length of X
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate static int
extract_name(name)3567c478bd9Sstevel@tonic-gate extract_name(name)
3577c478bd9Sstevel@tonic-gate 	char **name;
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	char *ls;			/* string after LIB root */
3607c478bd9Sstevel@tonic-gate 	char *dp;			/* string before first delimiter */
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (strncmp(*name, MSG_ORIG(MSG_FIL_LIB), MSG_FIL_LIB_SIZE) == 0) {
3637c478bd9Sstevel@tonic-gate 		ls = *name + MSG_FIL_LIB_SIZE;
3647c478bd9Sstevel@tonic-gate 		if ((dp = (char *)strchr(ls, '.')) != (char *)0) {
3657c478bd9Sstevel@tonic-gate 			*name = ls;
3667c478bd9Sstevel@tonic-gate 			return (dp - ls);
3677c478bd9Sstevel@tonic-gate 		}
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 	return (-1);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /*
3737c478bd9Sstevel@tonic-gate  * Make a pass through the data base to set the dbe_name of a dbe.  This
3747c478bd9Sstevel@tonic-gate  * is necessary because there may be several revisions of a library
3757c478bd9Sstevel@tonic-gate  * but only one will be chosen.
3767c478bd9Sstevel@tonic-gate  */
3777c478bd9Sstevel@tonic-gate static void
fix_lo(dbp)3787c478bd9Sstevel@tonic-gate fix_lo(dbp)
3797c478bd9Sstevel@tonic-gate 	struct db *dbp;
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	int i;				/* loop temporary */
3827c478bd9Sstevel@tonic-gate 	int dirlen = strlen(&AP(dbp)[dbp->db_name]);
3837c478bd9Sstevel@tonic-gate 					/* length of directory pathname */
3847c478bd9Sstevel@tonic-gate 	char *cp;			/* working temporary */
3857c478bd9Sstevel@tonic-gate 	char *tp;			/* working temporary */
3867c478bd9Sstevel@tonic-gate 	struct dbe *ep;			/* working copy of dbe */
3877c478bd9Sstevel@tonic-gate 	struct link_object *lop;	/* working copy of link_object */
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	for (i = 0; i < DB_HASH; i++) {
3907c478bd9Sstevel@tonic-gate 		for (ep = &(dbp->db_hash[i]); ep && ep->dbe_lop;
3917c478bd9Sstevel@tonic-gate 		    (ep = ep->dbe_next == 0 ? NULL :
3927c478bd9Sstevel@tonic-gate 		    /* LINTED */
3937c478bd9Sstevel@tonic-gate 		    (struct dbe *)&AP(dbp)[ep->dbe_next])) {
3947c478bd9Sstevel@tonic-gate 			/* LINTED */
3957c478bd9Sstevel@tonic-gate 			lop = (struct link_object *)&AP(dbp)[ep->dbe_lop];
3967c478bd9Sstevel@tonic-gate 			tp = &AP(dbp)[lop->lo_next];
3977c478bd9Sstevel@tonic-gate 			ep->dbe_name = RELPTR(dbp,
3987c478bd9Sstevel@tonic-gate 			    calloc((dirlen + strlen(tp) + 2), 1));
3997c478bd9Sstevel@tonic-gate 			lop->lo_minor += dirlen + 1;
4007c478bd9Sstevel@tonic-gate 			cp = strncpy(&AP(dbp)[ep->dbe_name],
4017c478bd9Sstevel@tonic-gate 			    &AP(dbp)[dbp->db_name], dirlen);
4027c478bd9Sstevel@tonic-gate 			cp = strncpy(cp + dirlen, MSG_ORIG(MSG_STR_SLASH),
4037c478bd9Sstevel@tonic-gate 			    MSG_STR_SLASH_SIZE);
4047c478bd9Sstevel@tonic-gate 			(void) strcpy(cp + 1, tp);
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate  * Allocate a new dbd, append it after dbdpp and set the dbd_dbp to dbp.
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate static struct dbd *
new_dbd(dbdpp,dbp)4137c478bd9Sstevel@tonic-gate new_dbd(dbdpp, dbp)
4147c478bd9Sstevel@tonic-gate 	struct dbd **dbdpp;		/* insertion point */
4157c478bd9Sstevel@tonic-gate 	struct db *dbp;			/* db associated with this dbd */
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate 	struct dbd *dbdp;		/* working dbd ptr. */
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	dbdp = malloc(sizeof (struct dbd));
4207c478bd9Sstevel@tonic-gate 	dbdp->dbd_db = dbp;
4217c478bd9Sstevel@tonic-gate 	dbdp->dbd_next = NULL;
4227c478bd9Sstevel@tonic-gate 	*dbdpp = dbdp;
4237c478bd9Sstevel@tonic-gate 	return (dbdp);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate  * Calculate hash index for link object.
4287c478bd9Sstevel@tonic-gate  * This is based on X.major from libX.so.major.minor.
4297c478bd9Sstevel@tonic-gate  */
4307c478bd9Sstevel@tonic-gate static int
hash(np,nchrs,m)4317c478bd9Sstevel@tonic-gate hash(np, nchrs, m)
4327c478bd9Sstevel@tonic-gate 	char *np; 			/* X of libX */
4337c478bd9Sstevel@tonic-gate 	int nchrs;			/* no of chrs. to hash on */
4347c478bd9Sstevel@tonic-gate 	int m;				/* the major version */
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	int h;				/* for loop counter */
4377c478bd9Sstevel@tonic-gate 	char *cp;			/* working (char *) ptr */
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	for (h = 0, cp = np; h < nchrs; h++, cp++)
4407c478bd9Sstevel@tonic-gate 		h = (h << 1) + *cp;
4417c478bd9Sstevel@tonic-gate 	h += (h << 1) + m;
4427c478bd9Sstevel@tonic-gate 	h = ((h & 0x7fffffff) % DB_HASH);
4437c478bd9Sstevel@tonic-gate 	return (h);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate  * Test whether the string is of digit[.digit]* format
4487c478bd9Sstevel@tonic-gate  */
4497c478bd9Sstevel@tonic-gate static int
rest_ok(str)4507c478bd9Sstevel@tonic-gate rest_ok(str)
4517c478bd9Sstevel@tonic-gate 	char *str;			/* input string */
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	int dummy;			/* integer place holder */
4547c478bd9Sstevel@tonic-gate 	int legal = 1;			/* return flag */
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	while (!EMPTY(str)) {
4577c478bd9Sstevel@tonic-gate 		if (!stol(str, '.', &str, &dummy)) {
4587c478bd9Sstevel@tonic-gate 			legal = 0;
4597c478bd9Sstevel@tonic-gate 			break;
4607c478bd9Sstevel@tonic-gate 		}
4617c478bd9Sstevel@tonic-gate 		if (EMPTY(str))
4627c478bd9Sstevel@tonic-gate 			break;
4637c478bd9Sstevel@tonic-gate 		else
4647c478bd9Sstevel@tonic-gate 			/* LINTED */
4657c478bd9Sstevel@tonic-gate 			(SKIP_DOT(str));
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 	return (legal);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate /*
4717c478bd9Sstevel@tonic-gate  * Compare 2 strings and test whether they are of the form digit[.digit]*.
4727c478bd9Sstevel@tonic-gate  * It will return -1, 0, or 1 depending on whether c1p is less, equal or
4737c478bd9Sstevel@tonic-gate  * greater than c2p
4747c478bd9Sstevel@tonic-gate  */
4757c478bd9Sstevel@tonic-gate static int
verscmp(const char * c1p,const char * c2p)4767c478bd9Sstevel@tonic-gate verscmp(const char *c1p, const char *c2p)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	char	*l_c1p = (char *)c1p;	/* working copy of c1p */
4797c478bd9Sstevel@tonic-gate 	char	*l_c2p = (char *)c2p;	/* working copy of c2p */
4807c478bd9Sstevel@tonic-gate 	int	l_c1p_ok = 0;		/* is c1p a legal string */
4817c478bd9Sstevel@tonic-gate 	int	c2p_dig = 0;		/* int that c1p currently */
4827c478bd9Sstevel@tonic-gate 					/*	represents */
4837c478bd9Sstevel@tonic-gate 	int	c1p_dig = 0;		/* int that c2p currently */
4847c478bd9Sstevel@tonic-gate 					/*	represents */
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	while (((l_c1p_ok = stol(l_c1p, '.', &l_c1p, &c1p_dig)) == 1) &&
4877c478bd9Sstevel@tonic-gate 	    stol(l_c2p, '.', &l_c2p, &c2p_dig) && (c2p_dig == c1p_dig)) {
4887c478bd9Sstevel@tonic-gate 		if (EMPTY(l_c1p) && EMPTY(l_c2p))
4897c478bd9Sstevel@tonic-gate 			return (0);
4907c478bd9Sstevel@tonic-gate 		else if (EMPTY(l_c1p) && !EMPTY(l_c2p) &&
4917c478bd9Sstevel@tonic-gate 		    rest_ok(SKIP_DOT(l_c2p)))
4927c478bd9Sstevel@tonic-gate 			return (-1);
4937c478bd9Sstevel@tonic-gate 		else if (EMPTY(l_c2p) && !EMPTY(l_c1p) &&
4947c478bd9Sstevel@tonic-gate 		    rest_ok(SKIP_DOT(l_c1p)))
4957c478bd9Sstevel@tonic-gate 			return (1);
4967c478bd9Sstevel@tonic-gate 		l_c1p++; l_c2p++;
4977c478bd9Sstevel@tonic-gate 	};
4987c478bd9Sstevel@tonic-gate 	if (!l_c1p_ok)
4997c478bd9Sstevel@tonic-gate 		return (-1);
5007c478bd9Sstevel@tonic-gate 	else if (c1p_dig < c2p_dig)
5017c478bd9Sstevel@tonic-gate 		return (-1);
5027c478bd9Sstevel@tonic-gate 	else if ((c1p_dig > c2p_dig) && rest_ok(SKIP_DOT(l_c1p)))
5037c478bd9Sstevel@tonic-gate 		return (1);
5047c478bd9Sstevel@tonic-gate 	else return (-1);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate  * "stol" attempts to interpret a collection of characters between delimiters
5097c478bd9Sstevel@tonic-gate  * as a decimal digit. It stops interpreting when it reaches a delimiter or
5107c478bd9Sstevel@tonic-gate  * when character does not represent a digit. In the first case it returns
5117c478bd9Sstevel@tonic-gate  * success and the latter failure.
5127c478bd9Sstevel@tonic-gate  */
5137c478bd9Sstevel@tonic-gate static int
stol(cp,delimit,ptr,i)5147c478bd9Sstevel@tonic-gate stol(cp, delimit, ptr, i)
5157c478bd9Sstevel@tonic-gate 	char *cp;			/* ptr to input string */
5167c478bd9Sstevel@tonic-gate 	char delimit;			/* delimiter */
5177c478bd9Sstevel@tonic-gate 	char **ptr;			/* left pointing to next del. or */
5187c478bd9Sstevel@tonic-gate 					/* illegal character */
5197c478bd9Sstevel@tonic-gate 	int *i;				/* digit that the string represents */
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	int c = 0;			/* current char */
5227c478bd9Sstevel@tonic-gate 	int n = 0;			/* working copy of i */
5237c478bd9Sstevel@tonic-gate 	int neg = 0;			/* is number negative */
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (ptr != (char **)0)
5267c478bd9Sstevel@tonic-gate 		*ptr = cp; /* in case no number is formed */
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	if (EMPTY(cp))
5297c478bd9Sstevel@tonic-gate 		return (0);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (!isdigit(c = *cp) && (c == '-')) {
5327c478bd9Sstevel@tonic-gate 		neg++;
5337c478bd9Sstevel@tonic-gate 		c = *++cp;
5347c478bd9Sstevel@tonic-gate 	};
5357c478bd9Sstevel@tonic-gate 	if (EMPTY(cp) || !isdigit(c))
5367c478bd9Sstevel@tonic-gate 		return (0);
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	while (isdigit(c = *cp) && (*cp++ != '\0')) {
5397c478bd9Sstevel@tonic-gate 		n *= 10;
5407c478bd9Sstevel@tonic-gate 		n += c - '0';
5417c478bd9Sstevel@tonic-gate 	};
5427c478bd9Sstevel@tonic-gate 	if (ptr != (char **)0)
5437c478bd9Sstevel@tonic-gate 		*ptr = cp;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	if ((*cp == '\0') || (*cp == delimit)) {
5467c478bd9Sstevel@tonic-gate 		*i = neg ? -n : n;
5477c478bd9Sstevel@tonic-gate 		return (1);
5487c478bd9Sstevel@tonic-gate 	};
5497c478bd9Sstevel@tonic-gate 	return (0);
5507c478bd9Sstevel@tonic-gate }
551