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://illumos.org/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(8) log)"); 117 case FMD_ADM_ERR_MODLOAD: 118 return ("module failed to load (consult fmd(8) 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(8) 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(*(char **)lp, *(char **)rp)); 894 } 895 896 int 897 fmd_adm_serd_iter(fmd_adm_t *ap, const char *name, 898 fmd_adm_serd_f *func, void *arg) 899 { 900 struct fmd_rpc_serdlist rsl; 901 struct fmd_rpc_serdinfo rsi; 902 char **serds, *p; 903 fmd_adm_serdinfo_t asi; 904 enum clnt_stat cs; 905 uint_t retries = 0; 906 int i, rv; 907 908 bzero(&rsl, sizeof (rsl)); /* tell xdr to allocate memory for us */ 909 910 do { 911 cs = fmd_adm_serdlist_1((char *)name, &rsl, ap->adm_clnt); 912 } while (fmd_adm_retry(ap, cs, &retries)); 913 914 if (cs != RPC_SUCCESS) 915 return (fmd_adm_set_errno(ap, EPROTO)); 916 917 if (rsl.rsl_err != 0 || rsl.rsl_len == 0) { 918 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 919 return (fmd_adm_set_svcerr(ap, rsl.rsl_err)); 920 } 921 922 if ((serds = malloc(sizeof (char *) * rsl.rsl_cnt)) == NULL) { 923 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 924 return (fmd_adm_set_errno(ap, EAGAIN)); 925 } 926 927 p = rsl.rsl_buf.rsl_buf_val; 928 929 for (i = 0; i < rsl.rsl_cnt; i++, p += strlen(p) + 1) 930 serds[i] = p; 931 932 qsort(serds, rsl.rsl_cnt, sizeof (char *), fmd_adm_serd_cmp); 933 934 for (i = 0; i < rsl.rsl_cnt; i++) { 935 bzero(&rsi, sizeof (rsi)); 936 937 retries = 0; 938 do { 939 cs = fmd_adm_serdinfo_1((char *)name, serds[i], &rsi, 940 ap->adm_clnt); 941 } while (fmd_adm_retry(ap, cs, &retries)); 942 943 if (cs != RPC_SUCCESS) { 944 free(serds); 945 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 946 return (fmd_adm_set_errno(ap, EPROTO)); 947 } 948 949 if (rsi.rsi_err != 0 && rsi.rsi_err != FMD_ADM_ERR_SERDSRCH) { 950 free(serds); 951 xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi); 952 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 953 return (fmd_adm_set_svcerr(ap, rsi.rsi_err)); 954 } 955 956 if (rsi.rsi_err == FMD_ADM_ERR_SERDSRCH) { 957 xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi); 958 continue; 959 } 960 961 bzero(&asi, sizeof (asi)); 962 963 asi.asi_name = rsi.rsi_name; 964 asi.asi_delta = rsi.rsi_delta; 965 asi.asi_n = rsi.rsi_n; 966 asi.asi_t = rsi.rsi_t; 967 asi.asi_count = rsi.rsi_count; 968 asi.asi_flags = 0; 969 970 if (rsi.rsi_fired) 971 asi.asi_flags |= FMD_ADM_SERD_FIRED; 972 973 rv = func(&asi, arg); 974 975 xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi); 976 977 if (rv != 0) 978 break; 979 } 980 981 free(serds); 982 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 983 return (0); 984 } 985 986 int 987 fmd_adm_serd_reset(fmd_adm_t *ap, const char *mod, const char *name) 988 { 989 char *s1 = (char *)mod, *s2 = (char *)name; 990 int err; 991 enum clnt_stat cs; 992 uint_t retries = 0; 993 994 if (mod == NULL || name == NULL || strchr(mod, '/') != NULL) 995 return (fmd_adm_set_errno(ap, EINVAL)); 996 997 do { 998 cs = fmd_adm_serdreset_1(s1, s2, &err, ap->adm_clnt); 999 } while (fmd_adm_retry(ap, cs, &retries)); 1000 1001 if (cs != RPC_SUCCESS) 1002 return (fmd_adm_set_errno(ap, EPROTO)); 1003 1004 return (fmd_adm_set_svcerr(ap, err)); 1005 } 1006 1007 int 1008 fmd_adm_xprt_iter(fmd_adm_t *ap, fmd_adm_xprt_f *func, void *arg) 1009 { 1010 struct fmd_rpc_xprtlist rxl; 1011 uint_t i; 1012 enum clnt_stat cs; 1013 uint_t retries = 0; 1014 1015 bzero(&rxl, sizeof (rxl)); /* tell xdr to allocate memory for us */ 1016 1017 do { 1018 cs = fmd_adm_xprtlist_1(&rxl, ap->adm_clnt); 1019 } while (fmd_adm_retry(ap, cs, &retries)); 1020 1021 if (cs != RPC_SUCCESS) 1022 return (fmd_adm_set_errno(ap, EPROTO)); 1023 1024 if (rxl.rxl_err != 0) { 1025 xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl); 1026 return (fmd_adm_set_svcerr(ap, rxl.rxl_err)); 1027 } 1028 1029 for (i = 0; i < rxl.rxl_len; i++) 1030 func(rxl.rxl_buf.rxl_buf_val[i], arg); 1031 1032 xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl); 1033 return (0); 1034 } 1035 1036 int 1037 fmd_adm_xprt_stats(fmd_adm_t *ap, id_t id, fmd_adm_stats_t *sp) 1038 { 1039 struct fmd_rpc_modstat rms; 1040 enum clnt_stat cs; 1041 uint_t retries = 0; 1042 1043 if (sp == NULL) 1044 return (fmd_adm_set_errno(ap, EINVAL)); 1045 1046 bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */ 1047 1048 do { 1049 cs = fmd_adm_xprtstat_1(id, &rms, ap->adm_clnt); 1050 } while (fmd_adm_retry(ap, cs, &retries)); 1051 1052 if (cs != RPC_SUCCESS) 1053 return (fmd_adm_set_errno(ap, EPROTO)); 1054 1055 if (rms.rms_err != 0) { 1056 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms); 1057 return (fmd_adm_set_svcerr(ap, rms.rms_err)); 1058 } 1059 1060 sp->ams_buf = rms.rms_buf.rms_buf_val; 1061 sp->ams_len = rms.rms_buf.rms_buf_len; 1062 1063 return (0); 1064 } 1065 1066 int 1067 fmd_adm_log_rotate(fmd_adm_t *ap, const char *log) 1068 { 1069 int err; 1070 enum clnt_stat cs; 1071 uint_t retries = 0; 1072 1073 if (log == NULL) 1074 return (fmd_adm_set_errno(ap, EINVAL)); 1075 1076 do { 1077 cs = fmd_adm_logrotate_1((char *)log, &err, ap->adm_clnt); 1078 } while (fmd_adm_retry(ap, cs, &retries)); 1079 1080 if (cs != RPC_SUCCESS) 1081 return (fmd_adm_set_errno(ap, EPROTO)); 1082 1083 return (fmd_adm_set_svcerr(ap, err)); 1084 } 1085 1086 /* 1087 * Custom XDR routine for our API structure fmd_stat_t. This function must 1088 * match the definition of fmd_stat_t in <fm/fmd_api.h> and must also match 1089 * the corresponding routine in usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c. 1090 */ 1091 bool_t 1092 xdr_fmd_stat(XDR *xp, fmd_stat_t *sp) 1093 { 1094 bool_t rv = TRUE; 1095 1096 rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name)); 1097 rv &= xdr_u_int(xp, &sp->fmds_type); 1098 rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc)); 1099 1100 switch (sp->fmds_type) { 1101 case FMD_TYPE_BOOL: 1102 rv &= xdr_int(xp, &sp->fmds_value.bool); 1103 break; 1104 case FMD_TYPE_INT32: 1105 rv &= xdr_int32_t(xp, &sp->fmds_value.i32); 1106 break; 1107 case FMD_TYPE_UINT32: 1108 rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32); 1109 break; 1110 case FMD_TYPE_INT64: 1111 rv &= xdr_int64_t(xp, &sp->fmds_value.i64); 1112 break; 1113 case FMD_TYPE_UINT64: 1114 case FMD_TYPE_TIME: 1115 case FMD_TYPE_SIZE: 1116 rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64); 1117 break; 1118 case FMD_TYPE_STRING: 1119 rv &= xdr_string(xp, &sp->fmds_value.str, ~0); 1120 break; 1121 } 1122 1123 return (rv); 1124 } 1125