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