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