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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <strings.h> 28 #include <stdlib.h> 29 #include <netdir.h> 30 #include <errno.h> 31 #include <alloca.h> 32 #include <locale.h> 33 #include <uuid/uuid.h> 34 35 #include <sys/fm/protocol.h> 36 #include <fmd_adm_impl.h> 37 #include <fmd_rpc_adm.h> 38 39 static const uint_t _fmd_adm_bufsize = 128 * 1024; 40 static const char _url_fallback[] = "http://sun.com/msg/"; 41 42 fmd_adm_t * 43 fmd_adm_open(const char *host, uint32_t prog, int version) 44 { 45 fmd_adm_t *ap; 46 CLIENT *c; 47 rpcvers_t v; 48 49 if (version != FMD_ADM_VERSION) { 50 errno = ENOTSUP; 51 return (NULL); 52 } 53 54 if (host == NULL) 55 host = HOST_SELF; 56 57 if (prog == FMD_ADM_PROGRAM) 58 prog = FMD_ADM; 59 60 if ((ap = malloc(sizeof (fmd_adm_t))) == NULL) 61 return (NULL); 62 63 if (strcmp(host, HOST_SELF) == 0) { 64 c = clnt_door_create(prog, FMD_ADM_VERSION_1, _fmd_adm_bufsize); 65 ap->adm_maxretries = 1; 66 } else { 67 c = clnt_create_vers(host, prog, &v, 68 FMD_ADM_VERSION_1, FMD_ADM_VERSION_1, NULL); 69 ap->adm_maxretries = 0; 70 } 71 72 if (c == NULL) { 73 errno = EPROTO; 74 free(ap); 75 return (NULL); 76 } 77 78 ap->adm_prog = prog; 79 ap->adm_clnt = c; 80 ap->adm_version = version; 81 ap->adm_svcerr = 0; 82 ap->adm_errno = 0; 83 84 return (ap); 85 } 86 87 void 88 fmd_adm_close(fmd_adm_t *ap) 89 { 90 if (ap == NULL) 91 return; /* permit NULL to simply caller code */ 92 93 clnt_destroy(ap->adm_clnt); 94 free(ap); 95 } 96 97 static const char * 98 fmd_adm_svc_errmsg(enum fmd_adm_error err) 99 { 100 switch (err) { 101 case FMD_ADM_ERR_NOMEM: 102 return ("unable to perform request due to allocation failure"); 103 case FMD_ADM_ERR_PERM: 104 return ("operation requires additional privilege"); 105 case FMD_ADM_ERR_MODSRCH: 106 return ("specified module is not loaded in fault manager"); 107 case FMD_ADM_ERR_MODBUSY: 108 return ("module is in use and cannot be unloaded"); 109 case FMD_ADM_ERR_MODFAIL: 110 return ("module failed and can no longer export statistics"); 111 case FMD_ADM_ERR_MODNOENT: 112 return ("file missing or cannot be accessed by fault manager"); 113 case FMD_ADM_ERR_MODEXIST: 114 return ("module using same name is already loaded"); 115 case FMD_ADM_ERR_MODINIT: 116 return ("module failed to initialize (consult fmd(1M) log)"); 117 case FMD_ADM_ERR_MODLOAD: 118 return ("module failed to load (consult fmd(1M) log)"); 119 case FMD_ADM_ERR_RSRCSRCH: 120 return ("specified resource is not cached by fault manager"); 121 case FMD_ADM_ERR_RSRCNOTF: 122 return ("specified resource is not known to be faulty"); 123 case FMD_ADM_ERR_SERDSRCH: 124 return ("specified serd engine not present in module"); 125 case FMD_ADM_ERR_SERDFIRED: 126 return ("specified serd engine has already fired"); 127 case FMD_ADM_ERR_ROTSRCH: 128 return ("invalid log file name"); 129 case FMD_ADM_ERR_ROTFAIL: 130 return ("failed to rotate log file (consult fmd(1M) log)"); 131 case FMD_ADM_ERR_ROTBUSY: 132 return ("log file is too busy to rotate (try again later)"); 133 case FMD_ADM_ERR_CASESRCH: 134 return ("specified UUID is invalid or has been repaired"); 135 case FMD_ADM_ERR_CASEOPEN: 136 return ("specified UUID is still being diagnosed"); 137 case FMD_ADM_ERR_XPRTSRCH: 138 return ("specified transport ID is invalid or has been closed"); 139 case FMD_ADM_ERR_CASEXPRT: 140 return ("specified UUID is owned by a different fault manager"); 141 case FMD_ADM_ERR_RSRCNOTR: 142 return ("specified resource has not been replaced"); 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 /* 200 * If the server (fmd) is restarted, this will cause all future door calls to 201 * fail. Unfortunately, once the server comes back up, we have no way of 202 * reestablishing the connection. To get around this, if the error indicates 203 * that the RPC call failed, we reopen the client handle and try again. For 204 * simplicity we only deal with the door case, as it's unclear whether the 205 * remote case suffers from the same pathology. 206 */ 207 boolean_t 208 fmd_adm_retry(fmd_adm_t *ap, enum clnt_stat cs, uint_t *retries) 209 { 210 CLIENT *c; 211 struct rpc_err err; 212 213 if (cs == RPC_SUCCESS || *retries == ap->adm_maxretries) 214 return (B_FALSE); 215 216 clnt_geterr(ap->adm_clnt, &err); 217 if (err.re_status != RPC_CANTSEND) 218 return (B_FALSE); 219 220 if ((c = clnt_door_create(ap->adm_prog, FMD_ADM_VERSION_1, 221 _fmd_adm_bufsize)) == NULL) 222 return (B_FALSE); 223 224 (*retries)++; 225 226 clnt_destroy(ap->adm_clnt); 227 ap->adm_clnt = c; 228 229 return (B_TRUE); 230 } 231 232 int 233 fmd_adm_stats_read(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp) 234 { 235 struct fmd_rpc_modstat rms; 236 enum clnt_stat cs; 237 uint_t retries = 0; 238 239 if (sp == NULL) 240 return (fmd_adm_set_errno(ap, EINVAL)); 241 242 bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */ 243 244 do { 245 if (name != NULL) 246 cs = fmd_adm_modcstat_1((char *)name, &rms, 247 ap->adm_clnt); 248 else 249 cs = fmd_adm_modgstat_1(&rms, ap->adm_clnt); 250 } while (fmd_adm_retry(ap, cs, &retries)); 251 252 if (cs != RPC_SUCCESS) 253 return (fmd_adm_set_errno(ap, EPROTO)); 254 255 if (rms.rms_err != 0) { 256 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms); 257 return (fmd_adm_set_svcerr(ap, rms.rms_err)); 258 } 259 260 sp->ams_buf = rms.rms_buf.rms_buf_val; 261 sp->ams_len = rms.rms_buf.rms_buf_len; 262 263 if (sp->ams_len != 0) { 264 qsort(sp->ams_buf, sp->ams_len, 265 sizeof (fmd_stat_t), fmd_adm_stats_cmp); 266 } 267 268 return (0); 269 } 270 271 int 272 fmd_adm_stats_free(fmd_adm_t *ap, fmd_adm_stats_t *sp) 273 { 274 struct fmd_rpc_modstat rms; 275 276 if (sp == NULL) 277 return (fmd_adm_set_errno(ap, EINVAL)); 278 279 rms.rms_buf.rms_buf_val = sp->ams_buf; 280 rms.rms_buf.rms_buf_len = sp->ams_len; 281 rms.rms_err = 0; 282 283 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms); 284 bzero(sp, sizeof (fmd_adm_stats_t)); 285 286 return (0); 287 } 288 289 static int 290 fmd_adm_module_cmp(const void *lp, const void *rp) 291 { 292 return (strcmp((*(struct fmd_rpc_modinfo **)lp)->rmi_name, 293 (*(struct fmd_rpc_modinfo **)rp)->rmi_name)); 294 } 295 296 int 297 fmd_adm_module_iter(fmd_adm_t *ap, fmd_adm_module_f *func, void *arg) 298 { 299 struct fmd_rpc_modinfo *rmi, **rms, **rmp; 300 struct fmd_rpc_modlist rml; 301 fmd_adm_modinfo_t ami; 302 enum clnt_stat cs; 303 uint_t retries = 0; 304 305 bzero(&rml, sizeof (rml)); /* tell xdr to allocate memory for us */ 306 307 do { 308 cs = fmd_adm_modinfo_1(&rml, ap->adm_clnt); 309 } while (fmd_adm_retry(ap, cs, &retries)); 310 311 if (cs != RPC_SUCCESS) 312 return (fmd_adm_set_errno(ap, EPROTO)); 313 314 if (rml.rml_err != 0 || rml.rml_len == 0) { 315 xdr_free(xdr_fmd_rpc_modlist, (char *)&rml); 316 return (fmd_adm_set_svcerr(ap, rml.rml_err)); 317 } 318 319 if ((rms = rmp = malloc(sizeof (void *) * rml.rml_len)) == NULL) { 320 xdr_free(xdr_fmd_rpc_modlist, (char *)&rml); 321 return (fmd_adm_set_errno(ap, EAGAIN)); 322 } 323 324 for (rmi = rml.rml_list; rmi != NULL; rmi = rmi->rmi_next) 325 *rmp++ = rmi; /* store copy of pointer in array for sorting */ 326 327 qsort(rms, rml.rml_len, sizeof (void *), fmd_adm_module_cmp); 328 329 for (rmp = rms; rmp < rms + rml.rml_len; rmp++) { 330 rmi = *rmp; 331 332 ami.ami_name = rmi->rmi_name; 333 ami.ami_desc = rmi->rmi_desc; 334 ami.ami_vers = rmi->rmi_vers; 335 ami.ami_flags = 0; 336 337 if (rmi->rmi_faulty) 338 ami.ami_flags |= FMD_ADM_MOD_FAILED; 339 340 if (func(&ami, arg) != 0) 341 break; 342 } 343 344 free(rms); 345 xdr_free(xdr_fmd_rpc_modlist, (char *)&rml); 346 return (0); 347 } 348 349 int 350 fmd_adm_module_load(fmd_adm_t *ap, const char *path) 351 { 352 char *str = (char *)path; 353 int err; 354 enum clnt_stat cs; 355 uint_t retries = 0; 356 357 if (path == NULL || path[0] != '/') 358 return (fmd_adm_set_errno(ap, EINVAL)); 359 360 do { 361 cs = fmd_adm_modload_1(str, &err, ap->adm_clnt); 362 } while (fmd_adm_retry(ap, cs, &retries)); 363 364 if (cs != RPC_SUCCESS) 365 return (fmd_adm_set_errno(ap, EPROTO)); 366 367 return (fmd_adm_set_svcerr(ap, err)); 368 } 369 370 int 371 fmd_adm_module_unload(fmd_adm_t *ap, const char *name) 372 { 373 char *str = (char *)name; 374 int err; 375 enum clnt_stat cs; 376 uint_t retries = 0; 377 378 if (name == NULL || strchr(name, '/') != NULL) 379 return (fmd_adm_set_errno(ap, EINVAL)); 380 381 do { 382 cs = fmd_adm_modunload_1(str, &err, ap->adm_clnt); 383 } while (fmd_adm_retry(ap, cs, &retries)); 384 385 if (cs != RPC_SUCCESS) 386 return (fmd_adm_set_errno(ap, EPROTO)); 387 388 return (fmd_adm_set_svcerr(ap, err)); 389 } 390 391 int 392 fmd_adm_module_reset(fmd_adm_t *ap, const char *name) 393 { 394 char *str = (char *)name; 395 int err; 396 enum clnt_stat cs; 397 uint_t retries = 0; 398 399 if (name == NULL || strchr(name, '/') != NULL) 400 return (fmd_adm_set_errno(ap, EINVAL)); 401 402 do { 403 cs = fmd_adm_modreset_1(str, &err, ap->adm_clnt); 404 } while (fmd_adm_retry(ap, cs, &retries)); 405 406 if (cs != RPC_SUCCESS) 407 return (fmd_adm_set_errno(ap, EPROTO)); 408 409 return (fmd_adm_set_svcerr(ap, err)); 410 } 411 412 int 413 fmd_adm_module_gc(fmd_adm_t *ap, const char *name) 414 { 415 char *str = (char *)name; 416 int err; 417 enum clnt_stat cs; 418 uint_t retries = 0; 419 420 if (name == NULL || strchr(name, '/') != NULL) 421 return (fmd_adm_set_errno(ap, EINVAL)); 422 423 do { 424 cs = fmd_adm_modgc_1(str, &err, ap->adm_clnt); 425 } while (fmd_adm_retry(ap, cs, &retries)); 426 427 if (cs != RPC_SUCCESS) 428 return (fmd_adm_set_errno(ap, EPROTO)); 429 430 return (fmd_adm_set_svcerr(ap, err)); 431 } 432 433 int 434 fmd_adm_module_stats(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp) 435 { 436 struct fmd_rpc_modstat rms; 437 enum clnt_stat cs; 438 uint_t retries = 0; 439 440 if (name == NULL || sp == NULL) 441 return (fmd_adm_set_errno(ap, EINVAL)); 442 443 bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */ 444 445 do { 446 cs = fmd_adm_moddstat_1((char *)name, &rms, ap->adm_clnt); 447 } while (fmd_adm_retry(ap, cs, &retries)); 448 449 if (cs != RPC_SUCCESS) 450 return (fmd_adm_set_errno(ap, EPROTO)); 451 452 if (rms.rms_err != 0) { 453 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms); 454 return (fmd_adm_set_svcerr(ap, rms.rms_err)); 455 } 456 457 sp->ams_buf = rms.rms_buf.rms_buf_val; 458 sp->ams_len = rms.rms_buf.rms_buf_len; 459 460 return (0); 461 } 462 463 int 464 fmd_adm_rsrc_count(fmd_adm_t *ap, int all, uint32_t *rcp) 465 { 466 struct fmd_rpc_rsrclist rrl; 467 enum clnt_stat cs; 468 uint_t retries = 0; 469 470 if (rcp == NULL) 471 return (fmd_adm_set_errno(ap, EINVAL)); 472 473 bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */ 474 475 do { 476 cs = fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt); 477 } while (fmd_adm_retry(ap, cs, &retries)); 478 479 if (cs != RPC_SUCCESS) 480 return (fmd_adm_set_errno(ap, EPROTO)); 481 482 if (rrl.rrl_err != 0) { 483 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl); 484 return (fmd_adm_set_svcerr(ap, rrl.rrl_err)); 485 } 486 487 *rcp = rrl.rrl_cnt; 488 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl); 489 return (0); 490 } 491 492 static int 493 fmd_adm_rsrc_cmp(const void *lp, const void *rp) 494 { 495 return (strcmp(*(char **)lp, *(char **)rp)); 496 } 497 498 int 499 fmd_adm_rsrc_iter(fmd_adm_t *ap, int all, fmd_adm_rsrc_f *func, void *arg) 500 { 501 struct fmd_rpc_rsrclist rrl; 502 struct fmd_rpc_rsrcinfo rri; 503 fmd_adm_rsrcinfo_t ari; 504 char **fmris, *p; 505 int i, rv; 506 enum clnt_stat cs; 507 uint_t retries = 0; 508 509 bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */ 510 511 do { 512 cs = fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt); 513 } while (fmd_adm_retry(ap, cs, &retries)); 514 515 if (cs != RPC_SUCCESS) 516 return (fmd_adm_set_errno(ap, EPROTO)); 517 518 if (rrl.rrl_err != 0) { 519 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl); 520 return (fmd_adm_set_svcerr(ap, rrl.rrl_err)); 521 } 522 523 if ((fmris = malloc(sizeof (char *) * rrl.rrl_cnt)) == NULL) { 524 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl); 525 return (fmd_adm_set_errno(ap, EAGAIN)); 526 } 527 528 /* 529 * The fmd_adm_rsrclist_1 request returns an opaque XDR buffer that is 530 * a string table of FMRIs (e.g. "fmriA\0fmriB\0...") where rrl_cnt is 531 * the number of strings in the table and rrl_buf_val is its address. 532 * We construct an array of pointers into the string table and sort it. 533 */ 534 p = rrl.rrl_buf.rrl_buf_val; 535 536 for (i = 0; i < rrl.rrl_cnt; i++, p += strlen(p) + 1) 537 fmris[i] = p; /* store fmri pointer in array for sorting */ 538 539 qsort(fmris, rrl.rrl_cnt, sizeof (char *), fmd_adm_rsrc_cmp); 540 541 /* 542 * For each FMRI in the resource cache snapshot, use fmd_adm_rsrcinfo_1 543 * to get more information and the invoke the callback function. If 544 * FMD_ADM_ERR_RSRCSRCH is returned, the FMRI has been purged from the 545 * cache since our snapshot: this error is therefore silently ignored. 546 */ 547 for (i = 0; i < rrl.rrl_cnt; i++) { 548 bzero(&rri, sizeof (rri)); 549 550 retries = 0; 551 do { 552 cs = fmd_adm_rsrcinfo_1(fmris[i], &rri, ap->adm_clnt); 553 } while (fmd_adm_retry(ap, cs, &retries)); 554 555 if (cs != RPC_SUCCESS) { 556 free(fmris); 557 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl); 558 return (fmd_adm_set_errno(ap, EPROTO)); 559 } 560 561 if (rri.rri_err != 0 && rri.rri_err != FMD_ADM_ERR_RSRCSRCH) { 562 xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri); 563 free(fmris); 564 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl); 565 return (fmd_adm_set_svcerr(ap, rri.rri_err)); 566 } 567 568 if (rri.rri_err == FMD_ADM_ERR_RSRCSRCH) { 569 xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri); 570 continue; 571 } 572 573 ari.ari_fmri = rri.rri_fmri; 574 ari.ari_uuid = rri.rri_uuid; 575 ari.ari_case = rri.rri_case; 576 ari.ari_flags = 0; 577 578 if (rri.rri_faulty) 579 ari.ari_flags |= FMD_ADM_RSRC_FAULTY; 580 if (rri.rri_unusable) 581 ari.ari_flags |= FMD_ADM_RSRC_UNUSABLE; 582 if (rri.rri_invisible) 583 ari.ari_flags |= FMD_ADM_RSRC_INVISIBLE; 584 585 rv = func(&ari, arg); 586 xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri); 587 588 if (rv != 0) 589 break; 590 } 591 592 free(fmris); 593 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl); 594 return (0); 595 } 596 597 int 598 fmd_adm_rsrc_flush(fmd_adm_t *ap, const char *fmri) 599 { 600 char *str = (char *)fmri; 601 int err; 602 enum clnt_stat cs; 603 uint_t retries = 0; 604 605 if (fmri == NULL) 606 return (fmd_adm_set_errno(ap, EINVAL)); 607 608 do { 609 cs = fmd_adm_rsrcflush_1(str, &err, ap->adm_clnt); 610 } while (fmd_adm_retry(ap, cs, &retries)); 611 612 if (cs != RPC_SUCCESS) 613 return (fmd_adm_set_errno(ap, EPROTO)); 614 615 return (fmd_adm_set_svcerr(ap, err)); 616 } 617 618 int 619 fmd_adm_rsrc_repaired(fmd_adm_t *ap, const char *fmri) 620 { 621 char *str = (char *)fmri; 622 int err; 623 enum clnt_stat cs; 624 uint_t retries = 0; 625 626 if (fmri == NULL) 627 return (fmd_adm_set_errno(ap, EINVAL)); 628 629 do { 630 cs = fmd_adm_rsrcrepaired_1(str, &err, ap->adm_clnt); 631 } while (fmd_adm_retry(ap, cs, &retries)); 632 633 if (cs != RPC_SUCCESS) 634 return (fmd_adm_set_errno(ap, EPROTO)); 635 636 return (fmd_adm_set_svcerr(ap, err)); 637 } 638 639 int 640 fmd_adm_rsrc_replaced(fmd_adm_t *ap, const char *fmri) 641 { 642 char *str = (char *)fmri; 643 int err; 644 enum clnt_stat cs; 645 uint_t retries = 0; 646 647 if (fmri == NULL) 648 return (fmd_adm_set_errno(ap, EINVAL)); 649 650 do { 651 cs = fmd_adm_rsrcreplaced_1(str, &err, ap->adm_clnt); 652 } while (fmd_adm_retry(ap, cs, &retries)); 653 654 if (cs != RPC_SUCCESS) 655 return (fmd_adm_set_errno(ap, EPROTO)); 656 657 return (fmd_adm_set_svcerr(ap, err)); 658 } 659 660 int 661 fmd_adm_rsrc_acquit(fmd_adm_t *ap, const char *fmri, const char *uuid) 662 { 663 char *str = (char *)fmri; 664 char *str2 = (char *)uuid; 665 int err; 666 enum clnt_stat cs; 667 uint_t retries = 0; 668 669 if (fmri == NULL) 670 return (fmd_adm_set_errno(ap, EINVAL)); 671 672 do { 673 cs = fmd_adm_rsrcacquit_1(str, str2, &err, ap->adm_clnt); 674 } while (fmd_adm_retry(ap, cs, &retries)); 675 676 if (cs != RPC_SUCCESS) 677 return (fmd_adm_set_errno(ap, EPROTO)); 678 679 return (fmd_adm_set_svcerr(ap, err)); 680 } 681 682 int 683 fmd_adm_case_repair(fmd_adm_t *ap, const char *uuid) 684 { 685 char *str = (char *)uuid; 686 int err; 687 enum clnt_stat cs; 688 uint_t retries = 0; 689 690 if (uuid == NULL) 691 return (fmd_adm_set_errno(ap, EINVAL)); 692 693 do { 694 cs = fmd_adm_caserepair_1(str, &err, ap->adm_clnt); 695 } while (fmd_adm_retry(ap, cs, &retries)); 696 697 if (cs != RPC_SUCCESS) 698 return (fmd_adm_set_errno(ap, EPROTO)); 699 700 return (fmd_adm_set_svcerr(ap, err)); 701 } 702 703 int 704 fmd_adm_case_acquit(fmd_adm_t *ap, const char *uuid) 705 { 706 char *str = (char *)uuid; 707 int err; 708 enum clnt_stat cs; 709 uint_t retries = 0; 710 711 if (uuid == NULL) 712 return (fmd_adm_set_errno(ap, EINVAL)); 713 714 do { 715 cs = fmd_adm_caseacquit_1(str, &err, ap->adm_clnt); 716 } while (fmd_adm_retry(ap, cs, &retries)); 717 718 if (cs != RPC_SUCCESS) 719 return (fmd_adm_set_errno(ap, EPROTO)); 720 721 return (fmd_adm_set_svcerr(ap, err)); 722 } 723 724 static int 725 fmd_adm_case_cmp(const void *lp, const void *rp) 726 { 727 return (strcmp(*(char **)lp, *(char **)rp)); 728 } 729 730 static int 731 fmd_adm_case_one(fmd_adm_caseinfo_t *acp, const char *url_token, 732 fmd_adm_case_f *func, void *arg) 733 { 734 char *p, *urlcode, *dict, *olang; 735 const char *url; 736 size_t len; 737 738 if ((p = strchr(acp->aci_code, '-')) == NULL || 739 p == acp->aci_code) { 740 acp->aci_url = NULL; 741 } else { 742 dict = alloca((size_t)(p - acp->aci_code) + 1); 743 (void) strncpy(dict, acp->aci_code, 744 (size_t)(p - acp->aci_code)); 745 dict[(size_t)(p - acp->aci_code)] = '\0'; 746 747 /* 748 * If we're given a token to use in looking up the URL, try 749 * to use it. Otherwise, or if we don't find it that way, 750 * use the fallback. 751 */ 752 if (url_token == NULL) { 753 url = _url_fallback; 754 } else if ((url = dgettext(dict, url_token)) == url_token) { 755 /* 756 * We didn't find a translation in the 757 * dictionary for the current language. Fall 758 * back to C and try again. 759 */ 760 olang = setlocale(LC_MESSAGES, NULL); 761 (void) setlocale(LC_MESSAGES, "C"); 762 if ((url = dgettext(dict, url_token)) == url_token) 763 url = _url_fallback; 764 (void) setlocale(LC_MESSAGES, olang); 765 } 766 len = strlen(url); 767 if (url[len - 1] == '/') { 768 len += strlen(acp->aci_code) + 1; 769 urlcode = alloca(len); 770 (void) snprintf(urlcode, len, "%s%s", url, 771 acp->aci_code); 772 } else { 773 urlcode = (char *)url; 774 } 775 acp->aci_url = urlcode; 776 } 777 778 return (func(acp, arg)); 779 } 780 781 /* 782 * Our approach to cases is the same as for resources: we first obtain a 783 * list of UUIDs, sort them, then obtain the case information for each. 784 */ 785 int 786 fmd_adm_case_iter(fmd_adm_t *ap, const char *url_token, fmd_adm_case_f *func, 787 void *arg) 788 { 789 struct fmd_rpc_caselist rcl; 790 struct fmd_rpc_caseinfo rci; 791 fmd_adm_caseinfo_t aci; 792 char **uuids, *p; 793 int i, rv; 794 enum clnt_stat cs; 795 uint_t retries = 0; 796 797 bzero(&rcl, sizeof (rcl)); /* tell xdr to allocate memory for us */ 798 799 do { 800 cs = fmd_adm_caselist_1(&rcl, ap->adm_clnt); 801 } while (fmd_adm_retry(ap, cs, &retries)); 802 803 if (cs != RPC_SUCCESS) 804 return (fmd_adm_set_errno(ap, EPROTO)); 805 806 if (rcl.rcl_err != 0) { 807 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 808 return (fmd_adm_set_svcerr(ap, rcl.rcl_err)); 809 } 810 811 if ((uuids = malloc(sizeof (char *) * rcl.rcl_cnt)) == NULL) { 812 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 813 return (fmd_adm_set_errno(ap, EAGAIN)); 814 } 815 816 p = rcl.rcl_buf.rcl_buf_val; 817 818 for (i = 0; i < rcl.rcl_cnt; i++, p += strlen(p) + 1) 819 uuids[i] = p; 820 821 qsort(uuids, rcl.rcl_cnt, sizeof (char *), fmd_adm_case_cmp); 822 823 for (i = 0; i < rcl.rcl_cnt; i++) { 824 bzero(&rci, sizeof (rci)); 825 826 retries = 0; 827 do { 828 cs = fmd_adm_caseinfo_1(uuids[i], &rci, ap->adm_clnt); 829 } while (fmd_adm_retry(ap, cs, &retries)); 830 831 if (cs != RPC_SUCCESS) { 832 free(uuids); 833 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 834 return (fmd_adm_set_errno(ap, EPROTO)); 835 } 836 837 if (rci.rci_err != 0 && rci.rci_err != FMD_ADM_ERR_CASESRCH) { 838 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 839 free(uuids); 840 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 841 return (fmd_adm_set_svcerr(ap, rci.rci_err)); 842 } 843 844 if (rci.rci_err == FMD_ADM_ERR_CASESRCH) { 845 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 846 continue; 847 } 848 849 bzero(&aci, sizeof (aci)); 850 851 if ((rv = nvlist_unpack(rci.rci_evbuf.rci_evbuf_val, 852 rci.rci_evbuf.rci_evbuf_len, &aci.aci_event, 0)) != 0) { 853 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 854 free(uuids); 855 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 856 return (fmd_adm_set_errno(ap, rv)); 857 } 858 859 if ((rv = nvlist_lookup_string(aci.aci_event, FM_SUSPECT_UUID, 860 (char **)&aci.aci_uuid)) != 0) { 861 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 862 free(uuids); 863 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 864 nvlist_free(aci.aci_event); 865 return (fmd_adm_set_errno(ap, rv)); 866 } 867 if ((rv = nvlist_lookup_string(aci.aci_event, 868 FM_SUSPECT_DIAG_CODE, (char **)&aci.aci_code)) != 0) { 869 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 870 free(uuids); 871 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 872 nvlist_free(aci.aci_event); 873 return (fmd_adm_set_errno(ap, rv)); 874 } 875 876 rv = fmd_adm_case_one(&aci, url_token, func, arg); 877 878 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 879 nvlist_free(aci.aci_event); 880 881 if (rv != 0) 882 break; 883 } 884 885 free(uuids); 886 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 887 return (0); 888 } 889 890 static int 891 fmd_adm_serd_cmp(const void *lp, const void *rp) 892 { 893 return (strcmp((*(struct fmd_rpc_serdinfo **)lp)->rsi_name, 894 (*(struct fmd_rpc_serdinfo **)rp)->rsi_name)); 895 } 896 897 int 898 fmd_adm_serd_iter(fmd_adm_t *ap, const char *name, 899 fmd_adm_serd_f *func, void *arg) 900 { 901 struct fmd_rpc_serdinfo *rsi, **ris, **rip; 902 struct fmd_rpc_serdlist rsl; 903 fmd_adm_serdinfo_t asi; 904 enum clnt_stat cs; 905 uint_t retries = 0; 906 907 bzero(&rsl, sizeof (rsl)); /* tell xdr to allocate memory for us */ 908 909 do { 910 cs = fmd_adm_serdinfo_1((char *)name, &rsl, ap->adm_clnt); 911 } while (fmd_adm_retry(ap, cs, &retries)); 912 913 if (cs != RPC_SUCCESS) 914 return (fmd_adm_set_errno(ap, EPROTO)); 915 916 if (rsl.rsl_err != 0 || rsl.rsl_len == 0) { 917 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 918 return (fmd_adm_set_svcerr(ap, rsl.rsl_err)); 919 } 920 921 if ((ris = rip = malloc(sizeof (void *) * rsl.rsl_len)) == NULL) { 922 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 923 return (fmd_adm_set_errno(ap, EAGAIN)); 924 } 925 926 for (rsi = rsl.rsl_list; rsi != NULL; rsi = rsi->rsi_next) 927 *rip++ = rsi; /* store copy of pointer in array for sorting */ 928 929 qsort(ris, rsl.rsl_len, sizeof (void *), fmd_adm_serd_cmp); 930 931 for (rip = ris; rip < ris + rsl.rsl_len; rip++) { 932 rsi = *rip; 933 934 asi.asi_name = rsi->rsi_name; 935 asi.asi_delta = rsi->rsi_delta; 936 asi.asi_n = rsi->rsi_n; 937 asi.asi_t = rsi->rsi_t; 938 asi.asi_count = rsi->rsi_count; 939 asi.asi_flags = 0; 940 941 if (rsi->rsi_fired) 942 asi.asi_flags |= FMD_ADM_SERD_FIRED; 943 944 if (func(&asi, arg) != 0) 945 break; 946 } 947 948 free(ris); 949 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 950 return (0); 951 } 952 953 int 954 fmd_adm_serd_reset(fmd_adm_t *ap, const char *mod, const char *name) 955 { 956 char *s1 = (char *)mod, *s2 = (char *)name; 957 int err; 958 enum clnt_stat cs; 959 uint_t retries = 0; 960 961 if (mod == NULL || name == NULL || strchr(mod, '/') != NULL) 962 return (fmd_adm_set_errno(ap, EINVAL)); 963 964 do { 965 cs = fmd_adm_serdreset_1(s1, s2, &err, ap->adm_clnt); 966 } while (fmd_adm_retry(ap, cs, &retries)); 967 968 if (cs != RPC_SUCCESS) 969 return (fmd_adm_set_errno(ap, EPROTO)); 970 971 return (fmd_adm_set_svcerr(ap, err)); 972 } 973 974 int 975 fmd_adm_xprt_iter(fmd_adm_t *ap, fmd_adm_xprt_f *func, void *arg) 976 { 977 struct fmd_rpc_xprtlist rxl; 978 uint_t i; 979 enum clnt_stat cs; 980 uint_t retries = 0; 981 982 bzero(&rxl, sizeof (rxl)); /* tell xdr to allocate memory for us */ 983 984 do { 985 cs = fmd_adm_xprtlist_1(&rxl, ap->adm_clnt); 986 } while (fmd_adm_retry(ap, cs, &retries)); 987 988 if (cs != RPC_SUCCESS) 989 return (fmd_adm_set_errno(ap, EPROTO)); 990 991 if (rxl.rxl_err != 0) { 992 xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl); 993 return (fmd_adm_set_svcerr(ap, rxl.rxl_err)); 994 } 995 996 for (i = 0; i < rxl.rxl_len; i++) 997 func(rxl.rxl_buf.rxl_buf_val[i], arg); 998 999 xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl); 1000 return (0); 1001 } 1002 1003 int 1004 fmd_adm_xprt_stats(fmd_adm_t *ap, id_t id, fmd_adm_stats_t *sp) 1005 { 1006 struct fmd_rpc_modstat rms; 1007 enum clnt_stat cs; 1008 uint_t retries = 0; 1009 1010 if (sp == NULL) 1011 return (fmd_adm_set_errno(ap, EINVAL)); 1012 1013 bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */ 1014 1015 do { 1016 cs = fmd_adm_xprtstat_1(id, &rms, ap->adm_clnt); 1017 } while (fmd_adm_retry(ap, cs, &retries)); 1018 1019 if (cs != RPC_SUCCESS) 1020 return (fmd_adm_set_errno(ap, EPROTO)); 1021 1022 if (rms.rms_err != 0) { 1023 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms); 1024 return (fmd_adm_set_svcerr(ap, rms.rms_err)); 1025 } 1026 1027 sp->ams_buf = rms.rms_buf.rms_buf_val; 1028 sp->ams_len = rms.rms_buf.rms_buf_len; 1029 1030 return (0); 1031 } 1032 1033 int 1034 fmd_adm_log_rotate(fmd_adm_t *ap, const char *log) 1035 { 1036 int err; 1037 enum clnt_stat cs; 1038 uint_t retries = 0; 1039 1040 if (log == NULL) 1041 return (fmd_adm_set_errno(ap, EINVAL)); 1042 1043 do { 1044 cs = fmd_adm_logrotate_1((char *)log, &err, ap->adm_clnt); 1045 } while (fmd_adm_retry(ap, cs, &retries)); 1046 1047 if (cs != RPC_SUCCESS) 1048 return (fmd_adm_set_errno(ap, EPROTO)); 1049 1050 return (fmd_adm_set_svcerr(ap, err)); 1051 } 1052 1053 /* 1054 * Custom XDR routine for our API structure fmd_stat_t. This function must 1055 * match the definition of fmd_stat_t in <fm/fmd_api.h> and must also match 1056 * the corresponding routine in usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c. 1057 */ 1058 bool_t 1059 xdr_fmd_stat(XDR *xp, fmd_stat_t *sp) 1060 { 1061 bool_t rv = TRUE; 1062 1063 rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name)); 1064 rv &= xdr_u_int(xp, &sp->fmds_type); 1065 rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc)); 1066 1067 switch (sp->fmds_type) { 1068 case FMD_TYPE_BOOL: 1069 rv &= xdr_int(xp, &sp->fmds_value.bool); 1070 break; 1071 case FMD_TYPE_INT32: 1072 rv &= xdr_int32_t(xp, &sp->fmds_value.i32); 1073 break; 1074 case FMD_TYPE_UINT32: 1075 rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32); 1076 break; 1077 case FMD_TYPE_INT64: 1078 rv &= xdr_int64_t(xp, &sp->fmds_value.i64); 1079 break; 1080 case FMD_TYPE_UINT64: 1081 case FMD_TYPE_TIME: 1082 case FMD_TYPE_SIZE: 1083 rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64); 1084 break; 1085 case FMD_TYPE_STRING: 1086 rv &= xdr_string(xp, &sp->fmds_value.str, ~0); 1087 break; 1088 } 1089 1090 return (rv); 1091 } 1092