One, foreword

When learning some project code, especially the code involving command line parameters, often encountered getopt related functions, to this kind of function can be said to be both unfamiliar and familiar. Strange because do not know what it is, familiar because often encountered. After tracing the ipsec configuration file resolution process for several days, you are ready to learn this command-line parsing tool.

With so many command-line arguments to parse, it’s hard to imagine, and if you don’t have a good way to parse them, it’s even worse. But there is a class of command-line parsing functions that make these parsing operations a little easier. Getopt, getopt_long, and getopt_long_only are the main functions of this class.

Man manual information is as follows:

NAME
       getopt, getopt_long, getopt_long_only, optarg, optind, opterr, optopt - Parse command-line options

SYNOPSIS
       #include <unistd.h>
       int getopt(int argc, char * const argv[],
                  const char *optstring);

       extern char *optarg;
       extern int optind, opterr, optopt;

       #include <getopt.h>
       int getopt_long(int argc, char * const argv[],
                  const char *optstring,
                  const struct option *longopts, int *longindex);

       int getopt_long_only(int argc, char * const argv[],
                  const char *optstring,
                  const struct option *longopts, int *longindex);
Copy the code

Let’s start with the simplest, most basic getopt function. The enhanced getopt_long function is then introduced.

Second,getoptfunction

2.1 Introduction to functions:

int getopt(int argc, char * const argv[], const char *optstring);

The parameters are explained as follows:

The functionality

-d /root is used to parse command-line option arguments. Only short options: -d /root; Cannot resolve long options –arch, –help, etc

Argc

Number of arguments passed to main from the command line

argv

An array of string Pointers passed to main as arguments from the command line

optstring

Option string. Tells getopt which options can be parsed, which options require arguments, the return value of the function, etc. (A character followed by a colon requires arguments, and two means arguments are optional)

The return value

Return the option letter on success; The command line returns -1 when parsing is complete. If the option is not defined, an error message is displayed and a ‘? ‘; Return ‘:’ if the argument is missing and the first character is ‘:’, otherwise return ‘? ‘

A brief explanation of the optString format:

A single character, indicating no parameter

A single character followed by a colon indicates that there must be an argument (**) in the format of -d XXX or -dxxx**

A single character followed by two colons indicates that the parameter is optional. The format is -dxxx**

Char *optstring=”ab:c::”;

Note: This option specifies three options, ‘a’, ‘b’, and ‘c’. Among them

For option a, no parameter is required. The format is -a

B Option must have an argument in the format of -d XXX

C Option This parameter is optional. The format is -c ooo

In such a function, several important variables are required to work together to resolve the command-line arguments:

The variable name

role

Char *optarg

Pointer to the current option argument

Int optind

Index used to record the currently traversed options, so that the next call can directly find the next option

Int opterr

Normally, an error message is displayed when the resolution fails. If the error message is not required, set opterr to 0

Int optopt

The last unknown option

2.2 Examples:

The code is as follows:

/************************************************************************* > File Name: getopt.c > Author: Toney > Mail: [email protected] > Created Time: On Saturday 21st January 30, 2021 at 45 seconds * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * / # include < stdio. H > #include <unistd.h> #include <getopt.h> void main(int argc, char **argv) { int flags, opt; while((opt = getopt(argc, argv, "ab:c::")) ! = -1){ switch(opt){ case 'a': printf("Input %d parameter is -a=%s\n", optind, optarg); break; case 'b': printf("Input %d parameter is -b=%s\n", optind, optarg); break; case 'c': printf("Input %d parameter is -c=%s\n", optind, optarg); break; default: printf("Not match!!!" ); } } return ; }Copy the code

Three,getopt_longfunction

3.1 Introduction to functions:

int getopt_long(int argc, char * const argv[], const char *optstring,const struct option *longopts, int *longindex);

The parameters are explained as follows:

The functionality

It is used to parse command-line option arguments. In addition to the short options supported by the getopt function, it also supports long options such as –help, –prefix

Argc

Number of arguments passed to main from the command line

argv

An array of string Pointers passed to main as arguments from the command line

optstring

Option string. Tells getopt which options can be parsed, which options require arguments, the return value of the function, etc. (A character followed by a colon requires arguments, and two means arguments are optional)

longopts

Structural information such as the name, property, and return value of the long option parameter

longindex

Index used to record the index of the current long option parsed, i.e., the index of longopts.

The return value

For short options, return the same value as the getopt function; For long options, return val if flag is NULL, or 0 otherwise; Return the same value as the getopt function for error cases

Struct option structure:

struct option { const char *name; /* Parameter name */ int has_arg; /* specifies whether to take arguments */ int *flag; /* if flag=NULL, return value; If not null,*flag=val, 0 */ int val; /* is used to specify whether the function finds the return value of the option or to specify the value of flag if the flag is not null */};

The value of has_arg can be:

No_argument

You don’t need parameters

Required_argument

Must have parameters

Optional_argument

Parameters can be chosen

In such a function, several important variables are required to work together to resolve the command-line arguments:

The variable name

role

Char *optarg

Pointer to the current option argument

Int optind

Index used to record the currently traversed options, so that the next call can directly find the next option

Int opterr

Normally, an error message is displayed when the resolution fails. If the error message is not required, set opterr to 0

Int optopt

The last unknown option

3.2 An example in the ipsec**** project:

Take a look at an example of using getopt_long to parse a command line in the OpenSwan source code (hold on tight, everybody) :

static const struct option long_opts[] = {
#   define OO	OPTION_OFFSET
    /* name, has_arg, flag, val */

    { "help", no_argument, NULL, 'h' },
    { "version", no_argument, NULL, 'v' },
    { "optionsfrom", required_argument, NULL, '+' },
    { "label", required_argument, NULL, 'l' },

    { "ctlbase", required_argument, NULL, OPT_CTLBASE + OO },
    { "name", required_argument, NULL, OPT_NAME + OO },
    { "connalias", required_argument, NULL, OPT_CONNALIAS + OO },

    { "keyid", required_argument, NULL, OPT_KEYID + OO },
    { "addkey", no_argument, NULL, OPT_ADDKEY + OO },
    { "pubkeyrsa", required_argument, NULL, OPT_PUBKEYRSA + OO },

    { "myid", required_argument, NULL, OPT_MYID + OO },

    { "route", no_argument, NULL, OPT_ROUTE + OO },
    { "unroute", no_argument, NULL, OPT_UNROUTE + OO },

    { "initiate", no_argument, NULL, OPT_INITIATE + OO },
    { "terminate", no_argument, NULL, OPT_TERMINATE + OO },
    { "delete", no_argument, NULL, OPT_DELETE + OO },
    { "deletestate", required_argument, NULL, OPT_DELETESTATE + OO + NUMERIC_ARG },
    { "crash", required_argument, NULL, OPT_DELETECRASH + OO },
    { "listen", no_argument, NULL, OPT_LISTEN + OO },
    { "unlisten", no_argument, NULL, OPT_UNLISTEN + OO },
    { "purgeocsp", no_argument, NULL, OPT_PURGEOCSP + OO },

    { "rereadsecrets", no_argument, NULL, OPT_REREADSECRETS + OO },
    { "rereadcacerts", no_argument, NULL, OPT_REREADCACERTS + OO },
    { "rereadaacerts", no_argument, NULL, OPT_REREADAACERTS + OO },
    { "rereadocspcerts", no_argument, NULL, OPT_REREADOCSPCERTS + OO },
    { "rereadacerts", no_argument, NULL, OPT_REREADACERTS + OO },

    { "rereadcrls", no_argument, NULL, OPT_REREADCRLS + OO },
    { "rereadall", no_argument, NULL, OPT_REREADALL + OO },
    { "status", no_argument, NULL, OPT_STATUS + OO },
    { "shutdown", no_argument, NULL, OPT_SHUTDOWN + OO },
    { "xauthname", required_argument, NULL, OPT_XAUTHNAME + OO },
    { "xauthuser", required_argument, NULL, OPT_XAUTHNAME + OO },
    { "xauthpass", required_argument, NULL, OPT_XAUTHPASS + OO },
    { "tpmeval",   required_argument, NULL, OPT_TPMEVAL   + OO },

    { "oppohere", required_argument, NULL, OPT_OPPO_HERE + OO },
    { "oppothere", required_argument, NULL, OPT_OPPO_THERE + OO },

    { "asynchronous", no_argument, NULL, OPT_ASYNC + OO },

    /* list options */

    { "utc", no_argument, NULL, LST_UTC + OO },
    { "checkpubkeys", no_argument, NULL, LST_CHECKPUBKEYS + OO },
    { "listpubkeys", no_argument, NULL, LST_PUBKEYS + OO },
    { "listcerts", no_argument, NULL, LST_CERTS + OO },
    { "listcacerts", no_argument, NULL, LST_CACERTS + OO },
    { "listacerts", no_argument, NULL, LST_ACERTS + OO },
    { "listaacerts", no_argument, NULL, LST_AACERTS + OO },
    { "listocspcerts", no_argument, NULL, LST_OCSPCERTS + OO },
    { "listgroups", no_argument, NULL, LST_GROUPS + OO },
    { "listcrls", no_argument, NULL, LST_CRLS + OO },
    { "listocsp", no_argument, NULL, LST_OCSP + OO },
    { "listpsks", no_argument, NULL, LST_PSKS + OO },
    { "listevents", no_argument, NULL, LST_EVENTS + OO },
    { "listpairs",     no_argument, NULL, LST_HOSTPAIRS + OO },
    { "listhostpairs", no_argument, NULL, LST_HOSTPAIRS + OO },
    { "listall", no_argument, NULL, LST_ALL + OO },


    /* options for an end description */

    { "host", required_argument, NULL, END_HOST + OO },
    { "id", required_argument, NULL, END_ID + OO },
    { "cert", required_argument, NULL, END_CERT + OO },
    { "ca", required_argument, NULL, END_CA + OO },
    { "groups", required_argument, NULL, END_GROUPS + OO },
    { "ikeport", required_argument, NULL, END_IKEPORT + OO + NUMERIC_ARG },
    { "nexthop", required_argument, NULL, END_NEXTHOP + OO },
    { "client", required_argument, NULL, END_CLIENT + OO },
    { "clientwithin", required_argument, NULL, END_CLIENTWITHIN + OO },
    { "clientprotoport", required_argument, NULL, END_CLIENTPROTOPORT + OO },
    { "dnskeyondemand", no_argument, NULL, END_DNSKEYONDEMAND + OO },
    { "srcip",  required_argument, NULL, END_SRCIP + OO },
    { "updown", required_argument, NULL, END_UPDOWN + OO },
    { "tundev", required_argument, NULL, END_TUNDEV + OO + NUMERIC_ARG },


    /* options for a connection description */

    { "to", no_argument, NULL, CD_TO + OO },

    { "psk", no_argument, NULL, CD_PSK + OO },
    { "rsasig", no_argument, NULL, CD_RSASIG + OO },

    { "encrypt", no_argument, NULL, CD_ENCRYPT + OO },
    { "authenticate", no_argument, NULL, CD_AUTHENTICATE + OO },
    { "compress",  no_argument, NULL, CD_COMPRESS + OO },
    { "overlapip", no_argument, NULL, CD_OVERLAPIP + OO },
    { "tunnel", no_argument, NULL, CD_TUNNEL + OO },
    { "tunnelipv4", no_argument, NULL, CD_TUNNELIPV4 + OO },
    { "tunnelipv6", no_argument, NULL, CD_TUNNELIPV6 + OO },
    { "pfs", no_argument, NULL, CD_PFS + OO },
    { "sha2_truncbug", no_argument, NULL, CD_SHA2_TRUNCBUG + OO },
    { "aggrmode", no_argument, NULL, CD_AGGRESSIVE + OO },
    { "disablearrivalcheck", no_argument, NULL, CD_DISABLEARRIVALCHECK + OO },
    { "initiateontraffic", no_argument, NULL
	, CD_SHUNT0 + (POLICY_SHUNT_TRAP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
    { "pass", no_argument, NULL
	, CD_SHUNT0 + (POLICY_SHUNT_PASS >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
    { "drop", no_argument, NULL
	, CD_SHUNT0 + (POLICY_SHUNT_DROP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
    { "reject", no_argument, NULL
	, CD_SHUNT0 + (POLICY_SHUNT_REJECT >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
    { "failnone", no_argument, NULL
	, CD_FAIL0 + (POLICY_FAIL_NONE >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
    { "failpass", no_argument, NULL
	, CD_FAIL0 + (POLICY_FAIL_PASS >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
    { "faildrop", no_argument, NULL
	, CD_FAIL0 + (POLICY_FAIL_DROP >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
    { "failreject", no_argument, NULL
	, CD_FAIL0 + (POLICY_FAIL_REJECT >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
    { "dontrekey", no_argument, NULL, CD_DONT_REKEY + OO },
    { "forceencaps", no_argument, NULL, CD_FORCEENCAPS + OO },
    { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG },
    { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG },
    { "dpdaction", required_argument, NULL, CD_DPDACTION + OO },
#ifdef XAUTH
    { "xauth", no_argument, NULL, END_XAUTHSERVER + OO },
    { "xauthserver", no_argument, NULL, END_XAUTHSERVER + OO },
    { "xauthclient", no_argument, NULL, END_XAUTHCLIENT + OO },
#endif
#ifdef MODECFG
    { "modecfgpull",   no_argument, NULL, CD_MODECFGPULL + OO },
    { "modecfgserver", no_argument, NULL, END_MODECFGSERVER + OO },
    { "modecfgclient", no_argument, NULL, END_MODECFGCLIENT + OO },
#ifdef MODECFG_DNSWINS
    { "modecfgdns1", required_argument, NULL, CD_MODECFGDNS1 + OO },
    { "modecfgdns2", required_argument, NULL, CD_MODECFGDNS2 + OO },
    { "modecfgwins1", required_argument, NULL, CD_MODECFGWINS1 + OO },
    { "modecfgwins2", required_argument, NULL, CD_MODECFGWINS2 + OO },
    { "modeconfigserver", no_argument, NULL, END_MODECFGSERVER + OO },
    { "modeconfigclient", no_argument, NULL, END_MODECFGCLIENT + OO },
#endif
#endif
    { "metric", required_argument, NULL, CD_METRIC + OO + NUMERIC_ARG },
    { "mtu", required_argument, NULL, CD_CONNMTU + OO + NUMERIC_ARG },
    { "sendcert", required_argument, NULL, END_SENDCERT + OO },
    { "certtype", required_argument, NULL, END_CERTTYPE + OO + NUMERIC_ARG },
    { "ipv4", no_argument, NULL, CD_CONNIPV4 + OO },
    { "ipv6", no_argument, NULL, CD_CONNIPV6 + OO },

    { "ikelifetime", required_argument, NULL, CD_IKELIFETIME + OO + NUMERIC_ARG },
    { "ipseclifetime", required_argument, NULL, CD_IPSECLIFETIME + OO + NUMERIC_ARG },
    { "rekeymargin", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },
    { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },	/* OBSOLETE */
    { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG },
    { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG },
    { "ike",    required_argument, NULL, CD_IKE + OO },
    { "ikealg", required_argument, NULL, CD_IKE + OO },
    { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO },
    { "esp", required_argument, NULL, CD_ESP + OO },
    { "remote_peer_type", required_argument, NULL, CD_REMOTEPEERTYPE + OO},
#ifdef HAVE_NM
    { "nm_configured", no_argument, NULL, CD_NMCONFIGURED + OO},
#endif
#ifdef HAVE_LABELED_IPSEC
    { "loopback", no_argument, NULL, CD_LOOPBACK + OO},
    { "labeledipsec", no_argument, NULL, CD_LABELED_IPSEC + OO},
    { "policylabel", required_argument, NULL, CD_POLICY_LABEL + OO },
#endif
#ifdef DEBUG
    { "debug-none", no_argument, NULL, DBGOPT_NONE + OO },
    { "debug-all", no_argument, NULL, DBGOPT_ALL + OO },
    { "debug-raw", no_argument, NULL, DBGOPT_RAW + OO },
    { "debug-crypt", no_argument, NULL, DBGOPT_CRYPT + OO },
    { "debug-parsing", no_argument, NULL, DBGOPT_PARSING + OO },
    { "debug-emitting", no_argument, NULL, DBGOPT_EMITTING + OO },
    { "debug-control", no_argument, NULL, DBGOPT_CONTROL + OO },
    { "debug-lifecycle", no_argument, NULL, DBGOPT_LIFECYCLE + OO },
    { "debug-klips",  no_argument, NULL, DBGOPT_KLIPS + OO },
    { "debug-netkey", no_argument, NULL, DBGOPT_KLIPS + OO },
    { "debug-xfrm",   no_argument, NULL, DBGOPT_KLIPS + OO },
    { "debug-dns", no_argument, NULL, DBGOPT_DNS + OO },
    { "debug-oppo", no_argument, NULL, DBGOPT_OPPO + OO },
    { "debug-oppoinfo", no_argument, NULL, DBGOPT_OPPOINFO + OO },
    { "debug-whackwatch",  no_argument, NULL, DBGOPT_WHACKWATCH + OO },
    { "debug-controlmore", no_argument, NULL, DBGOPT_CONTROLMORE + OO },
    { "debug-pfkey",   no_argument, NULL, DBGOPT_PFKEY + OO },
    { "debug-nattraversal", no_argument, NULL, DBGOPT_NATT + OO },
    { "debug-natt",    no_argument, NULL, DBGOPT_NATT + OO },
    { "debug-nat_t",   no_argument, NULL, DBGOPT_NATT + OO },
    { "debug-nat-t",   no_argument, NULL, DBGOPT_NATT + OO },
    { "debug-x509",    no_argument, NULL, DBGOPT_X509 + OO },
    { "debug-dpd",     no_argument, NULL, DBGOPT_DPD + OO },
    { "debug-private", no_argument, NULL, DBGOPT_PRIVATE + OO },

    { "impair-delay-adns-key-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER + OO },
    { "impair-delay-adns-txt-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER + OO },
    { "impair-bust-mi2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MI2 + OO },
    { "impair-bust-mr2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MR2 + OO },
    { "impair-sa-fail",    no_argument, NULL, DBGOPT_IMPAIR_SA_CREATION + OO },
    { "impair-die-oninfo", no_argument, NULL, DBGOPT_IMPAIR_DIE_ONINFO  + OO },
    { "impair-jacob-two-two", no_argument, NULL, DBGOPT_IMPAIR_JACOB_TWO_TWO + OO },
    { "impair-major-version-bump", no_argument, NULL, DBGOPT_IMPAIR_MAJOR_VERSION_BUMP + OO },
    { "impair-minor-version-bump", no_argument, NULL, DBGOPT_IMPAIR_MINOR_VERSION_BUMP + OO },
    { "impair-retransmits", no_argument, NULL, DBGOPT_IMPAIR_RETRANSMITS + OO },
    { "impair-send-bogus-isakmp-flag", no_argument, NULL, DBGOPT_IMPAIR_SEND_BOGUS_ISAKMP_FLAG + OO },
    { "whackrecord",     required_argument, NULL, OPT_WHACKRECORD + OO},
    { "whackstoprecord", no_argument, NULL, OPT_WHACKSTOPRECORD + OO},
#endif
#   undef OO
    { 0,0,0,0 }
};
Copy the code

This is the structural information that the Whack command parses, and you can imagine how many configuration commands it has, which is roughly 800 lines of C code. Note that val in struct option structures is usually a single character or a number. Since the number of single characters is limited, characters can be used when the parameters are small, but if there are many parameters like above, the enum type is usually used to facilitate expansion.

Four,getopt_long_onlyfunction

Getopt_long_only uses the same argument list as getopt_long. Getopt_long uses only –name as a long argument. But getopt_long_only matches both –name and -name as long arguments. Getopt_long_only If option -name does not match in longopts, but does match a short option, it will resolve to a short option.