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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <malloc.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include "xlator.h"
337c478bd9Sstevel@tonic-gate #include "util.h"
347c478bd9Sstevel@tonic-gate #include "bucket.h"
357c478bd9Sstevel@tonic-gate #include "errlog.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /* Statics: */
387c478bd9Sstevel@tonic-gate #define	TRUE	1
397c478bd9Sstevel@tonic-gate #define	FALSE	0
407c478bd9Sstevel@tonic-gate #define	NLISTS	50
417c478bd9Sstevel@tonic-gate #define	NPAR	25
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static bucket_t **Buckethead;
447c478bd9Sstevel@tonic-gate static int N_lists;
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate static int Bc = -1; /* For iterators. */
477c478bd9Sstevel@tonic-gate static bucket_t *Bp;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static void start_new_list(const bucket_t *);
507c478bd9Sstevel@tonic-gate static void grow_lists(void);
517c478bd9Sstevel@tonic-gate static bucket_t *new_bucket(const char *, int);
527c478bd9Sstevel@tonic-gate static void print_iface(const Interface *);
537c478bd9Sstevel@tonic-gate static void new_hashmap(void);
547c478bd9Sstevel@tonic-gate static int add_to_hashmap(const char *, const bucket_t *);
557c478bd9Sstevel@tonic-gate static bucket_t *find_in_hashmap(const char *);
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * initialization interfaces.
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * create_lists -- initialize the bucket list and hash map.
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate void
create_lists(void)647c478bd9Sstevel@tonic-gate create_lists(void)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "create_lists() {");
687c478bd9Sstevel@tonic-gate 	new_hashmap();
697c478bd9Sstevel@tonic-gate 	if ((Buckethead = calloc(sizeof (bucket_t *), NLISTS)) == NULL) {
707c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory creating initial "
717c478bd9Sstevel@tonic-gate 			"list of versions");
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	}
747c478bd9Sstevel@tonic-gate 	N_lists = NLISTS;
757c478bd9Sstevel@tonic-gate 	errlog(END, "}");
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * data-loading interfaces -- adding buckets to lists and
817c478bd9Sstevel@tonic-gate  *	interfaces to buckets.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * add_parent -- add a parent node. Returns TRUE or FALSE.
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  * 	if *version == NULL, then
887c478bd9Sstevel@tonic-gate  * 		the bucket version (eg, SUNW_1.1) hasn't
897c478bd9Sstevel@tonic-gate  * 		been parsed correctly.  Die.
907c478bd9Sstevel@tonic-gate  * 	if *after == NULL, then this is the ``initial case'',
917c478bd9Sstevel@tonic-gate  * 		where no predecessor (child) exists.  We start a new
927c478bd9Sstevel@tonic-gate  * 		tree of buckets.
937c478bd9Sstevel@tonic-gate  * 	if *after != NULL, we have the normal case, and
947c478bd9Sstevel@tonic-gate  * 		add to an existing tree.
957c478bd9Sstevel@tonic-gate  * 	if *after is not a version name found among the buckets,
967c478bd9Sstevel@tonic-gate  * 		then something got misparsed or the versions file is
977c478bd9Sstevel@tonic-gate  * 		malformed. Function will print problem and
987c478bd9Sstevel@tonic-gate  * 		return 0 so caller can report location of error.
997c478bd9Sstevel@tonic-gate  *      If either version or after is NULL, it's a programmer error.
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate int
add_parent(const char * version,const char * after,int weak)1027c478bd9Sstevel@tonic-gate add_parent(const char *version, const char *after, int weak)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	bucket_t *new, *child;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	/* Sanity-check parameters. */
1077c478bd9Sstevel@tonic-gate 	assert(version != NULL, "passed a null version to add_parent");
1087c478bd9Sstevel@tonic-gate 	assert(after != NULL, "passed a null after to add_parent");
1097c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_parent(%s,%s,%d) {", version, after, weak);
1107c478bd9Sstevel@tonic-gate 	if ((new = find_in_hashmap(version)) == NULL) {
1117c478bd9Sstevel@tonic-gate 		/* We don't have one have one yet. */
1127c478bd9Sstevel@tonic-gate 		new = new_bucket(version, weak);
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 	new->b_weak = weak;
1157c478bd9Sstevel@tonic-gate 	if (*after == '\0') {
1167c478bd9Sstevel@tonic-gate 		/*
1177c478bd9Sstevel@tonic-gate 		 * This is the ``initial case'', where no
1187c478bd9Sstevel@tonic-gate 		 * child exists.  We start a new tree of buckets.
1197c478bd9Sstevel@tonic-gate 		 */
1207c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
1217c478bd9Sstevel@tonic-gate 		start_new_list(new);
1227c478bd9Sstevel@tonic-gate 	} else {
1237c478bd9Sstevel@tonic-gate 		if ((child = find_in_hashmap(after)) == NULL) {
1247c478bd9Sstevel@tonic-gate 			/*
1257c478bd9Sstevel@tonic-gate 			 * The version in the spec doesn't appear in the
1267c478bd9Sstevel@tonic-gate 			 * versions file.  One or the other is lying.
1277c478bd9Sstevel@tonic-gate 			 */
1287c478bd9Sstevel@tonic-gate 			errlog(WARNING, "set file: can't find version \"%s\","
1297c478bd9Sstevel@tonic-gate 			    "therefor can't add it's parent, \"%s\"",
1307c478bd9Sstevel@tonic-gate 			    after, version);
1317c478bd9Sstevel@tonic-gate 			errlog(END, "} /* add_parent */");
1327c478bd9Sstevel@tonic-gate 			return (FALSE);
1337c478bd9Sstevel@tonic-gate 		}
1347c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
1357c478bd9Sstevel@tonic-gate 		child->b_parent = new;
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 	errlog(END, "} /* add_parent */");
1387c478bd9Sstevel@tonic-gate 	return (TRUE);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * add_uncle -- adds an uncle node
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate int
add_uncle(const char * version,const char * after,int weak)1457c478bd9Sstevel@tonic-gate add_uncle(const char *version, const char *after, int weak)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	bucket_t *new, *child;
1487c478bd9Sstevel@tonic-gate 	struct bucketlist *uncle;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/* Sanity-check parameters. */
1517c478bd9Sstevel@tonic-gate 	assert(version != NULL, "passed a null version to add_uncle");
1527c478bd9Sstevel@tonic-gate 	assert(after != NULL, "passed a null after to add_uncle");
1537c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_uncle(%s,%s,%d) {", version, after, weak);
1547c478bd9Sstevel@tonic-gate 	if ((new = find_in_hashmap(version)) == NULL) {
1557c478bd9Sstevel@tonic-gate 		/* We don't have one have one yet. */
1567c478bd9Sstevel@tonic-gate 		new = new_bucket(version, weak);
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 	if (*after == '\0') {
1597c478bd9Sstevel@tonic-gate 		/*
1607c478bd9Sstevel@tonic-gate 		 * This is the ``initial case'', where no
1617c478bd9Sstevel@tonic-gate 		 * child exists.  We start a new tree of buckets.
1627c478bd9Sstevel@tonic-gate 		 */
1637c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
1647c478bd9Sstevel@tonic-gate 		start_new_list(new);
1657c478bd9Sstevel@tonic-gate 	} else {
1667c478bd9Sstevel@tonic-gate 		if ((child = find_in_hashmap(after)) == NULL) {
1677c478bd9Sstevel@tonic-gate 			/*
1687c478bd9Sstevel@tonic-gate 			 * The version in the spec doesn't appear in the
1697c478bd9Sstevel@tonic-gate 			 * versions file.  One or the other is lying.
1707c478bd9Sstevel@tonic-gate 			 */
1717c478bd9Sstevel@tonic-gate 			errlog(WARNING, "set file: can't find version \"%s\","
1727c478bd9Sstevel@tonic-gate 			    "therefor can't add it's uncle, \"%s\"",
1737c478bd9Sstevel@tonic-gate 			    after, version);
1747c478bd9Sstevel@tonic-gate 			errlog(END, "}");
1757c478bd9Sstevel@tonic-gate 			return (FALSE);
1767c478bd9Sstevel@tonic-gate 		}
1777c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
1787c478bd9Sstevel@tonic-gate 		uncle =	malloc(sizeof (struct bucketlist));
1797c478bd9Sstevel@tonic-gate 		uncle->bl_next = child->b_uncles;
1807c478bd9Sstevel@tonic-gate 		uncle->bl_bucket = new;
1817c478bd9Sstevel@tonic-gate 		child->b_uncles = uncle;
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 	errlog(END, "}");
1847c478bd9Sstevel@tonic-gate 	return (TRUE);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /*
1887c478bd9Sstevel@tonic-gate  * set_weak -- set a version to be a weak version
1897c478bd9Sstevel@tonic-gate  */
1907c478bd9Sstevel@tonic-gate void
set_weak(const char * version,int weak)1917c478bd9Sstevel@tonic-gate set_weak(const char *version, int weak)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	bucket_t *v;
1947c478bd9Sstevel@tonic-gate 	if ((v = find_in_hashmap(version)) == NULL) {
1957c478bd9Sstevel@tonic-gate 		/* We don't have one have one yet. */
1967c478bd9Sstevel@tonic-gate 		errlog(ERROR|FATAL, "Unable to set weak. Version not found");
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 	v->b_weak = weak;
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * add_by_name -- look up bucket and add an interface to it.
2037c478bd9Sstevel@tonic-gate  *      Returns 0 for success or an errno.h value for failure.
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  * 	if *version is not among the buckets, then the
2067c478bd9Sstevel@tonic-gate  * 		version in the spec doesn't appear in the
2077c478bd9Sstevel@tonic-gate  * 		set file.  One or the other is lying. Function will
2087c478bd9Sstevel@tonic-gate  * 		report the problem and return ENOENT
2097c478bd9Sstevel@tonic-gate  * 		so the front end can report and exit (or
2107c478bd9Sstevel@tonic-gate  * 		continue if it wants).
2117c478bd9Sstevel@tonic-gate  * 	if interface ore version is NULL, then
2127c478bd9Sstevel@tonic-gate  * 		the begin line code should
2137c478bd9Sstevel@tonic-gate  * 		have caught it long before, to avoid passing
2147c478bd9Sstevel@tonic-gate  * 		a null pointer around. Die.
2157c478bd9Sstevel@tonic-gate  *
2167c478bd9Sstevel@tonic-gate  */
2177c478bd9Sstevel@tonic-gate #define	ADD_EQUALS(str)	if (strchr(str, '=') == NULL) (void) strcat(str, " =")
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate int
add_by_name(const char * version,const Interface * interface)2207c478bd9Sstevel@tonic-gate add_by_name(const char *version, const Interface *interface)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	bucket_t *b;
2237c478bd9Sstevel@tonic-gate 	char buffer[1024];
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	assert(version != NULL, "passed a null version to add_by_name");
2267c478bd9Sstevel@tonic-gate 	assert(interface != NULL, "passed a null interface to add_by_name");
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_by_name(%s,", version);
2297c478bd9Sstevel@tonic-gate 	print_iface(interface);
2307c478bd9Sstevel@tonic-gate 	errlog(TRACING, ");");
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	/* Sanity-check the parameters. */
2337c478bd9Sstevel@tonic-gate 	if ((b = find_in_hashmap(version)) == NULL) {
2347c478bd9Sstevel@tonic-gate 		/*
2357c478bd9Sstevel@tonic-gate 		 * The version in the spec doesn't appear in the
2367c478bd9Sstevel@tonic-gate 		 * versions file. Alas, this isn't an error.  It can
2377c478bd9Sstevel@tonic-gate 		 * happen whenever doing just sparc, just i386
2387c478bd9Sstevel@tonic-gate 		 * or the like.
2397c478bd9Sstevel@tonic-gate 		 */
2407c478bd9Sstevel@tonic-gate 		errlog(END, "}");
2417c478bd9Sstevel@tonic-gate 		return (ENOENT);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * Add to bucket.
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	(void) snprintf(buffer, sizeof (buffer), "%s", interface->IF_name);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (interface->IF_filter && interface->IF_auxiliary) {
2497c478bd9Sstevel@tonic-gate 		errlog(FATAL, "Error: cannot set both FILTER and AUXILIARY "
2507c478bd9Sstevel@tonic-gate 		    "for an interface: %s", interface->IF_name);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	if (interface->IF_filter) {
2547c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
2557c478bd9Sstevel@tonic-gate 		if (interface->IF_type == FUNCTION) {
2567c478bd9Sstevel@tonic-gate 			(void) strcat(buffer, " FUNCTION");
2577c478bd9Sstevel@tonic-gate 		} else if (interface->IF_type == DATA) {
2587c478bd9Sstevel@tonic-gate 			(void) strcat(buffer, " DATA");
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " FILTER ");
2617c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, interface->IF_filter);
2627c478bd9Sstevel@tonic-gate 	} else if (interface->IF_auxiliary) {
2637c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
2647c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " AUXILIARY ");
2657c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, interface->IF_auxiliary);
2667c478bd9Sstevel@tonic-gate 	} else if (IsFilterLib) {
2677c478bd9Sstevel@tonic-gate 		/*
2687c478bd9Sstevel@tonic-gate 		 * For DATA types it is currently assumed that they are
2697c478bd9Sstevel@tonic-gate 		 * handled via a minimal C file, e.g. 'data.c', in the
2707c478bd9Sstevel@tonic-gate 		 * library's build.  Hence, we do not append '= DATA' here.
2717c478bd9Sstevel@tonic-gate 		 */
2727c478bd9Sstevel@tonic-gate 		if (interface->IF_type == FUNCTION) {
2737c478bd9Sstevel@tonic-gate 			ADD_EQUALS(buffer);
2747c478bd9Sstevel@tonic-gate 			(void) strcat(buffer, " FUNCTION");
2757c478bd9Sstevel@tonic-gate 		}
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	switch (interface->IF_binding) {
2797c478bd9Sstevel@tonic-gate 	case DIRECT:
2807c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
2817c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " DIRECT");
2827c478bd9Sstevel@tonic-gate 		break;
2837c478bd9Sstevel@tonic-gate 	case NODIRECT:
2847c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
2857c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " NODIRECT");
2867c478bd9Sstevel@tonic-gate 		break;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	if (interface->IF_binding == PROTECTED) {
2907c478bd9Sstevel@tonic-gate 		/* Assign in case of realloc. */
2917c478bd9Sstevel@tonic-gate 		b->b_protected_table =
2927c478bd9Sstevel@tonic-gate 		    add_to_stringtable(b->b_protected_table, buffer);
2937c478bd9Sstevel@tonic-gate 		b->b_has_protecteds = 1;
2947c478bd9Sstevel@tonic-gate 		errlog(VERBOSE, "set has_protecteds on bucket 0x%p", b);
2957c478bd9Sstevel@tonic-gate 	} else {
2967c478bd9Sstevel@tonic-gate 		/* Assign in case of realloc. */
2977c478bd9Sstevel@tonic-gate 		b->b_global_table = add_to_stringtable(b->b_global_table,
2987c478bd9Sstevel@tonic-gate 			buffer);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 	errlog(END, "}");
3017c478bd9Sstevel@tonic-gate 	return (0);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate  * Processing interfaces
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * sort_buckets -- sort the interfaces within the buckets into
3117c478bd9Sstevel@tonic-gate  *      alphabetical order.
3127c478bd9Sstevel@tonic-gate  */
3137c478bd9Sstevel@tonic-gate void
sort_buckets(void)3147c478bd9Sstevel@tonic-gate sort_buckets(void)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate 	bucket_t *l, *b;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "sort_buckets() {");
3197c478bd9Sstevel@tonic-gate 	for (l = first_list(); l != NULL; l = next_list()) {
3207c478bd9Sstevel@tonic-gate 		errlog(VERBOSE, "l-bucket: %s", l->b_name);
3217c478bd9Sstevel@tonic-gate 		for (b = first_from_list(l); b != NULL; b = next_from_list()) {
3227c478bd9Sstevel@tonic-gate 			errlog(VERBOSE, "   b-bkt: %s", b->b_name);
3237c478bd9Sstevel@tonic-gate 			sort_stringtable(b->b_global_table);
3247c478bd9Sstevel@tonic-gate 			sort_stringtable(b->b_protected_table);
3257c478bd9Sstevel@tonic-gate 			if (b->b_uncles) {
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 				if (b->b_uncles->bl_bucket) {
3287c478bd9Sstevel@tonic-gate 		sort_stringtable(b->b_uncles->bl_bucket->b_global_table);
3297c478bd9Sstevel@tonic-gate 		sort_stringtable(b->b_uncles->bl_bucket->b_protected_table);
3307c478bd9Sstevel@tonic-gate 				}
3317c478bd9Sstevel@tonic-gate 			}
3327c478bd9Sstevel@tonic-gate 		}
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 	errlog(END, "}");
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  * add_local -- set the local flag on the logically first bucket.
3407c478bd9Sstevel@tonic-gate  *     This decision may belong in the caller, as it is about
3417c478bd9Sstevel@tonic-gate  *     mapfiles, not inherent ordering or bucket contents...
3427c478bd9Sstevel@tonic-gate  */
3437c478bd9Sstevel@tonic-gate void
add_local(void)3447c478bd9Sstevel@tonic-gate add_local(void)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	bucket_t *b, *list;
3477c478bd9Sstevel@tonic-gate 	int	done = 0;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_local() {");
3507c478bd9Sstevel@tonic-gate 	/* Iterate across lists of buckets */
3517c478bd9Sstevel@tonic-gate 	for (list = first_list(); list != NULL; list = next_list()) {
3527c478bd9Sstevel@tonic-gate 		/* Traverse the list found. */
3537c478bd9Sstevel@tonic-gate 		for (b = list; b != NULL; b = b->b_parent) {
3547c478bd9Sstevel@tonic-gate 			if (b->b_weak != 1) {
3557c478bd9Sstevel@tonic-gate 				/* We've found the first non-weak. */
3567c478bd9Sstevel@tonic-gate 				b->b_has_locals = done = 1;
3577c478bd9Sstevel@tonic-gate 				errlog(VERBOSE,
3587c478bd9Sstevel@tonic-gate 				    "set has_locals on bucket 0x%p", b);
3597c478bd9Sstevel@tonic-gate 				break;
3607c478bd9Sstevel@tonic-gate 			}
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 		if (b != NULL && b->b_has_locals == 1)
3637c478bd9Sstevel@tonic-gate 			break;
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 	if (done == 0) {
3667c478bd9Sstevel@tonic-gate 		errlog(WARNING, "has_locals never set");
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	errlog(END, "}");
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /*
3737c478bd9Sstevel@tonic-gate  * Output interfaces, mostly iterators
3747c478bd9Sstevel@tonic-gate  */
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /*
3787c478bd9Sstevel@tonic-gate  * parents_of -- return a list of all parents.
3797c478bd9Sstevel@tonic-gate  */
3807c478bd9Sstevel@tonic-gate char **
parents_of(const bucket_t * start)3817c478bd9Sstevel@tonic-gate parents_of(const bucket_t *start)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	static char *a[NPAR] = {NULL};
3847c478bd9Sstevel@tonic-gate 	const bucket_t *b = start;
3857c478bd9Sstevel@tonic-gate 	char **p = &a[0];
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	assert(start != NULL, "passed a null start to parents_of");
3887c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "parents_of() {");
3897c478bd9Sstevel@tonic-gate 	a[0] = '\0';
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/* Go to parent, print it and all its uncle. */
3927c478bd9Sstevel@tonic-gate 	if (b->b_parent == NULL) {
3937c478bd9Sstevel@tonic-gate 		errlog(TRACING, "returning empty string");
3947c478bd9Sstevel@tonic-gate 		errlog(END, "}");
3957c478bd9Sstevel@tonic-gate 		return (a);
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 	b = b->b_parent;
3987c478bd9Sstevel@tonic-gate 	*p++ = b->b_name;
3997c478bd9Sstevel@tonic-gate 	*p = '\0';
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	assert(p < &a[NPAR], "p fell off the end of a in parents_of");
4027c478bd9Sstevel@tonic-gate 	errlog(END, "}");
4037c478bd9Sstevel@tonic-gate 	return (a);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate  * first, next_from_bucket --iterators for bucket contents. Serially
4087c478bd9Sstevel@tonic-gate  *      reusable only.
4097c478bd9Sstevel@tonic-gate  */
4107c478bd9Sstevel@tonic-gate int Ic = -1;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * debugging interfaces
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate void
print_bucket(const bucket_t * b)4167c478bd9Sstevel@tonic-gate print_bucket(const bucket_t *b)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	errlog(TRACING, "bucket_t at 0x%p {", (void *)b);
4207c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    char   *b_name = \"%s\";", b->b_name);
4217c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    struct bucket_t *b_parent = 0x%p;",
4227c478bd9Sstevel@tonic-gate 		(void *)b->b_parent);
4237c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    struct bucketlist *b_uncles = 0x%p;",
4247c478bd9Sstevel@tonic-gate 		(void *)b->b_uncles);
4257c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    struct bucket_t *b_thread = 0x%p;",
4267c478bd9Sstevel@tonic-gate 		(void *)b->b_thread);
4277c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int	b_has_locals = %d;",
4287c478bd9Sstevel@tonic-gate 		b->b_has_locals);
4297c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int	b_has_protecteds = %d;",
4307c478bd9Sstevel@tonic-gate 		b->b_has_protecteds);
4317c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int        b_was_printed = %d;",
4327c478bd9Sstevel@tonic-gate 		b->b_was_printed);
4337c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int        b_weak = %d;",
4347c478bd9Sstevel@tonic-gate 		b->b_weak);
4357c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    table_t  *b_global_table = 0x%p;",
4367c478bd9Sstevel@tonic-gate 		(void *)b->b_global_table);
4377c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    table_t  *b_protected_table = 0x%p;",
4387c478bd9Sstevel@tonic-gate 		(void *)b->b_protected_table);
4397c478bd9Sstevel@tonic-gate 	errlog(TRACING, "}");
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate void
print_all_buckets(void)4437c478bd9Sstevel@tonic-gate print_all_buckets(void)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	bucket_t *l, *b;
4467c478bd9Sstevel@tonic-gate 	int i = 0, j = 0;
4477c478bd9Sstevel@tonic-gate 	char **p;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	for (i = 0, l = first_list(); l != NULL; l = next_list(), ++i) {
4507c478bd9Sstevel@tonic-gate 		errlog(TRACING, "list %d", i);
4517c478bd9Sstevel@tonic-gate 		for (j = 0, b = first_from_list(l);
4527c478bd9Sstevel@tonic-gate 		    b != NULL; b = next_from_list(), ++j) {
4537c478bd9Sstevel@tonic-gate 			errlog(TRACING, "bucket %d", j);
4547c478bd9Sstevel@tonic-gate 			print_bucket(b);
4557c478bd9Sstevel@tonic-gate 			errlog(TRACING, "global interfaces = {");
4567c478bd9Sstevel@tonic-gate 			print_stringtable(b->b_global_table);
4577c478bd9Sstevel@tonic-gate 			errlog(TRACING, "}");
4587c478bd9Sstevel@tonic-gate 			errlog(TRACING, "protected interfaces = {");
4597c478bd9Sstevel@tonic-gate 			print_stringtable(b->b_protected_table);
4607c478bd9Sstevel@tonic-gate 			errlog(TRACING, "}");
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 			for (p = parents_of(b); p != NULL && *p != NULL; ++p) {
4637c478bd9Sstevel@tonic-gate 				errlog(TRACING, " %s", *p);
4647c478bd9Sstevel@tonic-gate 			}
4657c478bd9Sstevel@tonic-gate 			errlog(TRACING, ";");
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 			if (b->b_uncles) {
4687c478bd9Sstevel@tonic-gate 				errlog(TRACING, " uncle bucket %d.1", j);
4697c478bd9Sstevel@tonic-gate 				print_bucket(b->b_uncles->bl_bucket);
4707c478bd9Sstevel@tonic-gate 				errlog(TRACING, "global interfaces = {");
4717c478bd9Sstevel@tonic-gate 				print_stringtable(
4727c478bd9Sstevel@tonic-gate 				    b->b_uncles->bl_bucket->b_global_table);
4737c478bd9Sstevel@tonic-gate 				errlog(TRACING, "}");
4747c478bd9Sstevel@tonic-gate 				errlog(TRACING, "protected interfaces = {");
4757c478bd9Sstevel@tonic-gate 				print_stringtable(
4767c478bd9Sstevel@tonic-gate 				    b->b_uncles->bl_bucket->b_protected_table);
4777c478bd9Sstevel@tonic-gate 				errlog(TRACING, "}");
4787c478bd9Sstevel@tonic-gate 			}
4797c478bd9Sstevel@tonic-gate 		}
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate  * lower-level functions, not visible outside the file.
4867c478bd9Sstevel@tonic-gate  */
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate /*
4897c478bd9Sstevel@tonic-gate  * new_bucket -- create a bucket for a given version. Must not fail.
4907c478bd9Sstevel@tonic-gate  */
4917c478bd9Sstevel@tonic-gate static bucket_t *
new_bucket(const char * name,int weak)4927c478bd9Sstevel@tonic-gate new_bucket(const char *name, int weak)
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate 	bucket_t *b;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	if ((b = (bucket_t *)calloc(1, sizeof (bucket_t))) == NULL) {
4977c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory creating a bucket "
4987c478bd9Sstevel@tonic-gate 			"to store interfaces in");
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 	if ((b->b_name = strdup(name)) == NULL) {
5017c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory storing an interface "
5027c478bd9Sstevel@tonic-gate 			"in a version bucket");
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 	b->b_uncles = NULL;
5057c478bd9Sstevel@tonic-gate 	b->b_global_table = create_stringtable(TABLE_INITIAL);
5067c478bd9Sstevel@tonic-gate 	b->b_protected_table = create_stringtable(TABLE_INITIAL);
5077c478bd9Sstevel@tonic-gate 	b->b_weak = weak;
5087c478bd9Sstevel@tonic-gate 	return (b);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate  * start_new_list -- start a list of buckets.
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate static void
start_new_list(const bucket_t * b)5167c478bd9Sstevel@tonic-gate start_new_list(const bucket_t *b)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	int i;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "start_new_list() {");
5217c478bd9Sstevel@tonic-gate 	assert(Buckethead != NULL, "Buckethead null in start_new_list");
5227c478bd9Sstevel@tonic-gate 	for (i = 0; Buckethead[i] != NULL && i < N_lists; ++i)
5237c478bd9Sstevel@tonic-gate 		continue;
5247c478bd9Sstevel@tonic-gate 	if (i >= N_lists) {
5257c478bd9Sstevel@tonic-gate 		grow_lists();
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 	Buckethead[i] = (bucket_t *)b;
5287c478bd9Sstevel@tonic-gate 	errlog(END, "}");
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate  * grow_list -- make more lists.  This should never occur...
5337c478bd9Sstevel@tonic-gate  */
5347c478bd9Sstevel@tonic-gate static void
grow_lists(void)5357c478bd9Sstevel@tonic-gate grow_lists(void)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	int i = N_lists;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "grow_lists() {");
5407c478bd9Sstevel@tonic-gate 	errlog(WARNING, "Warning: more than %d version lists "
5417c478bd9Sstevel@tonic-gate 	    "required (< %d is normal). Check sets file "
5427c478bd9Sstevel@tonic-gate 	    "to see why so many lines appear.",
5437c478bd9Sstevel@tonic-gate 	    N_lists, NLISTS);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	N_lists *= 2;
5467c478bd9Sstevel@tonic-gate 	if ((Buckethead = realloc(Buckethead, sizeof (bucket_t *) * N_lists))
5477c478bd9Sstevel@tonic-gate 		== NULL) {
5487c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory growing list of "
5497c478bd9Sstevel@tonic-gate 			"version buckets");
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate 	for (; i < N_lists; ++i) {
5527c478bd9Sstevel@tonic-gate 		Buckethead[i] = NULL;
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate /*
5577c478bd9Sstevel@tonic-gate  * delete_lists -- clean up afterwards.
5587c478bd9Sstevel@tonic-gate  */
5597c478bd9Sstevel@tonic-gate void
delete_lists(void)5607c478bd9Sstevel@tonic-gate delete_lists(void)
5617c478bd9Sstevel@tonic-gate {
5627c478bd9Sstevel@tonic-gate 	N_lists = 0;
5637c478bd9Sstevel@tonic-gate 	free(Buckethead);
5647c478bd9Sstevel@tonic-gate 	Buckethead = 0;
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate /*
5687c478bd9Sstevel@tonic-gate  * first_list, next_list -- an iterator for lists themselves.  Serially
5697c478bd9Sstevel@tonic-gate  *      reusable only.
5707c478bd9Sstevel@tonic-gate  */
5717c478bd9Sstevel@tonic-gate bucket_t *
first_list(void)5727c478bd9Sstevel@tonic-gate first_list(void)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	Bc = 0;
5757c478bd9Sstevel@tonic-gate 	return (Buckethead[Bc]);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate bucket_t *
next_list(void)5797c478bd9Sstevel@tonic-gate next_list(void)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate 	return (Buckethead[++Bc]);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate /*
5867c478bd9Sstevel@tonic-gate  * first, next, last_from_list -- iterators for individual lists. Serially
5877c478bd9Sstevel@tonic-gate  *      reusable only.
5887c478bd9Sstevel@tonic-gate  */
5897c478bd9Sstevel@tonic-gate bucket_t *
first_from_list(const bucket_t * l)5907c478bd9Sstevel@tonic-gate first_from_list(const bucket_t *l)
5917c478bd9Sstevel@tonic-gate {
5927c478bd9Sstevel@tonic-gate 	return (Bp = (bucket_t *)l);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate bucket_t *
next_from_list(void)5967c478bd9Sstevel@tonic-gate next_from_list(void)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	return (Bp = Bp->b_parent);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate /*
6047c478bd9Sstevel@tonic-gate  * Iface print utility
6057c478bd9Sstevel@tonic-gate  */
6067c478bd9Sstevel@tonic-gate static void
print_iface(const Interface * p)6077c478bd9Sstevel@tonic-gate print_iface(const Interface * p)
6087c478bd9Sstevel@tonic-gate {
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	errlog(TRACING, "%s (%s, %s, %s %d)", p->IF_name,
6117c478bd9Sstevel@tonic-gate 		(p->IF_type == FUNCTION) ? "function" :
6127c478bd9Sstevel@tonic-gate 		(p->IF_type == DATA) ? "data" : "unknown type",
6137c478bd9Sstevel@tonic-gate 		(p->IF_version) ? p->IF_version : "unknown version",
6147c478bd9Sstevel@tonic-gate 		(p->IF_class) ? p->IF_class : "unknown class",
6157c478bd9Sstevel@tonic-gate 		p->IF_binding);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate #define	HASHMAPSIZE	100
6217c478bd9Sstevel@tonic-gate #define	ERR	(-1)
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate static struct {
6247c478bd9Sstevel@tonic-gate 	hashmap_t *hh_map;
6257c478bd9Sstevel@tonic-gate 	int hh_map_size;
6267c478bd9Sstevel@tonic-gate 	int hh_mapC;
6277c478bd9Sstevel@tonic-gate 	hashmap_t *hh_last;
6287c478bd9Sstevel@tonic-gate } Hashhead = {
6297c478bd9Sstevel@tonic-gate 	NULL, -1, -1, NULL
6307c478bd9Sstevel@tonic-gate };
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate static int checksum(const char *);
6337c478bd9Sstevel@tonic-gate static void print_hashmap(const hashmap_t *);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate /*
6367c478bd9Sstevel@tonic-gate  * new_hashmap -- create the hash.
6377c478bd9Sstevel@tonic-gate  */
6387c478bd9Sstevel@tonic-gate static void
new_hashmap(void)6397c478bd9Sstevel@tonic-gate new_hashmap(void)
6407c478bd9Sstevel@tonic-gate {
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "new_hashmap() {");
6437c478bd9Sstevel@tonic-gate 	if ((Hashhead.hh_map = calloc(sizeof (hashmap_t), HASHMAPSIZE))
6447c478bd9Sstevel@tonic-gate 	    == NULL) {
6457c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory creating a hash-map of "
6467c478bd9Sstevel@tonic-gate 			"the versions");
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 	Hashhead.hh_mapC = 0;
6497c478bd9Sstevel@tonic-gate 	errlog(END, "}");
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate /*
6537c478bd9Sstevel@tonic-gate  * add_to_hashmap -- add a bucket to the map.  This is strictly for
6547c478bd9Sstevel@tonic-gate  *	use by add_parent()/add_uncle().
6557c478bd9Sstevel@tonic-gate  */
6567c478bd9Sstevel@tonic-gate static int
add_to_hashmap(const char * version_name,const bucket_t * bucket)6577c478bd9Sstevel@tonic-gate add_to_hashmap(const char *version_name, const bucket_t *bucket)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate 	hashmap_t *p;
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	assert(Hashhead.hh_map != NULL,
6627c478bd9Sstevel@tonic-gate 	    "Hashead.map was null in add_to_hashmap");
6637c478bd9Sstevel@tonic-gate 	assert(Hashhead.hh_mapC < HASHMAPSIZE,
6647c478bd9Sstevel@tonic-gate 	    "mapC too big in add_to_hashmap");
6657c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_to_hashmap(%s, %s) {", version_name, bucket);
6667c478bd9Sstevel@tonic-gate 	if (find_in_hashmap(version_name) != NULL) {
6677c478bd9Sstevel@tonic-gate 		/* Seen for the second time. TBD... */
6687c478bd9Sstevel@tonic-gate 		errlog(END, "} /* add_to_hashmap */");
6697c478bd9Sstevel@tonic-gate 		return (ERR);
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 	p = &Hashhead.hh_map[Hashhead.hh_mapC++];
6727c478bd9Sstevel@tonic-gate 	if ((p->h_version_name = strdup(version_name)) == NULL) {
6737c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory storing a version name");
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 	p->h_bucket = (bucket_t *)bucket;
6777c478bd9Sstevel@tonic-gate 	p->h_hash = checksum(version_name);
6787c478bd9Sstevel@tonic-gate 	Hashhead.hh_last = p;
6797c478bd9Sstevel@tonic-gate 	print_hashmap(p);
6807c478bd9Sstevel@tonic-gate 	errlog(END, "} /* add_to_hashmap */");
6817c478bd9Sstevel@tonic-gate 	return (0);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate /*
6867c478bd9Sstevel@tonic-gate  * find_in_hashmap -- find a bucket by name.  Strictly for use by addByName().
6877c478bd9Sstevel@tonic-gate  */
6887c478bd9Sstevel@tonic-gate static bucket_t *
find_in_hashmap(const char * version_name)6897c478bd9Sstevel@tonic-gate find_in_hashmap(const char *version_name)
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate 	hashmap_t *current;
6927c478bd9Sstevel@tonic-gate 	int hash = checksum(version_name);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	assert(Hashhead.hh_map != NULL,
6957c478bd9Sstevel@tonic-gate 		"Hashhead.hh_map was null in find_in_hashmap");
6967c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "find_in_hashmap(%s) {", version_name);
6977c478bd9Sstevel@tonic-gate 	if (Hashhead.hh_last != NULL && Hashhead.hh_last->h_hash == hash &&
6987c478bd9Sstevel@tonic-gate 	    strcmp(Hashhead.hh_last->h_version_name, version_name) == 0) {
6997c478bd9Sstevel@tonic-gate 		errlog(END, "}");
7007c478bd9Sstevel@tonic-gate 		return (Hashhead.hh_last->h_bucket);
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 	for (current = Hashhead.hh_map;
7037c478bd9Sstevel@tonic-gate 		current->h_version_name != NULL; ++current) {
7047c478bd9Sstevel@tonic-gate 		if (current->h_hash == hash &&
7057c478bd9Sstevel@tonic-gate 			strcmp(current->h_version_name, version_name) == 0) {
7067c478bd9Sstevel@tonic-gate 			/* Found it */
7077c478bd9Sstevel@tonic-gate 			Hashhead.hh_last = current;
7087c478bd9Sstevel@tonic-gate 			errlog(END, "}");
7097c478bd9Sstevel@tonic-gate 			return (current->h_bucket);
7107c478bd9Sstevel@tonic-gate 		}
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 	/* Doesn't exist, meaning version name is bogus. */
7137c478bd9Sstevel@tonic-gate 	errlog(END, "}");
7147c478bd9Sstevel@tonic-gate 	return (NULL);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate /*
7187c478bd9Sstevel@tonic-gate  * checksum -- from sum(1), algorithm 1.
7197c478bd9Sstevel@tonic-gate  */
7207c478bd9Sstevel@tonic-gate static int
checksum(const char * p)7217c478bd9Sstevel@tonic-gate checksum(const char *p)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	int sum;
7247c478bd9Sstevel@tonic-gate 
725*07c94cbfSToomas Soome 	for (sum = 0; *p != '\0'; ++p) {
7267c478bd9Sstevel@tonic-gate 		if (sum & 01)
7277c478bd9Sstevel@tonic-gate 			sum = (sum >> 1) + 0x8000;
7287c478bd9Sstevel@tonic-gate 		else
7297c478bd9Sstevel@tonic-gate 			sum >>= 1;
7307c478bd9Sstevel@tonic-gate 		sum += *p;
7317c478bd9Sstevel@tonic-gate 		sum &= 0xFFFF;
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 	return (sum);
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate static void
print_hashmap(const hashmap_t * h)7377c478bd9Sstevel@tonic-gate print_hashmap(const hashmap_t *h)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "struct hashmap_t at 0x4.4x {", h);
7407c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "    int    h_hash = %d;", h->h_hash);
7417c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "    char   *h_version_name = \"%s\";",
7427c478bd9Sstevel@tonic-gate 		h->h_version_name);
7437c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "    bucket_t *h_bucket = 0x%p;;",
7447c478bd9Sstevel@tonic-gate 		(void *) h->h_bucket);
7457c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "}");
7467c478bd9Sstevel@tonic-gate }
747