xref: /illumos-gate/usr/src/cmd/fm/fmd/common/fmd_fmri.c (revision 1a220b56b93ff1dc80855691548503117af4cc10)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <ctype.h>
31 #include <errno.h>
32 #include <stdarg.h>
33 
34 #include <fmd_alloc.h>
35 #include <fmd_subr.h>
36 #include <fmd_error.h>
37 #include <fmd_string.h>
38 #include <fmd_scheme.h>
39 #include <fmd_fmri.h>
40 #include <fmd.h>
41 
42 #include <fm/libtopo.h>
43 
44 /*
45  * Interfaces to be used by the plugins
46  */
47 
48 void *
49 fmd_fmri_alloc(size_t size)
50 {
51 	return (fmd_alloc(size, FMD_SLEEP));
52 }
53 
54 void *
55 fmd_fmri_zalloc(size_t size)
56 {
57 	return (fmd_zalloc(size, FMD_SLEEP));
58 }
59 
60 void
61 fmd_fmri_free(void *data, size_t size)
62 {
63 	fmd_free(data, size);
64 }
65 
66 int
67 fmd_fmri_set_errno(int err)
68 {
69 	errno = err;
70 	return (-1);
71 }
72 
73 void
74 fmd_fmri_warn(const char *format, ...)
75 {
76 	va_list ap;
77 
78 	va_start(ap, format);
79 	fmd_verror(EFMD_FMRI_SCHEME, format, ap);
80 	va_end(ap);
81 }
82 
83 /*
84  * Convert an input string to a URI escaped string and return the new string.
85  * RFC2396 Section 2.4 says that data must be escaped if it does not have a
86  * representation using an unreserved character, where an unreserved character
87  * is one that is either alphanumberic or one of the marks defined in S2.3.
88  */
89 static size_t
90 fmd_fmri_uriescape(const char *s, const char *xmark, char *buf, size_t len)
91 {
92 	static const char rfc2396_mark[] = "-_.!~*'()";
93 	static const char hex_digits[] = "0123456789ABCDEF";
94 	static const char empty_str[] = "";
95 
96 	const char *p;
97 	char c, *q;
98 	size_t n = 0;
99 
100 	if (s == NULL)
101 		s = empty_str;
102 
103 	if (xmark == NULL)
104 		xmark = empty_str;
105 
106 	for (p = s; (c = *p) != '\0'; p++) {
107 		if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c))
108 			n++;	/* represent c as itself */
109 		else
110 			n += 3; /* represent c as escape */
111 	}
112 
113 	if (buf == NULL)
114 		return (n);
115 
116 	for (p = s, q = buf; (c = *p) != '\0' && q < buf + len; p++) {
117 		if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) {
118 			*q++ = c;
119 		} else {
120 			*q++ = '%';
121 			*q++ = hex_digits[((uchar_t)c & 0xf0) >> 4];
122 			*q++ = hex_digits[(uchar_t)c & 0xf];
123 		}
124 	}
125 
126 	if (q == buf + len)
127 		q--; /* len is too small: truncate output string */
128 
129 	*q = '\0';
130 	return (n);
131 }
132 
133 /*
134  * Convert a name-value pair list representing an FMRI authority into the
135  * corresponding RFC2396 string representation and return the new string.
136  */
137 char *
138 fmd_fmri_auth2str(nvlist_t *nvl)
139 {
140 	nvpair_t *nvp;
141 	char *s, *p, *v;
142 	size_t n = 0;
143 
144 	for (nvp = nvlist_next_nvpair(nvl, NULL);
145 	    nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) {
146 
147 		if (nvpair_type(nvp) != DATA_TYPE_STRING)
148 			continue; /* do not format non-string elements */
149 
150 		n += fmd_fmri_uriescape(nvpair_name(nvp), NULL, NULL, 0) + 1;
151 		(void) nvpair_value_string(nvp, &v);
152 		n += fmd_fmri_uriescape(v, ":", NULL, 0) + 1;
153 	}
154 
155 	p = s = fmd_alloc(n, FMD_SLEEP);
156 
157 	for (nvp = nvlist_next_nvpair(nvl, NULL);
158 	    nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) {
159 
160 		if (nvpair_type(nvp) != DATA_TYPE_STRING)
161 			continue; /* do not format non-string elements */
162 
163 		if (p != s)
164 			*p++ = ',';
165 
166 		p += fmd_fmri_uriescape(nvpair_name(nvp), NULL, p, n);
167 		*p++ = '=';
168 		(void) nvpair_value_string(nvp, &v);
169 		p += fmd_fmri_uriescape(v, ":", p, n);
170 	}
171 
172 	return (s);
173 }
174 
175 /*
176  * Convert an input string to a URI escaped string and return the new string.
177  * We amend the unreserved character list to include commas and colons,
178  * as both are needed to make FMRIs readable without escaping.  We also permit
179  * "/" to pass through unescaped as any path delimiters used by the event
180  * creator are presumably intended to appear in the final path.
181  */
182 char *
183 fmd_fmri_strescape(const char *s)
184 {
185 	char *s2;
186 	size_t n;
187 
188 	if (s == NULL)
189 		return (NULL);
190 
191 	n = fmd_fmri_uriescape(s, ":,/", NULL, 0);
192 	s2 = fmd_alloc(n + 1, FMD_SLEEP);
193 	(void) fmd_fmri_uriescape(s, ":,/", s2, n + 1);
194 
195 	return (s2);
196 }
197 
198 char *
199 fmd_fmri_strdup(const char *s)
200 {
201 	return (fmd_strdup(s, FMD_SLEEP));
202 }
203 
204 void
205 fmd_fmri_strfree(char *s)
206 {
207 	fmd_strfree(s);
208 }
209 
210 const char *
211 fmd_fmri_get_rootdir(void)
212 {
213 	return (fmd.d_rootdir);
214 }
215 
216 const char *
217 fmd_fmri_get_platform(void)
218 {
219 	return (fmd.d_platform);
220 }
221 
222 uint64_t
223 fmd_fmri_get_drgen(void)
224 {
225 	uint64_t gen;
226 
227 	(void) pthread_mutex_lock(&fmd.d_stats_lock);
228 	gen = fmd.d_stats->ds_dr_gen.fmds_value.ui64;
229 	(void) pthread_mutex_unlock(&fmd.d_stats_lock);
230 
231 	return (gen);
232 }
233 
234 struct topo_hdl *
235 fmd_fmri_topology(int version)
236 {
237 	ASSERT(version == TOPO_VERSION);
238 	return (fmd.d_topo);
239 }
240 
241 /*
242  * Interfaces for users of the plugins
243  */
244 
245 static fmd_scheme_t *
246 nvl2scheme(nvlist_t *nvl)
247 {
248 	char *name;
249 
250 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) {
251 		(void) fmd_set_errno(EFMD_FMRI_INVAL);
252 		return (NULL);
253 	}
254 
255 	return (fmd_scheme_hash_lookup(fmd.d_schemes, name));
256 }
257 
258 ssize_t
259 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
260 {
261 	fmd_scheme_t *sp;
262 	char c;
263 	ssize_t rv;
264 
265 	if (buf == NULL && buflen == 0) {
266 		buf = &c;
267 		buflen = sizeof (c);
268 	}
269 
270 	if ((sp = nvl2scheme(nvl)) == NULL)
271 		return (-1); /* errno is set for us */
272 
273 	(void) pthread_mutex_lock(&sp->sch_opslock);
274 	ASSERT(buf != NULL || buflen == 0);
275 	rv = sp->sch_ops.sop_nvl2str(nvl, buf, buflen);
276 	(void) pthread_mutex_unlock(&sp->sch_opslock);
277 
278 	fmd_scheme_hash_release(fmd.d_schemes, sp);
279 	return (rv);
280 }
281 
282 int
283 fmd_fmri_expand(nvlist_t *nvl)
284 {
285 	fmd_scheme_t *sp;
286 	int rv;
287 
288 	if ((sp = nvl2scheme(nvl)) == NULL)
289 		return (-1); /* errno is set for us */
290 
291 	(void) pthread_mutex_lock(&sp->sch_opslock);
292 	rv = sp->sch_ops.sop_expand(nvl);
293 	(void) pthread_mutex_unlock(&sp->sch_opslock);
294 
295 	fmd_scheme_hash_release(fmd.d_schemes, sp);
296 	return (rv);
297 }
298 
299 int
300 fmd_fmri_present(nvlist_t *nvl)
301 {
302 	fmd_scheme_t *sp;
303 	int rv;
304 
305 	if ((sp = nvl2scheme(nvl)) == NULL)
306 		return (-1); /* errno is set for us */
307 
308 	(void) pthread_mutex_lock(&sp->sch_opslock);
309 	rv = sp->sch_ops.sop_present(nvl);
310 	(void) pthread_mutex_unlock(&sp->sch_opslock);
311 
312 	fmd_scheme_hash_release(fmd.d_schemes, sp);
313 	return (rv);
314 }
315 
316 int
317 fmd_fmri_unusable(nvlist_t *nvl)
318 {
319 	fmd_scheme_t *sp;
320 	int rv;
321 
322 	if ((sp = nvl2scheme(nvl)) == NULL)
323 		return (-1); /* errno is set for us */
324 
325 	(void) pthread_mutex_lock(&sp->sch_opslock);
326 	rv = sp->sch_ops.sop_unusable(nvl);
327 	(void) pthread_mutex_unlock(&sp->sch_opslock);
328 
329 	fmd_scheme_hash_release(fmd.d_schemes, sp);
330 	return (rv);
331 }
332 
333 int
334 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee)
335 {
336 	fmd_scheme_t *sp;
337 	char *ername, *eename;
338 	int rv;
339 
340 	if (nvlist_lookup_string(er, FM_FMRI_SCHEME, &ername) != 0 ||
341 	    nvlist_lookup_string(ee, FM_FMRI_SCHEME, &eename) != 0 ||
342 	    strcmp(ername, eename) != 0)
343 		return (fmd_set_errno(EFMD_FMRI_INVAL));
344 
345 	if ((sp = fmd_scheme_hash_lookup(fmd.d_schemes, ername)) == NULL)
346 		return (-1); /* errno is set for us */
347 
348 	(void) pthread_mutex_lock(&sp->sch_opslock);
349 	rv = sp->sch_ops.sop_contains(er, ee);
350 	(void) pthread_mutex_unlock(&sp->sch_opslock);
351 
352 	fmd_scheme_hash_release(fmd.d_schemes, sp);
353 	return (rv);
354 }
355 
356 nvlist_t *
357 fmd_fmri_translate(nvlist_t *fmri, nvlist_t *auth)
358 {
359 	fmd_scheme_t *sp;
360 	nvlist_t *nvl;
361 
362 	if ((sp = nvl2scheme(fmri)) == NULL)
363 		return (NULL); /* errno is set for us */
364 
365 	(void) pthread_mutex_lock(&sp->sch_opslock);
366 	nvl = sp->sch_ops.sop_translate(fmri, auth);
367 	(void) pthread_mutex_unlock(&sp->sch_opslock);
368 
369 	fmd_scheme_hash_release(fmd.d_schemes, sp);
370 	return (nvl);
371 }
372