xref: /titanic_51/usr/src/lib/libnsctl/common/machdep.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 <sys/types.h>
27 #include <sys/utsname.h>
28 #include <fcntl.h>
29 #include <sys/param.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "libnsctl.h"
38 #include <nsctl.h>
39 #include <sys/ncall/ncall.h>
40 
41 
42 
43 /*
44  * Internal routine to fetch all the current nodes that are
45  * considered 'up'.
46  * Returns the number of ncall_info structures that are valid
47  * returned via the nodelist pointer, or -1 on an error.
48  * If the call succeeds, then the memory returned via the
49  * nodelist pointer needs to be freed by the caller.
50  */
51 
52 static int
53 nsc_getcurrentnodes(ncall_node_t **nodelist)
54 {
55 	ncall_node_t *mynodelist;
56 	int size;
57 	int fd;
58 	int rc = -1;
59 	int save_errno = 0;
60 	int ioctlcmd;
61 
62 	if (nodelist == NULL) {
63 		errno = EINVAL;
64 		return (-1);
65 	}
66 	*nodelist = NULL;
67 	if ((fd = open("/dev/ncall", O_RDONLY)) < 0) {
68 		return (-1);
69 	}
70 	if ((size = ioctl(fd, NC_IOC_GETNETNODES, NULL)) < 1) {
71 		size = 1;
72 		ioctlcmd = NC_IOC_GETNODE;
73 	} else {
74 		ioctlcmd = NC_IOC_GETNETNODES;
75 	}
76 
77 	mynodelist = malloc(size * sizeof (*mynodelist));
78 	if (mynodelist == NULL) {
79 		save_errno = ENOMEM;
80 	} else {
81 		rc = ioctl(fd, ioctlcmd, mynodelist);
82 		if (rc < 0) {
83 			save_errno = errno;
84 			free(mynodelist);
85 		} else {
86 			/* fixup return value for single node ioctl */
87 			if (ioctlcmd == NC_IOC_GETNODE)
88 				rc = 1;
89 			*nodelist = mynodelist;
90 		}
91 	}
92 	close(fd);
93 	errno = save_errno;
94 	return (rc);
95 }
96 
97 
98 /*
99  * return the system id (the current value in the kernel
100  * currently running).
101  *
102  * on error return -1 and set errno.
103  */
104 int
105 nsc_getsystemid(int *id)
106 {
107 	ncall_node_t node;
108 	int rval = 0;
109 	int save_errno = 0;
110 	int fd;
111 
112 	*id = 0;
113 
114 	fd = open("/dev/ncall", O_RDONLY);
115 	if (fd < 0)
116 		return (-1);
117 
118 	memset(&node, 0, sizeof (node));
119 
120 	rval = ioctl(fd, NC_IOC_GETNODE, &node);
121 	if (rval < 0)
122 		save_errno = errno;
123 	else {
124 		*id = node.nc_nodeid;
125 		/*
126 		 * Return 0, not the mirror node id as returned
127 		 * from the ioctl.
128 		 */
129 		rval = 0;
130 	}
131 
132 	close(fd);
133 
134 	errno = save_errno;
135 	return (rval);
136 }
137 
138 
139 /*
140  * Runtime Solaris release checking.
141  *
142  * Compare the build release to the runtime release to check for an
143  * acceptable match.
144  *
145  * Arguments:
146  *	build_ver   - the string Solaris build release (e.g. "5.8")
147  *	map         - optional array of nsc_release_t defining
148  *			acceptable build release / runtime release
149  *			matches. If supplied, must end will a NULL
150  *			array element.  See src/head/nsctl.h for info.
151  *	reqd        - used to return the required OS versions if the
152  *			return value is not -1.  The returned string
153  *			is readonly.
154  *
155  * Returns:
156  *	TRUE	- acceptable match
157  *	FALSE	- no match (component should not continue to run)
158  *	-1	- error (errno is set)
159  */
160 
161 int
162 nsc_check_release(const char *build_rel, nsc_release_t *map, char **reqd)
163 {
164 	struct utsname uts;
165 	nsc_release_t *mp;
166 	const char *sep = ", ";
167 	char *cp, *tofree, *last;
168 	int rc;
169 
170 	if (reqd)
171 		*reqd = NULL;
172 
173 	if (build_rel == NULL || *build_rel == '\0') {
174 		errno = EINVAL;
175 		return (-1);
176 	}
177 
178 	/* assume that build_rel is the required release for now */
179 	if (reqd)
180 		*reqd = (char *)build_rel;
181 
182 	if (uname(&uts) < 0)
183 		return (-1);
184 
185 	/* build release == runtime release is always acceptable */
186 	if (strcmp(build_rel, uts.release) == 0)
187 		return (TRUE);
188 
189 	if (map == NULL)
190 		return (FALSE);
191 
192 	rc = FALSE;
193 	tofree = NULL;
194 
195 	for (mp = map; mp->build != NULL && mp->runtime != NULL; mp++) {
196 		if (strcmp(mp->build, build_rel) == 0) {
197 			/*
198 			 * found an entry for this build release
199 			 * - search for a match in the runtime releases
200 			 */
201 
202 			/* reset reqd to this entry */
203 			if (reqd)
204 				*reqd = (char *)mp->runtime;
205 
206 			/*
207 			 * operate on a copy of the string since strtok
208 			 * is destructive.
209 			 */
210 			tofree = cp = strdup(mp->runtime);
211 			if (cp == NULL) {
212 				errno = ENOMEM;
213 				rc = -1;
214 				break;
215 			}
216 
217 			cp = strtok_r(cp, sep, &last);
218 			while (cp != NULL) {
219 				if (strcmp(cp, uts.release) == 0) {
220 					rc = TRUE;
221 					break;
222 				}
223 
224 				cp = strtok_r(NULL, sep, &last);
225 			}
226 
227 			break;
228 		}
229 	}
230 
231 	if (tofree)
232 		free(tofree);
233 
234 	return (rc);
235 }
236 
237 
238 /*
239  * return the system id corresponding to name
240  *
241  * on error return -1 and set errno.
242  */
243 int
244 nsc_name_to_id(char *name, int *id)
245 {
246 	ncall_node_t *nodes;
247 	int rval = 0;
248 	int nodecnt;
249 	int slot;
250 
251 	*id = 0;
252 
253 	nodecnt = nsc_getcurrentnodes(&nodes);
254 	if (nodecnt < 0) {
255 		rval = -1;
256 	} else {
257 		for (slot = 0; slot < nodecnt; slot++) {
258 			if (strcmp(name, nodes[slot].nc_nodename) == 0) {
259 				*id = nodes[slot].nc_nodeid;
260 				break;
261 			}
262 		}
263 		if (slot >= nodecnt) {
264 			errno = ENOENT;
265 			rval = -1;
266 		}
267 		free(nodes);
268 	}
269 	return (rval);
270 }
271 
272 /*
273  * return the node name corresponding to system id
274  *
275  * on error return -1 and set errno.
276  * The returned string has been strdup() and needs
277  * to be freed by the caller.
278  */
279 int
280 nsc_id_to_name(char **name, int id)
281 {
282 	ncall_node_t *nodes;
283 	int rval = 0;
284 	int nodecnt;
285 	int slot;
286 	char *foundname;
287 
288 	*name = 0;
289 	foundname = NULL;
290 
291 	nodecnt = nsc_getcurrentnodes(&nodes);
292 	if (nodecnt < 0) {
293 		rval = -1;
294 	} else {
295 		for (slot = 0; slot < nodecnt; slot++) {
296 			if (nodes[slot].nc_nodeid == id) {
297 				foundname = strdup(nodes[slot].nc_nodename);
298 				if (foundname) {
299 					*name = foundname;
300 				} else {
301 					errno = ENOMEM;
302 					rval = -1;
303 				}
304 				break;
305 			}
306 		}
307 		if (slot >= nodecnt) {
308 			errno = ENOENT;
309 			rval = -1;
310 		}
311 		free(nodes);
312 	}
313 	return (rval);
314 }
315