Hi Neel,

Neel Chauhan wrote on Tue, Aug 29, 2023 at 02:48:54PM -0700:

> I have noticed a bug. When running "sysctl ." or "sysctl kern." without 
> my other patch, I get an extra space between "name" and "in":
 
>> sysctl: top level name  in . is invalid

Technically, that message is correct.  The name being complained about
is a zero length string, and of course there are space characters
marking a word boundary before and after it, resulting in two adjacent
space characters around a zero-length word.  But i see how some users
might find that confusing.

If people want that improved, see below for a patch that actually
improves the diagnostic message, resulting in:

   $ sysctl kern.=test
  sysctl: empty second level name in kern.
   $ sysctl kern.      
  sysctl: empty second level name in kern.
   $ sysctl .=test
  sysctl: empty top level name in .
   $ sysctl .      
  sysctl: empty top level name in .
   $ sysctl =test  
  sysctl: empty top level name in 
   $ sysctl ''    
  sysctl: empty top level name in 

Note this only happens for pathological names that are completely
empty or end in a dot, so i'm not sure it is very important.

Besides, there are other ways to provoke highly confusing error
messages by providing insane arguments.  Consider, for example:

   $ sysctl ' '      
  sysctl: top level name   in   is invalid
   $ sysctl 'kern.ostype'   
  kern.ostype=OpenBSD
   $ sysctl 'kern.os^Atype'
  sysctl: second level name ostype in kern.ostype is invalid
   $ sysctl 'kern.os^Gtype' 
  sysctl: second level name ostype in kern.ostype is invalid
   $ sysctl '^H'
  sysctl: top level name in is invalid

I'm not convinced accurately diagnosing every possible kind
of insane input is a priority.

Regarding the patch, note that the condition *bufp == NULL that
is being tested cannot actually happen because all callers test
that very condition right before calling findname(), and they
have to do that because they all want to call listall() in that
case.

Strangely, the property that *bufp cannot be NULL was already present
in McKusick's very first version of the program dated "5.1 93/03/30
23:48:06", about 3 months before the initial 4.4BSD release.  I have
no idea why he considered testing that useful.  Maybe he fell pray
to the confusing design of the strsep(3) API and actually wanted to
test for *name == '\0' but inadvertently wrote name == NULL and no
one ever noticed?

Maybe one argument in favor of my patch is that it makes the
source code of findname() easier to read in addition to making
the error message less confusing in your corner case.

Lightly tested so far.

Yours,
  Ingo


Index: sysctl.c
===================================================================
RCS file: /cvs/src/sbin/sysctl/sysctl.c,v
retrieving revision 1.259
diff -u -p -r1.259 sysctl.c
--- sysctl.c    17 May 2023 22:12:51 -0000      1.259
+++ sysctl.c    29 Aug 2023 23:31:09 -0000
@@ -2948,8 +2948,13 @@ findname(char *string, char *level, char
        char *name;
        int i;
 
-       if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+       if (namelist->list == 0) {
                warnx("%s: incomplete specification", string);
+               return (-1);
+       }
+       name = strsep(bufp, ".");
+       if (*name == '\0') {
+               warnx("empty %s level name in %s", level, string);
                return (-1);
        }
        for (i = 0; i < namelist->size; i++)

Reply via email to