Subject: Re: changing sysctl_string() and sysctl_rdstring()
To: Simon Burge <simonb@netbsd.org>
From: Zdenek Salvet <salvet@ics.muni.cz>
List: tech-kern
Date: 06/29/1999 09:37:48
> I've logged PR kern/7836, where gethostname() fails if the
> buffer passed is shorter than the real hostname.  Both the
> man page for gethostname() and Single Unix Specification (at
> http://www.opengroup.org/onlinepubs/007908799/xns/gethostname.html -
> thanks Zdenek!) say the hostname should be truncated if the buffer is
> too short.
> 
> I think the cleanest way to fix this is to change sysctl_string() (and
> sysctl_rdstring() for completeness) to take an extra flags argument, and
> define a SYSCTL_TRUNC_RESULT value that some callers of sysctl_string()
> can pass.  There would also have to be a mention in the sysctl(3)
> manpage that some calls return truncated data if the buffer is too small
> rather than erroring with ENOMEM.  This however means that you don't
> know if you got the full hostname.

I think sysctl_string() and sysctl_rdstring() should be changed to
match the sysctl(3) manpage:
   ...
   If the amount of data available is greater than the size of the
   buffer supplied, the call supplies as much data as fits in the buffer
   provided and returns with the error code ENOMEM.

This way you get both properly truncated hostname and indication
whether the full hostname was returned.
How about this:

--- kern_sysctl.c.orig  Tue Jun 29 08:46:15 1999
+++ kern_sysctl.c       Tue Jun 29 08:57:43 1999
@@ -552,25 +552,30 @@
        void *newp;
        size_t newlen;
        char *str;
        int maxlen;
 {
-       int len, error = 0;
+       int len, error, truncated = 0;
 
        len = strlen(str) + 1;
-       if (oldp && *oldlenp < len)
-               return (ENOMEM);
+       *oldlenp = len;
+       if (oldp && *oldlenp < len) {
+               truncated = 1;
+               len = *oldlenp;
+       }
        if (newp && newlen >= maxlen)
                return (EINVAL);
        if (oldp) {
                *oldlenp = len;
                error = copyout(str, oldp, len);
        }
        if (error == 0 && newp) {
                error = copyin(newp, str, newlen);
                str[newlen] = 0;
        }
+       if (error == 0 && truncated == 1)
+               error = ENOMEM;
        return (error);
 }
 
 /*
  * As above, but read-only.

> >From the reading the SUS and tests on Ultrix and Solaris, gethostname()
> returns success even when truncating the hostname.  From a quick look,
> it doesn't seem possible for sysctl() to return success but still set
> errno to ENOMEM if the hostname is truncated.  Is this either (a) a
> desired way to work out of the hostname is truncated or (b) a valid
> thing to do?

If sysctl() fails with ENOMEM, truncated hostname should be returned anyway.

-- 
Zdenek Salvet                                              salvet@ics.muni.cz 
Ustav vypocetni techniky Masarykovy univerzity, Brno
tel.: ++420-5-41 512 257                           Fax: ++420-5-41 212 747
----------------------------------------------------------------------------
           If God had meant for us to be in the Army,
         we would have been born with green, baggy skin.