2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <strings.h>
2N/A#include <stdlib.h>
2N/A#include <netdir.h>
2N/A#include <errno.h>
2N/A#include <alloca.h>
2N/A#include <locale.h>
2N/A#include <uuid/uuid.h>
2N/A
2N/A#include <sys/fm/protocol.h>
2N/A#include <fmd_adm_impl.h>
2N/A#include <fmd_rpc_adm.h>
2N/A
2N/A#include <fm/fmd_msg.h>
2N/A
2N/Astatic const uint_t _fmd_adm_bufsize = 128 * 1024;
2N/Astatic const char _url_fallback[] = FMD_MSG_URL_DEFAULT;
2N/A
2N/Afmd_adm_t *
2N/Afmd_adm_open(const char *host, uint32_t prog, int version)
2N/A{
2N/A fmd_adm_t *ap;
2N/A CLIENT *c;
2N/A rpcvers_t v;
2N/A
2N/A if (version != FMD_ADM_VERSION) {
2N/A errno = ENOTSUP;
2N/A return (NULL);
2N/A }
2N/A
2N/A if (host == NULL)
2N/A host = HOST_SELF;
2N/A
2N/A if (prog == FMD_ADM_PROGRAM)
2N/A prog = FMD_ADM;
2N/A
2N/A if ((ap = malloc(sizeof (fmd_adm_t))) == NULL)
2N/A return (NULL);
2N/A
2N/A if (strcmp(host, HOST_SELF) == 0) {
2N/A c = clnt_door_create(prog, FMD_ADM_VERSION_1, _fmd_adm_bufsize);
2N/A ap->adm_maxretries = 1;
2N/A } else {
2N/A c = clnt_create_vers(host, prog, &v,
2N/A FMD_ADM_VERSION_1, FMD_ADM_VERSION_1, NULL);
2N/A ap->adm_maxretries = 0;
2N/A }
2N/A
2N/A if (c == NULL) {
2N/A errno = EPROTO;
2N/A free(ap);
2N/A return (NULL);
2N/A }
2N/A
2N/A ap->adm_prog = prog;
2N/A ap->adm_clnt = c;
2N/A ap->adm_version = version;
2N/A ap->adm_svcerr = 0;
2N/A ap->adm_errno = 0;
2N/A
2N/A return (ap);
2N/A}
2N/A
2N/Avoid
2N/Afmd_adm_close(fmd_adm_t *ap)
2N/A{
2N/A if (ap == NULL)
2N/A return; /* permit NULL to simply caller code */
2N/A
2N/A clnt_destroy(ap->adm_clnt);
2N/A free(ap);
2N/A}
2N/A
2N/Astatic const char *
2N/Afmd_adm_svc_errmsg(enum fmd_adm_error err)
2N/A{
2N/A switch (err) {
2N/A case FMD_ADM_ERR_NOMEM:
2N/A return ("unable to perform request due to allocation failure");
2N/A case FMD_ADM_ERR_PERM:
2N/A return ("operation requires additional privilege");
2N/A case FMD_ADM_ERR_MODSRCH:
2N/A return ("specified module is not loaded in fault manager");
2N/A case FMD_ADM_ERR_MODBUSY:
2N/A return ("module is in use and cannot be unloaded");
2N/A case FMD_ADM_ERR_MODFAIL:
2N/A return ("module failed and can no longer export statistics");
2N/A case FMD_ADM_ERR_MODNOENT:
2N/A return ("file missing or cannot be accessed by fault manager");
2N/A case FMD_ADM_ERR_MODEXIST:
2N/A return ("module using same name is already loaded");
2N/A case FMD_ADM_ERR_MODINIT:
2N/A return ("module failed to initialize (consult fmd(1M) log)");
2N/A case FMD_ADM_ERR_MODLOAD:
2N/A return ("module failed to load (consult fmd(1M) log)");
2N/A case FMD_ADM_ERR_RSRCSRCH:
2N/A return ("specified resource is not cached by fault manager");
2N/A case FMD_ADM_ERR_RSRCNOTF:
2N/A return ("specified resource is not known to be faulty");
2N/A case FMD_ADM_ERR_SERDSRCH:
2N/A return ("specified serd engine not present in module");
2N/A case FMD_ADM_ERR_SERDFIRED:
2N/A return ("specified serd engine has already fired");
2N/A case FMD_ADM_ERR_ROTSRCH:
2N/A return ("invalid log file name");
2N/A case FMD_ADM_ERR_ROTFAIL:
2N/A return ("failed to rotate log file (consult fmd(1M) log)");
2N/A case FMD_ADM_ERR_ROTBUSY:
2N/A return ("log file is too busy to rotate (try again later)");
2N/A case FMD_ADM_ERR_CASESRCH:
2N/A return ("specified UUID is invalid or has been repaired");
2N/A case FMD_ADM_ERR_CASEOPEN:
2N/A return ("specified UUID is still being diagnosed");
2N/A case FMD_ADM_ERR_XPRTSRCH:
2N/A return ("specified transport ID is invalid or has been closed");
2N/A case FMD_ADM_ERR_CASEXPRT:
2N/A return ("specified UUID is owned by a different fault manager");
2N/A case FMD_ADM_ERR_RSRCNOTR:
2N/A return ("specified resource has not been replaced");
2N/A default:
2N/A return ("unknown fault manager error");
2N/A }
2N/A}
2N/A
2N/Aconst char *
2N/Afmd_adm_errmsg(fmd_adm_t *ap)
2N/A{
2N/A if (ap == NULL) {
2N/A switch (errno) {
2N/A case ENOTSUP:
2N/A return ("client requires newer libfmd_adm version");
2N/A case EPROTO:
2N/A return (clnt_spcreateerror("failed to connect to fmd"));
2N/A }
2N/A }
2N/A
2N/A switch (ap ? ap->adm_errno : errno) {
2N/A case EPROTO:
2N/A return (clnt_sperror(ap->adm_clnt, "rpc call failed"));
2N/A case EREMOTE:
2N/A return (fmd_adm_svc_errmsg(ap->adm_svcerr));
2N/A default:
2N/A return (strerror(ap->adm_errno));
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_set_svcerr(fmd_adm_t *ap, enum fmd_adm_error err)
2N/A{
2N/A if (err != 0) {
2N/A ap->adm_svcerr = err;
2N/A ap->adm_errno = EREMOTE;
2N/A return (-1);
2N/A } else {
2N/A ap->adm_svcerr = err;
2N/A ap->adm_errno = 0;
2N/A return (0);
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_set_errno(fmd_adm_t *ap, int err)
2N/A{
2N/A ap->adm_errno = err;
2N/A errno = err;
2N/A return (-1);
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_stats_cmp(const void *lp, const void *rp)
2N/A{
2N/A return (strcmp(((fmd_stat_t *)lp)->fmds_name,
2N/A ((fmd_stat_t *)rp)->fmds_name));
2N/A}
2N/A
2N/A/*
2N/A * If the server (fmd) is restarted, this will cause all future door calls to
2N/A * fail. Unfortunately, once the server comes back up, we have no way of
2N/A * reestablishing the connection. To get around this, if the error indicates
2N/A * that the RPC call failed, we reopen the client handle and try again. For
2N/A * simplicity we only deal with the door case, as it's unclear whether the
2N/A * remote case suffers from the same pathology.
2N/A */
2N/Aboolean_t
2N/Afmd_adm_retry(fmd_adm_t *ap, enum clnt_stat cs, uint_t *retries)
2N/A{
2N/A CLIENT *c;
2N/A struct rpc_err err;
2N/A
2N/A if (cs == RPC_SUCCESS || *retries == ap->adm_maxretries)
2N/A return (B_FALSE);
2N/A
2N/A clnt_geterr(ap->adm_clnt, &err);
2N/A if (err.re_status != RPC_CANTSEND)
2N/A return (B_FALSE);
2N/A
2N/A if ((c = clnt_door_create(ap->adm_prog, FMD_ADM_VERSION_1,
2N/A _fmd_adm_bufsize)) == NULL)
2N/A return (B_FALSE);
2N/A
2N/A (*retries)++;
2N/A
2N/A clnt_destroy(ap->adm_clnt);
2N/A ap->adm_clnt = c;
2N/A
2N/A return (B_TRUE);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_stats_read(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp)
2N/A{
2N/A struct fmd_rpc_modstat rms;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (sp == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A if (name != NULL)
2N/A cs = fmd_adm_modcstat_1((char *)name, &rms,
2N/A ap->adm_clnt);
2N/A else
2N/A cs = fmd_adm_modgstat_1(&rms, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rms.rms_err != 0) {
2N/A xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
2N/A return (fmd_adm_set_svcerr(ap, rms.rms_err));
2N/A }
2N/A
2N/A sp->ams_buf = rms.rms_buf.rms_buf_val;
2N/A sp->ams_len = rms.rms_buf.rms_buf_len;
2N/A
2N/A if (sp->ams_len != 0) {
2N/A qsort(sp->ams_buf, sp->ams_len,
2N/A sizeof (fmd_stat_t), fmd_adm_stats_cmp);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_stats_free(fmd_adm_t *ap, fmd_adm_stats_t *sp)
2N/A{
2N/A struct fmd_rpc_modstat rms;
2N/A
2N/A if (sp == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A rms.rms_buf.rms_buf_val = sp->ams_buf;
2N/A rms.rms_buf.rms_buf_len = sp->ams_len;
2N/A rms.rms_err = 0;
2N/A
2N/A xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
2N/A bzero(sp, sizeof (fmd_adm_stats_t));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_module_cmp(const void *lp, const void *rp)
2N/A{
2N/A return (strcmp((*(struct fmd_rpc_modinfo **)lp)->rmi_name,
2N/A (*(struct fmd_rpc_modinfo **)rp)->rmi_name));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_module_iter(fmd_adm_t *ap, fmd_adm_module_f *func, void *arg)
2N/A{
2N/A struct fmd_rpc_modinfo *rmi, **rms, **rmp;
2N/A struct fmd_rpc_modlist rml;
2N/A fmd_adm_modinfo_t ami;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A bzero(&rml, sizeof (rml)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_modinfo_1(&rml, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rml.rml_err != 0 || rml.rml_len == 0) {
2N/A xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
2N/A return (fmd_adm_set_svcerr(ap, rml.rml_err));
2N/A }
2N/A
2N/A if ((rms = rmp = malloc(sizeof (void *) * rml.rml_len)) == NULL) {
2N/A xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
2N/A return (fmd_adm_set_errno(ap, EAGAIN));
2N/A }
2N/A
2N/A for (rmi = rml.rml_list; rmi != NULL; rmi = rmi->rmi_next)
2N/A *rmp++ = rmi; /* store copy of pointer in array for sorting */
2N/A
2N/A qsort(rms, rml.rml_len, sizeof (void *), fmd_adm_module_cmp);
2N/A
2N/A for (rmp = rms; rmp < rms + rml.rml_len; rmp++) {
2N/A rmi = *rmp;
2N/A
2N/A ami.ami_name = rmi->rmi_name;
2N/A ami.ami_desc = rmi->rmi_desc;
2N/A ami.ami_vers = rmi->rmi_vers;
2N/A ami.ami_flags = 0;
2N/A
2N/A if (rmi->rmi_faulty)
2N/A ami.ami_flags |= FMD_ADM_MOD_FAILED;
2N/A
2N/A if (func(&ami, arg) != 0)
2N/A break;
2N/A }
2N/A
2N/A free(rms);
2N/A xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_module_load(fmd_adm_t *ap, const char *path)
2N/A{
2N/A char *str = (char *)path;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (path == NULL || path[0] != '/')
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_modload_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_module_unload(fmd_adm_t *ap, const char *name)
2N/A{
2N/A char *str = (char *)name;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (name == NULL || strchr(name, '/') != NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_modunload_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_module_reset(fmd_adm_t *ap, const char *name)
2N/A{
2N/A char *str = (char *)name;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (name == NULL || strchr(name, '/') != NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_modreset_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_module_gc(fmd_adm_t *ap, const char *name)
2N/A{
2N/A char *str = (char *)name;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (name == NULL || strchr(name, '/') != NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_modgc_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_module_stats(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp)
2N/A{
2N/A struct fmd_rpc_modstat rms;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (name == NULL || sp == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_moddstat_1((char *)name, &rms, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rms.rms_err != 0) {
2N/A xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
2N/A return (fmd_adm_set_svcerr(ap, rms.rms_err));
2N/A }
2N/A
2N/A sp->ams_buf = rms.rms_buf.rms_buf_val;
2N/A sp->ams_len = rms.rms_buf.rms_buf_len;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_rsrc_count(fmd_adm_t *ap, int all, uint32_t *rcp)
2N/A{
2N/A struct fmd_rpc_rsrclist rrl;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (rcp == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rrl.rrl_err != 0) {
2N/A xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
2N/A return (fmd_adm_set_svcerr(ap, rrl.rrl_err));
2N/A }
2N/A
2N/A *rcp = rrl.rrl_cnt;
2N/A xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_rsrc_cmp(const void *lp, const void *rp)
2N/A{
2N/A return (strcmp(*(char **)lp, *(char **)rp));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_rsrc_iter(fmd_adm_t *ap, int all, fmd_adm_rsrc_f *func, void *arg)
2N/A{
2N/A struct fmd_rpc_rsrclist rrl;
2N/A struct fmd_rpc_rsrcinfo rri;
2N/A fmd_adm_rsrcinfo_t ari;
2N/A char **fmris, *p;
2N/A int i, rv;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rrl.rrl_err != 0) {
2N/A xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
2N/A return (fmd_adm_set_svcerr(ap, rrl.rrl_err));
2N/A }
2N/A
2N/A if ((fmris = malloc(sizeof (char *) * rrl.rrl_cnt)) == NULL) {
2N/A xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
2N/A return (fmd_adm_set_errno(ap, EAGAIN));
2N/A }
2N/A
2N/A /*
2N/A * The fmd_adm_rsrclist_1 request returns an opaque XDR buffer that is
2N/A * a string table of FMRIs (e.g. "fmriA\0fmriB\0...") where rrl_cnt is
2N/A * the number of strings in the table and rrl_buf_val is its address.
2N/A * We construct an array of pointers into the string table and sort it.
2N/A */
2N/A p = rrl.rrl_buf.rrl_buf_val;
2N/A
2N/A for (i = 0; i < rrl.rrl_cnt; i++, p += strlen(p) + 1)
2N/A fmris[i] = p; /* store fmri pointer in array for sorting */
2N/A
2N/A qsort(fmris, rrl.rrl_cnt, sizeof (char *), fmd_adm_rsrc_cmp);
2N/A
2N/A /*
2N/A * For each FMRI in the resource cache snapshot, use fmd_adm_rsrcinfo_1
2N/A * to get more information and the invoke the callback function. If
2N/A * FMD_ADM_ERR_RSRCSRCH is returned, the FMRI has been purged from the
2N/A * cache since our snapshot: this error is therefore silently ignored.
2N/A */
2N/A for (i = 0; i < rrl.rrl_cnt; i++) {
2N/A bzero(&rri, sizeof (rri));
2N/A
2N/A retries = 0;
2N/A do {
2N/A cs = fmd_adm_rsrcinfo_1(fmris[i], &rri, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS) {
2N/A free(fmris);
2N/A xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A }
2N/A
2N/A if (rri.rri_err != 0 && rri.rri_err != FMD_ADM_ERR_RSRCSRCH) {
2N/A xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
2N/A free(fmris);
2N/A xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
2N/A return (fmd_adm_set_svcerr(ap, rri.rri_err));
2N/A }
2N/A
2N/A if (rri.rri_err == FMD_ADM_ERR_RSRCSRCH) {
2N/A xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
2N/A continue;
2N/A }
2N/A
2N/A ari.ari_fmri = rri.rri_fmri;
2N/A ari.ari_uuid = rri.rri_uuid;
2N/A ari.ari_case = rri.rri_case;
2N/A ari.ari_flags = 0;
2N/A
2N/A if (rri.rri_faulty)
2N/A ari.ari_flags |= FMD_ADM_RSRC_FAULTY;
2N/A if (rri.rri_unusable)
2N/A ari.ari_flags |= FMD_ADM_RSRC_UNUSABLE;
2N/A if (rri.rri_invisible)
2N/A ari.ari_flags |= FMD_ADM_RSRC_INVISIBLE;
2N/A
2N/A rv = func(&ari, arg);
2N/A xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
2N/A
2N/A if (rv != 0)
2N/A break;
2N/A }
2N/A
2N/A free(fmris);
2N/A xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_rsrc_flush(fmd_adm_t *ap, const char *fmri)
2N/A{
2N/A char *str = (char *)fmri;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (fmri == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_rsrcflush_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_rsrc_repaired(fmd_adm_t *ap, const char *fmri)
2N/A{
2N/A char *str = (char *)fmri;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (fmri == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_rsrcrepaired_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_rsrc_replaced(fmd_adm_t *ap, const char *fmri)
2N/A{
2N/A char *str = (char *)fmri;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (fmri == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_rsrcreplaced_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_rsrc_acquit(fmd_adm_t *ap, const char *fmri, const char *uuid)
2N/A{
2N/A char *str = (char *)fmri;
2N/A char *str2 = (char *)uuid;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (fmri == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_rsrcacquit_1(str, str2, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_case_repair(fmd_adm_t *ap, const char *uuid)
2N/A{
2N/A char *str = (char *)uuid;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (uuid == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_caserepair_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_case_acquit(fmd_adm_t *ap, const char *uuid)
2N/A{
2N/A char *str = (char *)uuid;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (uuid == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_caseacquit_1(str, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_case_cmp(const void *lp, const void *rp)
2N/A{
2N/A return (strcmp(*(char **)lp, *(char **)rp));
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_case_one(fmd_adm_caseinfo_t *acp, const char *url_token,
2N/A fmd_adm_case_f *func, void *arg)
2N/A{
2N/A char *p, *urlcode, *dict, *olang;
2N/A const char *url;
2N/A size_t len;
2N/A
2N/A if ((p = strchr(acp->aci_code, '-')) == NULL ||
2N/A p == acp->aci_code) {
2N/A acp->aci_url = NULL;
2N/A } else {
2N/A dict = alloca((size_t)(p - acp->aci_code) + 1);
2N/A (void) strncpy(dict, acp->aci_code,
2N/A (size_t)(p - acp->aci_code));
2N/A dict[(size_t)(p - acp->aci_code)] = '\0';
2N/A
2N/A /*
2N/A * If we're given a token to use in looking up the URL, try
2N/A * to use it. Otherwise, or if we don't find it that way,
2N/A * use the fallback.
2N/A */
2N/A if (url_token == NULL) {
2N/A url = _url_fallback;
2N/A } else if ((url = dgettext(dict, url_token)) == url_token) {
2N/A /*
2N/A * We didn't find a translation in the
2N/A * dictionary for the current language. Fall
2N/A * back to C and try again.
2N/A */
2N/A olang = setlocale(LC_MESSAGES, NULL);
2N/A (void) setlocale(LC_MESSAGES, "C");
2N/A if ((url = dgettext(dict, url_token)) == url_token)
2N/A url = _url_fallback;
2N/A (void) setlocale(LC_MESSAGES, olang);
2N/A }
2N/A len = strlen(url);
2N/A if (url[len - 1] == '/') {
2N/A len += strlen(acp->aci_code) + 1;
2N/A urlcode = alloca(len);
2N/A (void) snprintf(urlcode, len, "%s%s", url,
2N/A acp->aci_code);
2N/A } else {
2N/A urlcode = (char *)url;
2N/A }
2N/A acp->aci_url = urlcode;
2N/A }
2N/A
2N/A return (func(acp, arg));
2N/A}
2N/A
2N/A/*
2N/A * Our approach to cases is the same as for resources: we first obtain a
2N/A * list of UUIDs, sort them, then obtain the case information for each.
2N/A */
2N/Aint
2N/Afmd_adm_case_iter(fmd_adm_t *ap, const char *url_token, fmd_adm_case_f *func,
2N/A void *arg)
2N/A{
2N/A struct fmd_rpc_caselist rcl;
2N/A struct fmd_rpc_caseinfo rci;
2N/A fmd_adm_caseinfo_t aci;
2N/A char **uuids, *p;
2N/A int i, rv;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A bzero(&rcl, sizeof (rcl)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_caselist_1(&rcl, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rcl.rcl_err != 0) {
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A return (fmd_adm_set_svcerr(ap, rcl.rcl_err));
2N/A }
2N/A
2N/A if ((uuids = malloc(sizeof (char *) * rcl.rcl_cnt)) == NULL) {
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A return (fmd_adm_set_errno(ap, EAGAIN));
2N/A }
2N/A
2N/A p = rcl.rcl_buf.rcl_buf_val;
2N/A
2N/A for (i = 0; i < rcl.rcl_cnt; i++, p += strlen(p) + 1)
2N/A uuids[i] = p;
2N/A
2N/A qsort(uuids, rcl.rcl_cnt, sizeof (char *), fmd_adm_case_cmp);
2N/A
2N/A for (i = 0; i < rcl.rcl_cnt; i++) {
2N/A bzero(&rci, sizeof (rci));
2N/A
2N/A retries = 0;
2N/A do {
2N/A cs = fmd_adm_caseinfo_1(uuids[i], &rci, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS) {
2N/A free(uuids);
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A }
2N/A
2N/A if (rci.rci_err != 0 && rci.rci_err != FMD_ADM_ERR_CASESRCH) {
2N/A xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
2N/A free(uuids);
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A return (fmd_adm_set_svcerr(ap, rci.rci_err));
2N/A }
2N/A
2N/A if (rci.rci_err == FMD_ADM_ERR_CASESRCH) {
2N/A xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
2N/A continue;
2N/A }
2N/A
2N/A bzero(&aci, sizeof (aci));
2N/A
2N/A if ((rv = nvlist_unpack(rci.rci_evbuf.rci_evbuf_val,
2N/A rci.rci_evbuf.rci_evbuf_len, &aci.aci_event, 0)) != 0) {
2N/A xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
2N/A free(uuids);
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A return (fmd_adm_set_errno(ap, rv));
2N/A }
2N/A
2N/A if ((rv = nvlist_lookup_string(aci.aci_event, FM_SUSPECT_UUID,
2N/A (char **)&aci.aci_uuid)) != 0) {
2N/A xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
2N/A free(uuids);
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A nvlist_free(aci.aci_event);
2N/A return (fmd_adm_set_errno(ap, rv));
2N/A }
2N/A if ((rv = nvlist_lookup_string(aci.aci_event,
2N/A FM_SUSPECT_DIAG_CODE, (char **)&aci.aci_code)) != 0) {
2N/A xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
2N/A free(uuids);
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A nvlist_free(aci.aci_event);
2N/A return (fmd_adm_set_errno(ap, rv));
2N/A }
2N/A
2N/A rv = fmd_adm_case_one(&aci, url_token, func, arg);
2N/A
2N/A xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
2N/A nvlist_free(aci.aci_event);
2N/A
2N/A if (rv != 0)
2N/A break;
2N/A }
2N/A
2N/A free(uuids);
2N/A xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Afmd_adm_serd_cmp(const void *lp, const void *rp)
2N/A{
2N/A return (strcmp(*(char **)lp, *(char **)rp));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_serd_iter(fmd_adm_t *ap, const char *name,
2N/A fmd_adm_serd_f *func, void *arg)
2N/A{
2N/A struct fmd_rpc_serdlist rsl;
2N/A struct fmd_rpc_serdinfo rsi;
2N/A char **serds, *p;
2N/A fmd_adm_serdinfo_t asi;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A int i, rv;
2N/A
2N/A bzero(&rsl, sizeof (rsl)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_serdlist_1((char *)name, &rsl, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rsl.rsl_err != 0 || rsl.rsl_len == 0) {
2N/A xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
2N/A return (fmd_adm_set_svcerr(ap, rsl.rsl_err));
2N/A }
2N/A
2N/A if ((serds = malloc(sizeof (char *) * rsl.rsl_cnt)) == NULL) {
2N/A xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
2N/A return (fmd_adm_set_errno(ap, EAGAIN));
2N/A }
2N/A
2N/A p = rsl.rsl_buf.rsl_buf_val;
2N/A
2N/A for (i = 0; i < rsl.rsl_cnt; i++, p += strlen(p) + 1)
2N/A serds[i] = p;
2N/A
2N/A qsort(serds, rsl.rsl_cnt, sizeof (char *), fmd_adm_serd_cmp);
2N/A
2N/A for (i = 0; i < rsl.rsl_cnt; i++) {
2N/A bzero(&rsi, sizeof (rsi));
2N/A
2N/A retries = 0;
2N/A do {
2N/A cs = fmd_adm_serdinfo_1((char *)name, serds[i], &rsi,
2N/A ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS) {
2N/A free(serds);
2N/A xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A }
2N/A
2N/A if (rsi.rsi_err != 0 && rsi.rsi_err != FMD_ADM_ERR_SERDSRCH) {
2N/A free(serds);
2N/A xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi);
2N/A xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
2N/A return (fmd_adm_set_svcerr(ap, rsi.rsi_err));
2N/A }
2N/A
2N/A if (rsi.rsi_err == FMD_ADM_ERR_SERDSRCH) {
2N/A xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi);
2N/A continue;
2N/A }
2N/A
2N/A bzero(&asi, sizeof (asi));
2N/A
2N/A asi.asi_name = rsi.rsi_name;
2N/A asi.asi_delta = rsi.rsi_delta;
2N/A asi.asi_n = rsi.rsi_n;
2N/A asi.asi_t = rsi.rsi_t;
2N/A asi.asi_count = rsi.rsi_count;
2N/A asi.asi_flags = 0;
2N/A
2N/A if (rsi.rsi_fired)
2N/A asi.asi_flags |= FMD_ADM_SERD_FIRED;
2N/A
2N/A rv = func(&asi, arg);
2N/A
2N/A xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi);
2N/A
2N/A if (rv != 0)
2N/A break;
2N/A }
2N/A
2N/A free(serds);
2N/A xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_serd_reset(fmd_adm_t *ap, const char *mod, const char *name)
2N/A{
2N/A char *s1 = (char *)mod, *s2 = (char *)name;
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (mod == NULL || name == NULL || strchr(mod, '/') != NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_serdreset_1(s1, s2, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_xprt_iter(fmd_adm_t *ap, fmd_adm_xprt_f *func, void *arg)
2N/A{
2N/A struct fmd_rpc_xprtlist rxl;
2N/A uint_t i;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A bzero(&rxl, sizeof (rxl)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_xprtlist_1(&rxl, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rxl.rxl_err != 0) {
2N/A xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl);
2N/A return (fmd_adm_set_svcerr(ap, rxl.rxl_err));
2N/A }
2N/A
2N/A for (i = 0; i < rxl.rxl_len; i++)
2N/A func(rxl.rxl_buf.rxl_buf_val[i], arg);
2N/A
2N/A xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl);
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_xprt_stats(fmd_adm_t *ap, id_t id, fmd_adm_stats_t *sp)
2N/A{
2N/A struct fmd_rpc_modstat rms;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (sp == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
2N/A
2N/A do {
2N/A cs = fmd_adm_xprtstat_1(id, &rms, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A if (rms.rms_err != 0) {
2N/A xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
2N/A return (fmd_adm_set_svcerr(ap, rms.rms_err));
2N/A }
2N/A
2N/A sp->ams_buf = rms.rms_buf.rms_buf_val;
2N/A sp->ams_len = rms.rms_buf.rms_buf_len;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmd_adm_log_rotate(fmd_adm_t *ap, const char *log)
2N/A{
2N/A int err;
2N/A enum clnt_stat cs;
2N/A uint_t retries = 0;
2N/A
2N/A if (log == NULL)
2N/A return (fmd_adm_set_errno(ap, EINVAL));
2N/A
2N/A do {
2N/A cs = fmd_adm_logrotate_1((char *)log, &err, ap->adm_clnt);
2N/A } while (fmd_adm_retry(ap, cs, &retries));
2N/A
2N/A if (cs != RPC_SUCCESS)
2N/A return (fmd_adm_set_errno(ap, EPROTO));
2N/A
2N/A return (fmd_adm_set_svcerr(ap, err));
2N/A}
2N/A
2N/A/*
2N/A * Custom XDR routine for our API structure fmd_stat_t. This function must
2N/A * match the definition of fmd_stat_t in <fm/fmd_api.h> and must also match
2N/A * the corresponding routine in usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c.
2N/A */
2N/Abool_t
2N/Axdr_fmd_stat(XDR *xp, fmd_stat_t *sp)
2N/A{
2N/A bool_t rv = TRUE;
2N/A
2N/A rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name));
2N/A rv &= xdr_u_int(xp, &sp->fmds_type);
2N/A rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc));
2N/A
2N/A switch (sp->fmds_type) {
2N/A case FMD_TYPE_BOOL:
2N/A rv &= xdr_int(xp, &sp->fmds_value.bool);
2N/A break;
2N/A case FMD_TYPE_INT32:
2N/A rv &= xdr_int32_t(xp, &sp->fmds_value.i32);
2N/A break;
2N/A case FMD_TYPE_UINT32:
2N/A rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32);
2N/A break;
2N/A case FMD_TYPE_INT64:
2N/A rv &= xdr_int64_t(xp, &sp->fmds_value.i64);
2N/A break;
2N/A case FMD_TYPE_UINT64:
2N/A case FMD_TYPE_TIME:
2N/A case FMD_TYPE_SIZE:
2N/A rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64);
2N/A break;
2N/A case FMD_TYPE_STRING:
2N/A rv &= xdr_string(xp, &sp->fmds_value.str, ~0);
2N/A break;
2N/A }
2N/A
2N/A return (rv);
2N/A}