summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_sysctl.c149
1 files changed, 136 insertions, 13 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 76f809fbeb99c..ad4f6cb6452e3 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
- * $Id: kern_sysctl.c,v 1.25 1995/05/30 08:05:46 rgrimes Exp $
+ * $Id: kern_sysctl.c,v 1.25.4.1 1995/07/29 05:14:28 davidg Exp $
*/
/*
@@ -250,14 +250,16 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
case KERN_HOSTNAME:
error = sysctl_string(oldp, oldlenp, newp, newlen,
hostname, sizeof(hostname));
- if (newp && !error)
- hostnamelen = newlen;
+ if (newp)
+ if (error == 0 || error == ENOMEM)
+ hostnamelen = newlen;
return (error);
case KERN_DOMAINNAME:
error = sysctl_string(oldp, oldlenp, newp, newlen,
domainname, sizeof(domainname));
- if (newp && !error)
- domainnamelen = newlen;
+ if (newp)
+ if (error == 0 || error == ENOMEM)
+ domainnamelen = newlen;
return (error);
case KERN_HOSTID:
inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */
@@ -458,22 +460,28 @@ sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
char *str;
int maxlen;
{
- int len, error = 0;
+ int len, error = 0, rval = 0;
len = strlen(str) + 1;
- if (oldp && *oldlenp < len)
+ if (oldp && *oldlenp < len) {
len = *oldlenp;
+ rval = ENOMEM;
+ }
if (newp && newlen >= maxlen)
return (EINVAL);
if (oldp) {
*oldlenp = len;
error = copyout(str, oldp, len);
+ if (error)
+ rval = error;
}
- if (error == 0 && newp) {
+ if ((error == 0 || error == ENOMEM) && newp) {
error = copyin(newp, str, newlen);
+ if (error)
+ rval = error;
str[newlen] = 0;
}
- return (error);
+ return (rval);
}
/*
@@ -486,17 +494,21 @@ sysctl_rdstring(oldp, oldlenp, newp, str)
void *newp;
char *str;
{
- int len, error = 0;
+ int len, error = 0, rval = 0;
len = strlen(str) + 1;
- if (oldp && *oldlenp < len)
- return (ENOMEM);
+ if (oldp && *oldlenp < len) {
+ len = *oldlenp;
+ rval = ENOMEM;
+ }
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(str, oldp, len);
- return (error);
+ if (error)
+ rval = error;
+ return (rval);
}
/*
@@ -768,6 +780,53 @@ fill_eproc(p, ep)
#define KINFO_LOADAVG (5<<8)
#define KINFO_CLOCKRATE (6<<8)
+/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
+#define KINFO_BSDI_SYSINFO (101<<8)
+
+/*
+ * XXX this is bloat, but I hope it's better here than on the potentially
+ * limited kernel stack... -Peter
+ */
+
+struct {
+ int bsdi_machine; /* "i386" on BSD/386 */
+/* ^^^ this is an offset to the string, relative to the struct start */
+ char *pad0;
+ long pad1;
+ long pad2;
+ long pad3;
+ u_long pad4;
+ u_long pad5;
+ u_long pad6;
+
+ int bsdi_ostype; /* "BSD/386" on BSD/386 */
+ int bsdi_osrelease; /* "1.1" on BSD/386 */
+ long pad7;
+ long pad8;
+ char *pad9;
+
+ long pad10;
+ long pad11;
+ int pad12;
+ long pad13;
+ quad_t pad14;
+ long pad15;
+
+ struct timeval pad16;
+ /* we dont set this, because BSDI's uname used gethostname() instead */
+ int bsdi_hostname; /* hostname on BSD/386 */
+
+ /* the actual string data is appended here */
+
+} bsdi_si;
+/*
+ * this data is appended to the end of the bsdi_si structure during copyout.
+ * The "char *" offsets are relative to the base of the bsdi_si struct.
+ * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
+ * should not exceed the length of the buffer here... (or else!! :-)
+ */
+char bsdi_strings[80]; /* It had better be less than this! */
+
struct getkerninfo_args {
int op;
char *where;
@@ -831,6 +890,70 @@ ogetkerninfo(p, uap, retval)
error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
break;
+ case KINFO_BSDI_SYSINFO: {
+ /*
+ * this is pretty crude, but it's just enough for uname()
+ * from BSDI's 1.x libc to work.
+ *
+ * In particular, it doesn't return the same results when
+ * the supplied buffer is too small. BSDI's version apparently
+ * will return the amount copied, and set the *size to how
+ * much was needed. The emulation framework here isn't capable
+ * of that, so we just set both to the amount copied.
+ * BSDI's 2.x product apparently fails with ENOMEM in this
+ * scenario.
+ */
+
+ u_int needed;
+ u_int left;
+ char *s;
+
+ bzero((char *)&bsdi_si, sizeof(bsdi_si));
+ bzero(bsdi_strings, sizeof(bsdi_strings));
+
+ s = bsdi_strings;
+
+ bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
+ strcpy(s, ostype);
+ s += strlen(s) + 1;
+
+ bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
+ strcpy(s, osrelease);
+ s += strlen(s) + 1;
+
+ bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
+ strcpy(s, machine);
+ s += strlen(s) + 1;
+
+ needed = sizeof(bsdi_si) + (s - bsdi_strings);
+
+ if (uap->where == NULL) {
+ /* process is asking how much buffer to supply.. */
+ size = needed;
+ error = 0;
+ break;
+ }
+
+
+ /* if too much buffer supplied, trim it down */
+ if (size > needed)
+ size = needed;
+
+ /* how much of the buffer is remaining */
+ left = size;
+
+ if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
+ break;
+
+ /* is there any point in continuing? */
+ if (left > sizeof(bsdi_si)) {
+ left -= sizeof(bsdi_si);
+ error = copyout(&bsdi_strings,
+ uap->where + sizeof(bsdi_si), left);
+ }
+ break;
+ }
+
default:
return (EOPNOTSUPP);
}