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  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <strings.h>
  26 #include <fm/fmd_fmri.h>
  27 #include <fm/libtopo.h>
  28 #include <fm/topo_mod.h>
  29 
  30 int
  31 fmd_fmri_init(void)
  32 {
  33         return (0);
  34 }
  35 
  36 void
  37 fmd_fmri_fini(void)
  38 {
  39 }
  40 
  41 ssize_t
  42 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
  43 {
  44         int err;
  45         uint8_t version;
  46         ssize_t len;
  47         topo_hdl_t *thp;
  48         char *str;
  49 
  50         if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
  51             version > FM_HC_SCHEME_VERSION)
  52                 return (fmd_fmri_set_errno(EINVAL));
  53 
  54         if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
  55                 return (fmd_fmri_set_errno(EINVAL));
  56         if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) {
  57                 fmd_fmri_topo_rele(thp);
  58                 return (fmd_fmri_set_errno(EINVAL));
  59         }
  60 
  61         if (buf != NULL)
  62                 len = snprintf(buf, buflen, "%s", str);
  63         else
  64                 len = strlen(str);
  65 
  66         topo_hdl_strfree(thp, str);
  67         fmd_fmri_topo_rele(thp);
  68 
  69         return (len);
  70 }
  71 
  72 int
  73 fmd_fmri_present(nvlist_t *nvl)
  74 {
  75         int err, present;
  76         topo_hdl_t *thp;
  77         nvlist_t **hcprs;
  78         char *nm;
  79         uint_t hcnprs;
  80 
  81         err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs);
  82         if (err != 0)
  83                 return (fmd_fmri_set_errno(EINVAL));
  84         err = nvlist_lookup_string(hcprs[0], FM_FMRI_HC_NAME, &nm);
  85         if (err != 0)
  86                 return (fmd_fmri_set_errno(EINVAL));
  87 
  88         if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
  89                 return (fmd_fmri_set_errno(EINVAL));
  90         present = topo_fmri_present(thp, nvl, &err);
  91         fmd_fmri_topo_rele(thp);
  92 
  93         return (present);
  94 }
  95 
  96 int
  97 fmd_fmri_replaced(nvlist_t *nvl)
  98 {
  99         int err, replaced;
 100         topo_hdl_t *thp;
 101         nvlist_t **hcprs;
 102         char *nm;
 103         uint_t hcnprs;
 104 
 105         err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs);
 106         if (err != 0)
 107                 return (fmd_fmri_set_errno(EINVAL));
 108         err = nvlist_lookup_string(hcprs[0], FM_FMRI_HC_NAME, &nm);
 109         if (err != 0)
 110                 return (fmd_fmri_set_errno(EINVAL));
 111 
 112         if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
 113                 return (fmd_fmri_set_errno(EINVAL));
 114         replaced = topo_fmri_replaced(thp, nvl, &err);
 115         fmd_fmri_topo_rele(thp);
 116 
 117         return (replaced);
 118 }
 119 
 120 int
 121 fmd_fmri_unusable(nvlist_t *nvl)
 122 {
 123         int err, unusable;
 124         topo_hdl_t *thp;
 125         nvlist_t **hcprs;
 126         char *nm;
 127         uint_t hcnprs;
 128 
 129         if (nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST,
 130             &hcprs, &hcnprs) != 0 ||
 131             nvlist_lookup_string(hcprs[0], FM_FMRI_HC_NAME, &nm) != 0)
 132                 return (0);
 133 
 134         if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
 135                 return (fmd_fmri_set_errno(EINVAL));
 136         unusable = topo_fmri_unusable(thp, nvl, &err);
 137         fmd_fmri_topo_rele(thp);
 138 
 139         return (unusable == 1 ? 1 : 0);
 140 }
 141 
 142 static int
 143 auth_compare(nvlist_t *nvl1, nvlist_t *nvl2)
 144 {
 145         const char *names[] = {
 146                 FM_FMRI_AUTH_PRODUCT,
 147                 FM_FMRI_AUTH_PRODUCT_SN,
 148                 FM_FMRI_AUTH_CHASSIS,
 149                 FM_FMRI_AUTH_SERVER,
 150                 FM_FMRI_AUTH_DOMAIN,
 151                 FM_FMRI_AUTH_HOST,
 152                 NULL
 153         };
 154         const char **namep;
 155         nvlist_t *auth1 = NULL, *auth2 = NULL;
 156 
 157         (void) nvlist_lookup_nvlist(nvl1, FM_FMRI_AUTHORITY, &auth1);
 158         (void) nvlist_lookup_nvlist(nvl2, FM_FMRI_AUTHORITY, &auth2);
 159         if (auth1 == NULL && auth2 == NULL)
 160                 return (0);
 161         if (auth1 == NULL || auth2 == NULL)
 162                 return (1);
 163 
 164         for (namep = names; *namep != NULL; namep++) {
 165                 char *val1 = NULL, *val2 = NULL;
 166 
 167                 (void) nvlist_lookup_string(auth1, *namep, &val1);
 168                 (void) nvlist_lookup_string(auth2, *namep, &val2);
 169                 if (val1 == NULL && val2 == NULL)
 170                         continue;
 171                 if (val1 == NULL || val2 == NULL || strcmp(val1, val2) != 0)
 172                         return (1);
 173         }
 174 
 175         return (0);
 176 }
 177 
 178 static int
 179 hclist_contains(nvlist_t **erhcl, uint_t erhclsz, nvlist_t **eehcl,
 180     uint_t eehclsz)
 181 {
 182         uint_t i;
 183         char *erval, *eeval;
 184 
 185         if (erhclsz > eehclsz || erhcl == NULL || eehcl == NULL)
 186                 return (0);
 187 
 188         for (i = 0; i < erhclsz; i++) {
 189                 (void) nvlist_lookup_string(erhcl[i], FM_FMRI_HC_NAME,
 190                     &erval);
 191                 (void) nvlist_lookup_string(eehcl[i], FM_FMRI_HC_NAME,
 192                     &eeval);
 193                 if (strcmp(erval, eeval) != 0)
 194                         return (0);
 195                 (void) nvlist_lookup_string(erhcl[i], FM_FMRI_HC_ID,
 196                     &erval);
 197                 (void) nvlist_lookup_string(eehcl[i], FM_FMRI_HC_ID,
 198                     &eeval);
 199                 if (strcmp(erval, eeval) != 0)
 200                         return (0);
 201         }
 202 
 203         return (1);
 204 }
 205 
 206 static int
 207 fru_compare(nvlist_t *r1, nvlist_t *r2)
 208 {
 209         topo_hdl_t *thp;
 210         nvlist_t *f1 = NULL, *f2 = NULL;
 211         nvlist_t **h1 = NULL, **h2 = NULL;
 212         uint_t h1sz, h2sz;
 213         int err, rc = 1;
 214 
 215         if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
 216                 return (fmd_fmri_set_errno(EINVAL));
 217 
 218         (void) topo_fmri_fru(thp, r1, &f1, &err);
 219         (void) topo_fmri_fru(thp, r2, &f2, &err);
 220         if (f1 != NULL && f2 != NULL) {
 221                 (void) nvlist_lookup_nvlist_array(f1, FM_FMRI_HC_LIST, &h1,
 222                     &h1sz);
 223                 (void) nvlist_lookup_nvlist_array(f2, FM_FMRI_HC_LIST, &h2,
 224                     &h2sz);
 225                 if (h1sz == h2sz && hclist_contains(h1, h1sz, h2, h2sz) == 1)
 226                         rc = 0;
 227         }
 228 
 229         fmd_fmri_topo_rele(thp);
 230         if (f1 != NULL)
 231                 nvlist_free(f1);
 232         if (f2 != NULL)
 233                 nvlist_free(f2);
 234         return (rc);
 235 }
 236 
 237 int
 238 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee)
 239 {
 240         nvlist_t **erhcl, **eehcl;
 241         uint_t erhclsz, eehclsz;
 242         nvlist_t *hcsp;
 243         uint64_t eroff, eeoff;
 244 
 245         if (nvlist_lookup_nvlist_array(er, FM_FMRI_HC_LIST, &erhcl,
 246             &erhclsz) != 0 || nvlist_lookup_nvlist_array(ee,
 247             FM_FMRI_HC_LIST, &eehcl, &eehclsz) != 0)
 248                 return (fmd_fmri_set_errno(EINVAL));
 249 
 250         /*
 251          * Check ee is further down the hc tree than er; er and ee have
 252          * the same auth and are on the same fru.
 253          */
 254         if (hclist_contains(erhcl, erhclsz, eehcl, eehclsz) == 0 ||
 255             auth_compare(er, ee) != 0 || fru_compare(er, ee) != 0)
 256                 return (0);
 257 
 258         /*
 259          * return true if er is parent of ee, or er is not a page
 260          */
 261         if (erhclsz < eehclsz || nvlist_lookup_nvlist(er,
 262             FM_FMRI_HC_SPECIFIC, &hcsp) != 0 || (nvlist_lookup_uint64(hcsp,
 263             FM_FMRI_HC_SPECIFIC_OFFSET, &eroff) != 0 &&
 264             nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET,
 265             &eroff) != 0))
 266                 return (1);
 267 
 268         /*
 269          * special case for page fmri: return true if ee is the same page
 270          */
 271         if (nvlist_lookup_nvlist(ee, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
 272             (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
 273             &eeoff) == 0 || nvlist_lookup_uint64(hcsp, "asru-"
 274             FM_FMRI_HC_SPECIFIC_OFFSET, &eeoff) == 0) && eroff == eeoff)
 275                 return (1);
 276 
 277         return (0);
 278 }
 279 
 280 int
 281 fmd_fmri_service_state(nvlist_t *nvl)
 282 {
 283         uint8_t version;
 284         int err, service_state;
 285         topo_hdl_t *thp;
 286 
 287         if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
 288             version > FM_DEV_SCHEME_VERSION)
 289                 return (fmd_fmri_set_errno(EINVAL));
 290 
 291         if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
 292                 return (fmd_fmri_set_errno(EINVAL));
 293         err = 0;
 294         service_state = topo_fmri_service_state(thp, nvl, &err);
 295         fmd_fmri_topo_rele(thp);
 296 
 297         if (err != 0)
 298                 return (FMD_SERVICE_STATE_UNKNOWN);
 299         else
 300                 return (service_state);
 301 }