1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <strings.h> 30 #include <limits.h> 31 #include <unistd.h> 32 #include <stdlib.h> 33 #include <alloca.h> 34 35 #include <fmd_rpc_adm.h> 36 #include <fmd_rpc.h> 37 #include <fmd_module.h> 38 #include <fmd_ustat.h> 39 #include <fmd_error.h> 40 #include <fmd_asru.h> 41 #include <fmd_ckpt.h> 42 #include <fmd_case.h> 43 #include <fmd_fmri.h> 44 45 #include <fmd.h> 46 47 bool_t 48 fmd_adm_modinfo_1_svc(struct fmd_rpc_modlist *rvp, struct svc_req *req) 49 { 50 struct fmd_rpc_modinfo *rmi; 51 fmd_module_t *mp; 52 53 rvp->rml_list = NULL; 54 rvp->rml_err = 0; 55 rvp->rml_len = 0; 56 57 if (fmd_rpc_deny(req)) { 58 rvp->rml_err = FMD_ADM_ERR_PERM; 59 return (TRUE); 60 } 61 62 (void) pthread_mutex_lock(&fmd.d_mod_lock); 63 64 for (mp = fmd_list_next(&fmd.d_mod_list); 65 mp != NULL; mp = fmd_list_next(mp)) { 66 67 if ((rmi = malloc(sizeof (struct fmd_rpc_modinfo))) == NULL) { 68 rvp->rml_err = FMD_ADM_ERR_NOMEM; 69 break; 70 } 71 72 fmd_module_lock(mp); 73 74 /* 75 * If mod_info is NULL, the module is in the middle of loading: 76 * do not report its presence to observability tools yet. 77 */ 78 if (mp->mod_info == NULL) { 79 fmd_module_unlock(mp); 80 free(rmi); 81 continue; 82 } 83 84 rmi->rmi_name = strdup(mp->mod_name); 85 rmi->rmi_desc = strdup(mp->mod_info->fmdi_desc); 86 rmi->rmi_vers = strdup(mp->mod_info->fmdi_vers); 87 rmi->rmi_faulty = mp->mod_error != 0; 88 rmi->rmi_next = rvp->rml_list; 89 90 fmd_module_unlock(mp); 91 rvp->rml_list = rmi; 92 rvp->rml_len++; 93 94 if (rmi->rmi_desc == NULL || rmi->rmi_vers == NULL) { 95 rvp->rml_err = FMD_ADM_ERR_NOMEM; 96 break; 97 } 98 } 99 100 (void) pthread_mutex_unlock(&fmd.d_mod_lock); 101 return (TRUE); 102 } 103 104 bool_t 105 fmd_adm_modcstat_1_svc(char *name, 106 struct fmd_rpc_modstat *rms, struct svc_req *req) 107 { 108 fmd_ustat_snap_t snap; 109 fmd_module_t *mp; 110 111 rms->rms_buf.rms_buf_val = NULL; 112 rms->rms_buf.rms_buf_len = 0; 113 rms->rms_err = 0; 114 115 if (fmd_rpc_deny(req)) { 116 rms->rms_err = FMD_ADM_ERR_PERM; 117 return (TRUE); 118 } 119 120 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) { 121 rms->rms_err = FMD_ADM_ERR_MODSRCH; 122 return (TRUE); 123 } 124 125 if (fmd_modstat_snapshot(mp, &snap) == 0) { 126 rms->rms_buf.rms_buf_val = snap.uss_buf; 127 rms->rms_buf.rms_buf_len = snap.uss_len; 128 } else if (errno == EFMD_HDL_ABORT) { 129 rms->rms_err = FMD_ADM_ERR_MODFAIL; 130 } else 131 rms->rms_err = FMD_ADM_ERR_NOMEM; 132 133 fmd_module_rele(mp); 134 return (TRUE); 135 } 136 137 bool_t 138 fmd_adm_moddstat_1_svc(char *name, 139 struct fmd_rpc_modstat *rms, struct svc_req *req) 140 { 141 fmd_module_t *mp; 142 143 rms->rms_buf.rms_buf_val = NULL; 144 rms->rms_buf.rms_buf_len = 0; 145 rms->rms_err = 0; 146 147 if (fmd_rpc_deny(req)) { 148 rms->rms_err = FMD_ADM_ERR_PERM; 149 return (TRUE); 150 } 151 152 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) { 153 rms->rms_err = FMD_ADM_ERR_MODSRCH; 154 return (TRUE); 155 } 156 157 rms->rms_buf.rms_buf_val = malloc(sizeof (fmd_modstat_t)); 158 rms->rms_buf.rms_buf_len = sizeof (fmd_modstat_t) / sizeof (fmd_stat_t); 159 160 if (rms->rms_buf.rms_buf_val == NULL) { 161 rms->rms_err = FMD_ADM_ERR_NOMEM; 162 rms->rms_buf.rms_buf_len = 0; 163 fmd_module_rele(mp); 164 return (TRUE); 165 } 166 167 /* 168 * Note: the bcopy() here is valid only if no FMD_TYPE_STRING stats 169 * are present in mp->mod_stats. We don't use any for the daemon- 170 * maintained stats and provide this function in order to reduce the 171 * overhead of the fmstat(1M) default view, where these minimal stats 172 * must be retrieved for all of the active modules. 173 */ 174 (void) pthread_mutex_lock(&mp->mod_stats_lock); 175 176 if (mp->mod_stats != NULL) { 177 mp->mod_stats->ms_snaptime.fmds_value.ui64 = gethrtime(); 178 bcopy(mp->mod_stats, rms->rms_buf.rms_buf_val, 179 sizeof (fmd_modstat_t)); 180 } else { 181 free(rms->rms_buf.rms_buf_val); 182 rms->rms_buf.rms_buf_val = NULL; 183 rms->rms_buf.rms_buf_len = 0; 184 rms->rms_err = FMD_ADM_ERR_MODFAIL; 185 } 186 187 (void) pthread_mutex_unlock(&mp->mod_stats_lock); 188 fmd_module_rele(mp); 189 return (TRUE); 190 } 191 192 bool_t 193 fmd_adm_modgstat_1_svc(struct fmd_rpc_modstat *rms, struct svc_req *req) 194 { 195 const size_t size = sizeof (fmd_statistics_t); 196 197 if (fmd_rpc_deny(req)) { 198 rms->rms_buf.rms_buf_val = NULL; 199 rms->rms_buf.rms_buf_len = 0; 200 rms->rms_err = FMD_ADM_ERR_PERM; 201 } else if ((rms->rms_buf.rms_buf_val = malloc(size)) != NULL) { 202 /* 203 * Note: the bcopy() here is valid only if no FMD_TYPE_STRING 204 * stats are present in fmd.d_stats (see definition in fmd.c). 205 */ 206 (void) pthread_mutex_lock(&fmd.d_stats_lock); 207 bcopy(fmd.d_stats, rms->rms_buf.rms_buf_val, size); 208 (void) pthread_mutex_unlock(&fmd.d_stats_lock); 209 rms->rms_buf.rms_buf_len = size / sizeof (fmd_stat_t); 210 rms->rms_err = 0; 211 } else { 212 rms->rms_buf.rms_buf_len = 0; 213 rms->rms_err = FMD_ADM_ERR_NOMEM; 214 } 215 216 return (TRUE); 217 } 218 219 bool_t 220 fmd_adm_modload_1_svc(char *path, int *rvp, struct svc_req *req) 221 { 222 fmd_module_t *mp; 223 const char *p; 224 int err = 0; 225 226 if (fmd_rpc_deny(req)) { 227 *rvp = FMD_ADM_ERR_PERM; 228 return (TRUE); 229 } 230 231 /* 232 * Before we endure the expense of constructing a module and attempting 233 * to load it, do a quick check to see if the pathname is valid. 234 */ 235 if (access(path, F_OK) != 0) { 236 *rvp = FMD_ADM_ERR_MODNOENT; 237 return (TRUE); 238 } 239 240 if ((p = strrchr(path, '.')) != NULL && strcmp(p, ".so") == 0) 241 mp = fmd_modhash_load(fmd.d_mod_hash, path, &fmd_rtld_ops); 242 else 243 mp = fmd_modhash_load(fmd.d_mod_hash, path, &fmd_proc_ops); 244 245 if (mp == NULL) { 246 switch (errno) { 247 case EFMD_MOD_LOADED: 248 err = FMD_ADM_ERR_MODEXIST; 249 break; 250 case EFMD_MOD_INIT: 251 err = FMD_ADM_ERR_MODINIT; 252 break; 253 default: 254 err = FMD_ADM_ERR_MODLOAD; 255 break; 256 } 257 } 258 259 *rvp = err; 260 return (TRUE); 261 } 262 263 bool_t 264 fmd_adm_modunload_1_svc(char *name, int *rvp, struct svc_req *req) 265 { 266 fmd_module_t *mp = NULL; 267 int err = 0; 268 269 if (fmd_rpc_deny(req)) 270 err = FMD_ADM_ERR_PERM; 271 else if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) 272 err = FMD_ADM_ERR_MODSRCH; 273 else if (mp == fmd.d_self) 274 err = FMD_ADM_ERR_MODBUSY; 275 else if (fmd_modhash_unload(fmd.d_mod_hash, name) != 0) 276 err = FMD_ADM_ERR_MODSRCH; 277 278 if (mp != NULL) 279 fmd_module_rele(mp); 280 281 *rvp = err; 282 return (TRUE); 283 } 284 285 bool_t 286 fmd_adm_modreset_1_svc(char *name, int *rvp, struct svc_req *req) 287 { 288 fmd_module_t *mp = NULL; 289 int err = 0; 290 291 if (fmd_rpc_deny(req)) 292 err = FMD_ADM_ERR_PERM; 293 else if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) 294 err = FMD_ADM_ERR_MODSRCH; 295 else if (mp == fmd.d_self) 296 err = FMD_ADM_ERR_MODBUSY; 297 else if (fmd_modhash_unload(fmd.d_mod_hash, name) != 0) 298 err = FMD_ADM_ERR_MODSRCH; 299 300 if (err == 0) 301 fmd_ckpt_delete(mp); /* erase any saved checkpoints */ 302 303 if (err == 0 && fmd_modhash_load(fmd.d_mod_hash, 304 mp->mod_path, mp->mod_ops) == NULL) { 305 if (errno == EFMD_MOD_INIT) 306 err = FMD_ADM_ERR_MODINIT; 307 else 308 err = FMD_ADM_ERR_MODLOAD; 309 } 310 311 if (mp != NULL) 312 fmd_module_rele(mp); 313 314 *rvp = err; 315 return (TRUE); 316 } 317 318 bool_t 319 fmd_adm_modgc_1_svc(char *name, int *rvp, struct svc_req *req) 320 { 321 fmd_module_t *mp; 322 int err = 0; 323 324 if (fmd_rpc_deny(req)) 325 err = FMD_ADM_ERR_PERM; 326 else if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) 327 err = FMD_ADM_ERR_MODSRCH; 328 else { 329 fmd_module_gc(mp); 330 fmd_module_rele(mp); 331 } 332 333 *rvp = err; 334 return (TRUE); 335 } 336 337 /* 338 * Unlike our other RPC callbacks, fmd_adm_rsrclist_1 can return large amounts 339 * of data that may exceed the underlying RPC transport buffer size if the 340 * resource cache is heavily populated and/or all resources are requested. 341 * To minimize the likelihood of running out of RPC buffer space and having to 342 * fail the client request, fmd_adm_rsrclist_1 returns a snapshot of the 343 * relevant FMRI strings only: the client can use fmd_adm_rsrcinfo_1 on an 344 * individual FMRI if more information is needed. To further reduce the XDR 345 * overhead, the string list is represented as XDR-opaque data where the 346 * entire list is returned as a string table (e.g. "fmriA\0fmriB\0..."). 347 */ 348 static void 349 fmd_adm_rsrclist_asru(fmd_asru_t *ap, void *arg) 350 { 351 struct fmd_rpc_rsrclist *rrl = arg; 352 size_t name_len, buf_len; 353 void *p; 354 355 /* 356 * If rrl_all is false, we take a quick look at asru_flags with no lock 357 * held to see if the ASRU is either not faulty or invisible. If so, 358 * we don't want to report it by default and can just skip this ASRU. 359 * This helps keep overhead low in the common case, as the call to 360 * fmd_asru_getstate() can be expensive depending on the scheme. 361 */ 362 if (rrl->rrl_all == B_FALSE && (ap->asru_flags & (FMD_ASRU_FAULTY | 363 FMD_ASRU_INVISIBLE)) != FMD_ASRU_FAULTY) 364 return; 365 366 if (rrl->rrl_err != 0 || fmd_asru_getstate(ap) == 0) 367 return; /* error has occurred or resource is in 'ok' state */ 368 369 /* 370 * Lock the ASRU and reallocate rrl_buf[] to be large enough to hold 371 * another string, doubling it as needed. Then copy the new string 372 * on to the end, and increment rrl_len to indicate the used space. 373 */ 374 (void) pthread_mutex_lock(&ap->asru_lock); 375 name_len = strlen(ap->asru_name) + 1; 376 377 while (rrl->rrl_len + name_len > rrl->rrl_buf.rrl_buf_len) { 378 if (rrl->rrl_buf.rrl_buf_len != 0) 379 buf_len = rrl->rrl_buf.rrl_buf_len * 2; 380 else 381 buf_len = 1024; /* default buffer size */ 382 383 if ((p = realloc(rrl->rrl_buf.rrl_buf_val, buf_len)) != NULL) { 384 bzero((char *)p + rrl->rrl_buf.rrl_buf_len, 385 buf_len - rrl->rrl_buf.rrl_buf_len); 386 rrl->rrl_buf.rrl_buf_val = p; 387 rrl->rrl_buf.rrl_buf_len = buf_len; 388 } else { 389 rrl->rrl_err = FMD_ADM_ERR_NOMEM; 390 break; 391 } 392 } 393 394 if (rrl->rrl_err == 0) { 395 bcopy(ap->asru_name, (char *)rrl->rrl_buf.rrl_buf_val + 396 rrl->rrl_len, name_len); 397 rrl->rrl_len += name_len; 398 rrl->rrl_cnt++; 399 } 400 401 (void) pthread_mutex_unlock(&ap->asru_lock); 402 } 403 404 bool_t 405 fmd_adm_rsrclist_1_svc(bool_t all, 406 struct fmd_rpc_rsrclist *rvp, struct svc_req *req) 407 { 408 rvp->rrl_buf.rrl_buf_len = 0; 409 rvp->rrl_buf.rrl_buf_val = NULL; 410 rvp->rrl_len = 0; 411 rvp->rrl_cnt = 0; 412 rvp->rrl_err = 0; 413 rvp->rrl_all = all; 414 415 if (fmd_rpc_deny(req)) 416 rvp->rrl_err = FMD_ADM_ERR_PERM; 417 else 418 fmd_asru_hash_apply(fmd.d_asrus, fmd_adm_rsrclist_asru, rvp); 419 420 return (TRUE); 421 } 422 423 bool_t 424 fmd_adm_rsrcinfo_1_svc(char *fmri, 425 struct fmd_rpc_rsrcinfo *rvp, struct svc_req *req) 426 { 427 fmd_asru_t *ap; 428 int state; 429 430 bzero(rvp, sizeof (struct fmd_rpc_rsrcinfo)); 431 432 if (fmd_rpc_deny(req)) { 433 rvp->rri_err = FMD_ADM_ERR_PERM; 434 return (TRUE); 435 } 436 437 if ((ap = fmd_asru_hash_lookup_name(fmd.d_asrus, fmri)) == NULL) { 438 rvp->rri_err = FMD_ADM_ERR_RSRCSRCH; 439 return (TRUE); 440 } 441 442 state = fmd_asru_getstate(ap); 443 (void) pthread_mutex_lock(&ap->asru_lock); 444 445 rvp->rri_fmri = strdup(ap->asru_name); 446 rvp->rri_uuid = strdup(ap->asru_uuid); 447 rvp->rri_case = ap->asru_case ? strdup(ap->asru_case) : NULL; 448 rvp->rri_faulty = (state & FMD_ASRU_FAULTY) != 0; 449 rvp->rri_unusable = (state & FMD_ASRU_UNUSABLE) != 0; 450 rvp->rri_invisible = (ap->asru_flags & FMD_ASRU_INVISIBLE) != 0; 451 452 (void) pthread_mutex_unlock(&ap->asru_lock); 453 fmd_asru_hash_release(fmd.d_asrus, ap); 454 455 if (rvp->rri_fmri == NULL || rvp->rri_uuid == NULL) 456 rvp->rri_err = FMD_ADM_ERR_NOMEM; 457 458 return (TRUE); 459 } 460 461 bool_t 462 fmd_adm_rsrcflush_1_svc(char *name, int *rvp, struct svc_req *req) 463 { 464 if (fmd_rpc_deny(req)) 465 *rvp = FMD_ADM_ERR_PERM; 466 else if (fmd_asru_hash_delete_name(fmd.d_asrus, name) != 0) 467 *rvp = FMD_ADM_ERR_RSRCSRCH; 468 else 469 *rvp = 0; 470 471 return (TRUE); 472 } 473 474 static int 475 fmd_adm_repair(fmd_asru_t *ap) 476 { 477 fmd_case_t *cp; 478 uint_t cidlen; 479 char *cid; 480 481 if (!fmd_asru_clrflags(ap, FMD_ASRU_FAULTY, NULL, NULL)) 482 return (FMD_ADM_ERR_RSRCNOTF); 483 484 (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &cidlen); 485 cid = alloca(cidlen + 1); 486 (void) fmd_asru_getcase(ap, cid, cidlen + 1); 487 488 if ((cp = fmd_case_hash_lookup(fmd.d_cases, cid)) != NULL) { 489 fmd_case_update(cp); 490 fmd_case_rele(cp); 491 } 492 493 return (0); 494 } 495 496 static void 497 fmd_adm_repair_containee(fmd_asru_t *ee, void *er) 498 { 499 if ((ee->asru_flags & FMD_ASRU_FAULTY) && 500 fmd_fmri_contains(er, ee->asru_fmri) > 0) 501 (void) fmd_adm_repair(ee); 502 } 503 504 bool_t 505 fmd_adm_rsrcrepair_1_svc(char *name, int *rvp, struct svc_req *req) 506 { 507 fmd_asru_t *ap = NULL; 508 int err = 0; 509 510 if (fmd_rpc_deny(req)) 511 err = FMD_ADM_ERR_PERM; 512 else if ((ap = fmd_asru_hash_lookup_name(fmd.d_asrus, name)) == NULL) 513 err = FMD_ADM_ERR_RSRCSRCH; 514 else if ((err = fmd_adm_repair(ap)) == 0) { 515 /* 516 * We've located the requested ASRU, and have repaired it. Now 517 * traverse the ASRU cache, looking for any faulty entries that 518 * are contained by this one. If we find any, repair them too. 519 */ 520 fmd_asru_hash_apply(fmd.d_asrus, 521 fmd_adm_repair_containee, ap->asru_fmri); 522 } 523 524 if (ap != NULL) 525 fmd_asru_hash_release(fmd.d_asrus, ap); 526 527 *rvp = err; 528 return (TRUE); 529 } 530 531 static void 532 fmd_adm_serdinfo_eng(fmd_serd_eng_t *sgp, void *arg) 533 { 534 struct fmd_rpc_serdlist *rsl = arg; 535 struct fmd_rpc_serdinfo *rsi = malloc(sizeof (struct fmd_rpc_serdinfo)); 536 537 uint64_t old, now = fmd_time_gethrtime(); 538 const fmd_serd_elem_t *oep; 539 540 if (rsi == NULL || (rsi->rsi_name = strdup(sgp->sg_name)) == NULL) { 541 rsl->rsl_err = FMD_ADM_ERR_NOMEM; 542 free(rsi); 543 return; 544 } 545 546 if ((oep = fmd_list_next(&sgp->sg_list)) != NULL) 547 old = fmd_event_hrtime(oep->se_event); 548 else 549 old = now; 550 551 rsi->rsi_delta = now >= old ? now - old : (UINT64_MAX - old) + now + 1; 552 rsi->rsi_count = sgp->sg_count; 553 rsi->rsi_fired = fmd_serd_eng_fired(sgp) != 0; 554 rsi->rsi_n = sgp->sg_n; 555 rsi->rsi_t = sgp->sg_t; 556 rsi->rsi_next = rsl->rsl_list; 557 558 rsl->rsl_list = rsi; 559 rsl->rsl_len++; 560 } 561 562 bool_t 563 fmd_adm_serdinfo_1_svc(char *name, 564 struct fmd_rpc_serdlist *rvp, struct svc_req *req) 565 { 566 fmd_module_t *mp; 567 568 rvp->rsl_list = NULL; 569 rvp->rsl_err = 0; 570 rvp->rsl_len = 0; 571 572 if (fmd_rpc_deny(req)) { 573 rvp->rsl_err = FMD_ADM_ERR_PERM; 574 return (TRUE); 575 } 576 577 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) { 578 rvp->rsl_err = FMD_ADM_ERR_MODSRCH; 579 return (TRUE); 580 } 581 582 fmd_module_lock(mp); 583 fmd_serd_hash_apply(&mp->mod_serds, fmd_adm_serdinfo_eng, rvp); 584 fmd_module_unlock(mp); 585 586 fmd_module_rele(mp); 587 return (TRUE); 588 } 589 590 bool_t 591 fmd_adm_serdreset_1_svc(char *mname, char *sname, int *rvp, struct svc_req *req) 592 { 593 fmd_module_t *mp; 594 fmd_serd_eng_t *sgp; 595 int err = 0; 596 597 if (fmd_rpc_deny(req)) { 598 *rvp = FMD_ADM_ERR_PERM; 599 return (TRUE); 600 } 601 602 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, mname)) == NULL) { 603 *rvp = FMD_ADM_ERR_MODSRCH; 604 return (TRUE); 605 } 606 607 fmd_module_lock(mp); 608 609 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, sname)) != NULL) { 610 if (fmd_serd_eng_fired(sgp)) { 611 err = FMD_ADM_ERR_SERDFIRED; 612 } else { 613 fmd_serd_eng_reset(sgp); 614 fmd_module_setdirty(mp); 615 } 616 } else 617 err = FMD_ADM_ERR_SERDSRCH; 618 619 fmd_module_unlock(mp); 620 fmd_module_rele(mp); 621 622 *rvp = err; 623 return (TRUE); 624 } 625 626 bool_t 627 fmd_adm_logrotate_1_svc(char *name, int *rvp, struct svc_req *req) 628 { 629 fmd_log_t **lpp, *old, *new; 630 int try = 1, trylimit = 1; 631 632 hrtime_t nsec = 0; 633 timespec_t tv; 634 635 if (fmd_rpc_deny(req)) { 636 *rvp = FMD_ADM_ERR_PERM; 637 return (TRUE); 638 } 639 640 if (strcmp(name, "errlog") == 0) 641 lpp = &fmd.d_errlog; 642 else if (strcmp(name, "fltlog") == 0) 643 lpp = &fmd.d_fltlog; 644 else { 645 *rvp = FMD_ADM_ERR_ROTSRCH; 646 return (TRUE); 647 } 648 649 (void) fmd_conf_getprop(fmd.d_conf, "log.tryrotate", &trylimit); 650 (void) fmd_conf_getprop(fmd.d_conf, "log.waitrotate", &nsec); 651 652 tv.tv_sec = nsec / NANOSEC; 653 tv.tv_nsec = nsec % NANOSEC; 654 655 /* 656 * To rotate a log file, grab d_log_lock as writer to make sure no 657 * one else can discover the current log pointer. Then try to rotate 658 * the log. If we're successful, release the old log pointer. 659 */ 660 do { 661 if (try > 1) 662 (void) nanosleep(&tv, NULL); /* wait for checkpoints */ 663 664 (void) pthread_rwlock_wrlock(&fmd.d_log_lock); 665 old = *lpp; 666 667 if ((new = fmd_log_rotate(old)) != NULL) { 668 fmd_log_rele(old); 669 *lpp = new; 670 } 671 672 (void) pthread_rwlock_unlock(&fmd.d_log_lock); 673 674 } while (new == NULL && errno == EFMD_LOG_ROTBUSY && try++ < trylimit); 675 676 if (new != NULL) 677 *rvp = 0; 678 else if (errno == EFMD_LOG_ROTBUSY) 679 *rvp = FMD_ADM_ERR_ROTBUSY; 680 else 681 *rvp = FMD_ADM_ERR_ROTFAIL; 682 683 return (TRUE); 684 } 685 686 struct fmd_adm_repair { 687 const char *rep_uuid; /* case uuid that we are using to match */ 688 char *rep_buf; /* buffer in which to store case ids */ 689 uint_t rep_buflen; /* length of rep_buf buffer minus one */ 690 uint_t rep_cnt; /* number of matching asrus found */ 691 }; 692 693 static void 694 fmd_adm_caserepair_asru(fmd_asru_t *ap, void *arg) 695 { 696 struct fmd_adm_repair *rp = arg; 697 698 if (fmd_asru_getcase(ap, rp->rep_buf, rp->rep_buflen + 1) == NULL || 699 strcmp(rp->rep_buf, rp->rep_uuid) != 0) 700 return; 701 702 /* 703 * If the UUID of the case associated with this ASRU matches, close all 704 * ASRUs contained by 'ap' and trigger appropriate case close events. 705 */ 706 fmd_asru_hash_apply(fmd.d_asrus, 707 fmd_adm_repair_containee, ap->asru_fmri); 708 709 /* 710 * We can call fmd_asru_clrflags() here rather than fmd_adm_repair() 711 * because if the case was still open, fmd_case_repair() closed it. 712 */ 713 (void) fmd_asru_clrflags(ap, FMD_ASRU_FAULTY, NULL, NULL); 714 rp->rep_cnt++; 715 } 716 717 bool_t 718 fmd_adm_caserepair_1_svc(char *uuid, int *rvp, struct svc_req *req) 719 { 720 fmd_case_t *cp = NULL; 721 int err = 0; 722 723 if (fmd_rpc_deny(req)) 724 err = FMD_ADM_ERR_PERM; 725 else if ((cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) == NULL) 726 err = FMD_ADM_ERR_CASESRCH; 727 else if (fmd_case_repair(cp) != 0) 728 err = FMD_ADM_ERR_CASEOPEN; 729 730 /* 731 * If the case is not found, it could be already closed (i.e. the ASRU 732 * was successfully offlined). Check all ASRUs for a matching UUID and 733 * try to repair them. If any are found, set err to indicate success. 734 * If the case is found, we also check all ASRUs so that any ASRUs 735 * contained by those that have been repaired are repaired recursively. 736 */ 737 if (err == FMD_ADM_ERR_CASESRCH || err == 0) { 738 struct fmd_adm_repair r; 739 740 r.rep_uuid = uuid; 741 (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &r.rep_buflen); 742 r.rep_buf = alloca(r.rep_buflen + 1); 743 r.rep_cnt = 0; 744 745 fmd_asru_hash_apply(fmd.d_asrus, fmd_adm_caserepair_asru, &r); 746 747 if (err == FMD_ADM_ERR_CASESRCH && r.rep_cnt != 0) 748 err = 0; /* one or more ASRUs had matching case IDs */ 749 } 750 751 if (cp != NULL) 752 fmd_case_rele(cp); 753 754 *rvp = err; 755 return (TRUE); 756 } 757 758 int 759 fmd_adm_1_freeresult(SVCXPRT *xprt, xdrproc_t proc, caddr_t data) 760 { 761 xdr_free(proc, data); 762 svc_done(xprt); 763 return (TRUE); 764 } 765 766 /* 767 * Custom XDR routine for our API structure fmd_stat_t. This function must 768 * match the definition of fmd_stat_t in <fmd_api.h> and must also match 769 * the corresponding routine in usr/src/lib/fm/libfmd_adm/common/fmd_adm.c. 770 */ 771 bool_t 772 xdr_fmd_stat(XDR *xp, fmd_stat_t *sp) 773 { 774 bool_t rv = TRUE; 775 776 rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name)); 777 rv &= xdr_u_int(xp, &sp->fmds_type); 778 rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc)); 779 780 switch (sp->fmds_type) { 781 case FMD_TYPE_BOOL: 782 rv &= xdr_int(xp, &sp->fmds_value.bool); 783 break; 784 case FMD_TYPE_INT32: 785 rv &= xdr_int32_t(xp, &sp->fmds_value.i32); 786 break; 787 case FMD_TYPE_UINT32: 788 rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32); 789 break; 790 case FMD_TYPE_INT64: 791 rv &= xdr_int64_t(xp, &sp->fmds_value.i64); 792 break; 793 case FMD_TYPE_UINT64: 794 case FMD_TYPE_TIME: 795 case FMD_TYPE_SIZE: 796 rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64); 797 break; 798 case FMD_TYPE_STRING: 799 rv &= xdr_string(xp, &sp->fmds_value.str, ~0); 800 break; 801 } 802 803 return (rv); 804 } 805