Command Line Arguments Parsing in glibc
Many Linux programs are command line based and sometimes the options can be complicated. Luckily, the GNU C library glibc provides some APIs to simplify the command line option parsing.
Specifically, there’re two methods for parsing the commands, getopt and getopt_long. getopt() is used to parse the single character option, and getopt_long() works with both long options and single-character options. It’s recommended to use getopt_long().
Explanation of getopt_long() Prototype
The function getopt_long has the following prototype,
int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *indexptr)
argc and argv are the argument count and argument vector, the same as the two input parameters in the standard main prototype.
shortopts is a string specifying the option characters that are valid as input options. An option character can be followed by a colon (‘:’) to indicate it takes a required argument. The character can also be followed by two colons (‘::’) to indicate the argument is optional. If nothing follows the option character, the option doesn’t take any arguments.
longopts describes the long options to accept, which is an array of struct option. longopts must be terminated by a struct option of all 0s.
The struct option describes a single long option, which is defined as below,
struct option {const char *name; //the name of the optionint has_arg; //can be no_argument, required_argument, or optional_argumentint *flag; //for flag option only, set to NULL for non-flag optionsint val; //for flag, val is the value to store in the flag when the flag option is seen;//for other options, val is a value that is uniquely identify the long option};indexptr takes address of an integer variable, and getopt_long will store the index of the matched long option in the array longopts into it.
The Command Line Parse in Mini Firewall
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#define print_value(x) (x==NULL?"-" : x)
static struct mf_rule_struct {
int in_out;
char *src_ip;
char *src_netmask;
char *src_port; //default to -1
char *dest_ip;
char *dest_netmask;
char *dest_port;
char *proto;
char *action;
} mf_rule;
static struct mf_delete_struct {
char *cmd;
char *row;
} mf_delete;
void send_rule_to_proc()
{
printf("TODO: send_rule_to_proc\n");
}
void send_delete_to_proc()
{
printf("TODO: send_delete_to_proc\n");
}
void print_rule()
{
printf("TODO: print_rule\n");
return;
}
int main(int argc, char **argv)
{
int c; int action = 1; //1: new rule; 2: print; 3: delete
mf_rule.in_out = -1; mf_rule.src_ip = NULL; mf_rule.src_netmask = NULL; mf_rule.src_port = NULL;
mf_rule.dest_ip = NULL; mf_rule.dest_netmask = NULL; mf_rule.dest_port = NULL;mf_rule.proto = NULL;
mf_rule.action = NULL;
while (1)
{
static struct option long_options[] =
{
/*set a flag*/
{"in", no_argument, &mf_rule.in_out, 1},
{"out", no_argument, &mf_rule.in_out, 0},
/*These options don't set a flag.
We distinguish them by their indices.*/
{"print", no_argument, 0, 'o'},
{"delete", required_argument, 0, 'd'},
{"srcip", required_argument, 0, 's'},
{"srcnetmask", required_argument, 0, 'm'},
{"srcport", required_argument, 0, 'p'},
{"destip", required_argument, 0, 't'},
{"destnetmask", required_argument, 0, 'n'},
{"destport", required_argument, 0, 'q'},
{"proto", required_argument, 0, 'c'},
{"action", required_argument, 0, 'a'},
{0, 0, 0, 0}
};
int option_index = 0;
c = getopt_long(argc, argv, "od:s:m:p:t:n:q:c:a:", long_options, &option_index);
/*Detect the end of the options. */
if (c == -1)
break;
action = 1;
switch (c)
{
case 0:
printf("flag option: %s, mf_rule.in_out = %d\n", long_options[option_index].name, mf_rule.in_out);
break;
case 'o':
action = 2; //print
break;
case 'd':
action = 3; //delete
mf_delete.cmd = (char *)long_options[option_index].name;
mf_delete.row = optarg;
break;
case 's':
mf_rule.src_ip = optarg; //src ip
break;
case 'm':
mf_rule.src_netmask = optarg; //srcnetmask:
break;
case 'p':
mf_rule.src_port = optarg; //srcport:
break;
case 't':
mf_rule.dest_ip = optarg; //destip:
break;
case 'n':
mf_rule.dest_netmask = optarg; //destnetmask
break;
case 'q':
mf_rule.dest_port = optarg; //destport
break;
case 'c':
mf_rule.proto = optarg; //proto
break;
case 'a':
mf_rule.action = optarg;//action
break;
case '?':
/* getopt_long printed an error message. */
break;
default:
abort();
}
if (c != 0)
printf("%s = %s\n", long_options[option_index].name, optarg);
}
if (action == 1) {
send_rule_to_proc();
} else if (action == 2) {
print_rule();
} else if (action == 3) {
send_delete_to_proc();
}
if (optind < argc)
{
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
putchar('\n');
}
}
In order to understand the code above, you may need to read the section below,
How getopt_long Matches the Input Options
For short option, getopt_long returns the character code for the option, and stores the option’s argument (if it has one) in optarg.
For long option, getopt_long takes action based on flag and val fields of the option matched.
If the flag is NULL, meaning the option is not a flag. getopt_long returns val. Normally you can use the short option’s character code in val if long option is equivalent to the short option.
If the flag is not NULL, meaning it’s a flag option. getopt_long will return 0, and the flag value will be set accordingly.
For all options, getopt_long stores the matched option’s index in array longopts to *indexptr. You can access the name of the option by longopts[*indexptr].name.
getopt_long will also put the argument value in optarg if the option has one. Otherwise, optarg is set to NULL.
When getopt_long has no more options to handle, it returns –1. The index of next remaining argument in argv is stored in variable optind.
Sample Input and Output of the Mini Firewall Command Line Parsing
Firstly, save the program as cmd.c and compile the code using the command below,
gcc -o cmd cmd.cInput 1:
./cmd --in --srcip 10.2.10.2 --srcnetmask 255.255.255.0 --srcport 1000 --destip 72.23.13.23 --destnetmask 255.255.0.0 --destport 80 --proto 6 --action 0Output 1:
flag option: in, mf_rule.in_out = 1
srcip = 10.2.10.2
srcnetmask = 255.255.255.0
srcport = 1000
destip = 72.23.13.23
destnetmask = 255.255.0.0
destport = 80
proto = 6
action = 0
TODO: send_rule_to_procInput 2:
./cmd --delete 1Output 2:
delete = 1
TODO: send_delete_to_procNote:
This post is part of the tutorial: How to write a Linux Firewall in Less than 1000 Lines
Part 2: Command Line Arguments Parsing in glibc
Part 3.1: Linux Kernel Module Basics and Hello World
Part 3.2: Linux Kernel Programming – Linked List
Part 3.3 Linux Kernel Programming – Memory Allocation
Part 4.1: How to Filter Network Packets using Netfilter – Part 1 Netfilter Hooks
Part 4.2 How to Filter Network Packets using Netfilter – Part 2 Implement the Hook Function
Part 5: Linux procfs Virtual File System
Part 6: Put Everything Together
Reference:
Leave a Reply Cancel reply
40% Discount on My Book — Android NDK Cookbook
Android NDK Cookbook ebook 40% discount with promotion code MREANC40 at Packt Publishing The promotion code is valid until 15th June.Categories
- Android Apps (18)
- Android Audio Editor (1)
- TS 2 (3)
- Video Converter Android (8)
- Video2Gif (1)
- Android Tutorial (27)
- Android Dev Tools (1)
- API illustrated (8)
- Multimedia API (3)
- ffmpeg on Android (4)
- NDK (6)
- UI (6)
- Animation (2)
- Code Snippet (2)
- Coding Beyond Technique (18)
- a word, a world (4)
- Bug Rectified (4)
- Programming Habit (1)
- Software as a Career (1)
- Software as User Experience (1)
- Compilers and Related (2)
- ELF (2)
- Computer Languages (31)
- C/C++ (13)
- Java (9)
- JavaScript (2)
- PHP (1)
- Python (8)
- Data Structure & Algorithms (29)
- Bits (1)
- Data Structure (5)
- Integers (10)
- BigInteger (1)
- Prime (4)
- Search (3)
- Sorting (5)
- Strings (5)
- Database (1)
- SQLite (1)
- Digital Signal Processing (33)
- Distributed Systems (17)
- Apache Cassandra (6)
- Apache Hadoop (8)
- Apache Avro (3)
- Apache Nutch (3)
- Apache Solr (1)
- Linux Study Notes (40)
- crontab (1)
- Linux Kernel Programming (8)
- Linux Programming (12)
- IPC (2)
- Linux Network Programming (5)
- Linux Signals (2)
- Linux Shell Scripting (1)
- ssh (3)
- Machinery (30)
- misc (1)
- My Ideas (1)
- My Project (3)
- Mobile Caching (1)
- Selective Decoding (2)
- My Publication (1)
- My Readings (1)
- Networking (15)
- Program for Performance (8)
- Uncategorized (1)
- Virtual Machine (2)
- Web Dev (8)
- web components (3)
- Android Apps (18)
Recent Comments
Archives
- May 2013 (2)
- April 2013 (1)
- March 2013 (4)
- December 2012 (2)
- November 2012 (6)
- October 2012 (6)
- September 2012 (3)
- August 2012 (13)
- July 2012 (15)
- June 2012 (3)
- May 2012 (8)
- April 2012 (4)
- March 2012 (13)
- February 2012 (19)
- January 2012 (9)
- December 2011 (11)
- November 2011 (12)
- October 2011 (4)
- September 2011 (12)
- August 2011 (16)
- July 2011 (15)
- June 2011 (6)
- May 2011 (10)
- April 2011 (13)
- March 2011 (20)
- February 2011 (4)
- November 2010 (2)
- May 2010 (1)
- April 2010 (1)
- February 2010 (1)




