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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All rights reserved. */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/sysmacros.h> 35 #include <sys/systm.h> 36 #include <sys/tuneable.h> 37 #include <sys/errno.h> 38 #include <sys/cred.h> 39 #include <sys/utsname.h> 40 #include <sys/systeminfo.h> 41 #include <sys/unistd.h> 42 #include <sys/debug.h> 43 #include <sys/bootconf.h> 44 #include <sys/socket.h> 45 #include <sys/policy.h> 46 #include <net/if.h> 47 #include <sys/sunddi.h> 48 #include <sys/promif.h> 49 #include <sys/zone.h> 50 #include <sys/model.h> 51 52 static void get_netif_name(char *, char *); 53 54 long 55 systeminfo(int command, char *buf, long count) 56 { 57 int error = 0; 58 long strcnt, getcnt; 59 char *kstr; 60 61 if (count < 0 && command != SI_SET_HOSTNAME && 62 command != SI_SET_SRPC_DOMAIN) 63 return (set_errno(EINVAL)); 64 65 /* 66 * Deal with the common "get a string" case first. 67 */ 68 switch (command) { 69 case SI_SYSNAME: 70 kstr = utsname.sysname; 71 break; 72 case SI_HOSTNAME: 73 kstr = uts_nodename(); 74 break; 75 case SI_RELEASE: 76 kstr = utsname.release; 77 break; 78 case SI_VERSION: 79 kstr = utsname.version; 80 break; 81 case SI_MACHINE: 82 kstr = utsname.machine; 83 break; 84 #ifdef _LP64 85 case SI_ARCHITECTURE_64: 86 case SI_ARCHITECTURE_K: 87 kstr = architecture; 88 break; 89 case SI_ARCHITECTURE_32: 90 case SI_ARCHITECTURE: 91 kstr = architecture_32; 92 break; 93 case SI_ARCHITECTURE_NATIVE: 94 kstr = get_udatamodel() == DATAMODEL_NATIVE ? 95 architecture : architecture_32; 96 break; 97 #else 98 case SI_ARCHITECTURE_K: 99 case SI_ARCHITECTURE_32: 100 case SI_ARCHITECTURE: 101 case SI_ARCHITECTURE_NATIVE: 102 kstr = architecture; 103 break; 104 #endif 105 case SI_HW_SERIAL: 106 kstr = hw_serial; 107 break; 108 case SI_HW_PROVIDER: 109 kstr = hw_provider; 110 break; 111 case SI_SRPC_DOMAIN: 112 kstr = curproc->p_zone->zone_domain; 113 break; 114 case SI_PLATFORM: 115 kstr = platform; 116 break; 117 case SI_ISALIST: 118 kstr = isa_list; 119 break; 120 default: 121 kstr = NULL; 122 break; 123 } 124 125 if (kstr != NULL) { 126 if ((strcnt = strlen(kstr)) >= count) { 127 getcnt = count - 1; 128 if (subyte(buf + count - 1, 0) < 0) 129 return (set_errno(EFAULT)); 130 } else 131 getcnt = strcnt + 1; 132 if (copyout(kstr, buf, getcnt)) 133 return (set_errno(EFAULT)); 134 return (strcnt + 1); 135 } 136 137 switch (command) { 138 case SI_DHCP_CACHE: 139 { 140 char *tmp; 141 142 if (dhcack == NULL) { 143 tmp = ""; 144 strcnt = 0; 145 } else { 146 /* 147 * If the interface name has not yet been resolved 148 * (first IFNAMSIZ bytes of dhcack[]) and a valid 149 * netdev_path[] was stashed by loadrootmodules in 150 * swapgeneric.c, resolve the interface name now. 151 */ 152 if (dhcack[0] == '\0' && 153 netdev_path != NULL && netdev_path[0] != '\0') { 154 get_netif_name(netdev_path, dhcack); 155 } 156 157 tmp = dhcack; 158 strcnt = IFNAMSIZ + strlen(&tmp[IFNAMSIZ]); 159 } 160 161 getcnt = (strcnt >= count) ? count : strcnt + 1; 162 163 if (copyout(tmp, buf, getcnt)) { 164 error = EFAULT; 165 break; 166 } 167 168 if (strcnt >= count && subyte((buf + count - 1), 0) < 0) { 169 error = EFAULT; 170 break; 171 } 172 173 return (strcnt + 1); 174 } 175 176 case SI_SET_HOSTNAME: 177 { 178 size_t len; 179 char name[SYS_NMLN]; 180 char *name_to_use; 181 182 if ((error = secpolicy_systeminfo(CRED())) != 0) 183 break; 184 185 name_to_use = uts_nodename(); 186 if ((error = copyinstr(buf, name, SYS_NMLN, &len)) != 0) 187 break; 188 189 /* 190 * Must be non-NULL string and string 191 * must be less than SYS_NMLN chars. 192 */ 193 if (len < 2 || (len == SYS_NMLN && name[SYS_NMLN-1] != '\0')) { 194 error = EINVAL; 195 break; 196 } 197 198 /* 199 * Copy the name into the relevant zone's nodename. 200 */ 201 (void) strcpy(name_to_use, name); 202 203 /* 204 * Notify other interested parties that the nodename was set 205 */ 206 if (name_to_use == utsname.nodename) /* global zone nodename */ 207 nodename_set(); 208 209 return (len); 210 } 211 212 case SI_SET_SRPC_DOMAIN: 213 { 214 char name[SYS_NMLN]; 215 size_t len; 216 217 if ((error = secpolicy_systeminfo(CRED())) != 0) 218 break; 219 if ((error = copyinstr(buf, name, SYS_NMLN, &len)) != 0) 220 break; 221 /* 222 * If string passed in is longer than length 223 * allowed for domain name, fail. 224 */ 225 if (len == SYS_NMLN && name[SYS_NMLN-1] != '\0') { 226 error = EINVAL; 227 break; 228 } 229 230 (void) strcpy(curproc->p_zone->zone_domain, name); 231 return (len); 232 } 233 234 default: 235 error = EINVAL; 236 break; 237 } 238 239 return (set_errno(error)); 240 } 241 242 /* 243 * i_path_find_node: Internal routine used by path_to_devinfo 244 * to locate a given nodeid in the device tree. 245 */ 246 struct i_path_findnode { 247 pnode_t nodeid; 248 dev_info_t *dip; 249 }; 250 251 static int 252 i_path_find_node(dev_info_t *dev, void *arg) 253 { 254 struct i_path_findnode *f = (struct i_path_findnode *)arg; 255 256 257 if (ddi_get_nodeid(dev) == (int)f->nodeid) { 258 f->dip = dev; 259 return (DDI_WALK_TERMINATE); 260 } 261 return (DDI_WALK_CONTINUE); 262 } 263 264 /* 265 * Return the devinfo node to a boot device 266 */ 267 static dev_info_t * 268 path_to_devinfo(char *path) 269 { 270 struct i_path_findnode fn; 271 extern dev_info_t *top_devinfo; 272 273 /* 274 * Get the nodeid of the given pathname, if such a mapping exists. 275 */ 276 fn.dip = NULL; 277 fn.nodeid = prom_finddevice(path); 278 if (fn.nodeid != OBP_BADNODE) { 279 /* 280 * Find the nodeid in our copy of the device tree and return 281 * whatever name we used to bind this node to a driver. 282 */ 283 ddi_walk_devs(top_devinfo, i_path_find_node, (void *)(&fn)); 284 } 285 286 return (fn.dip); 287 } 288 289 /* 290 * Determine the network interface name from the device path argument. 291 */ 292 static void 293 get_netif_name(char *devname, char *ifname) 294 { 295 dev_info_t *dip; 296 major_t ndev; 297 char *name; 298 int unit; 299 300 dip = path_to_devinfo(devname); 301 if (dip == NULL) { 302 cmn_err(CE_WARN, "get_netif_name: " 303 "can't bind driver for '%s'\n", devname); 304 return; 305 } 306 307 ndev = ddi_driver_major(dip); 308 if (ndev == -1) { 309 cmn_err(CE_WARN, "get_netif_name: " 310 "no driver bound to '%s'\n", devname); 311 return; 312 } 313 314 name = ddi_major_to_name(ndev); 315 if (name == NULL) { 316 cmn_err(CE_WARN, "get_netif_name: " 317 "no name for major number %d\n", ndev); 318 return; 319 } 320 321 unit = i_ddi_devi_get_ppa(dip); 322 if (unit < 0) { 323 cmn_err(CE_WARN, "get_netif_name: " 324 "illegal unit number %d\n", unit); 325 return; 326 } 327 328 (void) snprintf(ifname, IFNAMSIZ, "%s%d", name, unit); 329 } 330