[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-block] [PATCH v2] qemu-io: Reinitialize optind to 1 (not 0) be

From: Max Reitz
Subject: Re: [Qemu-block] [PATCH v2] qemu-io: Reinitialize optind to 1 (not 0) before parsing inner command.
Date: Mon, 7 Jan 2019 18:50:53 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.1

On 07.01.19 18:46, Eric Blake wrote:
> On 1/7/19 11:17 AM, Max Reitz wrote:
>> On 03.01.19 10:47, Richard W.M. Jones wrote:
>>> On FreeBSD 11.2:
>>>   $ nbdkit memory size=1M --run './qemu-io -f raw -c "aio_write 0 512" $nbd'
>>>   Parsing error: non-numeric argument, or extraneous/unrecognized suffix -- 
>>> aio_write
>>> After main option parsing, we reinitialize optind so we can parse each
>>> command.  However reinitializing optind to 0 does not work on FreeBSD.
>>> What happens when you do this is optind remains 0 after the option
>>> parsing loop, and the result is we try to parse argv[optind] ==
>>> argv[0] == "aio_write" as if it was the first parameter.
>>> The FreeBSD manual page says:
>>>   In order to use getopt() to evaluate multiple sets of arguments, or to
>>>   evaluate a single set of arguments multiple times, the variable optreset
>>>   must be set to 1 before the second and each additional set of calls to
>>>   getopt(), and the variable optind must be reinitialized.
>> [...]
>>> Note I didn't set optreset.  It's not present in glibc and the "hard
>>> reset" is not necessary in this context.
>> But it sure sounds like FreeBSD requires you to set it, doesn't it?
> The reason BSD and glibc have a hard reset path is because of hidden
> state - both BSD and glibc track state that remembers if the options
> began with '+' or '-' (both of those are extensions beyond POSIX), and
> whether POSIXLY_CORRECT was set.  Beyond that hidden state is a corner
> case of one more piece of state that you can trigger using only POSIX:
> if the user passes './prog -ab' while you had code:
> swich (getopt(argc, argv, "ab")) {
>   case 'a': optind = 1; ...
> then things fall apart for both BSD and glibc, because getopt() has to
> track invisible state in order to remember that the next call will
> process the -b portion of the merged short-option in argv[optind==1]
> rather than repeating the -a half and before moving on to optind==2.
> But this latter corner case can only happen when getopt() did not return -1.
> At the end of the day, both GNU optind=0 and BSD optreset=1 are
> sufficient to force a hard reset of all hidden state.  But if you don't
> use POSIX extensions, and always run getopt() until a -1 return, then
> setting optind=1 is a portable soft reset, regardless of how the hidden
> state is implemented, and regardless of how (or even if) libc offers a
> hard reset, even though POSIX itself is currently lacking that mention.
> (I should probably file a POSIX defect to get that wording listed in POSIX)

Hm, OK?  Is there any guarantee for that behavior for FreeBSD, or is
that just how it is?  Because the man page is very clear on it:
"optreset must be set to 1".  It doesn't talk about soft or hard resets
like the glibc man page does.

And if optreset not being available for glibc is the only issue, I'd say
adding it as a weak global variable would work without #ifdefs.


Attachment: signature.asc
Description: OpenPGP digital signature

reply via email to

[Prev in Thread] Current Thread [Next in Thread]