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 2008 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_CHASSIS, 145 FM_FMRI_AUTH_SERVER, 146 FM_FMRI_AUTH_DOMAIN, 147 FM_FMRI_AUTH_HOST, 148 NULL 149 }; 150 const char **namep; 151 nvlist_t *auth1 = NULL, *auth2 = NULL; 152 153 (void) nvlist_lookup_nvlist(nvl1, FM_FMRI_AUTHORITY, &auth1); 154 (void) nvlist_lookup_nvlist(nvl2, FM_FMRI_AUTHORITY, &auth2); 155 if (auth1 == NULL && auth2 == NULL) 156 return (0); 157 if (auth1 == NULL || auth2 == NULL) 158 return (1); 159 160 for (namep = names; *namep != NULL; namep++) { 161 char *val1 = NULL, *val2 = NULL; 162 163 (void) nvlist_lookup_string(auth1, *namep, &val1); 164 (void) nvlist_lookup_string(auth2, *namep, &val2); 165 if (val1 == NULL && val2 == NULL) 166 continue; 167 if (val1 == NULL || val2 == NULL || strcmp(val1, val2) != 0) 168 return (1); 169 } 170 171 return (0); 172 } 173 174 static int 175 hclist_contains(nvlist_t **erhcl, uint_t erhclsz, nvlist_t **eehcl, 176 uint_t eehclsz) 177 { 178 uint_t i; 179 char *erval, *eeval; 180 181 if (erhclsz > eehclsz || erhcl == NULL || eehcl == NULL) 182 return (0); 183 184 for (i = 0; i < erhclsz; i++) { 185 (void) nvlist_lookup_string(erhcl[i], FM_FMRI_HC_NAME, 186 &erval); 187 (void) nvlist_lookup_string(eehcl[i], FM_FMRI_HC_NAME, 188 &eeval); 189 if (strcmp(erval, eeval) != 0) 190 return (0); 191 (void) nvlist_lookup_string(erhcl[i], FM_FMRI_HC_ID, 192 &erval); 193 (void) nvlist_lookup_string(eehcl[i], FM_FMRI_HC_ID, 194 &eeval); 195 if (strcmp(erval, eeval) != 0) 196 return (0); 197 } 198 199 return (1); 200 } 201 202 static int 203 fru_compare(nvlist_t *r1, nvlist_t *r2) 204 { 205 topo_hdl_t *thp; 206 nvlist_t *f1 = NULL, *f2 = NULL; 207 nvlist_t **h1 = NULL, **h2 = NULL; 208 uint_t h1sz, h2sz; 209 int err, rc = 1; 210 211 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 212 return (fmd_fmri_set_errno(EINVAL)); 213 214 (void) topo_fmri_fru(thp, r1, &f1, &err); 215 (void) topo_fmri_fru(thp, r2, &f2, &err); 216 if (f1 != NULL && f2 != NULL) { 217 (void) nvlist_lookup_nvlist_array(f1, FM_FMRI_HC_LIST, &h1, 218 &h1sz); 219 (void) nvlist_lookup_nvlist_array(f2, FM_FMRI_HC_LIST, &h2, 220 &h2sz); 221 if (h1sz == h2sz && hclist_contains(h1, h1sz, h2, h2sz) == 1) 222 rc = 0; 223 } 224 225 fmd_fmri_topo_rele(thp); 226 if (f1 != NULL) 227 nvlist_free(f1); 228 if (f2 != NULL) 229 nvlist_free(f2); 230 return (rc); 231 } 232 233 int 234 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) 235 { 236 nvlist_t **erhcl, **eehcl; 237 uint_t erhclsz, eehclsz; 238 nvlist_t *hcsp; 239 uint64_t eroff, eeoff; 240 241 if (nvlist_lookup_nvlist_array(er, FM_FMRI_HC_LIST, &erhcl, 242 &erhclsz) != 0 || nvlist_lookup_nvlist_array(ee, 243 FM_FMRI_HC_LIST, &eehcl, &eehclsz) != 0) 244 return (fmd_fmri_set_errno(EINVAL)); 245 246 /* 247 * Check ee is further down the hc tree than er; er and ee have 248 * the same auth and are on the same fru. 249 */ 250 if (hclist_contains(erhcl, erhclsz, eehcl, eehclsz) == 0 || 251 auth_compare(er, ee) != 0 || fru_compare(er, ee) != 0) 252 return (0); 253 254 /* 255 * return true if er is parent of ee, or er is not a page 256 */ 257 if (erhclsz < eehclsz || nvlist_lookup_nvlist(er, 258 FM_FMRI_HC_SPECIFIC, &hcsp) != 0 || (nvlist_lookup_uint64(hcsp, 259 FM_FMRI_HC_SPECIFIC_OFFSET, &eroff) != 0 && 260 nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, 261 &eroff) != 0)) 262 return (1); 263 264 /* 265 * special case for page fmri: return true if ee is the same page 266 */ 267 if (nvlist_lookup_nvlist(ee, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 && 268 (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET, 269 &eeoff) == 0 || nvlist_lookup_uint64(hcsp, "asru-" 270 FM_FMRI_HC_SPECIFIC_OFFSET, &eeoff) == 0) && eroff == eeoff) 271 return (1); 272 273 return (0); 274 } 275 276 int 277 fmd_fmri_service_state(nvlist_t *nvl) 278 { 279 uint8_t version; 280 int err, service_state; 281 topo_hdl_t *thp; 282 283 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 284 version > FM_DEV_SCHEME_VERSION) 285 return (fmd_fmri_set_errno(EINVAL)); 286 287 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 288 return (fmd_fmri_set_errno(EINVAL)); 289 err = 0; 290 service_state = topo_fmri_service_state(thp, nvl, &err); 291 fmd_fmri_topo_rele(thp); 292 293 if (err != 0) 294 return (FMD_SERVICE_STATE_UNKNOWN); 295 else 296 return (service_state); 297 } 298