xref: /onnv-gate/usr/src/cmd/fm/schemes/dev/scheme.c (revision 555:35769a8a679f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*555Stimh  * Common Development and Distribution License (the "License").
6*555Stimh  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*555Stimh 
220Sstevel@tonic-gate /*
23*555Stimh  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <fm/fmd_fmri.h>
300Sstevel@tonic-gate #include <libdevinfo.h>
310Sstevel@tonic-gate #include <alloca.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate /*
350Sstevel@tonic-gate  * buf_append -- Append str to buf (if it's non-NULL).  Place prepend
360Sstevel@tonic-gate  * in buf in front of str and append behind it (if they're non-NULL).
370Sstevel@tonic-gate  * Continue to update size even if we run out of space to actually
380Sstevel@tonic-gate  * stuff characters in the buffer.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate static void
410Sstevel@tonic-gate buf_append(ssize_t *sz, char *buf, size_t buflen, char *str,
420Sstevel@tonic-gate     char *prepend, char *append)
430Sstevel@tonic-gate {
440Sstevel@tonic-gate 	ssize_t left;
450Sstevel@tonic-gate 
460Sstevel@tonic-gate 	if (str == NULL)
470Sstevel@tonic-gate 		return;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 	if (buflen == 0 || (left = buflen - *sz) < 0)
500Sstevel@tonic-gate 		left = 0;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	if (buf != NULL && left != 0)
530Sstevel@tonic-gate 		buf += *sz;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	if (prepend == NULL && append == NULL)
560Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s", str);
570Sstevel@tonic-gate 	else if (append == NULL)
580Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s%s", prepend, str);
590Sstevel@tonic-gate 	else if (prepend == NULL)
600Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s%s", str, append);
610Sstevel@tonic-gate 	else
620Sstevel@tonic-gate 		*sz += snprintf(buf, left, "%s%s%s", prepend, str, append);
630Sstevel@tonic-gate }
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 
660Sstevel@tonic-gate ssize_t
670Sstevel@tonic-gate fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	nvlist_t *anvl = NULL;
700Sstevel@tonic-gate 	uint8_t version;
710Sstevel@tonic-gate 	ssize_t size = 0;
720Sstevel@tonic-gate 	char *devid = NULL;
730Sstevel@tonic-gate 	char *devpath = NULL;
740Sstevel@tonic-gate 	char *achas = NULL;
750Sstevel@tonic-gate 	char *adom = NULL;
760Sstevel@tonic-gate 	char *aprod = NULL;
770Sstevel@tonic-gate 	char *asrvr = NULL;
780Sstevel@tonic-gate 	char *ahost = NULL;
790Sstevel@tonic-gate 	int more_auth = 0;
800Sstevel@tonic-gate 	int err;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
830Sstevel@tonic-gate 	    version > FM_DEV_SCHEME_VERSION)
840Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	/* Get authority, if present */
870Sstevel@tonic-gate 	err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
880Sstevel@tonic-gate 	if (err != 0 && err != ENOENT)
890Sstevel@tonic-gate 		return (fmd_fmri_set_errno(err));
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	/* Get devid, if present */
920Sstevel@tonic-gate 	err = nvlist_lookup_string(nvl, FM_FMRI_DEV_ID, &devid);
930Sstevel@tonic-gate 	if (err != 0 && err != ENOENT)
940Sstevel@tonic-gate 		return (fmd_fmri_set_errno(err));
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	/* There must be a device path present */
970Sstevel@tonic-gate 	err = nvlist_lookup_string(nvl, FM_FMRI_DEV_PATH, &devpath);
980Sstevel@tonic-gate 	if (err != 0 || devpath == NULL)
990Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if (anvl != NULL) {
1020Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
1030Sstevel@tonic-gate 		    FM_FMRI_AUTH_PRODUCT, &aprod);
1040Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
1050Sstevel@tonic-gate 		    FM_FMRI_AUTH_CHASSIS, &achas);
1060Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
1070Sstevel@tonic-gate 		    FM_FMRI_AUTH_DOMAIN, &adom);
1080Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
1090Sstevel@tonic-gate 		    FM_FMRI_AUTH_SERVER, &asrvr);
1100Sstevel@tonic-gate 		(void) nvlist_lookup_string(anvl,
1110Sstevel@tonic-gate 		    FM_FMRI_AUTH_HOST, &ahost);
1120Sstevel@tonic-gate 		if (aprod != NULL)
1130Sstevel@tonic-gate 			more_auth++;
1140Sstevel@tonic-gate 		if (achas != NULL)
1150Sstevel@tonic-gate 			more_auth++;
1160Sstevel@tonic-gate 		if (adom != NULL)
1170Sstevel@tonic-gate 			more_auth++;
1180Sstevel@tonic-gate 		if (asrvr != NULL)
1190Sstevel@tonic-gate 			more_auth++;
1200Sstevel@tonic-gate 		if (ahost != NULL)
1210Sstevel@tonic-gate 			more_auth++;
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	/* dev:// */
1250Sstevel@tonic-gate 	buf_append(&size, buf, buflen, FM_FMRI_SCHEME_DEV, NULL, "://");
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	/* authority, if any */
1280Sstevel@tonic-gate 	if (aprod != NULL)
1290Sstevel@tonic-gate 		buf_append(&size, buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=",
1300Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
1310Sstevel@tonic-gate 	if (achas != NULL)
1320Sstevel@tonic-gate 		buf_append(&size, buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=",
1330Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
1340Sstevel@tonic-gate 	if (adom != NULL)
1350Sstevel@tonic-gate 		buf_append(&size, buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=",
1360Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
1370Sstevel@tonic-gate 	if (asrvr != NULL)
1380Sstevel@tonic-gate 		buf_append(&size, buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=",
1390Sstevel@tonic-gate 		    --more_auth > 0 ? "," : NULL);
1400Sstevel@tonic-gate 	if (ahost != NULL)
1410Sstevel@tonic-gate 		buf_append(&size, buf, buflen, ahost, FM_FMRI_AUTH_HOST "=",
1420Sstevel@tonic-gate 		    NULL);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	/* device-id part */
1450Sstevel@tonic-gate 	buf_append(&size, buf, buflen, devid, "/:" FM_FMRI_DEV_ID "=", NULL);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/* device-path part */
1480Sstevel@tonic-gate 	buf_append(&size, buf, buflen, devpath, "/", NULL);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	return (size);
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * callback routine for di_walk_minor()
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate struct walkinfo {
1570Sstevel@tonic-gate 	int matched;
1580Sstevel@tonic-gate 	const char *path;
1590Sstevel@tonic-gate 	int len;
1600Sstevel@tonic-gate };
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static int
1630Sstevel@tonic-gate dev_match(di_node_t node, void *arg)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	struct walkinfo *wip = (struct walkinfo *)arg;
1660Sstevel@tonic-gate 	char *path = di_devfs_path(node);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	if (path != NULL && strncmp(path, wip->path, wip->len) == 0) {
1690Sstevel@tonic-gate 		/*
1700Sstevel@tonic-gate 		 * found the match we were looking for, set matched
1710Sstevel@tonic-gate 		 * flag and terminate the walk.
1720Sstevel@tonic-gate 		 */
1730Sstevel@tonic-gate 		wip->matched = 1;
1740Sstevel@tonic-gate 		di_devfs_path_free(path);
1750Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (path != NULL)
1790Sstevel@tonic-gate 		di_devfs_path_free(path);
1800Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate  * For now we only check for the presence of the device in the device
1850Sstevel@tonic-gate  * tree.  This is somewhat unsophisticated, because a device may have
1860Sstevel@tonic-gate  * been inserted into the same slot as the previous ASRU and we don't
1870Sstevel@tonic-gate  * know how to tell them apart yet.
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate int
1900Sstevel@tonic-gate fmd_fmri_present(nvlist_t *nvl)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	di_node_t parent;
1930Sstevel@tonic-gate 	uint8_t version;
1940Sstevel@tonic-gate 	char *devpath = NULL;
1950Sstevel@tonic-gate 	char *parentpath;
1960Sstevel@tonic-gate 	char *cp;
1970Sstevel@tonic-gate 	struct walkinfo walkinfo;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
2000Sstevel@tonic-gate 	    version > FM_DEV_SCHEME_VERSION ||
2010Sstevel@tonic-gate 	    nvlist_lookup_string(nvl, FM_FMRI_DEV_PATH, &devpath) != 0)
2020Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (devpath == NULL || (walkinfo.len = strlen(devpath)) == 0)
2050Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	/* strip off last component of path */
2080Sstevel@tonic-gate 	parentpath = alloca(walkinfo.len + 1);
2090Sstevel@tonic-gate 	(void) strcpy(parentpath, devpath);
2100Sstevel@tonic-gate 	if ((cp = strrchr(parentpath, '/')) == NULL)
2110Sstevel@tonic-gate 		parentpath = "/";
2120Sstevel@tonic-gate 	else
2130Sstevel@tonic-gate 		*cp = '\0';
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/* if the result is an empty path, start walk at "/" */
2160Sstevel@tonic-gate 	if (*parentpath == '\0')
2170Sstevel@tonic-gate 		parentpath = "/";
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	if ((parent = di_init(parentpath, DINFOSUBTREE)) == DI_NODE_NIL)
2200Sstevel@tonic-gate 		return (errno == ENXIO ? 0 : -1);
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	walkinfo.matched = 0;
2230Sstevel@tonic-gate 	walkinfo.path = devpath;
224*555Stimh 	(void) di_walk_node(parent,
225*555Stimh 	    DI_WALK_SIBFIRST, (void *)&walkinfo, dev_match);
2260Sstevel@tonic-gate 	di_fini(parent);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	return (walkinfo.matched);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate  *  We presently don't have a good indication of the usability of an
2330Sstevel@tonic-gate  *  ASRU in the dev scheme, so we'll assume its usable.
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate int
2360Sstevel@tonic-gate fmd_fmri_unusable(nvlist_t *nvl)
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate 	uint8_t version;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
2410Sstevel@tonic-gate 	    version > FM_DEV_SCHEME_VERSION)
2420Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	return (0);
2450Sstevel@tonic-gate }
246