xref: /titanic_51/usr/src/cmd/fm/modules/common/eversholt/ipath.c (revision 705e9f42059a29645037854181bc0bf216398c4c)
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
5b5016cbbSstephh  * Common Development and Distribution License (the "License").
6b5016cbbSstephh  * 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  */
217c478bd9Sstevel@tonic-gate /*
22*705e9f42SStephen Hanson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * ipath.c -- instanced pathname module
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * this module provides a cache of fully instantized component paths,
287c478bd9Sstevel@tonic-gate  * stored in a fairly compact format.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include "alloc.h"
347c478bd9Sstevel@tonic-gate #include "out.h"
357c478bd9Sstevel@tonic-gate #include "lut.h"
367c478bd9Sstevel@tonic-gate #include "tree.h"
377c478bd9Sstevel@tonic-gate #include "ptree.h"
387c478bd9Sstevel@tonic-gate #include "itree.h"
397c478bd9Sstevel@tonic-gate #include "ipath.h"
406cb1ca52Saf #include "ipath_impl.h"
417c478bd9Sstevel@tonic-gate #include "stats.h"
427c478bd9Sstevel@tonic-gate #include "eval.h"
437c478bd9Sstevel@tonic-gate #include "config.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static struct stats *Nipath;
467c478bd9Sstevel@tonic-gate static struct stats *Nbytes;
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static struct lut *Ipaths;	/* the ipath cache itself */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * ipath_init -- initialize the ipath module
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate void
547c478bd9Sstevel@tonic-gate ipath_init(void)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	Nipath = stats_new_counter("ievent.nipath", "ipath cache entries", 1);
577c478bd9Sstevel@tonic-gate 	Nbytes = stats_new_counter("ievent.nbytes", "total cache size", 1);
587c478bd9Sstevel@tonic-gate }
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * ipath_cmp -- compare two ipath entries
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  * since two ipaths containing the same components and instance
647c478bd9Sstevel@tonic-gate  * numbers always point to the same cache entry, they are equal
657c478bd9Sstevel@tonic-gate  * if their pointers are equal, so this function is not necessary
667c478bd9Sstevel@tonic-gate  * to test if two ipaths are same.  but when inserting a new ipath
677c478bd9Sstevel@tonic-gate  * into the cache, we must use the same lut comparison logic as when
687c478bd9Sstevel@tonic-gate  * we're searching for it, so this function must always match the
697c478bd9Sstevel@tonic-gate  * itree_epnamecmp() function's logic (see below) for searching the lut.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate static int
727c478bd9Sstevel@tonic-gate ipath_cmp(struct ipath *ipp1, struct ipath *ipp2)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	int i;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	ASSERT(ipp1 != NULL);
777c478bd9Sstevel@tonic-gate 	ASSERT(ipp2 != NULL);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	for (i = 0; ipp1[i].s != NULL && ipp2[i].s != NULL; i++)
807c478bd9Sstevel@tonic-gate 		if (ipp1[i].s != ipp2[i].s)
817c478bd9Sstevel@tonic-gate 			return (ipp2[i].s - ipp1[i].s);
827c478bd9Sstevel@tonic-gate 		else if (ipp1[i].i != ipp2[i].i)
837c478bd9Sstevel@tonic-gate 			return (ipp2[i].i - ipp1[i].i);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	if (ipp1[i].s == NULL && ipp2[i].s == NULL)
867c478bd9Sstevel@tonic-gate 		return (0);
877c478bd9Sstevel@tonic-gate 	else if (ipp1[i].s == NULL)
887c478bd9Sstevel@tonic-gate 		return (1);
897c478bd9Sstevel@tonic-gate 	else
907c478bd9Sstevel@tonic-gate 		return (-1);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * ipath_epnamecmp -- compare an ipath with a struct node *epname list
957c478bd9Sstevel@tonic-gate  *
967c478bd9Sstevel@tonic-gate  * this function is used when searching the cache, allowing us to search
977c478bd9Sstevel@tonic-gate  * a lut full of ipaths by looking directly at a struct node *epname
987c478bd9Sstevel@tonic-gate  * (without having to convert it first).  the comparison logic here must
997c478bd9Sstevel@tonic-gate  * exactly match itree_cmp()'s logic (see above) so lut lookups use find
1007c478bd9Sstevel@tonic-gate  * the same node as lut inserts.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate static int
1037c478bd9Sstevel@tonic-gate ipath_epnamecmp(struct ipath *ipp, struct node *np)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	int i;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
1087c478bd9Sstevel@tonic-gate 	ASSERT(ipp != NULL);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	for (i = 0; ipp[i].s != NULL && np != NULL; i++, np = np->u.name.next) {
1117c478bd9Sstevel@tonic-gate 		ASSERTinfo(np->t == T_NAME, ptree_nodetype2str(np->t));
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 		if (ipp[i].s != np->u.name.s)
1147c478bd9Sstevel@tonic-gate 			return (np->u.name.s - ipp[i].s);
1157c478bd9Sstevel@tonic-gate 		else {
1167c478bd9Sstevel@tonic-gate 			int inum;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 			if (np->u.name.child != NULL &&
1197c478bd9Sstevel@tonic-gate 			    np->u.name.child->t == T_NUM)
1207c478bd9Sstevel@tonic-gate 				inum = (int)np->u.name.child->u.ull;
1217c478bd9Sstevel@tonic-gate 			else
1227c478bd9Sstevel@tonic-gate 				config_getcompname(np->u.name.cp, NULL, &inum);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 			if (ipp[i].i != inum)
1257c478bd9Sstevel@tonic-gate 				return (inum - ipp[i].i);
1267c478bd9Sstevel@tonic-gate 		}
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	if (ipp[i].s == NULL && np == NULL)
1307c478bd9Sstevel@tonic-gate 		return (0);
1317c478bd9Sstevel@tonic-gate 	else if (ipp[i].s == NULL)
1327c478bd9Sstevel@tonic-gate 		return (1);
1337c478bd9Sstevel@tonic-gate 	else
1347c478bd9Sstevel@tonic-gate 		return (-1);
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1376e1fa242SStephen Hanson /*
1386e1fa242SStephen Hanson  * The following functions are only used in the "itree_create_dummy()" first
1396e1fa242SStephen Hanson  * pass at itree creation. ipath_dummy() creates paths used in the itree (see
1406e1fa242SStephen Hanson  * comment above add_event_dummy() for details). ipath_for_usednames() creates
1416e1fa242SStephen Hanson  * a different set of paths using the full names from the propagations. These
1426e1fa242SStephen Hanson  * are only used by ipath_dummy_lut() in order to set up the Usednames lut
1436e1fa242SStephen Hanson  * correctly, which in turn allows conf propteries on any alement in those
1446e1fa242SStephen Hanson  * names to be used in constraints.
1456e1fa242SStephen Hanson  */
146b5016cbbSstephh struct lut *Usednames;
147b5016cbbSstephh 
148b5016cbbSstephh void
149b5016cbbSstephh ipath_dummy_lut(struct arrow *arrowp)
150b5016cbbSstephh {
151b5016cbbSstephh 	const struct ipath *ipp;
152b5016cbbSstephh 
1536e1fa242SStephen Hanson 	ipp = arrowp->head->myevent->ipp_un;
154b5016cbbSstephh 	while (ipp->s != NULL) {
155b5016cbbSstephh 		Usednames = lut_add(Usednames, (void *)ipp->s,
156b5016cbbSstephh 		    (void *)ipp->s, NULL);
157b5016cbbSstephh 		ipp++;
158b5016cbbSstephh 	}
1596e1fa242SStephen Hanson 	ipp = arrowp->tail->myevent->ipp_un;
160b5016cbbSstephh 	while (ipp->s != NULL) {
161b5016cbbSstephh 		Usednames = lut_add(Usednames, (void *)ipp->s,
162b5016cbbSstephh 		    (void *)ipp->s, NULL);
163b5016cbbSstephh 		ipp++;
164b5016cbbSstephh 	}
165b5016cbbSstephh }
166b5016cbbSstephh 
167b5016cbbSstephh struct ipath *
168b5016cbbSstephh ipath_dummy(struct node *np, struct ipath *ipp)
169b5016cbbSstephh {
170b5016cbbSstephh 	struct ipath *ret;
171b5016cbbSstephh 
172b5016cbbSstephh 	ret = ipp;
173b5016cbbSstephh 	while (ipp[1].s != NULL)
174b5016cbbSstephh 		ipp++;
175b5016cbbSstephh 	if (strcmp(ipp[0].s, np->u.name.last->u.name.s) == 0)
176b5016cbbSstephh 		return (ret);
177b5016cbbSstephh 
178b5016cbbSstephh 	ret = MALLOC(sizeof (*ret) * 2);
179b5016cbbSstephh 	ret[0].s = np->u.name.last->u.name.s;
180b5016cbbSstephh 	ret[0].i = 0;
181b5016cbbSstephh 	ret[1].s = NULL;
182b5016cbbSstephh 	if ((ipp = lut_lookup(Ipaths, (void *)ret,
183b5016cbbSstephh 	    (lut_cmp)ipath_cmp)) != NULL) {
184b5016cbbSstephh 		FREE(ret);
185b5016cbbSstephh 		return (ipp);
186b5016cbbSstephh 	}
187b5016cbbSstephh 	Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp);
188b5016cbbSstephh 	stats_counter_bump(Nipath);
189b5016cbbSstephh 	stats_counter_add(Nbytes, 2 * sizeof (struct ipath));
190b5016cbbSstephh 	return (ret);
191b5016cbbSstephh }
192b5016cbbSstephh 
1936e1fa242SStephen Hanson struct ipath *
1946e1fa242SStephen Hanson ipath_for_usednames(struct node *np)
1956e1fa242SStephen Hanson {
1966e1fa242SStephen Hanson 	struct ipath *ret, *ipp;
1976e1fa242SStephen Hanson 	int i = 0;
1986e1fa242SStephen Hanson 	struct node *np2;
1996e1fa242SStephen Hanson 
2006e1fa242SStephen Hanson 	for (np2 = np; np2 != NULL; np2 = np2->u.name.next)
2016e1fa242SStephen Hanson 		i++;
2026e1fa242SStephen Hanson 	ret = MALLOC(sizeof (*ret) * (i + 1));
2036e1fa242SStephen Hanson 	for (i = 0, np2 = np; np2 != NULL; np2 = np2->u.name.next) {
2046e1fa242SStephen Hanson 		ret[i].s = np2->u.name.s;
2056e1fa242SStephen Hanson 		ret[i++].i = 0;
2066e1fa242SStephen Hanson 	}
2076e1fa242SStephen Hanson 	ret[i].s = NULL;
2086e1fa242SStephen Hanson 	if ((ipp = lut_lookup(Ipaths, (void *)ret,
2096e1fa242SStephen Hanson 	    (lut_cmp)ipath_cmp)) != NULL) {
2106e1fa242SStephen Hanson 		FREE(ret);
2116e1fa242SStephen Hanson 		return (ipp);
2126e1fa242SStephen Hanson 	}
2136e1fa242SStephen Hanson 	Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp);
2146e1fa242SStephen Hanson 	stats_counter_bump(Nipath);
2156e1fa242SStephen Hanson 	stats_counter_add(Nbytes, (i + 1) * sizeof (struct ipath));
2166e1fa242SStephen Hanson 	return (ret);
2176e1fa242SStephen Hanson }
2186e1fa242SStephen Hanson 
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate  * ipath -- find instanced path in cache, or add it if necessary
2217c478bd9Sstevel@tonic-gate  */
2227c478bd9Sstevel@tonic-gate const struct ipath *
2237c478bd9Sstevel@tonic-gate ipath(struct node *np)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	struct ipath *ret;
2267c478bd9Sstevel@tonic-gate 	int count;
2277c478bd9Sstevel@tonic-gate 	struct node *namep;
2287c478bd9Sstevel@tonic-gate 	int i;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if ((ret = lut_lookup(Ipaths, (void *)np,
2317c478bd9Sstevel@tonic-gate 	    (lut_cmp)ipath_epnamecmp)) != NULL)
2327c478bd9Sstevel@tonic-gate 		return (ret);	/* already in cache */
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	/*
2357c478bd9Sstevel@tonic-gate 	 * not in cache, make new cache entry.
2367c478bd9Sstevel@tonic-gate 	 * start by counting the length of the name.
2377c478bd9Sstevel@tonic-gate 	 */
2387c478bd9Sstevel@tonic-gate 	count = 0;
2397c478bd9Sstevel@tonic-gate 	namep = np;
2407c478bd9Sstevel@tonic-gate 	while (namep != NULL) {
2417c478bd9Sstevel@tonic-gate 		ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t));
2427c478bd9Sstevel@tonic-gate 		count++;
2437c478bd9Sstevel@tonic-gate 		namep = namep->u.name.next;
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	ASSERT(count > 0);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/* allocate array for name and last NULL entry */
2497c478bd9Sstevel@tonic-gate 	ret = MALLOC(sizeof (*ret) * (count + 1));
2507c478bd9Sstevel@tonic-gate 	ret[count].s = NULL;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/* fill in ipath entry */
2537c478bd9Sstevel@tonic-gate 	namep = np;
2547c478bd9Sstevel@tonic-gate 	i = 0;
2557c478bd9Sstevel@tonic-gate 	while (namep != NULL) {
2567c478bd9Sstevel@tonic-gate 		ASSERT(i < count);
2577c478bd9Sstevel@tonic-gate 		ret[i].s = namep->u.name.s;
2587c478bd9Sstevel@tonic-gate 		if (namep->u.name.child != NULL &&
2597c478bd9Sstevel@tonic-gate 		    namep->u.name.child->t == T_NUM)
2607c478bd9Sstevel@tonic-gate 			ret[i].i = (int)namep->u.name.child->u.ull;
2617c478bd9Sstevel@tonic-gate 		else
2627c478bd9Sstevel@tonic-gate 			config_getcompname(namep->u.name.cp, NULL, &ret[i].i);
2637c478bd9Sstevel@tonic-gate 		i++;
2647c478bd9Sstevel@tonic-gate 		namep = namep->u.name.next;
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/* add it to the cache */
2687c478bd9Sstevel@tonic-gate 	Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret,
2697c478bd9Sstevel@tonic-gate 	    (lut_cmp)ipath_cmp);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	stats_counter_bump(Nipath);
2727c478bd9Sstevel@tonic-gate 	stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath));
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	return (ret);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate  * ipath2str -- convert ename and ipath to class@path string
2797c478bd9Sstevel@tonic-gate  *
2807c478bd9Sstevel@tonic-gate  * if both ename and ipp are provided (non-NULL), the resulting string
2817c478bd9Sstevel@tonic-gate  * will be "class@path".  otherwise, the string will just contain the
2827c478bd9Sstevel@tonic-gate  * event class name (e.g. "ereport.io.pci.device") or just the path
2837c478bd9Sstevel@tonic-gate  * name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending
2847c478bd9Sstevel@tonic-gate  * on which argument is non-NULL.
2857c478bd9Sstevel@tonic-gate  */
2867c478bd9Sstevel@tonic-gate char *
2877c478bd9Sstevel@tonic-gate ipath2str(const char *ename, const struct ipath *ipp)
2887c478bd9Sstevel@tonic-gate {
2897c478bd9Sstevel@tonic-gate 	int i;
2907c478bd9Sstevel@tonic-gate 	size_t len = 0;
2917c478bd9Sstevel@tonic-gate 	char *ret;
2927c478bd9Sstevel@tonic-gate 	char *cp;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* count up length of class string */
2957c478bd9Sstevel@tonic-gate 	if (ename != NULL)
2967c478bd9Sstevel@tonic-gate 		len += strlen(ename);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/* count up length of path string, including slash separators */
2997c478bd9Sstevel@tonic-gate 	if (ipp != NULL) {
3007c478bd9Sstevel@tonic-gate 		for (i = 0; ipp[i].s != NULL; i++) {
3017c478bd9Sstevel@tonic-gate 			/* add slash separator, but no leading slash */
3027c478bd9Sstevel@tonic-gate 			if (i != 0)
3037c478bd9Sstevel@tonic-gate 				len++;
3047c478bd9Sstevel@tonic-gate 			len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
3057c478bd9Sstevel@tonic-gate 		}
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	if (ename != NULL && ipp != NULL)
3097c478bd9Sstevel@tonic-gate 		len++;	/* room for '@' */
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	len++;	/* room for final '\0' */
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	cp = ret = MALLOC(len);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (ename != NULL) {
3167c478bd9Sstevel@tonic-gate 		/* construct class string */
3177c478bd9Sstevel@tonic-gate 		(void) strcpy(cp, ename);
3187c478bd9Sstevel@tonic-gate 		cp += strlen(cp);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* if doing both strings, put '@' between them */
3227c478bd9Sstevel@tonic-gate 	if (ename != NULL && ipp != NULL)
3237c478bd9Sstevel@tonic-gate 		*cp++ = '@';
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if (ipp != NULL) {
3267c478bd9Sstevel@tonic-gate 		/* construct path string */
3277c478bd9Sstevel@tonic-gate 		for (i = 0; ipp[i].s != NULL; i++) {
3287c478bd9Sstevel@tonic-gate 			if (i != 0)
3297c478bd9Sstevel@tonic-gate 				*cp++ = '/';
3307c478bd9Sstevel@tonic-gate 			(void) snprintf(cp, &ret[len] - cp, "%s%d",
3317c478bd9Sstevel@tonic-gate 			    ipp[i].s, ipp[i].i);
3327c478bd9Sstevel@tonic-gate 			cp += strlen(cp);
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	*cp++ = '\0';
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	return (ret);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
341*705e9f42SStephen Hanson void
342*705e9f42SStephen Hanson ipathlastcomp(const struct ipath *ipp)
343*705e9f42SStephen Hanson {
344*705e9f42SStephen Hanson 	int i;
345*705e9f42SStephen Hanson 
346*705e9f42SStephen Hanson 	for (i = 0; ipp[i].s != NULL; i++)
347*705e9f42SStephen Hanson 		;
348*705e9f42SStephen Hanson 
349*705e9f42SStephen Hanson 	out(O_ALTFP, "newfme: add %s to Usednames", ipp[i - 1].s);
350*705e9f42SStephen Hanson 	Usednames = lut_add(Usednames, (void *)ipp[i - 1].s,
351*705e9f42SStephen Hanson 	    (void *)ipp[i - 1].s, NULL);
352*705e9f42SStephen Hanson }
353*705e9f42SStephen Hanson 
3547c478bd9Sstevel@tonic-gate /*
3557aec1d6eScindi  * ipath2strlen -- calculate the len of what ipath2str() would return
3567aec1d6eScindi  */
3577aec1d6eScindi size_t
3587aec1d6eScindi ipath2strlen(const char *ename, const struct ipath *ipp)
3597aec1d6eScindi {
3607aec1d6eScindi 	int i;
3617aec1d6eScindi 	size_t len = 0;
3627aec1d6eScindi 
3637aec1d6eScindi 	/* count up length of class string */
3647aec1d6eScindi 	if (ename != NULL)
3657aec1d6eScindi 		len += strlen(ename);
3667aec1d6eScindi 
3677aec1d6eScindi 	/* count up length of path string, including slash separators */
3687aec1d6eScindi 	if (ipp != NULL) {
3697aec1d6eScindi 		for (i = 0; ipp[i].s != NULL; i++) {
3707aec1d6eScindi 			/* add slash separator, but no leading slash */
3717aec1d6eScindi 			if (i != 0)
3727aec1d6eScindi 				len++;
3737aec1d6eScindi 			len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
3747aec1d6eScindi 		}
3757aec1d6eScindi 	}
3767aec1d6eScindi 
3777aec1d6eScindi 	if (ename != NULL && ipp != NULL)
3787aec1d6eScindi 		len++;	/* room for '@' */
3797aec1d6eScindi 
3807aec1d6eScindi 	return (len);
3817aec1d6eScindi }
3827aec1d6eScindi 
3837aec1d6eScindi /*
3847c478bd9Sstevel@tonic-gate  * ipath_print -- print out an ename, ipath, or both with '@' between them
3857c478bd9Sstevel@tonic-gate  */
3867c478bd9Sstevel@tonic-gate void
3877c478bd9Sstevel@tonic-gate ipath_print(int flags, const char *ename, const struct ipath *ipp)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	if (ename != NULL) {
3907c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, ename);
3917c478bd9Sstevel@tonic-gate 		if (ipp != NULL)
3927c478bd9Sstevel@tonic-gate 			out(flags|O_NONL, "@");
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	if (ipp != NULL) {
3957c478bd9Sstevel@tonic-gate 		char *sep = "";
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 		while (ipp->s != NULL) {
3987c478bd9Sstevel@tonic-gate 			out(flags|O_NONL, "%s%s%d", sep, ipp->s, ipp->i);
3997c478bd9Sstevel@tonic-gate 			ipp++;
4007c478bd9Sstevel@tonic-gate 			sep = "/";
4017c478bd9Sstevel@tonic-gate 		}
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4067c478bd9Sstevel@tonic-gate static void
4077c478bd9Sstevel@tonic-gate ipath_destructor(void *left, void *right, void *arg)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	struct ipath *ipp = (struct ipath *)right;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	FREE(ipp);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate  * ipath_fini -- free the ipath cache
4167c478bd9Sstevel@tonic-gate  */
4177c478bd9Sstevel@tonic-gate void
4187c478bd9Sstevel@tonic-gate ipath_fini(void)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate 	lut_free(Ipaths, ipath_destructor, NULL);
4217c478bd9Sstevel@tonic-gate 	Ipaths = NULL;
42227134bdaSstephh 	lut_free(Usednames, NULL, NULL);
42327134bdaSstephh 	Usednames = NULL;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	if (Nipath) {
4267c478bd9Sstevel@tonic-gate 		stats_delete(Nipath);
4277c478bd9Sstevel@tonic-gate 		Nipath = NULL;
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	if (Nbytes) {
4317c478bd9Sstevel@tonic-gate 		stats_delete(Nbytes);
4327c478bd9Sstevel@tonic-gate 		Nbytes = NULL;
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate }
435