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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <strings.h> 27 #include <limits.h> 28 #include <unistd.h> 29 #include <stdlib.h> 30 #include <alloca.h> 31 32 #include <fmd_rpc_adm.h> 33 #include <fmd_rpc.h> 34 #include <fmd_module.h> 35 #include <fmd_ustat.h> 36 #include <fmd_error.h> 37 #include <fmd_asru.h> 38 #include <fmd_ckpt.h> 39 #include <fmd_case.h> 40 #include <fmd_fmri.h> 41 #include <fmd_idspace.h> 42 #include <fmd_xprt.h> 43 44 #include <fmd.h> 45 46 bool_t 47 fmd_adm_modinfo_1_svc(struct fmd_rpc_modlist *rvp, struct svc_req *req) 48 { 49 struct fmd_rpc_modinfo *rmi; 50 fmd_module_t *mp; 51 52 rvp->rml_list = NULL; 53 rvp->rml_err = 0; 54 rvp->rml_len = 0; 55 56 if (fmd_rpc_deny(req)) { 57 rvp->rml_err = FMD_ADM_ERR_PERM; 58 return (TRUE); 59 } 60 61 (void) pthread_mutex_lock(&fmd.d_mod_lock); 62 63 for (mp = fmd_list_next(&fmd.d_mod_list); 64 mp != NULL; mp = fmd_list_next(mp)) { 65 66 if ((rmi = malloc(sizeof (struct fmd_rpc_modinfo))) == NULL) { 67 rvp->rml_err = FMD_ADM_ERR_NOMEM; 68 break; 69 } 70 71 fmd_module_lock(mp); 72 73 /* 74 * If mod_info is NULL, the module is in the middle of loading: 75 * do not report its presence to observability tools yet. 76 */ 77 if (mp->mod_info == NULL) { 78 fmd_module_unlock(mp); 79 free(rmi); 80 continue; 81 } 82 83 rmi->rmi_name = strdup(mp->mod_name); 84 rmi->rmi_desc = strdup(mp->mod_info->fmdi_desc); 85 rmi->rmi_vers = strdup(mp->mod_info->fmdi_vers); 86 rmi->rmi_faulty = mp->mod_error != 0; 87 rmi->rmi_next = rvp->rml_list; 88 89 fmd_module_unlock(mp); 90 rvp->rml_list = rmi; 91 rvp->rml_len++; 92 93 if (rmi->rmi_desc == NULL || rmi->rmi_vers == NULL) { 94 rvp->rml_err = FMD_ADM_ERR_NOMEM; 95 break; 96 } 97 } 98 99 (void) pthread_mutex_unlock(&fmd.d_mod_lock); 100 return (TRUE); 101 } 102 103 bool_t 104 fmd_adm_modcstat_1_svc(char *name, 105 struct fmd_rpc_modstat *rms, struct svc_req *req) 106 { 107 fmd_ustat_snap_t snap; 108 fmd_module_t *mp; 109 110 rms->rms_buf.rms_buf_val = NULL; 111 rms->rms_buf.rms_buf_len = 0; 112 rms->rms_err = 0; 113 114 if (fmd_rpc_deny(req)) { 115 rms->rms_err = FMD_ADM_ERR_PERM; 116 return (TRUE); 117 } 118 119 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) { 120 rms->rms_err = FMD_ADM_ERR_MODSRCH; 121 return (TRUE); 122 } 123 124 if (fmd_modstat_snapshot(mp, &snap) == 0) { 125 rms->rms_buf.rms_buf_val = snap.uss_buf; 126 rms->rms_buf.rms_buf_len = snap.uss_len; 127 } else if (errno == EFMD_HDL_ABORT) { 128 rms->rms_err = FMD_ADM_ERR_MODFAIL; 129 } else 130 rms->rms_err = FMD_ADM_ERR_NOMEM; 131 132 fmd_module_rele(mp); 133 return (TRUE); 134 } 135 136 bool_t 137 fmd_adm_moddstat_1_svc(char *name, 138 struct fmd_rpc_modstat *rms, struct svc_req *req) 139 { 140 fmd_module_t *mp; 141 142 rms->rms_buf.rms_buf_val = NULL; 143 rms->rms_buf.rms_buf_len = 0; 144 rms->rms_err = 0; 145 146 if (fmd_rpc_deny(req)) { 147 rms->rms_err = FMD_ADM_ERR_PERM; 148 return (TRUE); 149 } 150 151 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) { 152 rms->rms_err = FMD_ADM_ERR_MODSRCH; 153 return (TRUE); 154 } 155 156 rms->rms_buf.rms_buf_val = malloc(sizeof (fmd_modstat_t)); 157 rms->rms_buf.rms_buf_len = sizeof (fmd_modstat_t) / sizeof (fmd_stat_t); 158 159 if (rms->rms_buf.rms_buf_val == NULL) { 160 rms->rms_err = FMD_ADM_ERR_NOMEM; 161 rms->rms_buf.rms_buf_len = 0; 162 fmd_module_rele(mp); 163 return (TRUE); 164 } 165 166 /* 167 * Note: the bcopy() here is valid only if no FMD_TYPE_STRING stats 168 * are present in mp->mod_stats. We don't use any for the daemon- 169 * maintained stats and provide this function in order to reduce the 170 * overhead of the fmstat(1M) default view, where these minimal stats 171 * must be retrieved for all of the active modules. 172 */ 173 (void) pthread_mutex_lock(&mp->mod_stats_lock); 174 175 if (mp->mod_stats != NULL) { 176 mp->mod_stats->ms_snaptime.fmds_value.ui64 = gethrtime(); 177 bcopy(mp->mod_stats, rms->rms_buf.rms_buf_val, 178 sizeof (fmd_modstat_t)); 179 } else { 180 free(rms->rms_buf.rms_buf_val); 181 rms->rms_buf.rms_buf_val = NULL; 182 rms->rms_buf.rms_buf_len = 0; 183 rms->rms_err = FMD_ADM_ERR_MODFAIL; 184 } 185 186 (void) pthread_mutex_unlock(&mp->mod_stats_lock); 187 fmd_module_rele(mp); 188 return (TRUE); 189 } 190 191 bool_t 192 fmd_adm_modgstat_1_svc(struct fmd_rpc_modstat *rms, struct svc_req *req) 193 { 194 const size_t size = sizeof (fmd_statistics_t); 195 196 if (fmd_rpc_deny(req)) { 197 rms->rms_buf.rms_buf_val = NULL; 198 rms->rms_buf.rms_buf_len = 0; 199 rms->rms_err = FMD_ADM_ERR_PERM; 200 } else if ((rms->rms_buf.rms_buf_val = malloc(size)) != NULL) { 201 /* 202 * Note: the bcopy() here is valid only if no FMD_TYPE_STRING 203 * stats are present in fmd.d_stats (see definition in fmd.c). 204 */ 205 (void) pthread_mutex_lock(&fmd.d_stats_lock); 206 bcopy(fmd.d_stats, rms->rms_buf.rms_buf_val, size); 207 (void) pthread_mutex_unlock(&fmd.d_stats_lock); 208 rms->rms_buf.rms_buf_len = size / sizeof (fmd_stat_t); 209 rms->rms_err = 0; 210 } else { 211 rms->rms_buf.rms_buf_len = 0; 212 rms->rms_err = FMD_ADM_ERR_NOMEM; 213 } 214 215 return (TRUE); 216 } 217 218 bool_t 219 fmd_adm_modload_1_svc(char *path, int *rvp, struct svc_req *req) 220 { 221 fmd_module_t *mp; 222 const char *p; 223 int err = 0; 224 225 if (fmd_rpc_deny(req)) { 226 *rvp = FMD_ADM_ERR_PERM; 227 return (TRUE); 228 } 229 230 /* 231 * Before we endure the expense of constructing a module and attempting 232 * to load it, do a quick check to see if the pathname is valid. 233 */ 234 if (access(path, F_OK) != 0) { 235 *rvp = FMD_ADM_ERR_MODNOENT; 236 return (TRUE); 237 } 238 239 if ((p = strrchr(path, '.')) != NULL && strcmp(p, ".so") == 0) 240 mp = fmd_modhash_load(fmd.d_mod_hash, path, &fmd_rtld_ops); 241 else 242 mp = fmd_modhash_load(fmd.d_mod_hash, path, &fmd_proc_ops); 243 244 if (mp == NULL) { 245 switch (errno) { 246 case EFMD_MOD_LOADED: 247 err = FMD_ADM_ERR_MODEXIST; 248 break; 249 case EFMD_MOD_INIT: 250 err = FMD_ADM_ERR_MODINIT; 251 break; 252 default: 253 err = FMD_ADM_ERR_MODLOAD; 254 break; 255 } 256 } 257 258 *rvp = err; 259 return (TRUE); 260 } 261 262 bool_t 263 fmd_adm_modunload_1_svc(char *name, int *rvp, struct svc_req *req) 264 { 265 fmd_module_t *mp = NULL; 266 int err = 0; 267 268 if (fmd_rpc_deny(req)) 269 err = FMD_ADM_ERR_PERM; 270 else if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) 271 err = FMD_ADM_ERR_MODSRCH; 272 else if (mp == fmd.d_self) 273 err = FMD_ADM_ERR_MODBUSY; 274 else if (fmd_modhash_unload(fmd.d_mod_hash, name) != 0) 275 err = FMD_ADM_ERR_MODSRCH; 276 277 if (mp != NULL) 278 fmd_module_rele(mp); 279 280 *rvp = err; 281 return (TRUE); 282 } 283 284 bool_t 285 fmd_adm_modreset_1_svc(char *name, int *rvp, struct svc_req *req) 286 { 287 fmd_module_t *mp = NULL; 288 int err = 0; 289 290 if (fmd_rpc_deny(req)) 291 err = FMD_ADM_ERR_PERM; 292 else if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) 293 err = FMD_ADM_ERR_MODSRCH; 294 else if (mp == fmd.d_self) 295 err = FMD_ADM_ERR_MODBUSY; 296 else if (fmd_modhash_unload(fmd.d_mod_hash, name) != 0) 297 err = FMD_ADM_ERR_MODSRCH; 298 299 if (err == 0) 300 fmd_ckpt_delete(mp); /* erase any saved checkpoints */ 301 302 if (err == 0 && fmd_modhash_load(fmd.d_mod_hash, 303 mp->mod_path, mp->mod_ops) == NULL) { 304 if (errno == EFMD_MOD_INIT) 305 err = FMD_ADM_ERR_MODINIT; 306 else 307 err = FMD_ADM_ERR_MODLOAD; 308 } 309 310 if (mp != NULL) 311 fmd_module_rele(mp); 312 313 *rvp = err; 314 return (TRUE); 315 } 316 317 bool_t 318 fmd_adm_modgc_1_svc(char *name, int *rvp, struct svc_req *req) 319 { 320 fmd_module_t *mp; 321 int err = 0; 322 323 if (fmd_rpc_deny(req)) 324 err = FMD_ADM_ERR_PERM; 325 else if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) 326 err = FMD_ADM_ERR_MODSRCH; 327 else { 328 fmd_module_gc(mp); 329 fmd_module_rele(mp); 330 } 331 332 *rvp = err; 333 return (TRUE); 334 } 335 336 /* 337 * Unlike our other RPC callbacks, fmd_adm_rsrclist_1 can return large amounts 338 * of data that may exceed the underlying RPC transport buffer size if the 339 * resource cache is heavily populated and/or all resources are requested. 340 * To minimize the likelihood of running out of RPC buffer space and having to 341 * fail the client request, fmd_adm_rsrclist_1 returns a snapshot of the 342 * relevant FMRI strings only: the client can use fmd_adm_rsrcinfo_1 on an 343 * individual FMRI if more information is needed. To further reduce the XDR 344 * overhead, the string list is represented as XDR-opaque data where the 345 * entire list is returned as a string table (e.g. "fmriA\0fmriB\0..."). 346 */ 347 static void 348 fmd_adm_rsrclist_asru(fmd_asru_t *ap, void *arg) 349 { 350 struct fmd_rpc_rsrclist *rrl = arg; 351 size_t name_len, buf_len; 352 void *p; 353 354 /* 355 * Skip the ASRU if this fault is marked as invisible. 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 not faulty. 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 363 if (ap->asru_flags & FMD_ASRU_INVISIBLE) 364 return; 365 if (rrl->rrl_all == B_FALSE && !(ap->asru_flags & FMD_ASRU_FAULTY)) 366 return; 367 368 if (rrl->rrl_err != 0 || fmd_asru_getstate(ap) == 0) 369 return; /* error has occurred or resource is in 'ok' state */ 370 371 /* 372 * Lock the ASRU and reallocate rrl_buf[] to be large enough to hold 373 * another string, doubling it as needed. Then copy the new string 374 * on to the end, and increment rrl_len to indicate the used space. 375 */ 376 (void) pthread_mutex_lock(&ap->asru_lock); 377 name_len = strlen(ap->asru_name) + 1; 378 379 while (rrl->rrl_len + name_len > rrl->rrl_buf.rrl_buf_len) { 380 if (rrl->rrl_buf.rrl_buf_len != 0) 381 buf_len = rrl->rrl_buf.rrl_buf_len * 2; 382 else 383 buf_len = 1024; /* default buffer size */ 384 385 if ((p = realloc(rrl->rrl_buf.rrl_buf_val, buf_len)) != NULL) { 386 bzero((char *)p + rrl->rrl_buf.rrl_buf_len, 387 buf_len - rrl->rrl_buf.rrl_buf_len); 388 rrl->rrl_buf.rrl_buf_val = p; 389 rrl->rrl_buf.rrl_buf_len = buf_len; 390 } else { 391 rrl->rrl_err = FMD_ADM_ERR_NOMEM; 392 break; 393 } 394 } 395 396 if (rrl->rrl_err == 0) { 397 bcopy(ap->asru_name, (char *)rrl->rrl_buf.rrl_buf_val + 398 rrl->rrl_len, name_len); 399 rrl->rrl_len += name_len; 400 rrl->rrl_cnt++; 401 } 402 403 (void) pthread_mutex_unlock(&ap->asru_lock); 404 } 405 406 bool_t 407 fmd_adm_rsrclist_1_svc(bool_t all, 408 struct fmd_rpc_rsrclist *rvp, struct svc_req *req) 409 { 410 rvp->rrl_buf.rrl_buf_len = 0; 411 rvp->rrl_buf.rrl_buf_val = NULL; 412 rvp->rrl_len = 0; 413 rvp->rrl_cnt = 0; 414 rvp->rrl_err = 0; 415 rvp->rrl_all = all; 416 417 if (fmd_rpc_deny(req)) 418 rvp->rrl_err = FMD_ADM_ERR_PERM; 419 else 420 fmd_asru_hash_apply(fmd.d_asrus, fmd_adm_rsrclist_asru, rvp); 421 422 return (TRUE); 423 } 424 425 bool_t 426 fmd_adm_rsrcinfo_1_svc(char *fmri, 427 struct fmd_rpc_rsrcinfo *rvp, struct svc_req *req) 428 { 429 fmd_asru_t *ap; 430 fmd_case_impl_t *cip; 431 int state; 432 433 bzero(rvp, sizeof (struct fmd_rpc_rsrcinfo)); 434 435 if (fmd_rpc_deny(req)) { 436 rvp->rri_err = FMD_ADM_ERR_PERM; 437 return (TRUE); 438 } 439 440 if ((ap = fmd_asru_hash_lookup_name(fmd.d_asrus, fmri)) == NULL) { 441 rvp->rri_err = FMD_ADM_ERR_RSRCSRCH; 442 return (TRUE); 443 } 444 445 state = fmd_asru_getstate(ap); 446 (void) pthread_mutex_lock(&ap->asru_lock); 447 cip = (fmd_case_impl_t *)ap->asru_case; 448 449 rvp->rri_fmri = strdup(ap->asru_name); 450 rvp->rri_uuid = strdup(ap->asru_uuid); 451 rvp->rri_case = cip ? strdup(cip->ci_uuid) : NULL; 452 rvp->rri_faulty = (state & FMD_ASRU_FAULTY) != 0; 453 rvp->rri_unusable = (state & FMD_ASRU_UNUSABLE) != 0; 454 rvp->rri_invisible = (ap->asru_flags & FMD_ASRU_INVISIBLE) != 0; 455 456 (void) pthread_mutex_unlock(&ap->asru_lock); 457 fmd_asru_hash_release(fmd.d_asrus, ap); 458 459 if (rvp->rri_fmri == NULL || rvp->rri_uuid == NULL) 460 rvp->rri_err = FMD_ADM_ERR_NOMEM; 461 462 return (TRUE); 463 } 464 465 static void 466 fmd_adm_do_repair(char *name, struct svc_req *req, int *errp, uint8_t reason, 467 char *uuid) 468 { 469 if (fmd_rpc_deny(req)) 470 *errp = FMD_ADM_ERR_PERM; 471 else { 472 fmd_asru_rep_arg_t fara; 473 int err = FARA_ERR_RSRCNOTF; 474 475 fara.fara_reason = reason; 476 fara.fara_rval = &err; 477 fara.fara_uuid = uuid; 478 fara.fara_bywhat = FARA_BY_ASRU; 479 fmd_asru_hash_apply_by_asru(fmd.d_asrus, name, 480 fmd_asru_repaired, &fara); 481 fara.fara_bywhat = FARA_BY_LABEL; 482 fmd_asru_hash_apply_by_label(fmd.d_asrus, name, 483 fmd_asru_repaired, &fara); 484 fara.fara_bywhat = FARA_BY_FRU; 485 fmd_asru_hash_apply_by_fru(fmd.d_asrus, name, 486 fmd_asru_repaired, &fara); 487 fara.fara_bywhat = FARA_BY_RSRC; 488 fmd_asru_hash_apply_by_rsrc(fmd.d_asrus, name, 489 fmd_asru_repaired, &fara); 490 if (err == FARA_ERR_RSRCNOTR) 491 *errp = FMD_ADM_ERR_RSRCNOTR; 492 else if (err == FARA_OK) 493 *errp = 0; 494 } 495 } 496 497 bool_t 498 fmd_adm_rsrcflush_1_svc(char *name, int *rvp, struct svc_req *req) 499 { 500 int err = FMD_ADM_ERR_RSRCNOTF; 501 502 /* 503 * If anyone does an fmadm flush command, discard any resolved 504 * cases that were being retained for historic diagnosis. 505 */ 506 if (fmd_rpc_deny(req)) 507 err = FMD_ADM_ERR_PERM; 508 else { 509 fmd_asru_hash_apply_by_asru(fmd.d_asrus, name, 510 fmd_asru_flush, &err); 511 fmd_asru_hash_apply_by_label(fmd.d_asrus, name, 512 fmd_asru_flush, &err); 513 fmd_asru_hash_apply_by_fru(fmd.d_asrus, name, 514 fmd_asru_flush, &err); 515 fmd_asru_hash_apply_by_rsrc(fmd.d_asrus, name, 516 fmd_asru_flush, &err); 517 } 518 *rvp = err; 519 return (TRUE); 520 } 521 522 bool_t 523 fmd_adm_rsrcrepaired_1_svc(char *name, int *rvp, struct svc_req *req) 524 { 525 int err = FMD_ADM_ERR_RSRCNOTF; 526 527 fmd_adm_do_repair(name, req, &err, FMD_ASRU_REPAIRED, NULL); 528 *rvp = err; 529 return (TRUE); 530 } 531 532 bool_t 533 fmd_adm_rsrcreplaced_1_svc(char *name, int *rvp, struct svc_req *req) 534 { 535 int err = FMD_ADM_ERR_RSRCNOTF; 536 537 fmd_adm_do_repair(name, req, &err, FMD_ASRU_REPLACED, NULL); 538 *rvp = err; 539 return (TRUE); 540 } 541 542 bool_t 543 fmd_adm_rsrcacquit_1_svc(char *name, char *uuid, int *rvp, struct svc_req *req) 544 { 545 int err = FMD_ADM_ERR_RSRCNOTF; 546 547 fmd_adm_do_repair(name, req, &err, FMD_ASRU_ACQUITTED, uuid); 548 *rvp = err; 549 return (TRUE); 550 } 551 552 static void 553 fmd_adm_serdlist_measure(fmd_serd_eng_t *sgp, void *arg) 554 { 555 struct fmd_rpc_serdlist *rsl = arg; 556 557 rsl->rsl_len += strlen(sgp->sg_name) + 1; 558 rsl->rsl_cnt++; 559 } 560 561 static void 562 fmd_adm_serdlist_record(fmd_serd_eng_t *sgp, void *arg) 563 { 564 struct fmd_rpc_serdlist *rsl = arg; 565 566 bcopy(sgp->sg_name, rsl->rsl_buf.rsl_buf_val + rsl->rsl_len, 567 strlen(sgp->sg_name)); 568 rsl->rsl_len += strlen(sgp->sg_name) + 1; 569 } 570 571 bool_t 572 fmd_adm_serdlist_1_svc(char *name, struct fmd_rpc_serdlist *rvp, 573 struct svc_req *req) 574 { 575 fmd_module_t *mp; 576 void *p; 577 578 rvp->rsl_buf.rsl_buf_len = 0; 579 rvp->rsl_buf.rsl_buf_val = NULL; 580 rvp->rsl_len = 0; 581 rvp->rsl_cnt = 0; 582 rvp->rsl_err = 0; 583 584 if (fmd_rpc_deny(req)) { 585 rvp->rsl_err = FMD_ADM_ERR_PERM; 586 return (TRUE); 587 } 588 589 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) == NULL) { 590 rvp->rsl_err = FMD_ADM_ERR_MODSRCH; 591 return (TRUE); 592 } 593 594 fmd_module_lock(mp); 595 /* In the first pass, collect the overall length of the buffer. */ 596 fmd_serd_hash_apply(&mp->mod_serds, fmd_adm_serdlist_measure, rvp); 597 if (rvp->rsl_len == 0) { 598 fmd_module_unlock(mp); 599 fmd_module_rele(mp); 600 return (TRUE); 601 } 602 p = malloc(rvp->rsl_len); 603 if (p) { 604 rvp->rsl_buf.rsl_buf_val = p; 605 rvp->rsl_buf.rsl_buf_len = rvp->rsl_len; 606 bzero(rvp->rsl_buf.rsl_buf_val, rvp->rsl_buf.rsl_buf_len); 607 rvp->rsl_len = 0; 608 /* In the second pass, populate the buffer with data. */ 609 fmd_serd_hash_apply(&mp->mod_serds, fmd_adm_serdlist_record, 610 rvp); 611 } else { 612 rvp->rsl_err = FMD_ADM_ERR_NOMEM; 613 } 614 fmd_module_unlock(mp); 615 616 fmd_module_rele(mp); 617 return (TRUE); 618 } 619 620 static void 621 fmd_adm_serdinfo_record(fmd_serd_eng_t *sgp, struct fmd_rpc_serdinfo *rsi) 622 { 623 uint64_t old, now = fmd_time_gethrtime(); 624 const fmd_serd_elem_t *oep; 625 626 if ((rsi->rsi_name = strdup(sgp->sg_name)) == NULL) { 627 rsi->rsi_err = FMD_ADM_ERR_NOMEM; 628 return; 629 } 630 631 if ((oep = fmd_list_next(&sgp->sg_list)) != NULL) 632 old = fmd_event_hrtime(oep->se_event); 633 else 634 old = now; 635 636 rsi->rsi_delta = now >= old ? now - old : (UINT64_MAX - old) + now + 1; 637 rsi->rsi_count = sgp->sg_count; 638 rsi->rsi_fired = fmd_serd_eng_fired(sgp) != 0; 639 rsi->rsi_n = sgp->sg_n; 640 rsi->rsi_t = sgp->sg_t; 641 } 642 643 bool_t 644 fmd_adm_serdinfo_1_svc(char *mname, char *sname, struct fmd_rpc_serdinfo *rvp, 645 struct svc_req *req) 646 { 647 fmd_module_t *mp; 648 fmd_serd_eng_t *sgp; 649 650 bzero(rvp, sizeof (struct fmd_rpc_serdinfo)); 651 652 if (fmd_rpc_deny(req)) { 653 rvp->rsi_err = FMD_ADM_ERR_PERM; 654 return (TRUE); 655 } 656 657 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, mname)) == NULL) { 658 rvp->rsi_err = FMD_ADM_ERR_MODSRCH; 659 return (TRUE); 660 } 661 662 fmd_module_lock(mp); 663 664 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, sname)) != NULL) { 665 fmd_adm_serdinfo_record(sgp, rvp); 666 } else 667 rvp->rsi_err = FMD_ADM_ERR_SERDSRCH; 668 669 fmd_module_unlock(mp); 670 fmd_module_rele(mp); 671 672 return (TRUE); 673 } 674 675 /*ARGSUSED*/ 676 bool_t 677 fmd_adm_serdinfo_old_1_svc(char *name, struct fmd_rpc_serdlist *rvp, 678 struct svc_req *req) 679 { 680 return (FALSE); 681 } 682 683 bool_t 684 fmd_adm_serdreset_1_svc(char *mname, char *sname, int *rvp, struct svc_req *req) 685 { 686 fmd_module_t *mp; 687 fmd_serd_eng_t *sgp; 688 int err = 0; 689 690 if (fmd_rpc_deny(req)) { 691 *rvp = FMD_ADM_ERR_PERM; 692 return (TRUE); 693 } 694 695 if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, mname)) == NULL) { 696 *rvp = FMD_ADM_ERR_MODSRCH; 697 return (TRUE); 698 } 699 700 fmd_module_lock(mp); 701 702 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, sname)) != NULL) { 703 if (fmd_serd_eng_fired(sgp)) { 704 err = FMD_ADM_ERR_SERDFIRED; 705 } else { 706 fmd_serd_eng_reset(sgp); 707 fmd_module_setdirty(mp); 708 } 709 } else 710 err = FMD_ADM_ERR_SERDSRCH; 711 712 fmd_module_unlock(mp); 713 fmd_module_rele(mp); 714 715 *rvp = err; 716 return (TRUE); 717 } 718 719 bool_t 720 fmd_adm_logrotate_1_svc(char *name, int *rvp, struct svc_req *req) 721 { 722 fmd_log_t **lpp, *old, *new; 723 int try = 1, trylimit = 1; 724 pthread_rwlock_t *lockp; 725 726 hrtime_t nsec = 0; 727 timespec_t tv; 728 729 if (fmd_rpc_deny(req)) { 730 *rvp = FMD_ADM_ERR_PERM; 731 return (TRUE); 732 } 733 734 if (strcmp(name, "errlog") == 0) { 735 lpp = &fmd.d_errlog; 736 lockp = &fmd.d_log_lock; 737 } else if (strcmp(name, "fltlog") == 0) { 738 lpp = &fmd.d_fltlog; 739 lockp = &fmd.d_log_lock; 740 } else if (strcmp(name, "infolog") == 0) { 741 lpp = &fmd.d_ilog; 742 lockp = &fmd.d_ilog_lock; 743 } else if (strcmp(name, "infolog_hival") == 0) { 744 lpp = &fmd.d_hvilog; 745 lockp = &fmd.d_hvilog_lock; 746 } else { 747 *rvp = FMD_ADM_ERR_ROTSRCH; 748 return (TRUE); 749 } 750 751 (void) fmd_conf_getprop(fmd.d_conf, "log.tryrotate", &trylimit); 752 (void) fmd_conf_getprop(fmd.d_conf, "log.waitrotate", &nsec); 753 754 tv.tv_sec = nsec / NANOSEC; 755 tv.tv_nsec = nsec % NANOSEC; 756 757 /* 758 * To rotate a log file, grab d_log_lock as writer to make sure no 759 * one else can discover the current log pointer. Then try to rotate 760 * the log. If we're successful, release the old log pointer. 761 */ 762 do { 763 if (try > 1) 764 (void) nanosleep(&tv, NULL); /* wait for checkpoints */ 765 766 (void) pthread_rwlock_wrlock(lockp); 767 old = *lpp; 768 769 if ((new = fmd_log_rotate(old)) != NULL) { 770 fmd_log_rele(old); 771 *lpp = new; 772 } 773 774 (void) pthread_rwlock_unlock(lockp); 775 776 } while (new == NULL && errno == EFMD_LOG_ROTBUSY && try++ < trylimit); 777 778 if (new != NULL) 779 *rvp = 0; 780 else if (errno == EFMD_LOG_ROTBUSY) 781 *rvp = FMD_ADM_ERR_ROTBUSY; 782 else 783 *rvp = FMD_ADM_ERR_ROTFAIL; 784 785 return (TRUE); 786 } 787 788 bool_t 789 fmd_adm_caserepair_1_svc(char *uuid, int *rvp, struct svc_req *req) 790 { 791 fmd_case_t *cp = NULL; 792 int err = 0; 793 794 if (fmd_rpc_deny(req)) 795 err = FMD_ADM_ERR_PERM; 796 else if ((cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) == NULL) 797 err = FMD_ADM_ERR_CASESRCH; 798 else if (fmd_case_repair(cp) != 0) { 799 err = errno == EFMD_CASE_OWNER ? 800 FMD_ADM_ERR_CASEXPRT : FMD_ADM_ERR_CASEOPEN; 801 } 802 803 if (cp != NULL) 804 fmd_case_rele(cp); 805 806 *rvp = err; 807 return (TRUE); 808 } 809 810 bool_t 811 fmd_adm_caseacquit_1_svc(char *uuid, int *rvp, struct svc_req *req) 812 { 813 fmd_case_t *cp = NULL; 814 int err = 0; 815 816 if (fmd_rpc_deny(req)) 817 err = FMD_ADM_ERR_PERM; 818 else if ((cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) == NULL) 819 err = FMD_ADM_ERR_CASESRCH; 820 else if (fmd_case_acquit(cp) != 0) { 821 err = errno == EFMD_CASE_OWNER ? 822 FMD_ADM_ERR_CASEXPRT : FMD_ADM_ERR_CASEOPEN; 823 } 824 825 if (cp != NULL) 826 fmd_case_rele(cp); 827 828 *rvp = err; 829 return (TRUE); 830 } 831 832 void 833 fmd_adm_caselist_case(fmd_case_t *cp, void *arg) 834 { 835 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 836 struct fmd_rpc_caselist *rcl = arg; 837 size_t uuid_len, buf_len; 838 void *p; 839 840 if (rcl->rcl_err != 0) 841 return; 842 843 /* 844 * skip invisible cases 845 */ 846 if (cip->ci_flags & FMD_CF_INVISIBLE) 847 return; 848 849 /* 850 * Lock the case and reallocate rcl_buf[] to be large enough to hold 851 * another string, doubling it as needed. Then copy the new string 852 * on to the end, and increment rcl_len to indicate the used space. 853 */ 854 if (!(cip->ci_flags & FMD_CF_SOLVED)) 855 return; 856 857 (void) pthread_mutex_lock(&cip->ci_lock); 858 859 uuid_len = cip->ci_uuidlen + 1; 860 861 while (rcl->rcl_len + uuid_len > rcl->rcl_buf.rcl_buf_len) { 862 if (rcl->rcl_buf.rcl_buf_len != 0) 863 buf_len = rcl->rcl_buf.rcl_buf_len * 2; 864 else 865 buf_len = 1024; /* default buffer size */ 866 867 if ((p = realloc(rcl->rcl_buf.rcl_buf_val, buf_len)) != NULL) { 868 bzero((char *)p + rcl->rcl_buf.rcl_buf_len, 869 buf_len - rcl->rcl_buf.rcl_buf_len); 870 rcl->rcl_buf.rcl_buf_val = p; 871 rcl->rcl_buf.rcl_buf_len = buf_len; 872 } else { 873 rcl->rcl_err = FMD_ADM_ERR_NOMEM; 874 break; 875 } 876 } 877 878 if (rcl->rcl_err == 0) { 879 bcopy(cip->ci_uuid, (char *)rcl->rcl_buf.rcl_buf_val + 880 rcl->rcl_len, uuid_len); 881 rcl->rcl_len += uuid_len; 882 rcl->rcl_cnt++; 883 } 884 885 (void) pthread_mutex_unlock(&cip->ci_lock); 886 } 887 888 bool_t 889 fmd_adm_caselist_1_svc(struct fmd_rpc_caselist *rvp, struct svc_req *req) 890 { 891 rvp->rcl_buf.rcl_buf_len = 0; 892 rvp->rcl_buf.rcl_buf_val = NULL; 893 rvp->rcl_len = 0; 894 rvp->rcl_cnt = 0; 895 rvp->rcl_err = 0; 896 897 if (fmd_rpc_deny(req)) 898 rvp->rcl_err = FMD_ADM_ERR_PERM; 899 else 900 fmd_case_hash_apply(fmd.d_cases, fmd_adm_caselist_case, rvp); 901 902 return (TRUE); 903 } 904 905 bool_t 906 fmd_adm_caseinfo_1_svc(char *uuid, struct fmd_rpc_caseinfo *rvp, 907 struct svc_req *req) 908 { 909 fmd_case_t *cp; 910 nvlist_t *nvl; 911 int err = 0; 912 913 bzero(rvp, sizeof (struct fmd_rpc_caseinfo)); 914 915 if (fmd_rpc_deny(req)) { 916 rvp->rci_err = FMD_ADM_ERR_PERM; 917 return (TRUE); 918 } 919 920 if ((cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) == NULL) { 921 rvp->rci_err = FMD_ADM_ERR_CASESRCH; 922 return (TRUE); 923 } 924 925 if (!(((fmd_case_impl_t *)cp)->ci_flags & FMD_CF_SOLVED)) { 926 fmd_case_rele(cp); 927 rvp->rci_err = FMD_ADM_ERR_CASESRCH; 928 return (TRUE); 929 } 930 931 nvl = fmd_case_mkevent(cp, FM_LIST_SUSPECT_CLASS); 932 933 err = nvlist_pack(nvl, &rvp->rci_evbuf.rci_evbuf_val, 934 &rvp->rci_evbuf.rci_evbuf_len, NV_ENCODE_XDR, 0); 935 936 nvlist_free(nvl); 937 938 if (err != 0) 939 rvp->rci_err = FMD_ADM_ERR_NOMEM; 940 941 fmd_case_rele(cp); 942 943 return (TRUE); 944 } 945 946 /*ARGSUSED*/ 947 static void 948 fmd_adm_xprtlist_one(fmd_idspace_t *ids, id_t id, void *arg) 949 { 950 struct fmd_rpc_xprtlist *rvp = arg; 951 952 if (rvp->rxl_len < rvp->rxl_buf.rxl_buf_len) 953 rvp->rxl_buf.rxl_buf_val[rvp->rxl_len++] = id; 954 } 955 956 bool_t 957 fmd_adm_xprtlist_1_svc(struct fmd_rpc_xprtlist *rvp, struct svc_req *req) 958 { 959 if (fmd_rpc_deny(req)) { 960 rvp->rxl_buf.rxl_buf_len = 0; 961 rvp->rxl_buf.rxl_buf_val = NULL; 962 rvp->rxl_len = 0; 963 rvp->rxl_err = FMD_ADM_ERR_PERM; 964 return (TRUE); 965 } 966 967 /* 968 * Since we're taking a snapshot of the transports, and these could 969 * change after we return our result, there's no need to hold any kind 970 * of lock between retrieving ids_count and taking the snapshot. We'll 971 * just capture up to a maximum of whatever ids_count value we sampled. 972 */ 973 rvp->rxl_buf.rxl_buf_len = fmd.d_xprt_ids->ids_count; 974 rvp->rxl_buf.rxl_buf_val = malloc(sizeof (int32_t) * 975 rvp->rxl_buf.rxl_buf_len); 976 rvp->rxl_len = 0; 977 rvp->rxl_err = 0; 978 979 if (rvp->rxl_buf.rxl_buf_val == NULL) { 980 rvp->rxl_err = FMD_ADM_ERR_NOMEM; 981 return (TRUE); 982 } 983 984 fmd_idspace_apply(fmd.d_xprt_ids, fmd_adm_xprtlist_one, rvp); 985 return (TRUE); 986 } 987 988 bool_t 989 fmd_adm_xprtstat_1_svc(int32_t id, 990 struct fmd_rpc_modstat *rms, struct svc_req *req) 991 { 992 fmd_xprt_impl_t *xip; 993 fmd_stat_t *sp, *ep, *cp; 994 995 if (fmd_rpc_deny(req)) { 996 rms->rms_buf.rms_buf_val = NULL; 997 rms->rms_buf.rms_buf_len = 0; 998 rms->rms_err = FMD_ADM_ERR_PERM; 999 return (TRUE); 1000 } 1001 1002 rms->rms_buf.rms_buf_val = malloc(sizeof (fmd_xprt_stat_t)); 1003 rms->rms_buf.rms_buf_len = sizeof (fmd_xprt_stat_t) / 1004 sizeof (fmd_stat_t); 1005 rms->rms_err = 0; 1006 1007 if (rms->rms_buf.rms_buf_val == NULL) { 1008 rms->rms_err = FMD_ADM_ERR_NOMEM; 1009 rms->rms_buf.rms_buf_len = 0; 1010 return (TRUE); 1011 } 1012 1013 if ((xip = fmd_idspace_hold(fmd.d_xprt_ids, id)) == NULL) { 1014 rms->rms_err = FMD_ADM_ERR_XPRTSRCH; 1015 return (TRUE); 1016 } 1017 1018 /* 1019 * Grab the stats lock and bcopy the entire transport stats array in 1020 * one shot. Then go back through and duplicate any string values. 1021 */ 1022 (void) pthread_mutex_lock(&xip->xi_stats_lock); 1023 1024 sp = (fmd_stat_t *)xip->xi_stats; 1025 ep = sp + rms->rms_buf.rms_buf_len; 1026 cp = rms->rms_buf.rms_buf_val; 1027 1028 bcopy(sp, cp, sizeof (fmd_xprt_stat_t)); 1029 1030 for (; sp < ep; sp++, cp++) { 1031 if (sp->fmds_type == FMD_TYPE_STRING && 1032 sp->fmds_value.str != NULL) 1033 cp->fmds_value.str = strdup(sp->fmds_value.str); 1034 } 1035 1036 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1037 fmd_idspace_rele(fmd.d_xprt_ids, id); 1038 1039 return (TRUE); 1040 } 1041 1042 int 1043 fmd_adm_1_freeresult(SVCXPRT *xprt, xdrproc_t proc, caddr_t data) 1044 { 1045 xdr_free(proc, data); 1046 svc_done(xprt); 1047 return (TRUE); 1048 } 1049 1050 /* 1051 * Custom XDR routine for our API structure fmd_stat_t. This function must 1052 * match the definition of fmd_stat_t in <fmd_api.h> and must also match 1053 * the corresponding routine in usr/src/lib/fm/libfmd_adm/common/fmd_adm.c. 1054 */ 1055 bool_t 1056 xdr_fmd_stat(XDR *xp, fmd_stat_t *sp) 1057 { 1058 bool_t rv = TRUE; 1059 1060 rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name)); 1061 rv &= xdr_u_int(xp, &sp->fmds_type); 1062 rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc)); 1063 1064 switch (sp->fmds_type) { 1065 case FMD_TYPE_BOOL: 1066 rv &= xdr_int(xp, &sp->fmds_value.bool); 1067 break; 1068 case FMD_TYPE_INT32: 1069 rv &= xdr_int32_t(xp, &sp->fmds_value.i32); 1070 break; 1071 case FMD_TYPE_UINT32: 1072 rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32); 1073 break; 1074 case FMD_TYPE_INT64: 1075 rv &= xdr_int64_t(xp, &sp->fmds_value.i64); 1076 break; 1077 case FMD_TYPE_UINT64: 1078 case FMD_TYPE_TIME: 1079 case FMD_TYPE_SIZE: 1080 rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64); 1081 break; 1082 case FMD_TYPE_STRING: 1083 rv &= xdr_string(xp, &sp->fmds_value.str, ~0); 1084 break; 1085 } 1086 1087 return (rv); 1088 } 1089