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