systeminfo.c revision fa9e4066f08beec538e775443c5be79dd423fcab
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All rights reserved. */
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/systm.h>
#include <sys/tuneable.h>
#include <sys/errno.h>
#include <sys/cred.h>
#include <sys/utsname.h>
#include <sys/systeminfo.h>
#include <sys/unistd.h>
#include <sys/debug.h>
#include <sys/bootconf.h>
#include <sys/socket.h>
#include <sys/policy.h>
#include <net/if.h>
#include <sys/sunddi.h>
#include <sys/promif.h>
#include <sys/zone.h>
#include <sys/model.h>
static void get_netif_name(char *, char *);
long
systeminfo(int command, char *buf, long count)
{
int error = 0;
long strcnt, getcnt;
char *kstr;
if (count < 0 && command != SI_SET_HOSTNAME &&
command != SI_SET_SRPC_DOMAIN)
return (set_errno(EINVAL));
/*
* Deal with the common "get a string" case first.
*/
switch (command) {
case SI_SYSNAME:
kstr = utsname.sysname;
break;
case SI_HOSTNAME:
kstr = uts_nodename();
break;
case SI_RELEASE:
kstr = utsname.release;
break;
case SI_VERSION:
kstr = utsname.version;
break;
case SI_MACHINE:
kstr = utsname.machine;
break;
#ifdef _LP64
case SI_ARCHITECTURE_64:
case SI_ARCHITECTURE_K:
kstr = architecture;
break;
case SI_ARCHITECTURE_32:
case SI_ARCHITECTURE:
kstr = architecture_32;
break;
case SI_ARCHITECTURE_NATIVE:
kstr = get_udatamodel() == DATAMODEL_NATIVE ?
architecture : architecture_32;
break;
#else
case SI_ARCHITECTURE_K:
case SI_ARCHITECTURE_32:
case SI_ARCHITECTURE:
case SI_ARCHITECTURE_NATIVE:
kstr = architecture;
break;
#endif
case SI_HW_SERIAL:
kstr = hw_serial;
break;
case SI_HW_PROVIDER:
kstr = hw_provider;
break;
case SI_SRPC_DOMAIN:
kstr = curproc->p_zone->zone_domain;
break;
case SI_PLATFORM:
kstr = platform;
break;
case SI_ISALIST:
kstr = isa_list;
break;
default:
kstr = NULL;
break;
}
if (kstr != NULL) {
if ((strcnt = strlen(kstr)) >= count) {
getcnt = count - 1;
if (subyte(buf + count - 1, 0) < 0)
return (set_errno(EFAULT));
} else
getcnt = strcnt + 1;
if (copyout(kstr, buf, getcnt))
return (set_errno(EFAULT));
return (strcnt + 1);
}
switch (command) {
case SI_DHCP_CACHE:
{
char *tmp;
if (dhcack == NULL) {
tmp = "";
strcnt = 0;
} else {
/*
* If the interface name has not yet been resolved
* (first IFNAMSIZ bytes of dhcack[]) and a valid
* netdev_path[] was stashed by loadrootmodules in
* swapgeneric.c, resolve the interface name now.
*/
if (dhcack[0] == '\0' &&
netdev_path != NULL && netdev_path[0] != '\0') {
get_netif_name(netdev_path, dhcack);
}
tmp = dhcack;
strcnt = IFNAMSIZ + strlen(&tmp[IFNAMSIZ]);
}
getcnt = (strcnt >= count) ? count : strcnt + 1;
if (copyout(tmp, buf, getcnt)) {
error = EFAULT;
break;
}
if (strcnt >= count && subyte((buf + count - 1), 0) < 0) {
error = EFAULT;
break;
}
return (strcnt + 1);
}
case SI_SET_HOSTNAME:
{
size_t len;
char name[SYS_NMLN];
char *name_to_use;
if ((error = secpolicy_systeminfo(CRED())) != 0)
break;
name_to_use = uts_nodename();
if ((error = copyinstr(buf, name, SYS_NMLN, &len)) != 0)
break;
/*
* Must be non-NULL string and string
* must be less than SYS_NMLN chars.
*/
if (len < 2 || (len == SYS_NMLN && name[SYS_NMLN-1] != '\0')) {
error = EINVAL;
break;
}
/*
* Copy the name into the relevant zone's nodename.
*/
(void) strcpy(name_to_use, name);
/*
* Notify other interested parties that the nodename was set
*/
if (name_to_use == utsname.nodename) /* global zone nodename */
nodename_set();
return (len);
}
case SI_SET_SRPC_DOMAIN:
{
char name[SYS_NMLN];
size_t len;
if ((error = secpolicy_systeminfo(CRED())) != 0)
break;
if ((error = copyinstr(buf, name, SYS_NMLN, &len)) != 0)
break;
/*
* If string passed in is longer than length
* allowed for domain name, fail.
*/
if (len == SYS_NMLN && name[SYS_NMLN-1] != '\0') {
error = EINVAL;
break;
}
(void) strcpy(curproc->p_zone->zone_domain, name);
return (len);
}
default:
error = EINVAL;
break;
}
return (set_errno(error));
}
/*
* i_path_find_node: Internal routine used by path_to_devinfo
* to locate a given nodeid in the device tree.
*/
struct i_path_findnode {
pnode_t nodeid;
dev_info_t *dip;
};
static int
i_path_find_node(dev_info_t *dev, void *arg)
{
struct i_path_findnode *f = (struct i_path_findnode *)arg;
if (ddi_get_nodeid(dev) == (int)f->nodeid) {
f->dip = dev;
return (DDI_WALK_TERMINATE);
}
return (DDI_WALK_CONTINUE);
}
/*
* Return the devinfo node to a boot device
*/
static dev_info_t *
path_to_devinfo(char *path)
{
struct i_path_findnode fn;
extern dev_info_t *top_devinfo;
/*
* Get the nodeid of the given pathname, if such a mapping exists.
*/
fn.dip = NULL;
fn.nodeid = prom_finddevice(path);
if (fn.nodeid != OBP_BADNODE) {
/*
* Find the nodeid in our copy of the device tree and return
* whatever name we used to bind this node to a driver.
*/
ddi_walk_devs(top_devinfo, i_path_find_node, (void *)(&fn));
}
return (fn.dip);
}
/*
* Determine the network interface name from the device path argument.
*/
static void
get_netif_name(char *devname, char *ifname)
{
dev_info_t *dip;
major_t ndev;
char *name;
int unit;
dip = path_to_devinfo(devname);
if (dip == NULL) {
cmn_err(CE_WARN, "get_netif_name: "
"can't bind driver for '%s'\n", devname);
return;
}
ndev = ddi_driver_major(dip);
if (ndev == -1) {
cmn_err(CE_WARN, "get_netif_name: "
"no driver bound to '%s'\n", devname);
return;
}
name = ddi_major_to_name(ndev);
if (name == NULL) {
cmn_err(CE_WARN, "get_netif_name: "
"no name for major number %d\n", ndev);
return;
}
unit = i_ddi_devi_get_ppa(dip);
if (unit < 0) {
cmn_err(CE_WARN, "get_netif_name: "
"illegal unit number %d\n", unit);
return;
}
(void) snprintf(ifname, IFNAMSIZ, "%s%d", name, unit);
}