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 }