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 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/fm/protocol.h>
  28 #include <fm/fmd_msg.h>
  29 #include <strings.h>
  30 #include <alloca.h>
  31 #include <stdio.h>
  32 
  33 #include <fmd_protocol.h>
  34 #include <fmd_module.h>
  35 #include <fmd_conf.h>
  36 #include <fmd_subr.h>
  37 #include <fmd_error.h>
  38 #include <fmd_time.h>
  39 #include <fmd.h>
  40 
  41 /*
  42  * Create an FMRI authority element for the environment in which this instance
  43  * of fmd is deployed.  This function is called once and the result is cached.
  44  */
  45 nvlist_t *
  46 fmd_protocol_authority(void)
  47 {
  48         const char *str;
  49         nvlist_t *nvl;
  50         int err = 0;
  51 
  52         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
  53                 fmd_panic("failed to xalloc authority nvlist");
  54 
  55         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_FMRI_AUTH_VERSION);
  56 
  57         if ((str = fmd_conf_getnzstr(fmd.d_conf, "product")) == NULL)
  58                 str = fmd_conf_getnzstr(fmd.d_conf, "platform");
  59 
  60         if (str != NULL)
  61                 err |= nvlist_add_string(nvl, FM_FMRI_AUTH_PRODUCT, str);
  62 
  63         if ((str = fmd_conf_getnzstr(fmd.d_conf, "product_sn")) != NULL)
  64                 err |= nvlist_add_string(nvl, FM_FMRI_AUTH_PRODUCT_SN, str);
  65 
  66         if ((str = fmd_conf_getnzstr(fmd.d_conf, "chassis")) != NULL)
  67                 err |= nvlist_add_string(nvl, FM_FMRI_AUTH_CHASSIS, str);
  68 
  69         if ((str = fmd_conf_getnzstr(fmd.d_conf, "domain")) != NULL)
  70                 err |= nvlist_add_string(nvl, FM_FMRI_AUTH_DOMAIN, str);
  71 
  72         if ((str = fmd_conf_getnzstr(fmd.d_conf, "server")) != NULL)
  73                 err |= nvlist_add_string(nvl, FM_FMRI_AUTH_SERVER, str);
  74 
  75         if (err != 0)
  76                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
  77 
  78         return (nvl);
  79 }
  80 
  81 /*
  82  * Create an FMRI for the specified module.  We use the cached authority
  83  * nvlist saved in fmd.d_auth to fill in the authority member.
  84  */
  85 nvlist_t *
  86 fmd_protocol_fmri_module(fmd_module_t *mp)
  87 {
  88         nvlist_t *nvl;
  89         int err = 0;
  90 
  91         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
  92                 fmd_panic("failed to xalloc diag-engine fmri nvlist");
  93 
  94         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_FMD_SCHEME_VERSION);
  95         err |= nvlist_add_string(nvl, FM_FMRI_SCHEME, FM_FMRI_SCHEME_FMD);
  96         err |= nvlist_add_nvlist(nvl, FM_FMRI_AUTHORITY, fmd.d_auth);
  97         err |= nvlist_add_string(nvl, FM_FMRI_FMD_NAME, mp->mod_name);
  98 
  99         if (mp->mod_info != NULL) {
 100                 err |= nvlist_add_string(nvl,
 101                     FM_FMRI_FMD_VERSION, mp->mod_info->fmdi_vers);
 102         } else if (mp == fmd.d_rmod) {
 103                 err |= nvlist_add_string(nvl,
 104                     FM_FMRI_FMD_VERSION, fmd.d_version);
 105         }
 106 
 107         if (err != 0)
 108                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 109 
 110         return (nvl);
 111 }
 112 
 113 nvlist_t *
 114 fmd_protocol_fault(const char *class, uint8_t certainty,
 115     nvlist_t *asru, nvlist_t *fru, nvlist_t *resource, const char *location)
 116 {
 117         nvlist_t *nvl;
 118         int err = 0;
 119 
 120         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
 121                 fmd_panic("failed to xalloc fault nvlist");
 122 
 123         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_FAULT_VERSION);
 124         err |= nvlist_add_string(nvl, FM_CLASS, class);
 125         err |= nvlist_add_uint8(nvl, FM_FAULT_CERTAINTY, certainty);
 126 
 127         if (asru != NULL)
 128                 err |= nvlist_add_nvlist(nvl, FM_FAULT_ASRU, asru);
 129         if (fru != NULL)
 130                 err |= nvlist_add_nvlist(nvl, FM_FAULT_FRU, fru);
 131         if (resource != NULL)
 132                 err |= nvlist_add_nvlist(nvl, FM_FAULT_RESOURCE, resource);
 133         if (location != NULL)
 134                 err |= nvlist_add_string(nvl, FM_FAULT_LOCATION, location);
 135 
 136         if (err != 0)
 137                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 138 
 139         return (nvl);
 140 }
 141 
 142 nvlist_t *
 143 fmd_protocol_list(const char *class, nvlist_t *de_fmri, const char *uuid,
 144     const char *code, uint_t argc, nvlist_t **argv, uint8_t *flagv, int domsg,
 145     struct timeval *tvp, int injected)
 146 {
 147         int64_t tod[2];
 148         nvlist_t *nvl;
 149         int err = 0;
 150         fmd_msg_hdl_t *msghdl;
 151         char *severity;
 152 
 153         tod[0] = tvp->tv_sec;
 154         tod[1] = tvp->tv_usec;
 155 
 156         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
 157                 fmd_panic("failed to xalloc suspect list nvlist");
 158 
 159         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_SUSPECT_VERSION);
 160         err |= nvlist_add_string(nvl, FM_CLASS, class);
 161         err |= nvlist_add_string(nvl, FM_SUSPECT_UUID, uuid);
 162         err |= nvlist_add_string(nvl, FM_SUSPECT_DIAG_CODE, code);
 163         err |= nvlist_add_int64_array(nvl, FM_SUSPECT_DIAG_TIME, tod, 2);
 164         err |= nvlist_add_nvlist(nvl, FM_SUSPECT_DE, de_fmri);
 165         err |= nvlist_add_uint32(nvl, FM_SUSPECT_FAULT_SZ, argc);
 166 
 167         if (injected)
 168                 err |= nvlist_add_boolean_value(nvl, FM_SUSPECT_INJECTED,
 169                     B_TRUE);
 170 
 171         if (!domsg) {
 172                 err |= nvlist_add_boolean_value(nvl,
 173                     FM_SUSPECT_MESSAGE, B_FALSE);
 174         }
 175 
 176         if (argc != 0) {
 177                 err |= nvlist_add_nvlist_array(nvl,
 178                     FM_SUSPECT_FAULT_LIST, argv, argc);
 179                 err |= nvlist_add_uint8_array(nvl,
 180                     FM_SUSPECT_FAULT_STATUS, flagv, argc);
 181         }
 182 
 183         /*
 184          * Attempt to lookup the severity associated with this diagnosis from
 185          * the portable object file using the diag code.  Failure to init
 186          * libfmd_msg or add to the nvlist will be treated as fatal.  However,
 187          * we won't treat a fmd_msg_getitem_id failure as fatal since during
 188          * development it's not uncommon to be working with po/dict files that
 189          * haven't yet been updated with newly added diagnoses.
 190          */
 191         msghdl = fmd_msg_init(fmd.d_rootdir, FMD_MSG_VERSION);
 192         if (msghdl == NULL)
 193                 fmd_panic("failed to initialize libfmd_msg\n");
 194 
 195         if ((severity = fmd_msg_getitem_id(msghdl, NULL, code,
 196             FMD_MSG_ITEM_SEVERITY)) != NULL) {
 197                 err |= nvlist_add_string(nvl, FM_SUSPECT_SEVERITY, severity);
 198                 free(severity);
 199         }
 200         fmd_msg_fini(msghdl);
 201 
 202         if (err != 0)
 203                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 204 
 205         return (nvl);
 206 }
 207 
 208 nvlist_t *
 209 fmd_protocol_rsrc_asru(const char *class,
 210     nvlist_t *fmri, const char *uuid, const char *code,
 211     boolean_t faulty, boolean_t unusable, boolean_t message, nvlist_t *event,
 212     struct timeval *tvp, boolean_t repaired, boolean_t replaced,
 213     boolean_t acquitted, boolean_t resolved, nvlist_t *diag_de,
 214     boolean_t injected)
 215 {
 216         nvlist_t *nvl;
 217         int64_t tod[2];
 218         int err = 0;
 219 
 220         tod[0] = tvp->tv_sec;
 221         tod[1] = tvp->tv_usec;
 222 
 223         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
 224                 fmd_panic("failed to xalloc resource nvlist");
 225 
 226         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_RSRC_VERSION);
 227         err |= nvlist_add_string(nvl, FM_CLASS, class);
 228         if (fmri != NULL)
 229                 err |= nvlist_add_nvlist(nvl, FM_RSRC_RESOURCE, fmri);
 230 
 231         if (uuid != NULL)
 232                 err |= nvlist_add_string(nvl, FM_RSRC_ASRU_UUID, uuid);
 233 
 234         if (code != NULL)
 235                 err |= nvlist_add_string(nvl, FM_RSRC_ASRU_CODE, code);
 236 
 237         err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_FAULTY, faulty);
 238         err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_REPAIRED, repaired);
 239         err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_REPLACED, replaced);
 240         err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_ACQUITTED, acquitted);
 241         err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_RESOLVED, resolved);
 242         err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_UNUSABLE, unusable);
 243         err |= nvlist_add_boolean_value(nvl, FM_SUSPECT_MESSAGE, message);
 244         err |= nvlist_add_int64_array(nvl, FM_SUSPECT_DIAG_TIME, tod, 2);
 245 
 246         if (diag_de != NULL)
 247                 err |= nvlist_add_nvlist(nvl, FM_SUSPECT_DE, diag_de);
 248         if (injected)
 249                 err |= nvlist_add_boolean_value(nvl, FM_SUSPECT_INJECTED,
 250                     B_TRUE);
 251 
 252         if (event != NULL)
 253                 err |= nvlist_add_nvlist(nvl, FM_RSRC_ASRU_EVENT, event);
 254 
 255         if (err != 0)
 256                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 257 
 258         return (nvl);
 259 }
 260 
 261 nvlist_t *
 262 fmd_protocol_fmderror(int errnum, const char *format, va_list ap)
 263 {
 264         uint64_t ena = fmd_ena();
 265         nvlist_t *nvl;
 266         int err = 0;
 267         char c, *msg;
 268         size_t len;
 269 
 270         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
 271                 return (NULL);
 272 
 273         len = vsnprintf(&c, 1, format, ap);
 274         msg = alloca(len + 1);
 275         (void) vsnprintf(msg, len + 1, format, ap);
 276 
 277         if (msg[len] == '\n')
 278                 msg[len] = '\0';
 279 
 280         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_EREPORT_VERSION);
 281         err |= nvlist_add_string(nvl, FM_CLASS, fmd_errclass(errnum));
 282         err |= nvlist_add_uint64(nvl, FM_EREPORT_ENA, ena);
 283         err |= nvlist_add_string(nvl, FMD_ERR_MOD_MSG, msg);
 284 
 285         if (err != 0) {
 286                 nvlist_free(nvl);
 287                 return (NULL);
 288         }
 289 
 290         return (nvl);
 291 }
 292 
 293 nvlist_t *
 294 fmd_protocol_moderror(fmd_module_t *mp, int oserr, const char *msg)
 295 {
 296         uint64_t ena = fmd_ena();
 297         nvlist_t *nvl, *fmri;
 298         int err = 0;
 299 
 300         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
 301                 fmd_panic("failed to xalloc module error nvlist");
 302 
 303         if (mp->mod_fmri == NULL)
 304                 fmri = fmd_protocol_fmri_module(mp);
 305         else
 306                 fmri = mp->mod_fmri;
 307 
 308         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_EREPORT_VERSION);
 309         err |= nvlist_add_string(nvl, FM_CLASS, fmd_errclass(EFMD_MODULE));
 310         err |= nvlist_add_nvlist(nvl, FM_EREPORT_DETECTOR, fmri);
 311         err |= nvlist_add_uint64(nvl, FM_EREPORT_ENA, ena);
 312         err |= nvlist_add_string(nvl, FMD_ERR_MOD_MSG, msg);
 313 
 314         if (mp->mod_fmri == NULL)
 315                 nvlist_free(fmri);
 316 
 317         if (oserr != 0) {
 318                 err |= nvlist_add_int32(nvl, FMD_ERR_MOD_ERRNO, oserr);
 319                 err |= nvlist_add_string(nvl, FMD_ERR_MOD_ERRCLASS,
 320                     fmd_errclass(oserr));
 321         }
 322 
 323         if (err != 0)
 324                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 325 
 326         return (nvl);
 327 }
 328 
 329 nvlist_t *
 330 fmd_protocol_xprt_ctl(fmd_module_t *mp, const char *class, uint8_t version)
 331 {
 332         nvlist_t *nvl;
 333         int err = 0;
 334 
 335         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, &fmd.d_nva) != 0)
 336                 fmd_panic("failed to xalloc rsrc xprt nvlist");
 337 
 338         err |= nvlist_add_uint8(nvl, FM_VERSION, version);
 339         err |= nvlist_add_string(nvl, FM_CLASS, class);
 340         err |= nvlist_add_nvlist(nvl, FM_RSRC_RESOURCE, mp->mod_fmri);
 341 
 342         if (err != 0)
 343                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 344 
 345         return (nvl);
 346 }
 347 
 348 nvlist_t *
 349 fmd_protocol_xprt_sub(fmd_module_t *mp,
 350     const char *class, uint8_t version, const char *subclass)
 351 {
 352         nvlist_t *nvl = fmd_protocol_xprt_ctl(mp, class, version);
 353         int err = nvlist_add_string(nvl, FM_RSRC_XPRT_SUBCLASS, subclass);
 354 
 355         if (err != 0)
 356                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 357 
 358         return (nvl);
 359 }
 360 
 361 nvlist_t *
 362 fmd_protocol_xprt_uuclose(fmd_module_t *mp, const char *class, uint8_t version,
 363     const char *uuid)
 364 {
 365         nvlist_t *nvl = fmd_protocol_xprt_ctl(mp, class, version);
 366         int err = nvlist_add_string(nvl, FM_RSRC_XPRT_UUID, uuid);
 367 
 368         if (err != 0)
 369                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 370 
 371         return (nvl);
 372 }
 373 
 374 nvlist_t *
 375 fmd_protocol_xprt_uuresolved(fmd_module_t *mp, const char *class,
 376     uint8_t version, const char *uuid)
 377 {
 378         nvlist_t *nvl = fmd_protocol_xprt_ctl(mp, class, version);
 379         int err = nvlist_add_string(nvl, FM_RSRC_XPRT_UUID, uuid);
 380 
 381         if (err != 0)
 382                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 383 
 384         return (nvl);
 385 }
 386 
 387 nvlist_t *
 388 fmd_protocol_xprt_updated(fmd_module_t *mp, const char *class, uint8_t version,
 389     const char *uuid, uint8_t *statusp, uint8_t *has_asrup, uint_t nelem)
 390 {
 391         nvlist_t *nvl = fmd_protocol_xprt_ctl(mp, class, version);
 392         int err = nvlist_add_string(nvl, FM_RSRC_XPRT_UUID, uuid);
 393 
 394         err |= nvlist_add_uint8_array(nvl, FM_RSRC_XPRT_FAULT_STATUS, statusp,
 395             nelem);
 396         if (has_asrup)
 397                 err |= nvlist_add_uint8_array(nvl, FM_RSRC_XPRT_FAULT_HAS_ASRU,
 398                     has_asrup, nelem);
 399 
 400         if (err != 0)
 401                 fmd_panic("failed to populate nvlist: %s\n", fmd_strerror(err));
 402 
 403         return (nvl);
 404 }