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