1

i don't really understand how can i correctly handle command line arguments in c using getopt_long function, i create this code :

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

int main(int argc, char** argv) {
    int next_option;
    /* String of short options */
    const char *short_options = "hl:k";
    /* The array of long options */
    const struct option long_options[] = {
        { "help",  0, NULL, 'h' },
        { "launch", 1, NULL, 'l' },
        { "kill",  0, NULL, 'k' },
        { NULL,    0, NULL, 0   } 
    };

    do {
        next_option = getopt_long(argc, argv, short_options, long_options, NULL);
        switch (next_option) {
            case 'h':
                /* User requested help */
                fprintf(stdout, "HELP\n");
                break;
            case 'l':
                fprintf(stdout, "launching\n");
                fprintf(stdout, "Want to launch on port %s\n",\
                        optarg);
                break;
            case 'k':
                fprintf(stdout, "KILLING\n");
                break;
            case '?':
                /* The user specified an invalid option */
                fprintf(stdout, "Requested arg does not exist!\n");
                exit(EXIT_FAILURE);
            case -1:
                /* Done with options */
                break;

            default:
                /* Unexpected things */
                fprintf(stdout, "I can't handle this arg!\n");
                exit(EXIT_FAILURE);
        }
    } while(next_option != -1);

    return (EXIT_SUCCESS);
}

And the output is strange, cause we can pass garbage data as command line arguments and my program don't check this errors! How can i fix that.

An example of execution :

$ ./command_line -h garbage
HELP
$ ./command_line --help garbage
HELP
$ ./command_line --launch 1200 garbage
launching
Want to launch on port 1200
$ ./command_line --lBADARG 1200
command_line: unrecognized option `--lBADARG'
Requested arg does not exist!
$ ./command_line -lBADARG 1200
launching
Want to launch on port BADARG

Thanks for your help.

funnyCoder
  • 787
  • 2
  • 10
  • 30

2 Answers2

2

Okay, what's happening is this:

in this case:

$ ./command_line --lBADARG 1200
command_line: unrecognized option `--lBADARG'
Requested arg does not exist!

by giving it --lBADARG you're saying look for the LONG argument lBADARG, and you don't have one.

in this case:

$ ./command_line -lBADARG 1200
launching
Want to launch on port BADARG

you're successfully telling it to use the -l flag which has an argument. It behaves as expected, telling you that argument is BADARG.

If you try

$ ./command_line -l 1200

or

$ ./command_line -l1200

or

$ ./command_line --launch 1200

that should do what you expect. And if you want to get the arguments that are not options, you'll find them in the argv vector after you've done the getopt processing, because getopt_long conveniently permutes the argv vector to leave non-option arguments there.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • Thanks Charlie, i understand all this, my problem is how can i protect my program from bad arguments like this? – funnyCoder Dec 22 '11 at 23:37
  • You don't. The beauty of `getopt` is that all programs using it exhibit the same argument behavior. It's silly to mess with that. – Dave Dec 22 '11 at 23:47
  • 1
    @funnyCoder, you do it the way you normally would -- once getopt gets the option argument (like "1200" in `-l 1200`) then you check if it's meaningful and correct. getopt and its kin are option *parsers* -- they know the syntax, not the semantics. – Charlie Martin Dec 23 '11 at 18:59
  • @CharlieMartin, Thanks as you said i need to check if arguments are correct or not with some additional code. – funnyCoder Dec 23 '11 at 21:07
0

The reason the garbage is getting through okay is because getopt and its brethren are for processing options, not all command lne arguments. Not all arguments are options.

The reason that --lBADARG is treated differently to -lBADARG is because of the way it wants to handle them. --lBADARG is an option lBADARG with no parameters while -lBADARG is the -l option with a parameter of BADARG. The former is not listed as a valid option but the latter is.

And the final possible issue is that BADARG is being treated as a port. That's because the getopt stuff neither knows nor cares about parameter types, that's up to your code. If you want to ensure it's numeric, you should check for that. It may well be that you want to support symbolic port names (looked up in /etc/ports for example).

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thanks paxdiablo, so i assume that i need to check by my self command arguemnts? i can do that with a lot of if else loops and i don't need getopt_long at all! I was thinking that this function is able to do this stuff for me. – funnyCoder Dec 22 '11 at 23:39
  • @funnyCoder, it won't do _everything_ for you but it really does take away some of the grunt work. – paxdiablo Dec 23 '11 at 01:44
  • Thanks for this answer, i will try to handle args without getopt_long :). – funnyCoder Dec 23 '11 at 21:05