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 2006 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 <strings.h>
30 #include <stdlib.h>
31 #include <netdir.h>
32 #include <errno.h>
33 #include <alloca.h>
34 #include <locale.h>
35 #include <uuid/uuid.h>
36 
37 #include <sys/fm/protocol.h>
38 #include <fmd_adm_impl.h>
39 #include <fmd_rpc_adm.h>
40 
41 static const uint_t _fmd_adm_bufsize = 128 * 1024;
42 static const char _url_fallback[] = "http://sun.com/msg/";
43 
44 fmd_adm_t *
45 fmd_adm_open(const char *host, uint32_t prog, int version)
46 {
47 	fmd_adm_t *ap;
48 	CLIENT *c;
49 	int err;
50 	rpcvers_t v;
51 
52 	if (version != FMD_ADM_VERSION) {
53 		errno = ENOTSUP;
54 		return (NULL);
55 	}
56 
57 	if (host == NULL)
58 		host = HOST_SELF;
59 
60 	if (prog == FMD_ADM_PROGRAM)
61 		prog = FMD_ADM;
62 
63 	/*
64 	 * If we are connecting to the local host, attempt a door connection
65 	 * first.  If that fails or we need another host, fall through to
66 	 * using the standard clnt_create that iterates over all transports.
67 	 */
68 	if (strcmp(host, HOST_SELF) == 0)
69 		c = clnt_door_create(prog, FMD_ADM_VERSION_1, _fmd_adm_bufsize);
70 	else
71 		c = NULL;
72 
73 	if (c == NULL) {
74 		c = clnt_create_vers(host, prog, &v,
75 		    FMD_ADM_VERSION_1, FMD_ADM_VERSION_1, NULL);
76 	}
77 
78 	if (c == NULL) {
79 		errno = EPROTO;
80 		return (NULL);
81 	}
82 
83 	if ((ap = malloc(sizeof (fmd_adm_t))) == NULL) {
84 		err = errno;
85 		clnt_destroy(c);
86 		errno = err;
87 		return (NULL);
88 	}
89 
90 	ap->adm_clnt = c;
91 	ap->adm_version = version;
92 	ap->adm_svcerr = 0;
93 	ap->adm_errno = 0;
94 
95 	return (ap);
96 }
97 
98 void
99 fmd_adm_close(fmd_adm_t *ap)
100 {
101 	if (ap == NULL)
102 		return; /* permit NULL to simply caller code */
103 
104 	clnt_destroy(ap->adm_clnt);
105 	free(ap);
106 }
107 
108 static const char *
109 fmd_adm_svc_errmsg(enum fmd_adm_error err)
110 {
111 	switch (err) {
112 	case FMD_ADM_ERR_NOMEM:
113 		return ("unable to perform request due to allocation failure");
114 	case FMD_ADM_ERR_PERM:
115 		return ("operation requires additional privilege");
116 	case FMD_ADM_ERR_MODSRCH:
117 		return ("specified module is not loaded in fault manager");
118 	case FMD_ADM_ERR_MODBUSY:
119 		return ("module is in use and cannot be unloaded");
120 	case FMD_ADM_ERR_MODFAIL:
121 		return ("module failed and can no longer export statistics");
122 	case FMD_ADM_ERR_MODNOENT:
123 		return ("file missing or cannot be accessed by fault manager");
124 	case FMD_ADM_ERR_MODEXIST:
125 		return ("module using same name is already loaded");
126 	case FMD_ADM_ERR_MODINIT:
127 		return ("module failed to initialize (consult fmd(1M) log)");
128 	case FMD_ADM_ERR_MODLOAD:
129 		return ("module failed to load (consult fmd(1M) log)");
130 	case FMD_ADM_ERR_RSRCSRCH:
131 		return ("specified resource is not cached by fault manager");
132 	case FMD_ADM_ERR_RSRCNOTF:
133 		return ("specified resource is not known to be faulty");
134 	case FMD_ADM_ERR_SERDSRCH:
135 		return ("specified serd engine not present in module");
136 	case FMD_ADM_ERR_SERDFIRED:
137 		return ("specified serd engine has already fired");
138 	case FMD_ADM_ERR_ROTSRCH:
139 		return ("invalid log file name");
140 	case FMD_ADM_ERR_ROTFAIL:
141 		return ("failed to rotate log file (consult fmd(1M) log)");
142 	case FMD_ADM_ERR_ROTBUSY:
143 		return ("log file is too busy to rotate (try again later)");
144 	case FMD_ADM_ERR_CASESRCH:
145 		return ("specified UUID is invalid or has been repaired");
146 	case FMD_ADM_ERR_CASEOPEN:
147 		return ("specified UUID is still being diagnosed");
148 	case FMD_ADM_ERR_XPRTSRCH:
149 		return ("specified transport ID is invalid or has been closed");
150 	case FMD_ADM_ERR_CASEXPRT:
151 		return ("specified UUID is owned by a different fault manager");
152 	default:
153 		return ("unknown fault manager error");
154 	}
155 }
156 
157 const char *
158 fmd_adm_errmsg(fmd_adm_t *ap)
159 {
160 	if (ap == NULL) {
161 		switch (errno) {
162 		case ENOTSUP:
163 			return ("client requires newer libfmd_adm version");
164 		case EPROTO:
165 			return (clnt_spcreateerror("failed to connect to fmd"));
166 		}
167 	}
168 
169 	switch (ap ? ap->adm_errno : errno) {
170 	case EPROTO:
171 		return (clnt_sperror(ap->adm_clnt, "rpc call failed"));
172 	case EREMOTE:
173 		return (fmd_adm_svc_errmsg(ap->adm_svcerr));
174 	default:
175 		return (strerror(ap->adm_errno));
176 	}
177 }
178 
179 static int
180 fmd_adm_set_svcerr(fmd_adm_t *ap, enum fmd_adm_error err)
181 {
182 	if (err != 0) {
183 		ap->adm_svcerr = err;
184 		ap->adm_errno = EREMOTE;
185 		return (-1);
186 	} else {
187 		ap->adm_svcerr = err;
188 		ap->adm_errno = 0;
189 		return (0);
190 	}
191 }
192 
193 static int
194 fmd_adm_set_errno(fmd_adm_t *ap, int err)
195 {
196 	ap->adm_errno = err;
197 	errno = err;
198 	return (-1);
199 }
200 
201 static int
202 fmd_adm_stats_cmp(const void *lp, const void *rp)
203 {
204 	return (strcmp(((fmd_stat_t *)lp)->fmds_name,
205 	    ((fmd_stat_t *)rp)->fmds_name));
206 }
207 
208 int
209 fmd_adm_stats_read(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp)
210 {
211 	struct fmd_rpc_modstat rms;
212 	enum clnt_stat cs;
213 
214 	if (sp == NULL)
215 		return (fmd_adm_set_errno(ap, EINVAL));
216 
217 	bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
218 
219 	if (name != NULL)
220 		cs = fmd_adm_modcstat_1((char *)name, &rms, ap->adm_clnt);
221 	else
222 		cs = fmd_adm_modgstat_1(&rms, ap->adm_clnt);
223 
224 	if (cs != RPC_SUCCESS)
225 		return (fmd_adm_set_errno(ap, EPROTO));
226 
227 	if (rms.rms_err != 0) {
228 		xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
229 		return (fmd_adm_set_svcerr(ap, rms.rms_err));
230 	}
231 
232 	sp->ams_buf = rms.rms_buf.rms_buf_val;
233 	sp->ams_len = rms.rms_buf.rms_buf_len;
234 
235 	if (sp->ams_len != 0) {
236 		qsort(sp->ams_buf, sp->ams_len,
237 		    sizeof (fmd_stat_t), fmd_adm_stats_cmp);
238 	}
239 
240 	return (0);
241 }
242 
243 int
244 fmd_adm_stats_free(fmd_adm_t *ap, fmd_adm_stats_t *sp)
245 {
246 	struct fmd_rpc_modstat rms;
247 
248 	if (sp == NULL)
249 		return (fmd_adm_set_errno(ap, EINVAL));
250 
251 	rms.rms_buf.rms_buf_val = sp->ams_buf;
252 	rms.rms_buf.rms_buf_len = sp->ams_len;
253 	rms.rms_err = 0;
254 
255 	xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
256 	bzero(sp, sizeof (fmd_adm_stats_t));
257 
258 	return (0);
259 }
260 
261 static int
262 fmd_adm_module_cmp(const void *lp, const void *rp)
263 {
264 	return (strcmp((*(struct fmd_rpc_modinfo **)lp)->rmi_name,
265 	    (*(struct fmd_rpc_modinfo **)rp)->rmi_name));
266 }
267 
268 int
269 fmd_adm_module_iter(fmd_adm_t *ap, fmd_adm_module_f *func, void *arg)
270 {
271 	struct fmd_rpc_modinfo *rmi, **rms, **rmp;
272 	struct fmd_rpc_modlist rml;
273 	fmd_adm_modinfo_t ami;
274 
275 	bzero(&rml, sizeof (rml)); /* tell xdr to allocate memory for us */
276 
277 	if (fmd_adm_modinfo_1(&rml, ap->adm_clnt) != RPC_SUCCESS)
278 		return (fmd_adm_set_errno(ap, EPROTO));
279 
280 	if (rml.rml_err != 0 || rml.rml_len == 0) {
281 		xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
282 		return (fmd_adm_set_svcerr(ap, rml.rml_err));
283 	}
284 
285 	if ((rms = rmp = malloc(sizeof (void *) * rml.rml_len)) == NULL) {
286 		xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
287 		return (fmd_adm_set_errno(ap, EAGAIN));
288 	}
289 
290 	for (rmi = rml.rml_list; rmi != NULL; rmi = rmi->rmi_next)
291 		*rmp++ = rmi; /* store copy of pointer in array for sorting */
292 
293 	qsort(rms, rml.rml_len, sizeof (void *), fmd_adm_module_cmp);
294 
295 	for (rmp = rms; rmp < rms + rml.rml_len; rmp++) {
296 		rmi = *rmp;
297 
298 		ami.ami_name = rmi->rmi_name;
299 		ami.ami_desc = rmi->rmi_desc;
300 		ami.ami_vers = rmi->rmi_vers;
301 		ami.ami_flags = 0;
302 
303 		if (rmi->rmi_faulty)
304 			ami.ami_flags |= FMD_ADM_MOD_FAILED;
305 
306 		if (func(&ami, arg) != 0)
307 			break;
308 	}
309 
310 	free(rms);
311 	xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
312 	return (0);
313 }
314 
315 int
316 fmd_adm_module_load(fmd_adm_t *ap, const char *path)
317 {
318 	char *str = (char *)path;
319 	int err;
320 
321 	if (path == NULL || path[0] != '/')
322 		return (fmd_adm_set_errno(ap, EINVAL));
323 
324 	if (fmd_adm_modload_1(str, &err, ap->adm_clnt) != RPC_SUCCESS)
325 		return (fmd_adm_set_errno(ap, EPROTO));
326 
327 	return (fmd_adm_set_svcerr(ap, err));
328 }
329 
330 int
331 fmd_adm_module_unload(fmd_adm_t *ap, const char *name)
332 {
333 	char *str = (char *)name;
334 	int err;
335 
336 	if (name == NULL || strchr(name, '/') != NULL)
337 		return (fmd_adm_set_errno(ap, EINVAL));
338 
339 	if (fmd_adm_modunload_1(str, &err, ap->adm_clnt) != RPC_SUCCESS)
340 		return (fmd_adm_set_errno(ap, EPROTO));
341 
342 	return (fmd_adm_set_svcerr(ap, err));
343 }
344 
345 int
346 fmd_adm_module_reset(fmd_adm_t *ap, const char *name)
347 {
348 	char *str = (char *)name;
349 	int err;
350 
351 	if (name == NULL || strchr(name, '/') != NULL)
352 		return (fmd_adm_set_errno(ap, EINVAL));
353 
354 	if (fmd_adm_modreset_1(str, &err, ap->adm_clnt) != RPC_SUCCESS)
355 		return (fmd_adm_set_errno(ap, EPROTO));
356 
357 	return (fmd_adm_set_svcerr(ap, err));
358 }
359 
360 int
361 fmd_adm_module_gc(fmd_adm_t *ap, const char *name)
362 {
363 	char *str = (char *)name;
364 	int err;
365 
366 	if (name == NULL || strchr(name, '/') != NULL)
367 		return (fmd_adm_set_errno(ap, EINVAL));
368 
369 	if (fmd_adm_modgc_1(str, &err, ap->adm_clnt) != RPC_SUCCESS)
370 		return (fmd_adm_set_errno(ap, EPROTO));
371 
372 	return (fmd_adm_set_svcerr(ap, err));
373 }
374 
375 int
376 fmd_adm_module_stats(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp)
377 {
378 	struct fmd_rpc_modstat rms;
379 
380 	if (name == NULL || sp == NULL)
381 		return (fmd_adm_set_errno(ap, EINVAL));
382 
383 	bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
384 
385 	if (fmd_adm_moddstat_1((char *)name, &rms, ap->adm_clnt) != RPC_SUCCESS)
386 		return (fmd_adm_set_errno(ap, EPROTO));
387 
388 	if (rms.rms_err != 0) {
389 		xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
390 		return (fmd_adm_set_svcerr(ap, rms.rms_err));
391 	}
392 
393 	sp->ams_buf = rms.rms_buf.rms_buf_val;
394 	sp->ams_len = rms.rms_buf.rms_buf_len;
395 
396 	return (0);
397 }
398 
399 int
400 fmd_adm_rsrc_count(fmd_adm_t *ap, int all, uint32_t *rcp)
401 {
402 	struct fmd_rpc_rsrclist rrl;
403 
404 	if (rcp == NULL)
405 		return (fmd_adm_set_errno(ap, EINVAL));
406 
407 	bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */
408 
409 	if (fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt) != RPC_SUCCESS)
410 		return (fmd_adm_set_errno(ap, EPROTO));
411 
412 	if (rrl.rrl_err != 0) {
413 		xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
414 		return (fmd_adm_set_svcerr(ap, rrl.rrl_err));
415 	}
416 
417 	*rcp = rrl.rrl_cnt;
418 	xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
419 	return (0);
420 }
421 
422 static int
423 fmd_adm_rsrc_cmp(const void *lp, const void *rp)
424 {
425 	return (strcmp(*(char **)lp, *(char **)rp));
426 }
427 
428 int
429 fmd_adm_rsrc_iter(fmd_adm_t *ap, int all, fmd_adm_rsrc_f *func, void *arg)
430 {
431 	struct fmd_rpc_rsrclist rrl;
432 	struct fmd_rpc_rsrcinfo rri;
433 	fmd_adm_rsrcinfo_t ari;
434 	char **fmris, *p;
435 	int i, rv;
436 
437 	bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */
438 
439 	if (fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt) != RPC_SUCCESS)
440 		return (fmd_adm_set_errno(ap, EPROTO));
441 
442 	if (rrl.rrl_err != 0) {
443 		xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
444 		return (fmd_adm_set_svcerr(ap, rrl.rrl_err));
445 	}
446 
447 	if ((fmris = malloc(sizeof (char *) * rrl.rrl_cnt)) == NULL) {
448 		xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
449 		return (fmd_adm_set_errno(ap, EAGAIN));
450 	}
451 
452 	/*
453 	 * The fmd_adm_rsrclist_1 request returns an opaque XDR buffer that is
454 	 * a string table of FMRIs (e.g. "fmriA\0fmriB\0...") where rrl_cnt is
455 	 * the number of strings in the table and rrl_buf_val is its address.
456 	 * We construct an array of pointers into the string table and sort it.
457 	 */
458 	p = rrl.rrl_buf.rrl_buf_val;
459 
460 	for (i = 0; i < rrl.rrl_cnt; i++, p += strlen(p) + 1)
461 		fmris[i] = p; /* store fmri pointer in array for sorting */
462 
463 	qsort(fmris, rrl.rrl_cnt, sizeof (char *), fmd_adm_rsrc_cmp);
464 
465 	/*
466 	 * For each FMRI in the resource cache snapshot, use fmd_adm_rsrcinfo_1
467 	 * to get more information and the invoke the callback function.  If
468 	 * FMD_ADM_ERR_RSRCSRCH is returned, the FMRI has been purged from the
469 	 * cache since our snapshot: this error is therefore silently ignored.
470 	 */
471 	for (i = 0; i < rrl.rrl_cnt; i++) {
472 		bzero(&rri, sizeof (rri));
473 
474 		if (fmd_adm_rsrcinfo_1(fmris[i], &rri,
475 		    ap->adm_clnt) != RPC_SUCCESS) {
476 			free(fmris);
477 			xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
478 			return (fmd_adm_set_errno(ap, EPROTO));
479 		}
480 
481 		if (rri.rri_err != 0 && rri.rri_err != FMD_ADM_ERR_RSRCSRCH) {
482 			xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
483 			free(fmris);
484 			xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
485 			return (fmd_adm_set_svcerr(ap, rri.rri_err));
486 		}
487 
488 		if (rri.rri_err == FMD_ADM_ERR_RSRCSRCH) {
489 			xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
490 			continue;
491 		}
492 
493 		ari.ari_fmri = rri.rri_fmri;
494 		ari.ari_uuid = rri.rri_uuid;
495 		ari.ari_case = rri.rri_case;
496 		ari.ari_flags = 0;
497 
498 		if (rri.rri_faulty)
499 			ari.ari_flags |= FMD_ADM_RSRC_FAULTY;
500 		if (rri.rri_unusable)
501 			ari.ari_flags |= FMD_ADM_RSRC_UNUSABLE;
502 		if (rri.rri_invisible)
503 			ari.ari_flags |= FMD_ADM_RSRC_INVISIBLE;
504 
505 		rv = func(&ari, arg);
506 		xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
507 
508 		if (rv != 0)
509 			break;
510 	}
511 
512 	free(fmris);
513 	xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
514 	return (0);
515 }
516 
517 int
518 fmd_adm_rsrc_flush(fmd_adm_t *ap, const char *fmri)
519 {
520 	char *str = (char *)fmri;
521 	int err;
522 
523 	if (fmri == NULL)
524 		return (fmd_adm_set_errno(ap, EINVAL));
525 
526 	if (fmd_adm_rsrcflush_1(str, &err, ap->adm_clnt) != RPC_SUCCESS)
527 		return (fmd_adm_set_errno(ap, EPROTO));
528 
529 	return (fmd_adm_set_svcerr(ap, err));
530 }
531 
532 int
533 fmd_adm_rsrc_repair(fmd_adm_t *ap, const char *fmri)
534 {
535 	char *str = (char *)fmri;
536 	int err;
537 
538 	if (fmri == NULL)
539 		return (fmd_adm_set_errno(ap, EINVAL));
540 
541 	if (fmd_adm_rsrcrepair_1(str, &err, ap->adm_clnt) != RPC_SUCCESS)
542 		return (fmd_adm_set_errno(ap, EPROTO));
543 
544 	return (fmd_adm_set_svcerr(ap, err));
545 }
546 
547 int
548 fmd_adm_case_repair(fmd_adm_t *ap, const char *uuid)
549 {
550 	char *str = (char *)uuid;
551 	int err;
552 
553 	if (uuid == NULL)
554 		return (fmd_adm_set_errno(ap, EINVAL));
555 
556 	if (fmd_adm_caserepair_1(str, &err, ap->adm_clnt) != RPC_SUCCESS)
557 		return (fmd_adm_set_errno(ap, EPROTO));
558 
559 	return (fmd_adm_set_svcerr(ap, err));
560 }
561 
562 static int
563 fmd_adm_case_cmp(const void *lp, const void *rp)
564 {
565 	return (strcmp(*(char **)lp, *(char **)rp));
566 }
567 
568 static int
569 fmd_adm_case_one(fmd_adm_caseinfo_t *acp, const char *url_token,
570     fmd_adm_case_f *func, void *arg)
571 {
572 	char *p, *urlcode, *dict, *olang;
573 	const char *url;
574 	size_t	len;
575 
576 	if ((p = strchr(acp->aci_code, '-')) == NULL ||
577 	    p == acp->aci_code) {
578 		acp->aci_url = NULL;
579 	} else {
580 		dict = alloca((size_t)(p - acp->aci_code) + 1);
581 		(void) strncpy(dict, acp->aci_code,
582 		    (size_t)(p - acp->aci_code));
583 		dict[(size_t)(p - acp->aci_code)] = '\0';
584 
585 		/*
586 		 * If we're given a token to use in looking up the URL, try
587 		 * to use it.  Otherwise, or if we don't find it that way,
588 		 * use the fallback.
589 		 */
590 		if (url_token == NULL) {
591 			url = _url_fallback;
592 		} else if ((url = dgettext(dict, url_token)) == url_token) {
593 			/*
594 			 * We didn't find a translation in the
595 			 * dictionary for the current language.  Fall
596 			 * back to C and try again.
597 			 */
598 			olang = setlocale(LC_MESSAGES, NULL);
599 			(void) setlocale(LC_MESSAGES, "C");
600 			if ((url = dgettext(dict, url_token)) == url_token)
601 				url = _url_fallback;
602 			(void) setlocale(LC_MESSAGES, olang);
603 		}
604 		len = strlen(url);
605 		if (url[len - 1] == '/') {
606 			len += strlen(acp->aci_code) + 1;
607 			urlcode = alloca(len);
608 			(void) snprintf(urlcode, len, "%s%s", url,
609 			    acp->aci_code);
610 		} else {
611 			urlcode = (char *)url;
612 		}
613 		acp->aci_url = urlcode;
614 	}
615 
616 	return (func(acp, arg));
617 }
618 
619 /*
620  * Our approach to cases is the same as for resources: we first obtain a
621  * list of UUIDs, sort them, then obtain the case information for each.
622  */
623 int
624 fmd_adm_case_iter(fmd_adm_t *ap, const char *url_token, fmd_adm_case_f *func,
625     void *arg)
626 {
627 	struct fmd_rpc_caselist rcl;
628 	struct fmd_rpc_caseinfo rci;
629 	fmd_adm_caseinfo_t aci;
630 	char **uuids, *p;
631 	int i, rv;
632 
633 	bzero(&rcl, sizeof (rcl)); /* tell xdr to allocate memory for us */
634 
635 	if (fmd_adm_caselist_1(&rcl, ap->adm_clnt) != RPC_SUCCESS)
636 		return (fmd_adm_set_errno(ap, EPROTO));
637 
638 	if (rcl.rcl_err != 0) {
639 		xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
640 		return (fmd_adm_set_svcerr(ap, rcl.rcl_err));
641 	}
642 
643 	if ((uuids = malloc(sizeof (char *) * rcl.rcl_cnt)) == NULL) {
644 		xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
645 		return (fmd_adm_set_errno(ap, EAGAIN));
646 	}
647 
648 	p = rcl.rcl_buf.rcl_buf_val;
649 
650 	for (i = 0; i < rcl.rcl_cnt; i++, p += strlen(p) + 1)
651 		uuids[i] = p;
652 
653 	qsort(uuids, rcl.rcl_cnt, sizeof (char *), fmd_adm_case_cmp);
654 
655 	for (i = 0; i < rcl.rcl_cnt; i++) {
656 		bzero(&rci, sizeof (rci));
657 
658 		if (fmd_adm_caseinfo_1(uuids[i], &rci, ap->adm_clnt)
659 		    != RPC_SUCCESS) {
660 			free(uuids);
661 			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
662 			return (fmd_adm_set_errno(ap, EPROTO));
663 		}
664 
665 		if (rci.rci_err != 0 && rci.rci_err != FMD_ADM_ERR_CASESRCH) {
666 			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
667 			free(uuids);
668 			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
669 			return (fmd_adm_set_svcerr(ap, rci.rci_err));
670 		}
671 
672 		if (rci.rci_err == FMD_ADM_ERR_CASESRCH) {
673 			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
674 			continue;
675 		}
676 
677 		bzero(&aci, sizeof (aci));
678 
679 		if ((rv = nvlist_unpack(rci.rci_evbuf.rci_evbuf_val,
680 		    rci.rci_evbuf.rci_evbuf_len, &aci.aci_event, 0)) != 0) {
681 			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
682 			free(uuids);
683 			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
684 			return (fmd_adm_set_errno(ap, rv));
685 		}
686 
687 		if ((rv = nvlist_lookup_string(aci.aci_event, FM_SUSPECT_UUID,
688 		    (char **)&aci.aci_uuid)) != 0) {
689 			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
690 			free(uuids);
691 			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
692 			nvlist_free(aci.aci_event);
693 			return (fmd_adm_set_errno(ap, rv));
694 		}
695 		if ((rv = nvlist_lookup_string(aci.aci_event,
696 		    FM_SUSPECT_DIAG_CODE, (char **)&aci.aci_code)) != 0) {
697 			xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
698 			free(uuids);
699 			xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
700 			nvlist_free(aci.aci_event);
701 			return (fmd_adm_set_errno(ap, rv));
702 		}
703 
704 		rv = fmd_adm_case_one(&aci, url_token, func, arg);
705 
706 		xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
707 		nvlist_free(aci.aci_event);
708 
709 		if (rv != 0)
710 			break;
711 	}
712 
713 	free(uuids);
714 	xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
715 	return (0);
716 }
717 
718 static int
719 fmd_adm_serd_cmp(const void *lp, const void *rp)
720 {
721 	return (strcmp((*(struct fmd_rpc_serdinfo **)lp)->rsi_name,
722 	    (*(struct fmd_rpc_serdinfo **)rp)->rsi_name));
723 }
724 
725 int
726 fmd_adm_serd_iter(fmd_adm_t *ap, const char *name,
727     fmd_adm_serd_f *func, void *arg)
728 {
729 	struct fmd_rpc_serdinfo *rsi, **ris, **rip;
730 	struct fmd_rpc_serdlist rsl;
731 	fmd_adm_serdinfo_t asi;
732 
733 	bzero(&rsl, sizeof (rsl)); /* tell xdr to allocate memory for us */
734 
735 	if (fmd_adm_serdinfo_1((char *)name, &rsl, ap->adm_clnt) != RPC_SUCCESS)
736 		return (fmd_adm_set_errno(ap, EPROTO));
737 
738 	if (rsl.rsl_err != 0 || rsl.rsl_len == 0) {
739 		xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
740 		return (fmd_adm_set_svcerr(ap, rsl.rsl_err));
741 	}
742 
743 	if ((ris = rip = malloc(sizeof (void *) * rsl.rsl_len)) == NULL) {
744 		xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
745 		return (fmd_adm_set_errno(ap, EAGAIN));
746 	}
747 
748 	for (rsi = rsl.rsl_list; rsi != NULL; rsi = rsi->rsi_next)
749 		*rip++ = rsi; /* store copy of pointer in array for sorting */
750 
751 	qsort(ris, rsl.rsl_len, sizeof (void *), fmd_adm_serd_cmp);
752 
753 	for (rip = ris; rip < ris + rsl.rsl_len; rip++) {
754 		rsi = *rip;
755 
756 		asi.asi_name = rsi->rsi_name;
757 		asi.asi_delta = rsi->rsi_delta;
758 		asi.asi_n = rsi->rsi_n;
759 		asi.asi_t = rsi->rsi_t;
760 		asi.asi_count = rsi->rsi_count;
761 		asi.asi_flags = 0;
762 
763 		if (rsi->rsi_fired)
764 			asi.asi_flags |= FMD_ADM_SERD_FIRED;
765 
766 		if (func(&asi, arg) != 0)
767 			break;
768 	}
769 
770 	free(ris);
771 	xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
772 	return (0);
773 }
774 
775 int
776 fmd_adm_serd_reset(fmd_adm_t *ap, const char *mod, const char *name)
777 {
778 	char *s1 = (char *)mod, *s2 = (char *)name;
779 	int err;
780 
781 	if (mod == NULL || name == NULL || strchr(mod, '/') != NULL)
782 		return (fmd_adm_set_errno(ap, EINVAL));
783 
784 	if (fmd_adm_serdreset_1(s1, s2, &err, ap->adm_clnt) != RPC_SUCCESS)
785 		return (fmd_adm_set_errno(ap, EPROTO));
786 
787 	return (fmd_adm_set_svcerr(ap, err));
788 }
789 
790 int
791 fmd_adm_xprt_iter(fmd_adm_t *ap, fmd_adm_xprt_f *func, void *arg)
792 {
793 	struct fmd_rpc_xprtlist rxl;
794 	uint_t i;
795 
796 	bzero(&rxl, sizeof (rxl)); /* tell xdr to allocate memory for us */
797 
798 	if (fmd_adm_xprtlist_1(&rxl, ap->adm_clnt) != RPC_SUCCESS)
799 		return (fmd_adm_set_errno(ap, EPROTO));
800 
801 	if (rxl.rxl_err != 0) {
802 		xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl);
803 		return (fmd_adm_set_svcerr(ap, rxl.rxl_err));
804 	}
805 
806 	for (i = 0; i < rxl.rxl_len; i++)
807 		func(rxl.rxl_buf.rxl_buf_val[i], arg);
808 
809 	xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl);
810 	return (0);
811 }
812 
813 int
814 fmd_adm_xprt_stats(fmd_adm_t *ap, id_t id, fmd_adm_stats_t *sp)
815 {
816 	struct fmd_rpc_modstat rms;
817 
818 	if (sp == NULL)
819 		return (fmd_adm_set_errno(ap, EINVAL));
820 
821 	bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
822 
823 	if (fmd_adm_xprtstat_1(id, &rms, ap->adm_clnt) != RPC_SUCCESS)
824 		return (fmd_adm_set_errno(ap, EPROTO));
825 
826 	if (rms.rms_err != 0) {
827 		xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
828 		return (fmd_adm_set_svcerr(ap, rms.rms_err));
829 	}
830 
831 	sp->ams_buf = rms.rms_buf.rms_buf_val;
832 	sp->ams_len = rms.rms_buf.rms_buf_len;
833 
834 	return (0);
835 }
836 
837 int
838 fmd_adm_log_rotate(fmd_adm_t *ap, const char *log)
839 {
840 	int err;
841 
842 	if (log == NULL)
843 		return (fmd_adm_set_errno(ap, EINVAL));
844 
845 	if (fmd_adm_logrotate_1((char *)log, &err, ap->adm_clnt) != RPC_SUCCESS)
846 		return (fmd_adm_set_errno(ap, EPROTO));
847 
848 	return (fmd_adm_set_svcerr(ap, err));
849 }
850 
851 /*
852  * Custom XDR routine for our API structure fmd_stat_t.  This function must
853  * match the definition of fmd_stat_t in <fm/fmd_api.h> and must also match
854  * the corresponding routine in usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c.
855  */
856 bool_t
857 xdr_fmd_stat(XDR *xp, fmd_stat_t *sp)
858 {
859 	bool_t rv = TRUE;
860 
861 	rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name));
862 	rv &= xdr_u_int(xp, &sp->fmds_type);
863 	rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc));
864 
865 	switch (sp->fmds_type) {
866 	case FMD_TYPE_BOOL:
867 		rv &= xdr_int(xp, &sp->fmds_value.bool);
868 		break;
869 	case FMD_TYPE_INT32:
870 		rv &= xdr_int32_t(xp, &sp->fmds_value.i32);
871 		break;
872 	case FMD_TYPE_UINT32:
873 		rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32);
874 		break;
875 	case FMD_TYPE_INT64:
876 		rv &= xdr_int64_t(xp, &sp->fmds_value.i64);
877 		break;
878 	case FMD_TYPE_UINT64:
879 	case FMD_TYPE_TIME:
880 	case FMD_TYPE_SIZE:
881 		rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64);
882 		break;
883 	case FMD_TYPE_STRING:
884 		rv &= xdr_string(xp, &sp->fmds_value.str, ~0);
885 		break;
886 	}
887 
888 	return (rv);
889 }
890