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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <limits.h>
30 #include <string.h>
31 #include <sys/param.h>
32 #include <topo_error.h>
33 #include <topo_tree.h>
34 #include <topo_subr.h>
35 #include <topo_file.h>
36 
37 /*
38  * topo_file.c
39  *
40  *	This file hides the details of any file manipulation to
41  *	establish topology for a given scheme.  It has two outward
42  *	facing interfaces topo_file_load() and topo_file_unload().
43  */
44 
45 #define	TOPO_DEFAULT_FILE	"%s-topology.xml"
46 #define	PLATFORM_TOPO_PATH	"%susr/platform/%s/lib/fm/topo/%s"
47 #define	COMMON_TOPO_PATH	"%susr/lib/fm/topo/%s"
48 
49 static int
50 xml_read(topo_hdl_t *hp, ttree_t *tp)
51 {
52 	topo_file_t *tfp;
53 	char *pplat, *pmach;
54 	int err, e;
55 	char _topo_file[MAXNAMELEN * 2];
56 	char _topo_path[PATH_MAX];
57 
58 
59 	tfp = (topo_file_t *)tp->tt_file;
60 
61 	(void) snprintf(_topo_file,
62 	    2 * MAXNAMELEN, TOPO_DEFAULT_FILE, tp->tt_scheme);
63 
64 	/*
65 	 * Look for a platform-specific topology file first
66 	 */
67 	e = topo_prop_get_string(tp->tt_root, TOPO_PGROUP_SYSTEM,
68 	    TOPO_PROP_PLATFORM, &pplat, &err);
69 	if (e < 0)
70 		return (topo_hdl_seterrno(hp, err));
71 	(void) snprintf(_topo_path, PATH_MAX, PLATFORM_TOPO_PATH,
72 	    hp->th_rootdir, pplat, _topo_file);
73 
74 	tfp->tf_fileinfo =
75 	    topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme);
76 	if (tfp->tf_fileinfo != NULL) {
77 		topo_hdl_strfree(hp, pplat);
78 		return (0);
79 	}
80 
81 	topo_dprintf(TOPO_DBG_MOD, "failed to load topology file %s: %s\n",
82 	    _topo_path, topo_strerror(topo_hdl_errno(hp)));
83 
84 	/*
85 	 * No luck with the platform-specific file, how about a
86 	 * machine-specific one?
87 	 */
88 	e = topo_prop_get_string(tp->tt_root, TOPO_PGROUP_SYSTEM,
89 	    TOPO_PROP_MACHINE, &pmach, &err);
90 	if (e < 0) {
91 		topo_hdl_strfree(hp, pplat);
92 		return (topo_hdl_seterrno(hp, err));
93 	}
94 	/*
95 	 * Don't waste time trying to open the same file twice in the
96 	 * cases where the platform name is identical to the machine
97 	 * name
98 	 */
99 	if (strcmp(pplat, pmach) != 0) {
100 		(void) snprintf(_topo_path, PATH_MAX, PLATFORM_TOPO_PATH,
101 		    hp->th_rootdir, pmach, _topo_file);
102 		tfp->tf_fileinfo =
103 		    topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme);
104 	}
105 	if (tfp->tf_fileinfo != NULL) {
106 		topo_hdl_strfree(hp, pplat);
107 		topo_hdl_strfree(hp, pmach);
108 		return (0);
109 	} else {
110 		topo_dprintf(TOPO_DBG_MOD,
111 		    "failed to load topology file %s: %s\n",
112 		    _topo_path, topo_strerror(topo_hdl_errno(hp)));
113 	}
114 	topo_hdl_strfree(hp, pplat);
115 	topo_hdl_strfree(hp, pmach);
116 	(void) snprintf(_topo_path, PATH_MAX, COMMON_TOPO_PATH,
117 	    hp->th_rootdir, _topo_file);
118 	tfp->tf_fileinfo =
119 	    topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme);
120 	if (tfp->tf_fileinfo == NULL) {
121 		topo_dprintf(TOPO_DBG_MOD,
122 		    "failed to load topology file %s: %s\n",
123 		    _topo_path, topo_strerror(topo_hdl_errno(hp)));
124 		return (topo_hdl_seterrno(hp, ETOPO_FILE_NOENT));
125 	}
126 	return (0);
127 }
128 
129 int
130 topo_file_load(topo_hdl_t *thp, topo_mod_t *mod, ttree_t *tp)
131 {
132 	topo_file_t *tfp;
133 
134 	if ((tfp = topo_hdl_zalloc(thp, sizeof (topo_file_t))) == NULL)
135 		return (topo_hdl_seterrno(thp, ETOPO_NOMEM));
136 
137 	tp->tt_file = tfp;
138 
139 	tfp->tf_mod = mod;
140 
141 	if (xml_read(thp, tp) < 0) {
142 		topo_file_unload(thp, tp);
143 		return (-1);
144 	}
145 
146 	if (topo_xml_enum(tfp->tf_mod, tfp->tf_fileinfo, tp->tt_root) < 0) {
147 		topo_dprintf(TOPO_DBG_ERR,
148 		    "Failed to enumerate topology: %s\n",
149 		    topo_strerror(topo_hdl_errno(thp)));
150 		topo_file_unload(thp, tp);
151 		return (-1);
152 	}
153 	return (0);
154 }
155 
156 void
157 topo_file_unload(topo_hdl_t *thp, ttree_t *tp)
158 {
159 	topo_file_t *tfp = tp->tt_file;
160 
161 	if (tfp == NULL)
162 		return;
163 
164 	if (tfp->tf_fileinfo != NULL)
165 		tf_info_free(tfp->tf_mod, tfp->tf_fileinfo);
166 
167 	topo_hdl_free(thp, tfp, sizeof (topo_file_t));
168 	tp->tt_file = NULL;
169 }
170