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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <fm/topo_mod.h> 29 #include <fm/fmd_fmri.h> 30 #include <fm/libtopo.h> 31 32 typedef struct hc_walk_arg { 33 void *p; 34 int *resultp; 35 } hc_walk_arg_t; 36 37 static topo_hdl_t *HC_thp = NULL; 38 static char *HC_uuid = NULL; 39 40 int 41 fmd_fmri_init(void) 42 { 43 int err; 44 45 if ((HC_thp = topo_open(TOPO_VERSION, NULL, &err)) == NULL) 46 return (-1); 47 48 return (0); 49 } 50 51 void 52 fmd_fmri_fini(void) 53 { 54 if (HC_uuid) { 55 topo_snap_release(HC_thp); 56 topo_hdl_strfree(HC_thp, HC_uuid); 57 HC_uuid = NULL; 58 } 59 topo_close(HC_thp); 60 } 61 62 static int 63 hc_update_topology(void) 64 { 65 static uint64_t lastgen = 0; 66 int err; 67 uint64_t curgen; 68 69 if (HC_uuid == NULL || 70 (curgen = fmd_fmri_get_drgen()) > lastgen) { 71 72 lastgen = curgen; 73 74 if (HC_uuid) { 75 topo_snap_release(HC_thp); 76 topo_hdl_strfree(HC_thp, HC_uuid); 77 HC_uuid = NULL; 78 } 79 80 if ((HC_uuid = topo_snap_hold(HC_thp, NULL, &err)) == NULL) { 81 return (-1); 82 } 83 } 84 return (0); 85 } 86 87 static int 88 hc_topo_walk(topo_walk_cb_t fn, void *arg, int *resultp) 89 { 90 int err, rv; 91 topo_walk_t *twp; 92 hc_walk_arg_t hcarg; 93 94 hcarg.p = arg; 95 hcarg.resultp = resultp; 96 97 if ((twp = topo_walk_init(HC_thp, FM_FMRI_SCHEME_HC, fn, 98 &hcarg, &err)) == NULL) 99 return (-1); 100 101 rv = (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) 102 ? -1 : 0; 103 104 topo_walk_fini(twp); 105 return (rv); 106 } 107 108 /* 109 * buf_append -- Append str to buf (if it's non-NULL). Place prepend 110 * in buf in front of str and append behind it (if they're non-NULL). 111 * Continue to update size even if we run out of space to actually 112 * stuff characters in the buffer. 113 */ 114 static void 115 buf_append(ssize_t *sz, char *buf, size_t buflen, char *str, 116 char *prepend, char *append) 117 { 118 ssize_t left; 119 120 if (str == NULL) 121 return; 122 123 if (buflen == 0 || (left = buflen - *sz) < 0) 124 left = 0; 125 126 if (buf != NULL && left != 0) 127 buf += *sz; 128 129 if (prepend == NULL && append == NULL) 130 *sz += snprintf(buf, left, "%s", str); 131 else if (append == NULL) 132 *sz += snprintf(buf, left, "%s%s", prepend, str); 133 else if (prepend == NULL) 134 *sz += snprintf(buf, left, "%s%s", str, append); 135 else 136 *sz += snprintf(buf, left, "%s%s%s", prepend, str, append); 137 } 138 139 ssize_t 140 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 141 { 142 nvlist_t **hcprs = NULL; 143 nvlist_t *anvl = NULL; 144 uint8_t version; 145 ssize_t size = 0; 146 uint_t hcnprs; 147 char *achas = NULL; 148 char *adom = NULL; 149 char *aprod = NULL; 150 char *asrvr = NULL; 151 char *ahost = NULL; 152 char *serial = NULL; 153 char *part = NULL; 154 char *root = NULL; 155 char *rev = NULL; 156 int more_auth = 0; 157 int err, i; 158 159 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 160 version > FM_HC_SCHEME_VERSION) 161 return (fmd_fmri_set_errno(EINVAL)); 162 163 /* Get authority, if present */ 164 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); 165 if (err != 0 && err != ENOENT) 166 return (fmd_fmri_set_errno(err)); 167 168 if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0) 169 return (fmd_fmri_set_errno(EINVAL)); 170 171 err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); 172 if (err != 0 || hcprs == NULL) 173 return (fmd_fmri_set_errno(EINVAL)); 174 175 if (anvl != NULL) { 176 (void) nvlist_lookup_string(anvl, 177 FM_FMRI_AUTH_PRODUCT, &aprod); 178 (void) nvlist_lookup_string(anvl, 179 FM_FMRI_AUTH_CHASSIS, &achas); 180 (void) nvlist_lookup_string(anvl, 181 FM_FMRI_AUTH_DOMAIN, &adom); 182 (void) nvlist_lookup_string(anvl, 183 FM_FMRI_AUTH_SERVER, &asrvr); 184 (void) nvlist_lookup_string(anvl, 185 FM_FMRI_AUTH_HOST, &ahost); 186 if (aprod != NULL) 187 more_auth++; 188 if (achas != NULL) 189 more_auth++; 190 if (adom != NULL) 191 more_auth++; 192 if (asrvr != NULL) 193 more_auth++; 194 if (ahost != NULL) 195 more_auth++; 196 } 197 198 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial); 199 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part); 200 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev); 201 202 /* hc:// */ 203 buf_append(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://"); 204 205 /* authority, if any */ 206 if (aprod != NULL) 207 buf_append(&size, buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=", 208 --more_auth > 0 ? "," : NULL); 209 if (achas != NULL) 210 buf_append(&size, buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=", 211 --more_auth > 0 ? "," : NULL); 212 if (adom != NULL) 213 buf_append(&size, buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=", 214 --more_auth > 0 ? "," : NULL); 215 if (asrvr != NULL) 216 buf_append(&size, buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=", 217 --more_auth > 0 ? "," : NULL); 218 if (ahost != NULL) 219 buf_append(&size, buf, buflen, ahost, FM_FMRI_AUTH_HOST "=", 220 NULL); 221 222 /* separating slash */ 223 if (serial != NULL || part != NULL || rev != NULL) 224 buf_append(&size, buf, buflen, "/", NULL, NULL); 225 226 /* hardware-id part */ 227 buf_append(&size, buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", 228 NULL); 229 buf_append(&size, buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL); 230 buf_append(&size, buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL); 231 232 /* separating slash */ 233 buf_append(&size, buf, buflen, "/", NULL, NULL); 234 235 /* hc-root */ 236 buf_append(&size, buf, buflen, root, NULL, NULL); 237 238 /* all the pairs */ 239 for (i = 0; i < hcnprs; i++) { 240 char *nm = NULL; 241 char *id = NULL; 242 243 if (i > 0) 244 buf_append(&size, buf, buflen, "/", NULL, NULL); 245 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm); 246 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id); 247 if (nm == NULL || id == NULL) 248 return (fmd_fmri_set_errno(EINVAL)); 249 buf_append(&size, buf, buflen, nm, NULL, "="); 250 buf_append(&size, buf, buflen, id, NULL, NULL); 251 } 252 253 return (size); 254 } 255 256 /*ARGSUSED*/ 257 static int 258 hc_topo_present(topo_hdl_t *thp, tnode_t *node, void *arg) 259 { 260 int cmp, err; 261 nvlist_t *out = NULL; 262 nvlist_t *asru; 263 hc_walk_arg_t *hcargp = (hc_walk_arg_t *)arg; 264 265 if (topo_node_asru(node, &asru, NULL, &err) != 0 || 266 asru == NULL) { 267 return (TOPO_WALK_NEXT); 268 } 269 270 /* 271 * Check if the ASRU of this node matches the ASRU passed in 272 */ 273 cmp = topo_fmri_compare(thp, asru, (nvlist_t *)hcargp->p, &err); 274 275 nvlist_free(asru); 276 277 if (cmp <= 0) 278 return (TOPO_WALK_NEXT); 279 280 /* 281 * Yes, so try to execute the topo-present method. 282 */ 283 cmp = topo_method_invoke(node, TOPO_METH_PRESENT, 284 TOPO_METH_PRESENT_VERSION, (nvlist_t *)hcargp->p, &out, &err); 285 286 if (out) 287 nvlist_free(out); 288 289 if (cmp == 1) { 290 *(hcargp->resultp) = 1; 291 return (TOPO_WALK_TERMINATE); 292 } else if (cmp == 0) { 293 *(hcargp->resultp) = 0; 294 return (TOPO_WALK_TERMINATE); 295 } 296 297 return (TOPO_WALK_NEXT); 298 } 299 300 301 /* 302 * fmd_fmri_present() is called by fmadm to determine if a faulty ASRU 303 * is still present in the system. In general we don't expect to get 304 * ASRUs in this scheme, so it's unlikely this routine will get called. 305 * In case it does, though, we just traverse our libtopo snapshot, 306 * looking for a matching ASRU (minus the serial number information), 307 * then invoke the "topo_present" method to determine presence. 308 */ 309 int 310 fmd_fmri_present(nvlist_t *nvl) 311 { 312 int ispresent = 1; 313 314 /* 315 * If there's an error during the topology update, punt by 316 * indicating presence. 317 */ 318 if (hc_update_topology() < 0) 319 return (1); 320 321 (void) hc_topo_walk(hc_topo_present, nvl, &ispresent); 322 323 return (ispresent); 324 } 325 326 /* 327 * fmd_fmri_unusable() is called by fmadm to determine if a faulty ASRU 328 * is usable. In general we don't expect to get ASRUs in this scheme, 329 * so it's unlikely this routine will get called. In case it does, 330 * though, we just return false by default, as we have no real way to 331 * find the component or determine the component's usability. 332 */ 333 /*ARGSUSED*/ 334 int 335 fmd_fmri_unusable(nvlist_t *nvl) 336 { 337 return (0); 338 } 339