1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <fm/fmd_fmri.h>
30*0Sstevel@tonic-gate #include <libdevinfo.h>
31*0Sstevel@tonic-gate #include <alloca.h>
32*0Sstevel@tonic-gate #include <string.h>
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate /*
35*0Sstevel@tonic-gate  * buf_append -- Append str to buf (if it's non-NULL).  Place prepend
36*0Sstevel@tonic-gate  * in buf in front of str and append behind it (if they're non-NULL).
37*0Sstevel@tonic-gate  * Continue to update size even if we run out of space to actually
38*0Sstevel@tonic-gate  * stuff characters in the buffer.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate static void
41*0Sstevel@tonic-gate buf_append(ssize_t *sz, char *buf, size_t buflen, char *str,
42*0Sstevel@tonic-gate     char *prepend, char *append)
43*0Sstevel@tonic-gate {
44*0Sstevel@tonic-gate 	ssize_t left;
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate 	if (str == NULL)
47*0Sstevel@tonic-gate 		return;
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate 	if (buflen == 0 || (left = buflen - *sz) < 0)
50*0Sstevel@tonic-gate 		left = 0;
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate 	if (buf != NULL && left != 0)
53*0Sstevel@tonic-gate 		buf += *sz;
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate 	if (prepend == NULL && append == NULL)
56*0Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s", str);
57*0Sstevel@tonic-gate 	else if (append == NULL)
58*0Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s%s", prepend, str);
59*0Sstevel@tonic-gate 	else if (prepend == NULL)
60*0Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s%s", str, append);
61*0Sstevel@tonic-gate 	else
62*0Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s%s%s", prepend, str, append);
63*0Sstevel@tonic-gate }
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate ssize_t
67*0Sstevel@tonic-gate fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
68*0Sstevel@tonic-gate {
69*0Sstevel@tonic-gate 	nvlist_t *anvl = NULL;
70*0Sstevel@tonic-gate 	uint8_t version;
71*0Sstevel@tonic-gate 	ssize_t size = 0;
72*0Sstevel@tonic-gate 	char *devid = NULL;
73*0Sstevel@tonic-gate 	char *devpath = NULL;
74*0Sstevel@tonic-gate 	char *achas = NULL;
75*0Sstevel@tonic-gate 	char *adom = NULL;
76*0Sstevel@tonic-gate 	char *aprod = NULL;
77*0Sstevel@tonic-gate 	char *asrvr = NULL;
78*0Sstevel@tonic-gate 	char *ahost = NULL;
79*0Sstevel@tonic-gate 	int more_auth = 0;
80*0Sstevel@tonic-gate 	int err;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
83*0Sstevel@tonic-gate 	    version > FM_DEV_SCHEME_VERSION)
84*0Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	/* Get authority, if present */
87*0Sstevel@tonic-gate 	err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
88*0Sstevel@tonic-gate 	if (err != 0 && err != ENOENT)
89*0Sstevel@tonic-gate 		return (fmd_fmri_set_errno(err));
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	/* Get devid, if present */
92*0Sstevel@tonic-gate 	err = nvlist_lookup_string(nvl, FM_FMRI_DEV_ID, &devid);
93*0Sstevel@tonic-gate 	if (err != 0 && err != ENOENT)
94*0Sstevel@tonic-gate 		return (fmd_fmri_set_errno(err));
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	/* There must be a device path present */
97*0Sstevel@tonic-gate 	err = nvlist_lookup_string(nvl, FM_FMRI_DEV_PATH, &devpath);
98*0Sstevel@tonic-gate 	if (err != 0 || devpath == NULL)
99*0Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	if (anvl != NULL) {
102*0Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
103*0Sstevel@tonic-gate 		    FM_FMRI_AUTH_PRODUCT, &aprod);
104*0Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
105*0Sstevel@tonic-gate 		    FM_FMRI_AUTH_CHASSIS, &achas);
106*0Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
107*0Sstevel@tonic-gate 		    FM_FMRI_AUTH_DOMAIN, &adom);
108*0Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
109*0Sstevel@tonic-gate 		    FM_FMRI_AUTH_SERVER, &asrvr);
110*0Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
111*0Sstevel@tonic-gate 		    FM_FMRI_AUTH_HOST, &ahost);
112*0Sstevel@tonic-gate 		if (aprod != NULL)
113*0Sstevel@tonic-gate 			more_auth++;
114*0Sstevel@tonic-gate 		if (achas != NULL)
115*0Sstevel@tonic-gate 			more_auth++;
116*0Sstevel@tonic-gate 		if (adom != NULL)
117*0Sstevel@tonic-gate 			more_auth++;
118*0Sstevel@tonic-gate 		if (asrvr != NULL)
119*0Sstevel@tonic-gate 			more_auth++;
120*0Sstevel@tonic-gate 		if (ahost != NULL)
121*0Sstevel@tonic-gate 			more_auth++;
122*0Sstevel@tonic-gate 	}
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	/* dev:// */
125*0Sstevel@tonic-gate 	buf_append(&size, buf, buflen, FM_FMRI_SCHEME_DEV, NULL, "://");
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	/* authority, if any */
128*0Sstevel@tonic-gate 	if (aprod != NULL)
129*0Sstevel@tonic-gate 		buf_append(&size, buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=",
130*0Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
131*0Sstevel@tonic-gate 	if (achas != NULL)
132*0Sstevel@tonic-gate 		buf_append(&size, buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=",
133*0Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
134*0Sstevel@tonic-gate 	if (adom != NULL)
135*0Sstevel@tonic-gate 		buf_append(&size, buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=",
136*0Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
137*0Sstevel@tonic-gate 	if (asrvr != NULL)
138*0Sstevel@tonic-gate 		buf_append(&size, buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=",
139*0Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
140*0Sstevel@tonic-gate 	if (ahost != NULL)
141*0Sstevel@tonic-gate 		buf_append(&size, buf, buflen, ahost, FM_FMRI_AUTH_HOST "=",
142*0Sstevel@tonic-gate 		    NULL);
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	/* device-id part */
145*0Sstevel@tonic-gate 	buf_append(&size, buf, buflen, devid, "/:" FM_FMRI_DEV_ID "=", NULL);
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/* device-path part */
148*0Sstevel@tonic-gate 	buf_append(&size, buf, buflen, devpath, "/", NULL);
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	return (size);
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate /*
154*0Sstevel@tonic-gate  * callback routine for di_walk_minor()
155*0Sstevel@tonic-gate  */
156*0Sstevel@tonic-gate struct walkinfo {
157*0Sstevel@tonic-gate 	int matched;
158*0Sstevel@tonic-gate 	const char *path;
159*0Sstevel@tonic-gate 	int len;
160*0Sstevel@tonic-gate };
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate static int
163*0Sstevel@tonic-gate dev_match(di_node_t node, void *arg)
164*0Sstevel@tonic-gate {
165*0Sstevel@tonic-gate 	struct walkinfo *wip = (struct walkinfo *)arg;
166*0Sstevel@tonic-gate 	char *path = di_devfs_path(node);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	if (path != NULL && strncmp(path, wip->path, wip->len) == 0) {
169*0Sstevel@tonic-gate 		/*
170*0Sstevel@tonic-gate 		 * found the match we were looking for, set matched
171*0Sstevel@tonic-gate 		 * flag and terminate the walk.
172*0Sstevel@tonic-gate 		 */
173*0Sstevel@tonic-gate 		wip->matched = 1;
174*0Sstevel@tonic-gate 		di_devfs_path_free(path);
175*0Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	if (path != NULL)
179*0Sstevel@tonic-gate 		di_devfs_path_free(path);
180*0Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate /*
184*0Sstevel@tonic-gate  * For now we only check for the presence of the device in the device
185*0Sstevel@tonic-gate  * tree.  This is somewhat unsophisticated, because a device may have
186*0Sstevel@tonic-gate  * been inserted into the same slot as the previous ASRU and we don't
187*0Sstevel@tonic-gate  * know how to tell them apart yet.
188*0Sstevel@tonic-gate  */
189*0Sstevel@tonic-gate int
190*0Sstevel@tonic-gate fmd_fmri_present(nvlist_t *nvl)
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate 	di_node_t parent;
193*0Sstevel@tonic-gate 	uint8_t version;
194*0Sstevel@tonic-gate 	char *devpath = NULL;
195*0Sstevel@tonic-gate 	char *parentpath;
196*0Sstevel@tonic-gate 	char *cp;
197*0Sstevel@tonic-gate 	struct walkinfo walkinfo;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
200*0Sstevel@tonic-gate 	    version > FM_DEV_SCHEME_VERSION ||
201*0Sstevel@tonic-gate 	    nvlist_lookup_string(nvl, FM_FMRI_DEV_PATH, &devpath) != 0)
202*0Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	if (devpath == NULL || (walkinfo.len = strlen(devpath)) == 0)
205*0Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	/* strip off last component of path */
208*0Sstevel@tonic-gate 	parentpath = alloca(walkinfo.len + 1);
209*0Sstevel@tonic-gate 	(void) strcpy(parentpath, devpath);
210*0Sstevel@tonic-gate 	if ((cp = strrchr(parentpath, '/')) == NULL)
211*0Sstevel@tonic-gate 		parentpath = "/";
212*0Sstevel@tonic-gate 	else
213*0Sstevel@tonic-gate 		*cp = '\0';
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	/* if the result is an empty path, start walk at "/" */
216*0Sstevel@tonic-gate 	if (*parentpath == '\0')
217*0Sstevel@tonic-gate 		parentpath = "/";
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	if ((parent = di_init(parentpath, DINFOSUBTREE)) == DI_NODE_NIL)
220*0Sstevel@tonic-gate 		return (errno == ENXIO ? 0 : -1);
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	walkinfo.matched = 0;
223*0Sstevel@tonic-gate 	walkinfo.path = devpath;
224*0Sstevel@tonic-gate 	di_walk_node(parent, DI_WALK_SIBFIRST, (void *)&walkinfo, dev_match);
225*0Sstevel@tonic-gate 	di_fini(parent);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	return (walkinfo.matched);
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*
231*0Sstevel@tonic-gate  *  We presently don't have a good indication of the usability of an
232*0Sstevel@tonic-gate  *  ASRU in the dev scheme, so we'll assume its usable.
233*0Sstevel@tonic-gate  */
234*0Sstevel@tonic-gate int
235*0Sstevel@tonic-gate fmd_fmri_unusable(nvlist_t *nvl)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	uint8_t version;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
240*0Sstevel@tonic-gate 	    version > FM_DEV_SCHEME_VERSION)
241*0Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	return (0);
244*0Sstevel@tonic-gate }
245