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 } 302