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