1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <malloc.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <errno.h>
33*7c478bd9Sstevel@tonic-gate #include <string.h>
34*7c478bd9Sstevel@tonic-gate #include "xlator.h"
35*7c478bd9Sstevel@tonic-gate #include "util.h"
36*7c478bd9Sstevel@tonic-gate #include "bucket.h"
37*7c478bd9Sstevel@tonic-gate #include "errlog.h"
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate /* Statics: */
40*7c478bd9Sstevel@tonic-gate #define	TRUE	1
41*7c478bd9Sstevel@tonic-gate #define	FALSE	0
42*7c478bd9Sstevel@tonic-gate #define	NLISTS	50
43*7c478bd9Sstevel@tonic-gate #define	NPAR	25
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate static bucket_t **Buckethead;
46*7c478bd9Sstevel@tonic-gate static int N_lists;
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate static int Bc = -1; /* For iterators. */
49*7c478bd9Sstevel@tonic-gate static bucket_t *Bp;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate static void start_new_list(const bucket_t *);
52*7c478bd9Sstevel@tonic-gate static void grow_lists(void);
53*7c478bd9Sstevel@tonic-gate static bucket_t *new_bucket(const char *, int);
54*7c478bd9Sstevel@tonic-gate static void print_iface(const Interface *);
55*7c478bd9Sstevel@tonic-gate static void new_hashmap(void);
56*7c478bd9Sstevel@tonic-gate static int add_to_hashmap(const char *, const bucket_t *);
57*7c478bd9Sstevel@tonic-gate static bucket_t *find_in_hashmap(const char *);
58*7c478bd9Sstevel@tonic-gate /*
59*7c478bd9Sstevel@tonic-gate  * initialization interfaces.
60*7c478bd9Sstevel@tonic-gate  */
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /*
63*7c478bd9Sstevel@tonic-gate  * create_lists -- initialize the bucket list and hash map.
64*7c478bd9Sstevel@tonic-gate  */
65*7c478bd9Sstevel@tonic-gate void
66*7c478bd9Sstevel@tonic-gate create_lists(void)
67*7c478bd9Sstevel@tonic-gate {
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "create_lists() {");
70*7c478bd9Sstevel@tonic-gate 	new_hashmap();
71*7c478bd9Sstevel@tonic-gate 	if ((Buckethead = calloc(sizeof (bucket_t *), NLISTS)) == NULL) {
72*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory creating initial "
73*7c478bd9Sstevel@tonic-gate 			"list of versions");
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 	}
76*7c478bd9Sstevel@tonic-gate 	N_lists = NLISTS;
77*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
78*7c478bd9Sstevel@tonic-gate }
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * data-loading interfaces -- adding buckets to lists and
83*7c478bd9Sstevel@tonic-gate  *	interfaces to buckets.
84*7c478bd9Sstevel@tonic-gate  */
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate  * add_parent -- add a parent node. Returns TRUE or FALSE.
88*7c478bd9Sstevel@tonic-gate  *
89*7c478bd9Sstevel@tonic-gate  * 	if *version == NULL, then
90*7c478bd9Sstevel@tonic-gate  * 		the bucket version (eg, SUNW_1.1) hasn't
91*7c478bd9Sstevel@tonic-gate  * 		been parsed correctly.  Die.
92*7c478bd9Sstevel@tonic-gate  * 	if *after == NULL, then this is the ``initial case'',
93*7c478bd9Sstevel@tonic-gate  * 		where no predecessor (child) exists.  We start a new
94*7c478bd9Sstevel@tonic-gate  * 		tree of buckets.
95*7c478bd9Sstevel@tonic-gate  * 	if *after != NULL, we have the normal case, and
96*7c478bd9Sstevel@tonic-gate  * 		add to an existing tree.
97*7c478bd9Sstevel@tonic-gate  * 	if *after is not a version name found among the buckets,
98*7c478bd9Sstevel@tonic-gate  * 		then something got misparsed or the versions file is
99*7c478bd9Sstevel@tonic-gate  * 		malformed. Function will print problem and
100*7c478bd9Sstevel@tonic-gate  * 		return 0 so caller can report location of error.
101*7c478bd9Sstevel@tonic-gate  *      If either version or after is NULL, it's a programmer error.
102*7c478bd9Sstevel@tonic-gate  */
103*7c478bd9Sstevel@tonic-gate int
104*7c478bd9Sstevel@tonic-gate add_parent(const char *version, const char *after, int weak)
105*7c478bd9Sstevel@tonic-gate {
106*7c478bd9Sstevel@tonic-gate 	bucket_t *new, *child;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	/* Sanity-check parameters. */
109*7c478bd9Sstevel@tonic-gate 	assert(version != NULL, "passed a null version to add_parent");
110*7c478bd9Sstevel@tonic-gate 	assert(after != NULL, "passed a null after to add_parent");
111*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_parent(%s,%s,%d) {", version, after, weak);
112*7c478bd9Sstevel@tonic-gate 	if ((new = find_in_hashmap(version)) == NULL) {
113*7c478bd9Sstevel@tonic-gate 		/* We don't have one have one yet. */
114*7c478bd9Sstevel@tonic-gate 		new = new_bucket(version, weak);
115*7c478bd9Sstevel@tonic-gate 	}
116*7c478bd9Sstevel@tonic-gate 	new->b_weak = weak;
117*7c478bd9Sstevel@tonic-gate 	if (*after == '\0') {
118*7c478bd9Sstevel@tonic-gate 		/*
119*7c478bd9Sstevel@tonic-gate 		 * This is the ``initial case'', where no
120*7c478bd9Sstevel@tonic-gate 		 * child exists.  We start a new tree of buckets.
121*7c478bd9Sstevel@tonic-gate 		 */
122*7c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
123*7c478bd9Sstevel@tonic-gate 		start_new_list(new);
124*7c478bd9Sstevel@tonic-gate 	} else {
125*7c478bd9Sstevel@tonic-gate 		if ((child = find_in_hashmap(after)) == NULL) {
126*7c478bd9Sstevel@tonic-gate 			/*
127*7c478bd9Sstevel@tonic-gate 			 * The version in the spec doesn't appear in the
128*7c478bd9Sstevel@tonic-gate 			 * versions file.  One or the other is lying.
129*7c478bd9Sstevel@tonic-gate 			 */
130*7c478bd9Sstevel@tonic-gate 			errlog(WARNING, "set file: can't find version \"%s\","
131*7c478bd9Sstevel@tonic-gate 			    "therefor can't add it's parent, \"%s\"",
132*7c478bd9Sstevel@tonic-gate 			    after, version);
133*7c478bd9Sstevel@tonic-gate 			errlog(END, "} /* add_parent */");
134*7c478bd9Sstevel@tonic-gate 			return (FALSE);
135*7c478bd9Sstevel@tonic-gate 		}
136*7c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
137*7c478bd9Sstevel@tonic-gate 		child->b_parent = new;
138*7c478bd9Sstevel@tonic-gate 	}
139*7c478bd9Sstevel@tonic-gate 	errlog(END, "} /* add_parent */");
140*7c478bd9Sstevel@tonic-gate 	return (TRUE);
141*7c478bd9Sstevel@tonic-gate }
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate /*
144*7c478bd9Sstevel@tonic-gate  * add_uncle -- adds an uncle node
145*7c478bd9Sstevel@tonic-gate  */
146*7c478bd9Sstevel@tonic-gate int
147*7c478bd9Sstevel@tonic-gate add_uncle(const char *version, const char *after, int weak)
148*7c478bd9Sstevel@tonic-gate {
149*7c478bd9Sstevel@tonic-gate 	bucket_t *new, *child;
150*7c478bd9Sstevel@tonic-gate 	struct bucketlist *uncle;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	/* Sanity-check parameters. */
153*7c478bd9Sstevel@tonic-gate 	assert(version != NULL, "passed a null version to add_uncle");
154*7c478bd9Sstevel@tonic-gate 	assert(after != NULL, "passed a null after to add_uncle");
155*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_uncle(%s,%s,%d) {", version, after, weak);
156*7c478bd9Sstevel@tonic-gate 	if ((new = find_in_hashmap(version)) == NULL) {
157*7c478bd9Sstevel@tonic-gate 		/* We don't have one have one yet. */
158*7c478bd9Sstevel@tonic-gate 		new = new_bucket(version, weak);
159*7c478bd9Sstevel@tonic-gate 	}
160*7c478bd9Sstevel@tonic-gate 	if (*after == '\0') {
161*7c478bd9Sstevel@tonic-gate 		/*
162*7c478bd9Sstevel@tonic-gate 		 * This is the ``initial case'', where no
163*7c478bd9Sstevel@tonic-gate 		 * child exists.  We start a new tree of buckets.
164*7c478bd9Sstevel@tonic-gate 		 */
165*7c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
166*7c478bd9Sstevel@tonic-gate 		start_new_list(new);
167*7c478bd9Sstevel@tonic-gate 	} else {
168*7c478bd9Sstevel@tonic-gate 		if ((child = find_in_hashmap(after)) == NULL) {
169*7c478bd9Sstevel@tonic-gate 			/*
170*7c478bd9Sstevel@tonic-gate 			 * The version in the spec doesn't appear in the
171*7c478bd9Sstevel@tonic-gate 			 * versions file.  One or the other is lying.
172*7c478bd9Sstevel@tonic-gate 			 */
173*7c478bd9Sstevel@tonic-gate 			errlog(WARNING, "set file: can't find version \"%s\","
174*7c478bd9Sstevel@tonic-gate 			    "therefor can't add it's uncle, \"%s\"",
175*7c478bd9Sstevel@tonic-gate 			    after, version);
176*7c478bd9Sstevel@tonic-gate 			errlog(END, "}");
177*7c478bd9Sstevel@tonic-gate 			return (FALSE);
178*7c478bd9Sstevel@tonic-gate 		}
179*7c478bd9Sstevel@tonic-gate 		(void) add_to_hashmap(version, new);
180*7c478bd9Sstevel@tonic-gate 		uncle =	malloc(sizeof (struct bucketlist));
181*7c478bd9Sstevel@tonic-gate 		uncle->bl_next = child->b_uncles;
182*7c478bd9Sstevel@tonic-gate 		uncle->bl_bucket = new;
183*7c478bd9Sstevel@tonic-gate 		child->b_uncles = uncle;
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
186*7c478bd9Sstevel@tonic-gate 	return (TRUE);
187*7c478bd9Sstevel@tonic-gate }
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate /*
190*7c478bd9Sstevel@tonic-gate  * set_weak -- set a version to be a weak version
191*7c478bd9Sstevel@tonic-gate  */
192*7c478bd9Sstevel@tonic-gate void
193*7c478bd9Sstevel@tonic-gate set_weak(const char *version, int weak)
194*7c478bd9Sstevel@tonic-gate {
195*7c478bd9Sstevel@tonic-gate 	bucket_t *v;
196*7c478bd9Sstevel@tonic-gate 	if ((v = find_in_hashmap(version)) == NULL) {
197*7c478bd9Sstevel@tonic-gate 		/* We don't have one have one yet. */
198*7c478bd9Sstevel@tonic-gate 		errlog(ERROR|FATAL, "Unable to set weak. Version not found");
199*7c478bd9Sstevel@tonic-gate 	}
200*7c478bd9Sstevel@tonic-gate 	v->b_weak = weak;
201*7c478bd9Sstevel@tonic-gate }
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate /*
204*7c478bd9Sstevel@tonic-gate  * add_by_name -- look up bucket and add an interface to it.
205*7c478bd9Sstevel@tonic-gate  *      Returns 0 for success or an errno.h value for failure.
206*7c478bd9Sstevel@tonic-gate  *
207*7c478bd9Sstevel@tonic-gate  * 	if *version is not among the buckets, then the
208*7c478bd9Sstevel@tonic-gate  * 		version in the spec doesn't appear in the
209*7c478bd9Sstevel@tonic-gate  * 		set file.  One or the other is lying. Function will
210*7c478bd9Sstevel@tonic-gate  * 		report the problem and return ENOENT
211*7c478bd9Sstevel@tonic-gate  * 		so the front end can report and exit (or
212*7c478bd9Sstevel@tonic-gate  * 		continue if it wants).
213*7c478bd9Sstevel@tonic-gate  * 	if interface ore version is NULL, then
214*7c478bd9Sstevel@tonic-gate  * 		the begin line code should
215*7c478bd9Sstevel@tonic-gate  * 		have caught it long before, to avoid passing
216*7c478bd9Sstevel@tonic-gate  * 		a null pointer around. Die.
217*7c478bd9Sstevel@tonic-gate  *
218*7c478bd9Sstevel@tonic-gate  */
219*7c478bd9Sstevel@tonic-gate #define	ADD_EQUALS(str)	if (strchr(str, '=') == NULL) (void) strcat(str, " =")
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate int
222*7c478bd9Sstevel@tonic-gate add_by_name(const char *version, const Interface *interface)
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 	bucket_t *b;
225*7c478bd9Sstevel@tonic-gate 	char buffer[1024];
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	assert(version != NULL, "passed a null version to add_by_name");
228*7c478bd9Sstevel@tonic-gate 	assert(interface != NULL, "passed a null interface to add_by_name");
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_by_name(%s,", version);
231*7c478bd9Sstevel@tonic-gate 	print_iface(interface);
232*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, ");");
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/* Sanity-check the parameters. */
235*7c478bd9Sstevel@tonic-gate 	if ((b = find_in_hashmap(version)) == NULL) {
236*7c478bd9Sstevel@tonic-gate 		/*
237*7c478bd9Sstevel@tonic-gate 		 * The version in the spec doesn't appear in the
238*7c478bd9Sstevel@tonic-gate 		 * versions file. Alas, this isn't an error.  It can
239*7c478bd9Sstevel@tonic-gate 		 * happen whenever doing just sparc, just i386
240*7c478bd9Sstevel@tonic-gate 		 * or the like.
241*7c478bd9Sstevel@tonic-gate 		 */
242*7c478bd9Sstevel@tonic-gate 		errlog(END, "}");
243*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
244*7c478bd9Sstevel@tonic-gate 	}
245*7c478bd9Sstevel@tonic-gate 	/*
246*7c478bd9Sstevel@tonic-gate 	 * Add to bucket.
247*7c478bd9Sstevel@tonic-gate 	 */
248*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buffer, sizeof (buffer), "%s", interface->IF_name);
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	if (interface->IF_filter && interface->IF_auxiliary) {
251*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "Error: cannot set both FILTER and AUXILIARY "
252*7c478bd9Sstevel@tonic-gate 		    "for an interface: %s", interface->IF_name);
253*7c478bd9Sstevel@tonic-gate 	}
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	if (interface->IF_filter) {
256*7c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
257*7c478bd9Sstevel@tonic-gate 		if (interface->IF_type == FUNCTION) {
258*7c478bd9Sstevel@tonic-gate 			(void) strcat(buffer, " FUNCTION");
259*7c478bd9Sstevel@tonic-gate 		} else if (interface->IF_type == DATA) {
260*7c478bd9Sstevel@tonic-gate 			(void) strcat(buffer, " DATA");
261*7c478bd9Sstevel@tonic-gate 		}
262*7c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " FILTER ");
263*7c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, interface->IF_filter);
264*7c478bd9Sstevel@tonic-gate 	} else if (interface->IF_auxiliary) {
265*7c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
266*7c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " AUXILIARY ");
267*7c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, interface->IF_auxiliary);
268*7c478bd9Sstevel@tonic-gate 	} else if (IsFilterLib) {
269*7c478bd9Sstevel@tonic-gate 		/*
270*7c478bd9Sstevel@tonic-gate 		 * For DATA types it is currently assumed that they are
271*7c478bd9Sstevel@tonic-gate 		 * handled via a minimal C file, e.g. 'data.c', in the
272*7c478bd9Sstevel@tonic-gate 		 * library's build.  Hence, we do not append '= DATA' here.
273*7c478bd9Sstevel@tonic-gate 		 */
274*7c478bd9Sstevel@tonic-gate 		if (interface->IF_type == FUNCTION) {
275*7c478bd9Sstevel@tonic-gate 			ADD_EQUALS(buffer);
276*7c478bd9Sstevel@tonic-gate 			(void) strcat(buffer, " FUNCTION");
277*7c478bd9Sstevel@tonic-gate 		}
278*7c478bd9Sstevel@tonic-gate 	}
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	switch (interface->IF_binding) {
281*7c478bd9Sstevel@tonic-gate 	case DIRECT:
282*7c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
283*7c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " DIRECT");
284*7c478bd9Sstevel@tonic-gate 		break;
285*7c478bd9Sstevel@tonic-gate 	case NODIRECT:
286*7c478bd9Sstevel@tonic-gate 		ADD_EQUALS(buffer);
287*7c478bd9Sstevel@tonic-gate 		(void) strcat(buffer, " NODIRECT");
288*7c478bd9Sstevel@tonic-gate 		break;
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	if (interface->IF_binding == PROTECTED) {
292*7c478bd9Sstevel@tonic-gate 		/* Assign in case of realloc. */
293*7c478bd9Sstevel@tonic-gate 		b->b_protected_table =
294*7c478bd9Sstevel@tonic-gate 		    add_to_stringtable(b->b_protected_table, buffer);
295*7c478bd9Sstevel@tonic-gate 		b->b_has_protecteds = 1;
296*7c478bd9Sstevel@tonic-gate 		errlog(VERBOSE, "set has_protecteds on bucket 0x%p", b);
297*7c478bd9Sstevel@tonic-gate 	} else {
298*7c478bd9Sstevel@tonic-gate 		/* Assign in case of realloc. */
299*7c478bd9Sstevel@tonic-gate 		b->b_global_table = add_to_stringtable(b->b_global_table,
300*7c478bd9Sstevel@tonic-gate 			buffer);
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
303*7c478bd9Sstevel@tonic-gate 	return (0);
304*7c478bd9Sstevel@tonic-gate }
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate /*
308*7c478bd9Sstevel@tonic-gate  * Processing interfaces
309*7c478bd9Sstevel@tonic-gate  */
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate /*
312*7c478bd9Sstevel@tonic-gate  * sort_buckets -- sort the interfaces within the buckets into
313*7c478bd9Sstevel@tonic-gate  *      alphabetical order.
314*7c478bd9Sstevel@tonic-gate  */
315*7c478bd9Sstevel@tonic-gate void
316*7c478bd9Sstevel@tonic-gate sort_buckets(void)
317*7c478bd9Sstevel@tonic-gate {
318*7c478bd9Sstevel@tonic-gate 	bucket_t *l, *b;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "sort_buckets() {");
321*7c478bd9Sstevel@tonic-gate 	for (l = first_list(); l != NULL; l = next_list()) {
322*7c478bd9Sstevel@tonic-gate 		errlog(VERBOSE, "l-bucket: %s", l->b_name);
323*7c478bd9Sstevel@tonic-gate 		for (b = first_from_list(l); b != NULL; b = next_from_list()) {
324*7c478bd9Sstevel@tonic-gate 			errlog(VERBOSE, "   b-bkt: %s", b->b_name);
325*7c478bd9Sstevel@tonic-gate 			sort_stringtable(b->b_global_table);
326*7c478bd9Sstevel@tonic-gate 			sort_stringtable(b->b_protected_table);
327*7c478bd9Sstevel@tonic-gate 			if (b->b_uncles) {
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 				if (b->b_uncles->bl_bucket) {
330*7c478bd9Sstevel@tonic-gate 		sort_stringtable(b->b_uncles->bl_bucket->b_global_table);
331*7c478bd9Sstevel@tonic-gate 		sort_stringtable(b->b_uncles->bl_bucket->b_protected_table);
332*7c478bd9Sstevel@tonic-gate 				}
333*7c478bd9Sstevel@tonic-gate 			}
334*7c478bd9Sstevel@tonic-gate 		}
335*7c478bd9Sstevel@tonic-gate 	}
336*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
337*7c478bd9Sstevel@tonic-gate }
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate /*
341*7c478bd9Sstevel@tonic-gate  * add_local -- set the local flag on the logically first bucket.
342*7c478bd9Sstevel@tonic-gate  *     This decision may belong in the caller, as it is about
343*7c478bd9Sstevel@tonic-gate  *     mapfiles, not inherent ordering or bucket contents...
344*7c478bd9Sstevel@tonic-gate  */
345*7c478bd9Sstevel@tonic-gate void
346*7c478bd9Sstevel@tonic-gate add_local(void)
347*7c478bd9Sstevel@tonic-gate {
348*7c478bd9Sstevel@tonic-gate 	bucket_t *b, *list;
349*7c478bd9Sstevel@tonic-gate 	int	done = 0;
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_local() {");
352*7c478bd9Sstevel@tonic-gate 	/* Iterate across lists of buckets */
353*7c478bd9Sstevel@tonic-gate 	for (list = first_list(); list != NULL; list = next_list()) {
354*7c478bd9Sstevel@tonic-gate 		/* Traverse the list found. */
355*7c478bd9Sstevel@tonic-gate 		for (b = list; b != NULL; b = b->b_parent) {
356*7c478bd9Sstevel@tonic-gate 			if (b->b_weak != 1) {
357*7c478bd9Sstevel@tonic-gate 				/* We've found the first non-weak. */
358*7c478bd9Sstevel@tonic-gate 				b->b_has_locals = done = 1;
359*7c478bd9Sstevel@tonic-gate 				errlog(VERBOSE,
360*7c478bd9Sstevel@tonic-gate 				    "set has_locals on bucket 0x%p", b);
361*7c478bd9Sstevel@tonic-gate 				break;
362*7c478bd9Sstevel@tonic-gate 			}
363*7c478bd9Sstevel@tonic-gate 		}
364*7c478bd9Sstevel@tonic-gate 		if (b != NULL && b->b_has_locals == 1)
365*7c478bd9Sstevel@tonic-gate 			break;
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 	if (done == 0) {
368*7c478bd9Sstevel@tonic-gate 		errlog(WARNING, "has_locals never set");
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate /*
375*7c478bd9Sstevel@tonic-gate  * Output interfaces, mostly iterators
376*7c478bd9Sstevel@tonic-gate  */
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate /*
380*7c478bd9Sstevel@tonic-gate  * parents_of -- return a list of all parents.
381*7c478bd9Sstevel@tonic-gate  */
382*7c478bd9Sstevel@tonic-gate char **
383*7c478bd9Sstevel@tonic-gate parents_of(const bucket_t *start)
384*7c478bd9Sstevel@tonic-gate {
385*7c478bd9Sstevel@tonic-gate 	static char *a[NPAR] = {NULL};
386*7c478bd9Sstevel@tonic-gate 	const bucket_t *b = start;
387*7c478bd9Sstevel@tonic-gate 	char **p = &a[0];
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	assert(start != NULL, "passed a null start to parents_of");
390*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "parents_of() {");
391*7c478bd9Sstevel@tonic-gate 	a[0] = '\0';
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	/* Go to parent, print it and all its uncle. */
394*7c478bd9Sstevel@tonic-gate 	if (b->b_parent == NULL) {
395*7c478bd9Sstevel@tonic-gate 		errlog(TRACING, "returning empty string");
396*7c478bd9Sstevel@tonic-gate 		errlog(END, "}");
397*7c478bd9Sstevel@tonic-gate 		return (a);
398*7c478bd9Sstevel@tonic-gate 	}
399*7c478bd9Sstevel@tonic-gate 	b = b->b_parent;
400*7c478bd9Sstevel@tonic-gate 	*p++ = b->b_name;
401*7c478bd9Sstevel@tonic-gate 	*p = '\0';
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	assert(p < &a[NPAR], "p fell off the end of a in parents_of");
404*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
405*7c478bd9Sstevel@tonic-gate 	return (a);
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate /*
409*7c478bd9Sstevel@tonic-gate  * first, next_from_bucket --iterators for bucket contents. Serially
410*7c478bd9Sstevel@tonic-gate  *      reusable only.
411*7c478bd9Sstevel@tonic-gate  */
412*7c478bd9Sstevel@tonic-gate int Ic = -1;
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate /*
415*7c478bd9Sstevel@tonic-gate  * debugging interfaces
416*7c478bd9Sstevel@tonic-gate  */
417*7c478bd9Sstevel@tonic-gate void
418*7c478bd9Sstevel@tonic-gate print_bucket(const bucket_t *b)
419*7c478bd9Sstevel@tonic-gate {
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "bucket_t at 0x%p {", (void *)b);
422*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    char   *b_name = \"%s\";", b->b_name);
423*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    struct bucket_t *b_parent = 0x%p;",
424*7c478bd9Sstevel@tonic-gate 		(void *)b->b_parent);
425*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    struct bucketlist *b_uncles = 0x%p;",
426*7c478bd9Sstevel@tonic-gate 		(void *)b->b_uncles);
427*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    struct bucket_t *b_thread = 0x%p;",
428*7c478bd9Sstevel@tonic-gate 		(void *)b->b_thread);
429*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int	b_has_locals = %d;",
430*7c478bd9Sstevel@tonic-gate 		b->b_has_locals);
431*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int	b_has_protecteds = %d;",
432*7c478bd9Sstevel@tonic-gate 		b->b_has_protecteds);
433*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int        b_was_printed = %d;",
434*7c478bd9Sstevel@tonic-gate 		b->b_was_printed);
435*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    int        b_weak = %d;",
436*7c478bd9Sstevel@tonic-gate 		b->b_weak);
437*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    table_t  *b_global_table = 0x%p;",
438*7c478bd9Sstevel@tonic-gate 		(void *)b->b_global_table);
439*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "    table_t  *b_protected_table = 0x%p;",
440*7c478bd9Sstevel@tonic-gate 		(void *)b->b_protected_table);
441*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "}");
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate void
445*7c478bd9Sstevel@tonic-gate print_all_buckets(void)
446*7c478bd9Sstevel@tonic-gate {
447*7c478bd9Sstevel@tonic-gate 	bucket_t *l, *b;
448*7c478bd9Sstevel@tonic-gate 	int i = 0, j = 0;
449*7c478bd9Sstevel@tonic-gate 	char **p;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	for (i = 0, l = first_list(); l != NULL; l = next_list(), ++i) {
452*7c478bd9Sstevel@tonic-gate 		errlog(TRACING, "list %d", i);
453*7c478bd9Sstevel@tonic-gate 		for (j = 0, b = first_from_list(l);
454*7c478bd9Sstevel@tonic-gate 		    b != NULL; b = next_from_list(), ++j) {
455*7c478bd9Sstevel@tonic-gate 			errlog(TRACING, "bucket %d", j);
456*7c478bd9Sstevel@tonic-gate 			print_bucket(b);
457*7c478bd9Sstevel@tonic-gate 			errlog(TRACING, "global interfaces = {");
458*7c478bd9Sstevel@tonic-gate 			print_stringtable(b->b_global_table);
459*7c478bd9Sstevel@tonic-gate 			errlog(TRACING, "}");
460*7c478bd9Sstevel@tonic-gate 			errlog(TRACING, "protected interfaces = {");
461*7c478bd9Sstevel@tonic-gate 			print_stringtable(b->b_protected_table);
462*7c478bd9Sstevel@tonic-gate 			errlog(TRACING, "}");
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 			for (p = parents_of(b); p != NULL && *p != NULL; ++p) {
465*7c478bd9Sstevel@tonic-gate 				errlog(TRACING, " %s", *p);
466*7c478bd9Sstevel@tonic-gate 			}
467*7c478bd9Sstevel@tonic-gate 			errlog(TRACING, ";");
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 			if (b->b_uncles) {
470*7c478bd9Sstevel@tonic-gate 				errlog(TRACING, " uncle bucket %d.1", j);
471*7c478bd9Sstevel@tonic-gate 				print_bucket(b->b_uncles->bl_bucket);
472*7c478bd9Sstevel@tonic-gate 				errlog(TRACING, "global interfaces = {");
473*7c478bd9Sstevel@tonic-gate 				print_stringtable(
474*7c478bd9Sstevel@tonic-gate 				    b->b_uncles->bl_bucket->b_global_table);
475*7c478bd9Sstevel@tonic-gate 				errlog(TRACING, "}");
476*7c478bd9Sstevel@tonic-gate 				errlog(TRACING, "protected interfaces = {");
477*7c478bd9Sstevel@tonic-gate 				print_stringtable(
478*7c478bd9Sstevel@tonic-gate 				    b->b_uncles->bl_bucket->b_protected_table);
479*7c478bd9Sstevel@tonic-gate 				errlog(TRACING, "}");
480*7c478bd9Sstevel@tonic-gate 			}
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 	}
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate /*
487*7c478bd9Sstevel@tonic-gate  * lower-level functions, not visible outside the file.
488*7c478bd9Sstevel@tonic-gate  */
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate /*
491*7c478bd9Sstevel@tonic-gate  * new_bucket -- create a bucket for a given version. Must not fail.
492*7c478bd9Sstevel@tonic-gate  */
493*7c478bd9Sstevel@tonic-gate static bucket_t *
494*7c478bd9Sstevel@tonic-gate new_bucket(const char *name, int weak)
495*7c478bd9Sstevel@tonic-gate {
496*7c478bd9Sstevel@tonic-gate 	bucket_t *b;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	if ((b = (bucket_t *)calloc(1, sizeof (bucket_t))) == NULL) {
499*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory creating a bucket "
500*7c478bd9Sstevel@tonic-gate 			"to store interfaces in");
501*7c478bd9Sstevel@tonic-gate 	}
502*7c478bd9Sstevel@tonic-gate 	if ((b->b_name = strdup(name)) == NULL) {
503*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory storing an interface "
504*7c478bd9Sstevel@tonic-gate 			"in a version bucket");
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 	b->b_uncles = NULL;
507*7c478bd9Sstevel@tonic-gate 	b->b_global_table = create_stringtable(TABLE_INITIAL);
508*7c478bd9Sstevel@tonic-gate 	b->b_protected_table = create_stringtable(TABLE_INITIAL);
509*7c478bd9Sstevel@tonic-gate 	b->b_weak = weak;
510*7c478bd9Sstevel@tonic-gate 	return (b);
511*7c478bd9Sstevel@tonic-gate }
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate /*
515*7c478bd9Sstevel@tonic-gate  * start_new_list -- start a list of buckets.
516*7c478bd9Sstevel@tonic-gate  */
517*7c478bd9Sstevel@tonic-gate static void
518*7c478bd9Sstevel@tonic-gate start_new_list(const bucket_t *b)
519*7c478bd9Sstevel@tonic-gate {
520*7c478bd9Sstevel@tonic-gate 	int i;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "start_new_list() {");
523*7c478bd9Sstevel@tonic-gate 	assert(Buckethead != NULL, "Buckethead null in start_new_list");
524*7c478bd9Sstevel@tonic-gate 	for (i = 0; Buckethead[i] != NULL && i < N_lists; ++i)
525*7c478bd9Sstevel@tonic-gate 		continue;
526*7c478bd9Sstevel@tonic-gate 	if (i >= N_lists) {
527*7c478bd9Sstevel@tonic-gate 		grow_lists();
528*7c478bd9Sstevel@tonic-gate 	}
529*7c478bd9Sstevel@tonic-gate 	Buckethead[i] = (bucket_t *)b;
530*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
531*7c478bd9Sstevel@tonic-gate }
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate /*
534*7c478bd9Sstevel@tonic-gate  * grow_list -- make more lists.  This should never occur...
535*7c478bd9Sstevel@tonic-gate  */
536*7c478bd9Sstevel@tonic-gate static void
537*7c478bd9Sstevel@tonic-gate grow_lists(void)
538*7c478bd9Sstevel@tonic-gate {
539*7c478bd9Sstevel@tonic-gate 	int i = N_lists;
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "grow_lists() {");
542*7c478bd9Sstevel@tonic-gate 	errlog(WARNING, "Warning: more than %d version lists "
543*7c478bd9Sstevel@tonic-gate 	    "required (< %d is normal). Check sets file "
544*7c478bd9Sstevel@tonic-gate 	    "to see why so many lines appear.",
545*7c478bd9Sstevel@tonic-gate 	    N_lists, NLISTS);
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	N_lists *= 2;
548*7c478bd9Sstevel@tonic-gate 	if ((Buckethead = realloc(Buckethead, sizeof (bucket_t *) * N_lists))
549*7c478bd9Sstevel@tonic-gate 		== NULL) {
550*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory growing list of "
551*7c478bd9Sstevel@tonic-gate 			"version buckets");
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate 	for (; i < N_lists; ++i) {
554*7c478bd9Sstevel@tonic-gate 		Buckethead[i] = NULL;
555*7c478bd9Sstevel@tonic-gate 	}
556*7c478bd9Sstevel@tonic-gate }
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate /*
559*7c478bd9Sstevel@tonic-gate  * delete_lists -- clean up afterwards.
560*7c478bd9Sstevel@tonic-gate  */
561*7c478bd9Sstevel@tonic-gate void
562*7c478bd9Sstevel@tonic-gate delete_lists(void)
563*7c478bd9Sstevel@tonic-gate {
564*7c478bd9Sstevel@tonic-gate 	N_lists = 0;
565*7c478bd9Sstevel@tonic-gate 	free(Buckethead);
566*7c478bd9Sstevel@tonic-gate 	Buckethead = 0;
567*7c478bd9Sstevel@tonic-gate }
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate /*
570*7c478bd9Sstevel@tonic-gate  * first_list, next_list -- an iterator for lists themselves.  Serially
571*7c478bd9Sstevel@tonic-gate  *      reusable only.
572*7c478bd9Sstevel@tonic-gate  */
573*7c478bd9Sstevel@tonic-gate bucket_t *
574*7c478bd9Sstevel@tonic-gate first_list(void)
575*7c478bd9Sstevel@tonic-gate {
576*7c478bd9Sstevel@tonic-gate 	Bc = 0;
577*7c478bd9Sstevel@tonic-gate 	return (Buckethead[Bc]);
578*7c478bd9Sstevel@tonic-gate }
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate bucket_t *
581*7c478bd9Sstevel@tonic-gate next_list(void)
582*7c478bd9Sstevel@tonic-gate {
583*7c478bd9Sstevel@tonic-gate 	return (Buckethead[++Bc]);
584*7c478bd9Sstevel@tonic-gate }
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate /*
588*7c478bd9Sstevel@tonic-gate  * first, next, last_from_list -- iterators for individual lists. Serially
589*7c478bd9Sstevel@tonic-gate  *      reusable only.
590*7c478bd9Sstevel@tonic-gate  */
591*7c478bd9Sstevel@tonic-gate bucket_t *
592*7c478bd9Sstevel@tonic-gate first_from_list(const bucket_t *l)
593*7c478bd9Sstevel@tonic-gate {
594*7c478bd9Sstevel@tonic-gate 	return (Bp = (bucket_t *)l);
595*7c478bd9Sstevel@tonic-gate }
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate bucket_t *
598*7c478bd9Sstevel@tonic-gate next_from_list(void)
599*7c478bd9Sstevel@tonic-gate {
600*7c478bd9Sstevel@tonic-gate 	return (Bp = Bp->b_parent);
601*7c478bd9Sstevel@tonic-gate }
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate /*
606*7c478bd9Sstevel@tonic-gate  * Iface print utility
607*7c478bd9Sstevel@tonic-gate  */
608*7c478bd9Sstevel@tonic-gate static void
609*7c478bd9Sstevel@tonic-gate print_iface(const Interface * p)
610*7c478bd9Sstevel@tonic-gate {
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "%s (%s, %s, %s %d)", p->IF_name,
613*7c478bd9Sstevel@tonic-gate 		(p->IF_type == FUNCTION) ? "function" :
614*7c478bd9Sstevel@tonic-gate 		(p->IF_type == DATA) ? "data" : "unknown type",
615*7c478bd9Sstevel@tonic-gate 		(p->IF_version) ? p->IF_version : "unknown version",
616*7c478bd9Sstevel@tonic-gate 		(p->IF_class) ? p->IF_class : "unknown class",
617*7c478bd9Sstevel@tonic-gate 		p->IF_binding);
618*7c478bd9Sstevel@tonic-gate }
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate #define	HASHMAPSIZE	100
623*7c478bd9Sstevel@tonic-gate #define	ERR	(-1)
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate static struct {
626*7c478bd9Sstevel@tonic-gate 	hashmap_t *hh_map;
627*7c478bd9Sstevel@tonic-gate 	int hh_map_size;
628*7c478bd9Sstevel@tonic-gate 	int hh_mapC;
629*7c478bd9Sstevel@tonic-gate 	hashmap_t *hh_last;
630*7c478bd9Sstevel@tonic-gate } Hashhead = {
631*7c478bd9Sstevel@tonic-gate 	NULL, -1, -1, NULL
632*7c478bd9Sstevel@tonic-gate };
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate static int checksum(const char *);
635*7c478bd9Sstevel@tonic-gate static void print_hashmap(const hashmap_t *);
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate /*
638*7c478bd9Sstevel@tonic-gate  * new_hashmap -- create the hash.
639*7c478bd9Sstevel@tonic-gate  */
640*7c478bd9Sstevel@tonic-gate static void
641*7c478bd9Sstevel@tonic-gate new_hashmap(void)
642*7c478bd9Sstevel@tonic-gate {
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "new_hashmap() {");
645*7c478bd9Sstevel@tonic-gate 	if ((Hashhead.hh_map = calloc(sizeof (hashmap_t), HASHMAPSIZE))
646*7c478bd9Sstevel@tonic-gate 	    == NULL) {
647*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory creating a hash-map of "
648*7c478bd9Sstevel@tonic-gate 			"the versions");
649*7c478bd9Sstevel@tonic-gate 	}
650*7c478bd9Sstevel@tonic-gate 	Hashhead.hh_mapC = 0;
651*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
652*7c478bd9Sstevel@tonic-gate }
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate /*
655*7c478bd9Sstevel@tonic-gate  * add_to_hashmap -- add a bucket to the map.  This is strictly for
656*7c478bd9Sstevel@tonic-gate  *	use by add_parent()/add_uncle().
657*7c478bd9Sstevel@tonic-gate  */
658*7c478bd9Sstevel@tonic-gate static int
659*7c478bd9Sstevel@tonic-gate add_to_hashmap(const char *version_name, const bucket_t *bucket)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate 	hashmap_t *p;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	assert(Hashhead.hh_map != NULL,
664*7c478bd9Sstevel@tonic-gate 	    "Hashead.map was null in add_to_hashmap");
665*7c478bd9Sstevel@tonic-gate 	assert(Hashhead.hh_mapC < HASHMAPSIZE,
666*7c478bd9Sstevel@tonic-gate 	    "mapC too big in add_to_hashmap");
667*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "add_to_hashmap(%s, %s) {", version_name, bucket);
668*7c478bd9Sstevel@tonic-gate 	if (find_in_hashmap(version_name) != NULL) {
669*7c478bd9Sstevel@tonic-gate 		/* Seen for the second time. TBD... */
670*7c478bd9Sstevel@tonic-gate 		errlog(END, "} /* add_to_hashmap */");
671*7c478bd9Sstevel@tonic-gate 		return (ERR);
672*7c478bd9Sstevel@tonic-gate 	}
673*7c478bd9Sstevel@tonic-gate 	p = &Hashhead.hh_map[Hashhead.hh_mapC++];
674*7c478bd9Sstevel@tonic-gate 	if ((p->h_version_name = strdup(version_name)) == NULL) {
675*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "out of memory storing a version name");
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	}
678*7c478bd9Sstevel@tonic-gate 	p->h_bucket = (bucket_t *)bucket;
679*7c478bd9Sstevel@tonic-gate 	p->h_hash = checksum(version_name);
680*7c478bd9Sstevel@tonic-gate 	Hashhead.hh_last = p;
681*7c478bd9Sstevel@tonic-gate 	print_hashmap(p);
682*7c478bd9Sstevel@tonic-gate 	errlog(END, "} /* add_to_hashmap */");
683*7c478bd9Sstevel@tonic-gate 	return (0);
684*7c478bd9Sstevel@tonic-gate }
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate /*
688*7c478bd9Sstevel@tonic-gate  * find_in_hashmap -- find a bucket by name.  Strictly for use by addByName().
689*7c478bd9Sstevel@tonic-gate  */
690*7c478bd9Sstevel@tonic-gate static bucket_t *
691*7c478bd9Sstevel@tonic-gate find_in_hashmap(const char *version_name)
692*7c478bd9Sstevel@tonic-gate {
693*7c478bd9Sstevel@tonic-gate 	hashmap_t *current;
694*7c478bd9Sstevel@tonic-gate 	int hash = checksum(version_name);
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	assert(Hashhead.hh_map != NULL,
697*7c478bd9Sstevel@tonic-gate 		"Hashhead.hh_map was null in find_in_hashmap");
698*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "find_in_hashmap(%s) {", version_name);
699*7c478bd9Sstevel@tonic-gate 	if (Hashhead.hh_last != NULL && Hashhead.hh_last->h_hash == hash &&
700*7c478bd9Sstevel@tonic-gate 	    strcmp(Hashhead.hh_last->h_version_name, version_name) == 0) {
701*7c478bd9Sstevel@tonic-gate 		errlog(END, "}");
702*7c478bd9Sstevel@tonic-gate 		return (Hashhead.hh_last->h_bucket);
703*7c478bd9Sstevel@tonic-gate 	}
704*7c478bd9Sstevel@tonic-gate 	for (current = Hashhead.hh_map;
705*7c478bd9Sstevel@tonic-gate 		current->h_version_name != NULL; ++current) {
706*7c478bd9Sstevel@tonic-gate 		if (current->h_hash == hash &&
707*7c478bd9Sstevel@tonic-gate 			strcmp(current->h_version_name, version_name) == 0) {
708*7c478bd9Sstevel@tonic-gate 			/* Found it */
709*7c478bd9Sstevel@tonic-gate 			Hashhead.hh_last = current;
710*7c478bd9Sstevel@tonic-gate 			errlog(END, "}");
711*7c478bd9Sstevel@tonic-gate 			return (current->h_bucket);
712*7c478bd9Sstevel@tonic-gate 		}
713*7c478bd9Sstevel@tonic-gate 	}
714*7c478bd9Sstevel@tonic-gate 	/* Doesn't exist, meaning version name is bogus. */
715*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
716*7c478bd9Sstevel@tonic-gate 	return (NULL);
717*7c478bd9Sstevel@tonic-gate }
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate /*
720*7c478bd9Sstevel@tonic-gate  * checksum -- from sum(1), algorithm 1.
721*7c478bd9Sstevel@tonic-gate  */
722*7c478bd9Sstevel@tonic-gate static int
723*7c478bd9Sstevel@tonic-gate checksum(const char *p)
724*7c478bd9Sstevel@tonic-gate {
725*7c478bd9Sstevel@tonic-gate 	int sum;
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	for (sum = 0; *p != NULL; ++p) {
728*7c478bd9Sstevel@tonic-gate 		if (sum & 01)
729*7c478bd9Sstevel@tonic-gate 			sum = (sum >> 1) + 0x8000;
730*7c478bd9Sstevel@tonic-gate 		else
731*7c478bd9Sstevel@tonic-gate 			sum >>= 1;
732*7c478bd9Sstevel@tonic-gate 		sum += *p;
733*7c478bd9Sstevel@tonic-gate 		sum &= 0xFFFF;
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate 	return (sum);
736*7c478bd9Sstevel@tonic-gate }
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate static void
739*7c478bd9Sstevel@tonic-gate print_hashmap(const hashmap_t *h)
740*7c478bd9Sstevel@tonic-gate {
741*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "struct hashmap_t at 0x4.4x {", h);
742*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "    int    h_hash = %d;", h->h_hash);
743*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "    char   *h_version_name = \"%s\";",
744*7c478bd9Sstevel@tonic-gate 		h->h_version_name);
745*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "    bucket_t *h_bucket = 0x%p;;",
746*7c478bd9Sstevel@tonic-gate 		(void *) h->h_bucket);
747*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "}");
748*7c478bd9Sstevel@tonic-gate }
749