https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=291374

            Bug ID: 291374
           Summary: getopt(3) GNU extension wrong behavior
           Product: Base System
           Version: 14.3-STABLE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: bin
          Assignee: [email protected]
          Reporter: [email protected]
             Flags: mfc-stable15?, mfc-stable14?, mfc-stable13?

>From the getopt(3) manual page:

     The option string optstring may contain the following elements:
     individual characters, and characters followed by a colon to indicate an
     option argument is to follow.  If an individual character is followed by
     two colons, then the option argument is optional; optarg is set to the
     rest of the current argv word, or NULL if there were no more characters
     in the current word.  This is a GNU extension.  For example, an option
     string "x" recognizes an option "-x", and an option string "x:"
     recognizes an option and argument "-x argument".  It does not matter to
     getopt() if a following argument has leading white space.

Note the last clause about leading white space. It does not match the code.
For example, our date(1) utility uses getopt(argc, argv, "f:I::jnRr:uv:z:") and
look at this:

$ date -Idate
2025-12-04
$ date -I date
date: illegal time format
usage: date [-jnRu] [-I[date|hours|minutes|seconds]] [-f input_fmt]
            [-r filename|seconds] [-v[+|-]val[y|m|w|d|H|M|S]]
            [[[[[[cc]yy]mm]dd]HH]MM[.SS] | new_date] [+output_fmt]

But this is not all. Consider the following simple test programm:

#include <stdio.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    int         ch;

    while ((ch = getopt(argc, argv, "cCd::F:lnoOp:s:u:U:wW")) != -1) {
        printf("ch is %c optarg is %s\n",
            (char)ch, optarg ? optarg : " NULL");
    }

    return (0);
}

Option list taken from our tftpd(8) programm that uses "-s path" for a chroot
and optional "-d value" for debugging.

Build it: cc -o getoptest -ansi -pedantic -Wall getoptest.c
Run it:

$ ./getoptest -l -w -d14 -s /usr/local/admin/tftproot -u admin -U 0
ch is l optarg is  NULL
ch is w optarg is  NULL
ch is d optarg is 14
ch is s optarg is /usr/local/admin/tftproot
ch is u optarg is admin
ch is U optarg is 0

So far, so good. And now:

$ ./getoptest -l -w -d 14 -s /usr/local/admin/tftproot -u admin -U 0
ch is l optarg is  NULL
ch is w optarg is  NULL
ch is d optarg is  NULL

Option list silently truncated. No -s, no chrooting for tftpd.

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to