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