Page MenuHomeFreeBSD

man: reset OPTIND after parsing args
ClosedPublic

Authored by kevans on Sep 22 2021, 8:31 PM.

Details

Summary

From jilles: POSIX requires that a script set OPTIND=1 before using
different sets of parameters with getopts, or the results will be
unspecified.

The specific problem observed here is that we would execute man -f or
man -k without cleaning up state from man_parse_args()' getopts
loop. FreeBSD's /bin/sh seems to reset OPTIND to 1 after we hit the
second getopts loop, rendering the following shift harmless; other
/bin/sh implementations will leave it at what we came into the loop at
(e.g., bash as /bin/sh), shifting off any keywords that we had.

Diff Detail

Repository
R10 FreeBSD src repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

I agree that OPTIND=1 is needed, but I have another reason for it. POSIX requires that a script set OPTIND=1 between using different sets of parameters with getopts; otherwise, the results are unspecified.

An assignment OPTIND=1 resets the getopts state, even if OPTIND was already 1.

In FreeBSD sh, the whole getopts state is local to functions (along with the positional parameters). This is more useful (so that functions can use getopts from within a caller's getopts loop) but is not strictly compliant (wrapping getopts with a function will not work).

From this point of view, the assignment in man_parse_args suffices, since that is the only place where two getopts loops run in the same script execution. Alternatively, OPTIND=1 could be added before each getopts loop within a function.

Go ahead and reset getopts state before each, to be safe/correct.

This revision is now accepted and ready to land.Sep 23 2021, 10:10 AM
This revision was automatically updated to reflect the committed changes.