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 2008 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 rpcvers_t v; 50 51 if (version != FMD_ADM_VERSION) { 52 errno = ENOTSUP; 53 return (NULL); 54 } 55 56 if (host == NULL) 57 host = HOST_SELF; 58 59 if (prog == FMD_ADM_PROGRAM) 60 prog = FMD_ADM; 61 62 if ((ap = malloc(sizeof (fmd_adm_t))) == NULL) 63 return (NULL); 64 65 if (strcmp(host, HOST_SELF) == 0) { 66 c = clnt_door_create(prog, FMD_ADM_VERSION_1, _fmd_adm_bufsize); 67 ap->adm_maxretries = 1; 68 } else { 69 c = clnt_create_vers(host, prog, &v, 70 FMD_ADM_VERSION_1, FMD_ADM_VERSION_1, NULL); 71 ap->adm_maxretries = 0; 72 } 73 74 if (c == NULL) { 75 errno = EPROTO; 76 free(ap); 77 return (NULL); 78 } 79 80 ap->adm_prog = prog; 81 ap->adm_clnt = c; 82 ap->adm_version = version; 83 ap->adm_svcerr = 0; 84 ap->adm_errno = 0; 85 86 return (ap); 87 } 88 89 void 90 fmd_adm_close(fmd_adm_t *ap) 91 { 92 if (ap == NULL) 93 return; /* permit NULL to simply caller code */ 94 95 clnt_destroy(ap->adm_clnt); 96 free(ap); 97 } 98 99 static const char * 100 fmd_adm_svc_errmsg(enum fmd_adm_error err) 101 { 102 switch (err) { 103 case FMD_ADM_ERR_NOMEM: 104 return ("unable to perform request due to allocation failure"); 105 case FMD_ADM_ERR_PERM: 106 return ("operation requires additional privilege"); 107 case FMD_ADM_ERR_MODSRCH: 108 return ("specified module is not loaded in fault manager"); 109 case FMD_ADM_ERR_MODBUSY: 110 return ("module is in use and cannot be unloaded"); 111 case FMD_ADM_ERR_MODFAIL: 112 return ("module failed and can no longer export statistics"); 113 case FMD_ADM_ERR_MODNOENT: 114 return ("file missing or cannot be accessed by fault manager"); 115 case FMD_ADM_ERR_MODEXIST: 116 return ("module using same name is already loaded"); 117 case FMD_ADM_ERR_MODINIT: 118 return ("module failed to initialize (consult fmd(1M) log)"); 119 case FMD_ADM_ERR_MODLOAD: 120 return ("module failed to load (consult fmd(1M) log)"); 121 case FMD_ADM_ERR_RSRCSRCH: 122 return ("specified resource is not cached by fault manager"); 123 case FMD_ADM_ERR_RSRCNOTF: 124 return ("specified resource is not known to be faulty"); 125 case FMD_ADM_ERR_SERDSRCH: 126 return ("specified serd engine not present in module"); 127 case FMD_ADM_ERR_SERDFIRED: 128 return ("specified serd engine has already fired"); 129 case FMD_ADM_ERR_ROTSRCH: 130 return ("invalid log file name"); 131 case FMD_ADM_ERR_ROTFAIL: 132 return ("failed to rotate log file (consult fmd(1M) log)"); 133 case FMD_ADM_ERR_ROTBUSY: 134 return ("log file is too busy to rotate (try again later)"); 135 case FMD_ADM_ERR_CASESRCH: 136 return ("specified UUID is invalid or has been repaired"); 137 case FMD_ADM_ERR_CASEOPEN: 138 return ("specified UUID is still being diagnosed"); 139 case FMD_ADM_ERR_XPRTSRCH: 140 return ("specified transport ID is invalid or has been closed"); 141 case FMD_ADM_ERR_CASEXPRT: 142 return ("specified UUID is owned by a different fault manager"); 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_repair(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_rsrcrepair_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_case_repair(fmd_adm_t *ap, const char *uuid) 641 { 642 char *str = (char *)uuid; 643 int err; 644 enum clnt_stat cs; 645 uint_t retries = 0; 646 647 if (uuid == NULL) 648 return (fmd_adm_set_errno(ap, EINVAL)); 649 650 do { 651 cs = fmd_adm_caserepair_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 static int 661 fmd_adm_case_cmp(const void *lp, const void *rp) 662 { 663 return (strcmp(*(char **)lp, *(char **)rp)); 664 } 665 666 static int 667 fmd_adm_case_one(fmd_adm_caseinfo_t *acp, const char *url_token, 668 fmd_adm_case_f *func, void *arg) 669 { 670 char *p, *urlcode, *dict, *olang; 671 const char *url; 672 size_t len; 673 674 if ((p = strchr(acp->aci_code, '-')) == NULL || 675 p == acp->aci_code) { 676 acp->aci_url = NULL; 677 } else { 678 dict = alloca((size_t)(p - acp->aci_code) + 1); 679 (void) strncpy(dict, acp->aci_code, 680 (size_t)(p - acp->aci_code)); 681 dict[(size_t)(p - acp->aci_code)] = '\0'; 682 683 /* 684 * If we're given a token to use in looking up the URL, try 685 * to use it. Otherwise, or if we don't find it that way, 686 * use the fallback. 687 */ 688 if (url_token == NULL) { 689 url = _url_fallback; 690 } else if ((url = dgettext(dict, url_token)) == url_token) { 691 /* 692 * We didn't find a translation in the 693 * dictionary for the current language. Fall 694 * back to C and try again. 695 */ 696 olang = setlocale(LC_MESSAGES, NULL); 697 (void) setlocale(LC_MESSAGES, "C"); 698 if ((url = dgettext(dict, url_token)) == url_token) 699 url = _url_fallback; 700 (void) setlocale(LC_MESSAGES, olang); 701 } 702 len = strlen(url); 703 if (url[len - 1] == '/') { 704 len += strlen(acp->aci_code) + 1; 705 urlcode = alloca(len); 706 (void) snprintf(urlcode, len, "%s%s", url, 707 acp->aci_code); 708 } else { 709 urlcode = (char *)url; 710 } 711 acp->aci_url = urlcode; 712 } 713 714 return (func(acp, arg)); 715 } 716 717 /* 718 * Our approach to cases is the same as for resources: we first obtain a 719 * list of UUIDs, sort them, then obtain the case information for each. 720 */ 721 int 722 fmd_adm_case_iter(fmd_adm_t *ap, const char *url_token, fmd_adm_case_f *func, 723 void *arg) 724 { 725 struct fmd_rpc_caselist rcl; 726 struct fmd_rpc_caseinfo rci; 727 fmd_adm_caseinfo_t aci; 728 char **uuids, *p; 729 int i, rv; 730 enum clnt_stat cs; 731 uint_t retries = 0; 732 733 bzero(&rcl, sizeof (rcl)); /* tell xdr to allocate memory for us */ 734 735 do { 736 cs = fmd_adm_caselist_1(&rcl, ap->adm_clnt); 737 } while (fmd_adm_retry(ap, cs, &retries)); 738 739 if (cs != RPC_SUCCESS) 740 return (fmd_adm_set_errno(ap, EPROTO)); 741 742 if (rcl.rcl_err != 0) { 743 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 744 return (fmd_adm_set_svcerr(ap, rcl.rcl_err)); 745 } 746 747 if ((uuids = malloc(sizeof (char *) * rcl.rcl_cnt)) == NULL) { 748 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 749 return (fmd_adm_set_errno(ap, EAGAIN)); 750 } 751 752 p = rcl.rcl_buf.rcl_buf_val; 753 754 for (i = 0; i < rcl.rcl_cnt; i++, p += strlen(p) + 1) 755 uuids[i] = p; 756 757 qsort(uuids, rcl.rcl_cnt, sizeof (char *), fmd_adm_case_cmp); 758 759 for (i = 0; i < rcl.rcl_cnt; i++) { 760 bzero(&rci, sizeof (rci)); 761 762 retries = 0; 763 do { 764 cs = fmd_adm_caseinfo_1(uuids[i], &rci, ap->adm_clnt); 765 } while (fmd_adm_retry(ap, cs, &retries)); 766 767 if (cs != RPC_SUCCESS) { 768 free(uuids); 769 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 770 return (fmd_adm_set_errno(ap, EPROTO)); 771 } 772 773 if (rci.rci_err != 0 && rci.rci_err != FMD_ADM_ERR_CASESRCH) { 774 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 775 free(uuids); 776 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 777 return (fmd_adm_set_svcerr(ap, rci.rci_err)); 778 } 779 780 if (rci.rci_err == FMD_ADM_ERR_CASESRCH) { 781 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 782 continue; 783 } 784 785 bzero(&aci, sizeof (aci)); 786 787 if ((rv = nvlist_unpack(rci.rci_evbuf.rci_evbuf_val, 788 rci.rci_evbuf.rci_evbuf_len, &aci.aci_event, 0)) != 0) { 789 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 790 free(uuids); 791 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 792 return (fmd_adm_set_errno(ap, rv)); 793 } 794 795 if ((rv = nvlist_lookup_string(aci.aci_event, FM_SUSPECT_UUID, 796 (char **)&aci.aci_uuid)) != 0) { 797 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 798 free(uuids); 799 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 800 nvlist_free(aci.aci_event); 801 return (fmd_adm_set_errno(ap, rv)); 802 } 803 if ((rv = nvlist_lookup_string(aci.aci_event, 804 FM_SUSPECT_DIAG_CODE, (char **)&aci.aci_code)) != 0) { 805 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 806 free(uuids); 807 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 808 nvlist_free(aci.aci_event); 809 return (fmd_adm_set_errno(ap, rv)); 810 } 811 812 rv = fmd_adm_case_one(&aci, url_token, func, arg); 813 814 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci); 815 nvlist_free(aci.aci_event); 816 817 if (rv != 0) 818 break; 819 } 820 821 free(uuids); 822 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl); 823 return (0); 824 } 825 826 static int 827 fmd_adm_serd_cmp(const void *lp, const void *rp) 828 { 829 return (strcmp((*(struct fmd_rpc_serdinfo **)lp)->rsi_name, 830 (*(struct fmd_rpc_serdinfo **)rp)->rsi_name)); 831 } 832 833 int 834 fmd_adm_serd_iter(fmd_adm_t *ap, const char *name, 835 fmd_adm_serd_f *func, void *arg) 836 { 837 struct fmd_rpc_serdinfo *rsi, **ris, **rip; 838 struct fmd_rpc_serdlist rsl; 839 fmd_adm_serdinfo_t asi; 840 enum clnt_stat cs; 841 uint_t retries = 0; 842 843 bzero(&rsl, sizeof (rsl)); /* tell xdr to allocate memory for us */ 844 845 do { 846 cs = fmd_adm_serdinfo_1((char *)name, &rsl, ap->adm_clnt); 847 } while (fmd_adm_retry(ap, cs, &retries)); 848 849 if (cs != RPC_SUCCESS) 850 return (fmd_adm_set_errno(ap, EPROTO)); 851 852 if (rsl.rsl_err != 0 || rsl.rsl_len == 0) { 853 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 854 return (fmd_adm_set_svcerr(ap, rsl.rsl_err)); 855 } 856 857 if ((ris = rip = malloc(sizeof (void *) * rsl.rsl_len)) == NULL) { 858 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 859 return (fmd_adm_set_errno(ap, EAGAIN)); 860 } 861 862 for (rsi = rsl.rsl_list; rsi != NULL; rsi = rsi->rsi_next) 863 *rip++ = rsi; /* store copy of pointer in array for sorting */ 864 865 qsort(ris, rsl.rsl_len, sizeof (void *), fmd_adm_serd_cmp); 866 867 for (rip = ris; rip < ris + rsl.rsl_len; rip++) { 868 rsi = *rip; 869 870 asi.asi_name = rsi->rsi_name; 871 asi.asi_delta = rsi->rsi_delta; 872 asi.asi_n = rsi->rsi_n; 873 asi.asi_t = rsi->rsi_t; 874 asi.asi_count = rsi->rsi_count; 875 asi.asi_flags = 0; 876 877 if (rsi->rsi_fired) 878 asi.asi_flags |= FMD_ADM_SERD_FIRED; 879 880 if (func(&asi, arg) != 0) 881 break; 882 } 883 884 free(ris); 885 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl); 886 return (0); 887 } 888 889 int 890 fmd_adm_serd_reset(fmd_adm_t *ap, const char *mod, const char *name) 891 { 892 char *s1 = (char *)mod, *s2 = (char *)name; 893 int err; 894 enum clnt_stat cs; 895 uint_t retries = 0; 896 897 if (mod == NULL || name == NULL || strchr(mod, '/') != NULL) 898 return (fmd_adm_set_errno(ap, EINVAL)); 899 900 do { 901 cs = fmd_adm_serdreset_1(s1, s2, &err, ap->adm_clnt); 902 } while (fmd_adm_retry(ap, cs, &retries)); 903 904 if (cs != RPC_SUCCESS) 905 return (fmd_adm_set_errno(ap, EPROTO)); 906 907 return (fmd_adm_set_svcerr(ap, err)); 908 } 909 910 int 911 fmd_adm_xprt_iter(fmd_adm_t *ap, fmd_adm_xprt_f *func, void *arg) 912 { 913 struct fmd_rpc_xprtlist rxl; 914 uint_t i; 915 enum clnt_stat cs; 916 uint_t retries = 0; 917 918 bzero(&rxl, sizeof (rxl)); /* tell xdr to allocate memory for us */ 919 920 do { 921 cs = fmd_adm_xprtlist_1(&rxl, ap->adm_clnt); 922 } while (fmd_adm_retry(ap, cs, &retries)); 923 924 if (cs != RPC_SUCCESS) 925 return (fmd_adm_set_errno(ap, EPROTO)); 926 927 if (rxl.rxl_err != 0) { 928 xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl); 929 return (fmd_adm_set_svcerr(ap, rxl.rxl_err)); 930 } 931 932 for (i = 0; i < rxl.rxl_len; i++) 933 func(rxl.rxl_buf.rxl_buf_val[i], arg); 934 935 xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl); 936 return (0); 937 } 938 939 int 940 fmd_adm_xprt_stats(fmd_adm_t *ap, id_t id, fmd_adm_stats_t *sp) 941 { 942 struct fmd_rpc_modstat rms; 943 enum clnt_stat cs; 944 uint_t retries = 0; 945 946 if (sp == NULL) 947 return (fmd_adm_set_errno(ap, EINVAL)); 948 949 bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */ 950 951 do { 952 cs = fmd_adm_xprtstat_1(id, &rms, ap->adm_clnt); 953 } while (fmd_adm_retry(ap, cs, &retries)); 954 955 if (cs != RPC_SUCCESS) 956 return (fmd_adm_set_errno(ap, EPROTO)); 957 958 if (rms.rms_err != 0) { 959 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms); 960 return (fmd_adm_set_svcerr(ap, rms.rms_err)); 961 } 962 963 sp->ams_buf = rms.rms_buf.rms_buf_val; 964 sp->ams_len = rms.rms_buf.rms_buf_len; 965 966 return (0); 967 } 968 969 int 970 fmd_adm_log_rotate(fmd_adm_t *ap, const char *log) 971 { 972 int err; 973 enum clnt_stat cs; 974 uint_t retries = 0; 975 976 if (log == NULL) 977 return (fmd_adm_set_errno(ap, EINVAL)); 978 979 do { 980 cs = fmd_adm_logrotate_1((char *)log, &err, ap->adm_clnt); 981 } while (fmd_adm_retry(ap, cs, &retries)); 982 983 if (cs != RPC_SUCCESS) 984 return (fmd_adm_set_errno(ap, EPROTO)); 985 986 return (fmd_adm_set_svcerr(ap, err)); 987 } 988 989 /* 990 * Custom XDR routine for our API structure fmd_stat_t. This function must 991 * match the definition of fmd_stat_t in <fm/fmd_api.h> and must also match 992 * the corresponding routine in usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c. 993 */ 994 bool_t 995 xdr_fmd_stat(XDR *xp, fmd_stat_t *sp) 996 { 997 bool_t rv = TRUE; 998 999 rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name)); 1000 rv &= xdr_u_int(xp, &sp->fmds_type); 1001 rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc)); 1002 1003 switch (sp->fmds_type) { 1004 case FMD_TYPE_BOOL: 1005 rv &= xdr_int(xp, &sp->fmds_value.bool); 1006 break; 1007 case FMD_TYPE_INT32: 1008 rv &= xdr_int32_t(xp, &sp->fmds_value.i32); 1009 break; 1010 case FMD_TYPE_UINT32: 1011 rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32); 1012 break; 1013 case FMD_TYPE_INT64: 1014 rv &= xdr_int64_t(xp, &sp->fmds_value.i64); 1015 break; 1016 case FMD_TYPE_UINT64: 1017 case FMD_TYPE_TIME: 1018 case FMD_TYPE_SIZE: 1019 rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64); 1020 break; 1021 case FMD_TYPE_STRING: 1022 rv &= xdr_string(xp, &sp->fmds_value.str, ~0); 1023 break; 1024 } 1025 1026 return (rv); 1027 } 1028