On 2018年06月18日 20:02, David Sterba wrote:
> On Mon, Jun 18, 2018 at 07:40:44PM +0800, Qu Wenruo wrote:
>>
>>
>> On 2018年06月18日 19:34, David Sterba wrote:
>>> On Thu, Jun 14, 2018 at 03:17:45PM +0800, Qu Wenruo wrote:
>>>> I understand that btrfs-progs introduced restrict parameter/option order
>>>> to distinguish global and sub-command parameter/option.
>>>>
>>>> However it's really annoying if one just want to append some new options
>>>> to previous command:
>>>>
>>>> E.g.
>>>> # btrfs check /dev/data/btrfs
>>>> # !! --check-data-csum
>>>>
>>>> The last command will fail as current btrfs-progs doesn't allow any
>>>> option after parameter.
>>>>
>>>>
>>>> Despite the requirement to distinguish global and subcommand
>>>> option/parameter, is there any other requirement for such restrict
>>>> option-first-parameter-last policy?
>>>
>>> I'd say that it's a common and recommended pattern. Getopt is able to
>>> reorder the parameters so mixed options and non-options are accepted,
>>> unless POSIXLY_CORRECT (see man getopt(3)) is not set. With the more
>>> strict requirement, 'btrfs' option parser works the same regardless of
>>> that.
>>
>> But currently it doesn't work.
>> Just as the example, btrfs check /dev/data/btrfs --check-data-sum won't
>> work.
>> It's different from a lot of other common programs.
> 
> With POSIXLY_CORRECT set, it expectedly won't work. With POSIXLY_CORRECT
> unset, it would work in general, but not for 'btrfs'.
> 
> As this is per-application decision I find it ok, besides that I also
> find the 'options anywhere' pattern bad. Does it really save you that
> much time while typing the commands with new arguments? There are
> movement shortcuts to jump by words, you get the previous command by
> up-arrow. About the same number of keystrokes.
> 
> New code needs to be tested, documented and maintained, that's the cost
> I find too high for something that's convenience for people who are used
> to some shell builtins.
> 

Well, after some testing, the result looks pretty strange on my side.

With the testing code (*), mostly just copied from check/main.c, it
works to detect the final --check-data-csum without problem.

I'm originally planning to use '-' to make getopt_long() to keep the
original order, but the experiment I did shows it unnecessary.

And furthermore, even changing the optstring of btrfs check
getopt_long() with leading '-', it still doesn't work as expected to
detect non-option parameter.

Is there anything wrong/special in btrfs-progs getopt_long() usage?

Thanks,
Qu

*:
---
#include <stdio.h>
#include <getopt.h>
#include <unistd.h>

int main(int argc, char** argv)
{
        char *real_argv[] = { "btrfs check", "device", "--check-data-csum" , 
NULL};
        int real_argc = sizeof(real_argv) / sizeof(char *) - 1;

        while (1) {
                enum { GETOPT_VAL_REPAIR = 257, GETOPT_VAL_INIT_CSUM,
                        GETOPT_VAL_INIT_EXTENT, GETOPT_VAL_CHECK_CSUM,
                        GETOPT_VAL_READONLY, GETOPT_VAL_CHUNK_TREE,
                        GETOPT_VAL_MODE, GETOPT_VAL_CLEAR_SPACE_CACHE,
                        GETOPT_VAL_FORCE };
                static const struct option long_options[] = {
                        { "super", required_argument, NULL, 's' },
                        { "repair", no_argument, NULL, GETOPT_VAL_REPAIR },
                        { "readonly", no_argument, NULL, GETOPT_VAL_READONLY },
                        { "init-csum-tree", no_argument, NULL,
                                GETOPT_VAL_INIT_CSUM },
                        { "init-extent-tree", no_argument, NULL,
                                GETOPT_VAL_INIT_EXTENT },
                        { "check-data-csum", no_argument, NULL,
                                GETOPT_VAL_CHECK_CSUM },
                        { "backup", no_argument, NULL, 'b' },
                        { "subvol-extents", required_argument, NULL, 'E' },
                        { "qgroup-report", no_argument, NULL, 'Q' },
                        { "tree-root", required_argument, NULL, 'r' },
                        { "chunk-root", required_argument, NULL,
                                GETOPT_VAL_CHUNK_TREE },
                        { "progress", no_argument, NULL, 'p' },
                        { "mode", required_argument, NULL,
                                GETOPT_VAL_MODE },
                        { "clear-space-cache", required_argument, NULL,
                                GETOPT_VAL_CLEAR_SPACE_CACHE},
                        { "force", no_argument, NULL, GETOPT_VAL_FORCE },
                        { NULL, 0, NULL, 0}
                };
                int c;

                c = getopt_long(real_argc, real_argv, "as:br:pEQ", 
long_options, NULL);
                if (c < 0)
                        break;
                switch (c) {
                        case 'a':
                        case 'b':
                        case 'Q':
                        case 'E':
                        case 'p':
                                printf("option: %c\n", c);
                                break;
                        case 's':
                        case 'r':
                                printf("option: %c %s\n", c, optarg);
                                break;
                        case GETOPT_VAL_CHUNK_TREE:
                                printf("option: chunk tree %s\n", optarg);
                                break;
                        case '?':
                        case 'h':
                                printf("option: help\n");
                                break;
                        case GETOPT_VAL_REPAIR:
                                printf("option: repair\n");
                                break;
                        case GETOPT_VAL_READONLY:
                                printf("option: readonly\n");
                                break;
                        case GETOPT_VAL_INIT_CSUM:
                                printf("option: init cum tree\n");
                                break;
                        case GETOPT_VAL_INIT_EXTENT:
                                printf("option: init extent tree\n");
                                break;
                        case GETOPT_VAL_CHECK_CSUM:
                                printf("option: check csum\n");
                                break;
                        case GETOPT_VAL_MODE:
                                printf("option: mode %s\n", optarg);
                                break;
                        case GETOPT_VAL_CLEAR_SPACE_CACHE:
                                printf("option: clear space cache %s\n", 
optarg);
                                break;
                        case GETOPT_VAL_FORCE:
                                printf("option: force\n");
                                break;
                        default:
                                printf("unknown option %d\n", c);
                                break;
                }
        }
        return 0;
}
---

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to