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) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include <libintl.h>
  27 #include <libnvpair.h>
  28 #include <libscf.h>
  29 #include <libscf_priv.h>
  30 #include <libuutil.h>
  31 #include <stdarg.h>
  32 #include <stdio.h>
  33 #include <string.h>
  34 
  35 #include "notify_params.h"
  36 
  37 static struct events {
  38         const char *s;
  39         int32_t c;
  40 } smf_st_events[] = {
  41         { "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) },
  42         { "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) },
  43         { "uninitialized", SCF_TRANS(SCF_STATE_UNINIT, SCF_STATE_UNINIT) },
  44         { "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) },
  45         { "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) },
  46         { "maintenance", SCF_TRANS(SCF_STATE_MAINT, SCF_STATE_MAINT) },
  47         { "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) },
  48         { "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) },
  49         { "offline", SCF_TRANS(SCF_STATE_OFFLINE, SCF_STATE_OFFLINE) },
  50         { "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) },
  51         { "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) },
  52         { "disabled", SCF_TRANS(SCF_STATE_DISABLED, SCF_STATE_DISABLED) },
  53         { "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) },
  54         { "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) },
  55         { "online", SCF_TRANS(SCF_STATE_ONLINE, SCF_STATE_ONLINE) },
  56         { "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) },
  57         { "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) },
  58         { "degraded", SCF_TRANS(SCF_STATE_DEGRADED, SCF_STATE_DEGRADED) },
  59         { "to-all", SCF_TRANS(0, SCF_STATE_ALL) },
  60         { "from-all", SCF_TRANS(SCF_STATE_ALL, 0) },
  61         { "all", SCF_TRANS(SCF_STATE_ALL, SCF_STATE_ALL) },
  62         { NULL, 0 }
  63 };
  64 
  65 static struct fma_tags {
  66         const char *t;
  67         const char *s;
  68 } fma_tags[] = {
  69         { "problem-diagnosed", "list.suspect" },
  70         { "problem-updated", "list.updated" },
  71         { "problem-repaired", "list.repaired" },
  72         { "problem-resolved", "list.resolved" },
  73         { NULL, NULL }
  74 };
  75 
  76 static char *fma_classes[] = {
  77         "list.",
  78         "ireport.",
  79         NULL
  80 };
  81 
  82 /*
  83  * get_fma_tag()
  84  * return a pointer to the fma tag at the passed index. NULL if no entry exist
  85  * for index
  86  */
  87 const char *
  88 get_fma_tag(uint32_t index)
  89 {
  90         if (index > (sizeof (fma_tags) / sizeof (struct fma_tags)))
  91                 return (NULL);
  92 
  93         return (fma_tags[index].t);
  94 }
  95 
  96 /*
  97  * get_fma_class()
  98  * return a pointer to the fma class at the passed index. NULL if no entry exist
  99  * for index
 100  */
 101 const char *
 102 get_fma_class(uint32_t index)
 103 {
 104         if (index > (sizeof (fma_tags) / sizeof (struct fma_tags)))
 105                 return (NULL);
 106 
 107         return (fma_tags[index].s);
 108 }
 109 
 110 /*
 111  * is_fma_token()
 112  * check if the parameter is an fma token by comparing with the
 113  * fma_classes[] and the fma_tags[] arrays.
 114  */
 115 int
 116 is_fma_token(const char *t)
 117 {
 118         int i;
 119 
 120         for (i = 0; fma_classes[i]; ++i)
 121                 if (strncmp(t, fma_classes[i], strlen(fma_classes[i])) == 0)
 122                         return (1);
 123 
 124         for (i = 0; fma_tags[i].t; ++i)
 125                 if (strcmp(t, fma_tags[i].t) == 0)
 126                         return (1);
 127 
 128         return (0);
 129 }
 130 
 131 /*
 132  * has_fma_tag()
 133  * returns 1 if there is an fma tag for the passed class, 0 otherwise
 134  */
 135 int
 136 has_fma_tag(const char *c)
 137 {
 138         int i;
 139 
 140         for (i = 0; fma_tags[i].s; ++i)
 141                 if (strcmp(c, fma_tags[i].s) == 0)
 142                         return (1);
 143 
 144         return (0);
 145 }
 146 
 147 const char *
 148 de_tag(const char *tag)
 149 {
 150         int i;
 151 
 152         for (i = 0; fma_tags[i].t; ++i)
 153                 if (strcmp(tag, fma_tags[i].t) == 0)
 154                         return (fma_tags[i].s);
 155 
 156         return (tag);
 157 }
 158 
 159 const char *
 160 re_tag(const char *fma_event)
 161 {
 162         int i;
 163 
 164         for (i = 0; fma_tags[i].s; ++i)
 165                 if (strcmp(fma_event, fma_tags[i].s) == 0)
 166                         return (fma_tags[i].t);
 167 
 168         return (fma_event);
 169 }
 170 
 171 int32_t
 172 string_to_tset(const char *str)
 173 {
 174         int i;
 175 
 176         for (i = 0; smf_st_events[i].s != NULL; ++i) {
 177                 if (strcmp(str, smf_st_events[i].s) == 0)
 178                         return (smf_st_events[i].c);
 179         }
 180 
 181         return (0);
 182 }
 183 
 184 const char *
 185 tset_to_string(int32_t t)
 186 {
 187         int i;
 188 
 189         for (i = 0; smf_st_events[i].s != NULL; ++i) {
 190                 if (smf_st_events[i].c == t)
 191                         return (smf_st_events[i].s);
 192         }
 193 
 194         return (NULL);
 195 }
 196 
 197 void
 198 safe_printf(const char *fmt, ...)
 199 {
 200         va_list va;
 201 
 202         va_start(va, fmt);
 203         if (vprintf(fmt, va) < 0)
 204                 uu_die(gettext("Error writing to stdout"));
 205         va_end(va);
 206 }
 207 
 208 static uint32_t
 209 notify_params_get_version(nvlist_t *nvl)
 210 {
 211         uint32_t v;
 212 
 213         if (nvl == NULL)
 214                 return (0xFFFFFFFFU);
 215 
 216         if (nvlist_lookup_uint32(nvl, SCF_NOTIFY_NAME_VERSION, &v) != 0)
 217                 return (0xFFFFFFFFU);
 218         else
 219                 return (v);
 220 }
 221 
 222 static void
 223 nvpair_print(nvpair_t *p)
 224 {
 225         char **v;
 226         uint_t n;
 227         int i;
 228 
 229         safe_printf("            %s:", nvpair_name(p));
 230         (void) nvpair_value_string_array(p, &v, &n);
 231         for (i = 0; i < n; ++i) {
 232                 safe_printf(" %s", v[i]);
 233         }
 234         safe_printf("\n");
 235 }
 236 
 237 static void
 238 params_type_print(nvlist_t *p, const char *name, const char *fmri)
 239 {
 240         nvpair_t *tnvp, *nvp;
 241         nvlist_t *nvl;
 242         boolean_t *a;
 243         uint_t n;
 244         int has_output = 0;
 245 
 246         /* for each event e print all notification parameters */
 247         for (tnvp = nvlist_next_nvpair(p, NULL); tnvp != NULL;
 248             tnvp = nvlist_next_nvpair(p, tnvp)) {
 249                 /* We only want the NVLIST memebers */
 250                 if (nvpair_type(tnvp) != DATA_TYPE_NVLIST)
 251                         continue;
 252 
 253                 if (nvpair_value_nvlist(tnvp, &nvl) != 0)
 254                         uu_die("nvpair_value_nvlist");
 255 
 256                 if (!has_output)
 257                         if (fmri == NULL)
 258                                 safe_printf(gettext("    Event: %s\n"), name);
 259                         else
 260                                 safe_printf(gettext(
 261                                     "    Event: %s (source: %s)\n"),
 262                                     name, fmri);
 263 
 264                 has_output = 1;
 265 
 266                 safe_printf(gettext("        Notification Type: %s\n"),
 267                     nvpair_name(tnvp));
 268 
 269                 if (nvlist_lookup_boolean_array(nvl, PARAM_ACTIVE, &a, &n) != 0)
 270                         uu_warn(gettext("Missing 'active' property"));
 271                 else
 272                         safe_printf(gettext("            Active: %s\n"),
 273                             *a ? "true" : "false");
 274 
 275                 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
 276                     nvp = nvlist_next_nvpair(nvl, nvp)) {
 277                         if (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)
 278                                 continue;
 279                         nvpair_print(nvp);
 280                 }
 281                 safe_printf("\n");
 282         }
 283 }
 284 
 285 void
 286 listnotify_print(nvlist_t *nvl, const char *event)
 287 {
 288         char *fmri;
 289         nvlist_t **params;
 290         size_t n;
 291         int32_t tset;
 292         int i;
 293 
 294         /*
 295          * Check the nvl we got is from a version we understand
 296          */
 297         if (nvl != NULL && notify_params_get_version(nvl) !=
 298             SCF_NOTIFY_PARAMS_VERSION)
 299                 uu_die(gettext("libscf(3LIB) mismatch\n"));
 300 
 301         if (nvl != NULL && nvlist_lookup_nvlist_array(nvl, SCF_NOTIFY_PARAMS,
 302             &params, &n) != 0)
 303                 /* Sanity check. If we get here nvl is bad! */
 304                 uu_die(gettext("nvlist_lookup_nvlist_array\n"));
 305 
 306         if (event == NULL) {
 307                 /* this is an SMF state transition nvlist */
 308                 for (i = 0; i < n; ++i) {
 309                         nvlist_t *p = *(params + i);
 310 
 311                         if (nvlist_lookup_string(p,
 312                             SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0)
 313                                 fmri = NULL;
 314                         if (nvlist_lookup_int32(p, SCF_NOTIFY_NAME_TSET,
 315                             &tset) != 0)
 316                                 uu_die("nvlist_lookup_int32");
 317                         params_type_print(p, tset_to_string(tset), fmri);
 318                 }
 319         } else {
 320                 /* this is FMA event nvlist */
 321                 if (nvl == NULL) { /* preferences not found */
 322                         return;
 323                 }
 324                 for (i = 0; i < n; ++i) {
 325                         nvlist_t *p = *(params + i);
 326 
 327                         if (nvlist_lookup_string(p,
 328                             SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0)
 329                                 fmri = NULL;
 330                         params_type_print(p, event, fmri);
 331                 }
 332         }
 333 }