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.
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.
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]
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
32 #include <fmd_rpc_adm.h>
34 #include <fmd_module.h>
35 #include <fmd_ustat.h>
36 #include <fmd_error.h>
41 #include <fmd_idspace.h>
47 fmd_adm_modinfo_1_svc(struct fmd_rpc_modlist
*rvp
, struct svc_req
*req
)
49 struct fmd_rpc_modinfo
*rmi
;
56 if (fmd_rpc_deny(req
)) {
57 rvp
->rml_err
= FMD_ADM_ERR_PERM
;
61 (void) pthread_mutex_lock(&fmd
.d_mod_lock
);
63 for (mp
= fmd_list_next(&fmd
.d_mod_list
);
64 mp
!= NULL
; mp
= fmd_list_next(mp
)) {
66 if ((rmi
= malloc(sizeof (struct fmd_rpc_modinfo
))) == NULL
) {
67 rvp
->rml_err
= FMD_ADM_ERR_NOMEM
;
74 * If mod_info is NULL, the module is in the middle of loading:
75 * do not report its presence to observability tools yet.
77 if (mp
->mod_info
== NULL
) {
78 fmd_module_unlock(mp
);
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
;
89 fmd_module_unlock(mp
);
93 if (rmi
->rmi_desc
== NULL
|| rmi
->rmi_vers
== NULL
) {
94 rvp
->rml_err
= FMD_ADM_ERR_NOMEM
;
99 (void) pthread_mutex_unlock(&fmd
.d_mod_lock
);
104 fmd_adm_modcstat_1_svc(char *name
,
105 struct fmd_rpc_modstat
*rms
, struct svc_req
*req
)
107 fmd_ustat_snap_t snap
;
110 rms
->rms_buf
.rms_buf_val
= NULL
;
111 rms
->rms_buf
.rms_buf_len
= 0;
114 if (fmd_rpc_deny(req
)) {
115 rms
->rms_err
= FMD_ADM_ERR_PERM
;
119 if ((mp
= fmd_modhash_lookup(fmd
.d_mod_hash
, name
)) == NULL
) {
120 rms
->rms_err
= FMD_ADM_ERR_MODSRCH
;
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
;
130 rms
->rms_err
= FMD_ADM_ERR_NOMEM
;
137 fmd_adm_moddstat_1_svc(char *name
,
138 struct fmd_rpc_modstat
*rms
, struct svc_req
*req
)
142 rms
->rms_buf
.rms_buf_val
= NULL
;
143 rms
->rms_buf
.rms_buf_len
= 0;
146 if (fmd_rpc_deny(req
)) {
147 rms
->rms_err
= FMD_ADM_ERR_PERM
;
151 if ((mp
= fmd_modhash_lookup(fmd
.d_mod_hash
, name
)) == NULL
) {
152 rms
->rms_err
= FMD_ADM_ERR_MODSRCH
;
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
);
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;
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.
173 (void) pthread_mutex_lock(&mp
->mod_stats_lock
);
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
));
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
;
186 (void) pthread_mutex_unlock(&mp
->mod_stats_lock
);
192 fmd_adm_modgstat_1_svc(struct fmd_rpc_modstat
*rms
, struct svc_req
*req
)
194 const size_t size
= sizeof (fmd_statistics_t
);
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
) {
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).
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
);
211 rms
->rms_buf
.rms_buf_len
= 0;
212 rms
->rms_err
= FMD_ADM_ERR_NOMEM
;
219 fmd_adm_modload_1_svc(char *path
, int *rvp
, struct svc_req
*req
)
225 if (fmd_rpc_deny(req
)) {
226 *rvp
= FMD_ADM_ERR_PERM
;
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.
234 if (access(path
, F_OK
) != 0) {
235 *rvp
= FMD_ADM_ERR_MODNOENT
;
239 if ((p
= strrchr(path
, '.')) != NULL
&& strcmp(p
, ".so") == 0)
240 mp
= fmd_modhash_load(fmd
.d_mod_hash
, path
, &fmd_rtld_ops
);
242 mp
= fmd_modhash_load(fmd
.d_mod_hash
, path
, &fmd_proc_ops
);
246 case EFMD_MOD_LOADED
:
247 err
= FMD_ADM_ERR_MODEXIST
;
250 err
= FMD_ADM_ERR_MODINIT
;
253 err
= FMD_ADM_ERR_MODLOAD
;
263 fmd_adm_modunload_1_svc(char *name
, int *rvp
, struct svc_req
*req
)
265 fmd_module_t
*mp
= NULL
;
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
;
285 fmd_adm_modreset_1_svc(char *name
, int *rvp
, struct svc_req
*req
)
287 fmd_module_t
*mp
= NULL
;
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
;
300 fmd_ckpt_delete(mp
); /* erase any saved checkpoints */
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
;
307 err
= FMD_ADM_ERR_MODLOAD
;
318 fmd_adm_modgc_1_svc(char *name
, int *rvp
, struct svc_req
*req
)
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
;
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...").
348 fmd_adm_rsrclist_asru(fmd_asru_t
*ap
, void *arg
)
350 struct fmd_rpc_rsrclist
*rrl
= arg
;
351 size_t name_len
, buf_len
;
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.
363 if (ap
->asru_flags
& FMD_ASRU_INVISIBLE
)
365 if (rrl
->rrl_all
== B_FALSE
&& !(ap
->asru_flags
& FMD_ASRU_FAULTY
))
368 if (rrl
->rrl_err
!= 0 || fmd_asru_getstate(ap
) == 0)
369 return; /* error has occurred or resource is in 'ok' state */
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.
376 (void) pthread_mutex_lock(&ap
->asru_lock
);
377 name_len
= strlen(ap
->asru_name
) + 1;
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;
383 buf_len
= 1024; /* default buffer size */
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
;
391 rrl
->rrl_err
= FMD_ADM_ERR_NOMEM
;
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
;
403 (void) pthread_mutex_unlock(&ap
->asru_lock
);
407 fmd_adm_rsrclist_1_svc(bool_t all
,
408 struct fmd_rpc_rsrclist
*rvp
, struct svc_req
*req
)
410 rvp
->rrl_buf
.rrl_buf_len
= 0;
411 rvp
->rrl_buf
.rrl_buf_val
= NULL
;
417 if (fmd_rpc_deny(req
))
418 rvp
->rrl_err
= FMD_ADM_ERR_PERM
;
420 fmd_asru_hash_apply(fmd
.d_asrus
, fmd_adm_rsrclist_asru
, rvp
);
426 fmd_adm_rsrcinfo_1_svc(char *fmri
,
427 struct fmd_rpc_rsrcinfo
*rvp
, struct svc_req
*req
)
430 fmd_case_impl_t
*cip
;
433 bzero(rvp
, sizeof (struct fmd_rpc_rsrcinfo
));
435 if (fmd_rpc_deny(req
)) {
436 rvp
->rri_err
= FMD_ADM_ERR_PERM
;
440 if ((ap
= fmd_asru_hash_lookup_name(fmd
.d_asrus
, fmri
)) == NULL
) {
441 rvp
->rri_err
= FMD_ADM_ERR_RSRCSRCH
;
445 state
= fmd_asru_getstate(ap
);
446 (void) pthread_mutex_lock(&ap
->asru_lock
);
447 cip
= (fmd_case_impl_t
*)ap
->asru_case
;
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;
456 (void) pthread_mutex_unlock(&ap
->asru_lock
);
457 fmd_asru_hash_release(fmd
.d_asrus
, ap
);
459 if (rvp
->rri_fmri
== NULL
|| rvp
->rri_uuid
== NULL
)
460 rvp
->rri_err
= FMD_ADM_ERR_NOMEM
;
466 fmd_adm_do_repair(char *name
, struct svc_req
*req
, int *errp
, uint8_t reason
,
469 if (fmd_rpc_deny(req
))
470 *errp
= FMD_ADM_ERR_PERM
;
472 fmd_asru_rep_arg_t fara
;
473 int err
= FARA_ERR_RSRCNOTF
;
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
)
498 fmd_adm_rsrcflush_1_svc(char *name
, int *rvp
, struct svc_req
*req
)
500 int err
= FMD_ADM_ERR_RSRCNOTF
;
503 * If anyone does an fmadm flush command, discard any resolved
504 * cases that were being retained for historic diagnosis.
506 if (fmd_rpc_deny(req
))
507 err
= FMD_ADM_ERR_PERM
;
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
);
523 fmd_adm_rsrcrepaired_1_svc(char *name
, int *rvp
, struct svc_req
*req
)
525 int err
= FMD_ADM_ERR_RSRCNOTF
;
527 fmd_adm_do_repair(name
, req
, &err
, FMD_ASRU_REPAIRED
, NULL
);
533 fmd_adm_rsrcreplaced_1_svc(char *name
, int *rvp
, struct svc_req
*req
)
535 int err
= FMD_ADM_ERR_RSRCNOTF
;
537 fmd_adm_do_repair(name
, req
, &err
, FMD_ASRU_REPLACED
, NULL
);
543 fmd_adm_rsrcacquit_1_svc(char *name
, char *uuid
, int *rvp
, struct svc_req
*req
)
545 int err
= FMD_ADM_ERR_RSRCNOTF
;
547 fmd_adm_do_repair(name
, req
, &err
, FMD_ASRU_ACQUITTED
, uuid
);
553 fmd_adm_serdlist_measure(fmd_serd_eng_t
*sgp
, void *arg
)
555 struct fmd_rpc_serdlist
*rsl
= arg
;
557 rsl
->rsl_len
+= strlen(sgp
->sg_name
) + 1;
562 fmd_adm_serdlist_record(fmd_serd_eng_t
*sgp
, void *arg
)
564 struct fmd_rpc_serdlist
*rsl
= arg
;
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;
572 fmd_adm_serdlist_1_svc(char *name
, struct fmd_rpc_serdlist
*rvp
,
578 rvp
->rsl_buf
.rsl_buf_len
= 0;
579 rvp
->rsl_buf
.rsl_buf_val
= NULL
;
584 if (fmd_rpc_deny(req
)) {
585 rvp
->rsl_err
= FMD_ADM_ERR_PERM
;
589 if ((mp
= fmd_modhash_lookup(fmd
.d_mod_hash
, name
)) == NULL
) {
590 rvp
->rsl_err
= FMD_ADM_ERR_MODSRCH
;
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
);
602 p
= malloc(rvp
->rsl_len
);
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
);
608 /* In the second pass, populate the buffer with data. */
609 fmd_serd_hash_apply(&mp
->mod_serds
, fmd_adm_serdlist_record
,
612 rvp
->rsl_err
= FMD_ADM_ERR_NOMEM
;
614 fmd_module_unlock(mp
);
621 fmd_adm_serdinfo_record(fmd_serd_eng_t
*sgp
, struct fmd_rpc_serdinfo
*rsi
)
623 uint64_t old
, now
= fmd_time_gethrtime();
624 const fmd_serd_elem_t
*oep
;
626 if ((rsi
->rsi_name
= strdup(sgp
->sg_name
)) == NULL
) {
627 rsi
->rsi_err
= FMD_ADM_ERR_NOMEM
;
631 if ((oep
= fmd_list_next(&sgp
->sg_list
)) != NULL
)
632 old
= fmd_event_hrtime(oep
->se_event
);
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
;
644 fmd_adm_serdinfo_1_svc(char *mname
, char *sname
, struct fmd_rpc_serdinfo
*rvp
,
650 bzero(rvp
, sizeof (struct fmd_rpc_serdinfo
));
652 if (fmd_rpc_deny(req
)) {
653 rvp
->rsi_err
= FMD_ADM_ERR_PERM
;
657 if ((mp
= fmd_modhash_lookup(fmd
.d_mod_hash
, mname
)) == NULL
) {
658 rvp
->rsi_err
= FMD_ADM_ERR_MODSRCH
;
664 if ((sgp
= fmd_serd_eng_lookup(&mp
->mod_serds
, sname
)) != NULL
) {
665 fmd_adm_serdinfo_record(sgp
, rvp
);
667 rvp
->rsi_err
= FMD_ADM_ERR_SERDSRCH
;
669 fmd_module_unlock(mp
);
677 fmd_adm_serdinfo_old_1_svc(char *name
, struct fmd_rpc_serdlist
*rvp
,
684 fmd_adm_serdreset_1_svc(char *mname
, char *sname
, int *rvp
, struct svc_req
*req
)
690 if (fmd_rpc_deny(req
)) {
691 *rvp
= FMD_ADM_ERR_PERM
;
695 if ((mp
= fmd_modhash_lookup(fmd
.d_mod_hash
, mname
)) == NULL
) {
696 *rvp
= FMD_ADM_ERR_MODSRCH
;
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
;
706 fmd_serd_eng_reset(sgp
);
707 fmd_module_setdirty(mp
);
710 err
= FMD_ADM_ERR_SERDSRCH
;
712 fmd_module_unlock(mp
);
720 fmd_adm_logrotate_1_svc(char *name
, int *rvp
, struct svc_req
*req
)
722 fmd_log_t
**lpp
, *old
, *new;
723 int try = 1, trylimit
= 1;
724 pthread_rwlock_t
*lockp
;
729 if (fmd_rpc_deny(req
)) {
730 *rvp
= FMD_ADM_ERR_PERM
;
734 if (strcmp(name
, "errlog") == 0) {
736 lockp
= &fmd
.d_log_lock
;
737 } else if (strcmp(name
, "fltlog") == 0) {
739 lockp
= &fmd
.d_log_lock
;
740 } else if (strcmp(name
, "infolog") == 0) {
742 lockp
= &fmd
.d_ilog_lock
;
743 } else if (strcmp(name
, "infolog_hival") == 0) {
745 lockp
= &fmd
.d_hvilog_lock
;
747 *rvp
= FMD_ADM_ERR_ROTSRCH
;
751 (void) fmd_conf_getprop(fmd
.d_conf
, "log.tryrotate", &trylimit
);
752 (void) fmd_conf_getprop(fmd
.d_conf
, "log.waitrotate", &nsec
);
754 tv
.tv_sec
= nsec
/ NANOSEC
;
755 tv
.tv_nsec
= nsec
% NANOSEC
;
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.
764 (void) nanosleep(&tv
, NULL
); /* wait for checkpoints */
766 (void) pthread_rwlock_wrlock(lockp
);
769 if ((new = fmd_log_rotate(old
)) != NULL
) {
774 (void) pthread_rwlock_unlock(lockp
);
776 } while (new == NULL
&& errno
== EFMD_LOG_ROTBUSY
&& try++ < trylimit
);
780 else if (errno
== EFMD_LOG_ROTBUSY
)
781 *rvp
= FMD_ADM_ERR_ROTBUSY
;
783 *rvp
= FMD_ADM_ERR_ROTFAIL
;
789 fmd_adm_caserepair_1_svc(char *uuid
, int *rvp
, struct svc_req
*req
)
791 fmd_case_t
*cp
= NULL
;
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
;
811 fmd_adm_caseacquit_1_svc(char *uuid
, int *rvp
, struct svc_req
*req
)
813 fmd_case_t
*cp
= NULL
;
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
;
833 fmd_adm_caselist_case(fmd_case_t
*cp
, void *arg
)
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
;
840 if (rcl
->rcl_err
!= 0)
844 * skip invisible cases
846 if (cip
->ci_flags
& FMD_CF_INVISIBLE
)
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.
854 if (!(cip
->ci_flags
& FMD_CF_SOLVED
))
857 (void) pthread_mutex_lock(&cip
->ci_lock
);
859 uuid_len
= cip
->ci_uuidlen
+ 1;
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;
865 buf_len
= 1024; /* default buffer size */
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
;
873 rcl
->rcl_err
= FMD_ADM_ERR_NOMEM
;
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
;
885 (void) pthread_mutex_unlock(&cip
->ci_lock
);
889 fmd_adm_caselist_1_svc(struct fmd_rpc_caselist
*rvp
, struct svc_req
*req
)
891 rvp
->rcl_buf
.rcl_buf_len
= 0;
892 rvp
->rcl_buf
.rcl_buf_val
= NULL
;
897 if (fmd_rpc_deny(req
))
898 rvp
->rcl_err
= FMD_ADM_ERR_PERM
;
900 fmd_case_hash_apply(fmd
.d_cases
, fmd_adm_caselist_case
, rvp
);
906 fmd_adm_caseinfo_1_svc(char *uuid
, struct fmd_rpc_caseinfo
*rvp
,
913 bzero(rvp
, sizeof (struct fmd_rpc_caseinfo
));
915 if (fmd_rpc_deny(req
)) {
916 rvp
->rci_err
= FMD_ADM_ERR_PERM
;
920 if ((cp
= fmd_case_hash_lookup(fmd
.d_cases
, uuid
)) == NULL
) {
921 rvp
->rci_err
= FMD_ADM_ERR_CASESRCH
;
925 if (!(((fmd_case_impl_t
*)cp
)->ci_flags
& FMD_CF_SOLVED
)) {
927 rvp
->rci_err
= FMD_ADM_ERR_CASESRCH
;
931 nvl
= fmd_case_mkevent(cp
, FM_LIST_SUSPECT_CLASS
);
933 err
= nvlist_pack(nvl
, &rvp
->rci_evbuf
.rci_evbuf_val
,
934 &rvp
->rci_evbuf
.rci_evbuf_len
, NV_ENCODE_XDR
, 0);
939 rvp
->rci_err
= FMD_ADM_ERR_NOMEM
;
948 fmd_adm_xprtlist_one(fmd_idspace_t
*ids
, id_t id
, void *arg
)
950 struct fmd_rpc_xprtlist
*rvp
= arg
;
952 if (rvp
->rxl_len
< rvp
->rxl_buf
.rxl_buf_len
)
953 rvp
->rxl_buf
.rxl_buf_val
[rvp
->rxl_len
++] = id
;
957 fmd_adm_xprtlist_1_svc(struct fmd_rpc_xprtlist
*rvp
, struct svc_req
*req
)
959 if (fmd_rpc_deny(req
)) {
960 rvp
->rxl_buf
.rxl_buf_len
= 0;
961 rvp
->rxl_buf
.rxl_buf_val
= NULL
;
963 rvp
->rxl_err
= FMD_ADM_ERR_PERM
;
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.
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
);
979 if (rvp
->rxl_buf
.rxl_buf_val
== NULL
) {
980 rvp
->rxl_err
= FMD_ADM_ERR_NOMEM
;
984 fmd_idspace_apply(fmd
.d_xprt_ids
, fmd_adm_xprtlist_one
, rvp
);
989 fmd_adm_xprtstat_1_svc(int32_t id
,
990 struct fmd_rpc_modstat
*rms
, struct svc_req
*req
)
992 fmd_xprt_impl_t
*xip
;
993 fmd_stat_t
*sp
, *ep
, *cp
;
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
;
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
);
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;
1013 if ((xip
= fmd_idspace_hold(fmd
.d_xprt_ids
, id
)) == NULL
) {
1014 rms
->rms_err
= FMD_ADM_ERR_XPRTSRCH
;
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.
1022 (void) pthread_mutex_lock(&xip
->xi_stats_lock
);
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
;
1028 bcopy(sp
, cp
, sizeof (fmd_xprt_stat_t
));
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
);
1036 (void) pthread_mutex_unlock(&xip
->xi_stats_lock
);
1037 fmd_idspace_rele(fmd
.d_xprt_ids
, id
);
1043 fmd_adm_1_freeresult(SVCXPRT
*xprt
, xdrproc_t proc
, caddr_t data
)
1045 xdr_free(proc
, data
);
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.
1056 xdr_fmd_stat(XDR
*xp
, fmd_stat_t
*sp
)
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
));
1064 switch (sp
->fmds_type
) {
1066 rv
&= xdr_int(xp
, &sp
->fmds_value
.bool);
1068 case FMD_TYPE_INT32
:
1069 rv
&= xdr_int32_t(xp
, &sp
->fmds_value
.i32
);
1071 case FMD_TYPE_UINT32
:
1072 rv
&= xdr_uint32_t(xp
, &sp
->fmds_value
.ui32
);
1074 case FMD_TYPE_INT64
:
1075 rv
&= xdr_int64_t(xp
, &sp
->fmds_value
.i64
);
1077 case FMD_TYPE_UINT64
:
1080 rv
&= xdr_uint64_t(xp
, &sp
->fmds_value
.ui64
);
1082 case FMD_TYPE_STRING
:
1083 rv
&= xdr_string(xp
, &sp
->fmds_value
.str
, ~0);