use execl with some null arguments - c

the program reads from a config file some values, some are defined, some are not, some have value 0, some are active.
I have the following code:
char *arg1="", *arg1_value="", *arg2="", *arg2_value="", *arg3="", *arg3_value="", *arg4="", *arg4_value="";
//part where I read from config file
execl("./test", "test", arg1, arg1_value, arg2, arg2_value, arg3, arg3_value, arg4, arg4_value, (char*) 0);
How can I use execl but in case some variables are missing or set to 0 not to affect the others? I'm sure this is not the best approach by setting their value to ""

I assume that each argX is a switch like "-xxxx" and argX_value it's corresponding value and you always want to pass both if argX is defined. Then you could use execv() instead of execl() like that:
#define MAXARGS 4
char *argv[2*MAXARGS+2];
int i, argc;
argv[0] = "prog";
argc = 1;
if( arg1 && strcmp( arg1, "" ) != 0 ) {
argv[argc++] = arg1;
argv[argc++] = arg1_value;
}
// the same for arg2 to arg4
argv[argc] = NULL;
execv( "./prog", argv );

Initializing arguments with default values and passing appropriate arguments(by checking whether the values are default or not) to execl could be the only option we have in such condition.
if(argv1 == defval_arg1)
execl("./prog","prog", "required args in case argv1 is missing according to syntax of ./prog");
if(argv2 == defval_arg2)
execl("./prog","prog", "required args in case argv2 is missing");
Update
if there are more arguments to be checked you can simply use loop to form an array of args to be passed, by checking values of args.
for(i=0;i<10;i++){
if (args[i]!=default_value_args[i]) {
args_2b_passed[j++]=args[i];
}
}
and then use varient of exec function using args_2b_passed array. man 3 exec for more help.

Related

How to tell fuse3 that you need a device and a mount point in command-line arguments

I'm using fuse3 to write a file system driver that should parse all the fuse options and then take two arguments, a device path (or file containing a file system image) and a mount-point.
Is there a convenient way to use fuse's command-line parsing to extract the device from the command line? I've taken to manipulating the arguments before I hand them to fuse like this:
struct fuse_args args;
const char *device = NULL;
memset(&args, 0, sizeof(args));
for (int i = 0; i < argc; ++i)
if (i > 0 && i == argc - 2 && *argv[i] != '-')
image = argv[i];
else
fuse_opt_add_arg(&args, argv[i]);
if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
return 1;
if (!device) {
usage(argv[0]);
fuse_opt_add_arg(&args, "--help");
}
fuse_main(args.argc, args.argv, &oper, nullptr);
But this is totally gross and doesn't quite work if the user specified only one argument, unless that argument also happens to be a valid mountpoint, because fuse seems to check the mountpoint viability before printing the help.
Surely this must be a common thing to want to do, so I'm wondering what the correct idiom is for such a file system.
so for this you will have to restrict the user on the order of the cmd arguments(all fuse/mount options come before the devicepath and mountpoint). To make it simple, ensure that the path to the device and mount point are provided last:
So in your main function, this statement will check that there is a correct number of arguments and the mount point and device do not start with hyphens as with options.
if ((argc < 3) || (argv[argc-2][0] == '-') || (argv[argc-1][0] == '-'))
{
fprintf(stderr, "usage: ./myfuse [FUSE and mount options] devicepath mountPoint\n");
abort();
}
Then extract the device path and store it in a struct:
struct my_state *my_data;
my_data = malloc(sizeof(struct mi_state));
if (mi_data == NULL) {
perror("main calloc");
abort();
}
my_data->devicepath = realpath(argv[argc - 2], NULL);
argv[argc-2] = argv[argc-1];
argv[argc-1] = NULL;
argc--;
Notice that I remove the device paths from argv and decrement argc by 1 before passing hem to the fuse_main function
Then while calling the fuse_main function make sure to pass the my_data struct:
fuse_main(argc, argv, &my_fuse_operations, mi_data);
Here is the defination of the my_state struct which you can put in a header file:
struct my_state{
char *devicepath;
};
You should also add this definition in the header file below the struct definition:
#define BB_DATA ((struct mi_state *) fuse_get_context()->private_data)
And also in your init function call fuse_get_context and return BB_DATA:
void *my_init()
{
fuse_get_context();
return BB_DATA;
}
The return value will be passed in the private_data field of fuse_context to all file operations and as a parameter to the destroy() method.
The fuse_context is set up before this function is called, and fuse_get_context()->private_data returns the user_data passed to fuse_main().

Parse to integer with argp.h

I would like to be able to receive program arguments and options in my C program. The options should be treated as floats or ints. For some reason, I couldn't find good articles, tutorials, docs about argp.h. I started my implementation with the examples on the GNU Libc Manual, though unfortunately, it didn't get me to the solution.
Here is how I tried to solve the problem (example can be compiled, included every necessary line):
#include <stdlib.h>
#include <argp.h>
static char doc[] = "Doc";
static char args_doc[] = "ARG1";
static struct argp_option options[] = {
{"bool", 'b', 0, 0, "Simple boolean flag, works as I expected."},
{"int", 'i', 0, 0, "Would like to be able to parse options as --int=4 or -i 4."}, // but I can't
{0}
};
struct arguments {char *args[1]; int xbool, xint;};
static error_t
parse_opt (int key, char *arg, struct argp_state *state) {
struct arguments *arguments = state->input;
printf("key = %c, arg = %s\n", key, arg); // My attempt to understand the problem
//if (arg == NULL) return 0; // Prevents segfaults, in order to see how the args and keys change
switch (key) {
case 'b': arguments->xbool = 1; break;
case 'i': arguments->xint = (int) strtol(arg, NULL, 10); break;
case ARGP_KEY_ARG: if (state->arg_num >= 1) {argp_usage(state);} arguments->args[state->arg_num] = arg; break;
case ARGP_KEY_END: if (state->arg_num < 1) {argp_usage(state);} break;
default: return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp argp = { options, parse_opt, args_doc, doc };
int main (int argc, char **argv) {
struct arguments arguments;
arguments.xbool = 0;
arguments.xint = 0;
argp_parse (&argp, argc, argv, 0, 0, &arguments);
printf("ARG1 = %s\nbool option = %s\nparsed int option = %d",
arguments.args[0], arguments.xbool ? "true" : "false", arguments.xint);
exit (0);
}
The simple boolean flag works, as expected, so ./myprogram.out myarg --bool and ./myprogram.out myarg -b changes the flag's value.
However, I can't seem to find a way to parse the arguments as integers or floating point numbers.
This it the output I get for ./a.out -b --int=2 myarg:
key = , arg = (null)
key = b, arg = (null)
./a.out: option '--int' doesn't allow an argument
Try `a.out --help' or `a.out --usage' for more information.
and for ./a.out -b --int 2 myarg I get a segmentation fault, as I try to parse a NULL: key = i, arg = (null). I added a NULL check, and this way I could see, that the option I would like to parse comes with a , key (expected to come with i).
key = i, arg = (null)
key = , arg = 2
I thought about using a library because the program needs to handle various float and int options, falling back to default values, and I've seen often that it's not recommended to roll your own argument and options parser. Based on the examples, argp.h looked promising, however I couldn't get it to work yet.
ps. I know that parsing directly to ints and floats are not part of argp, this is why I was (naively, it seems) trying to add it to the structures and parse_opt function.
As it turned out, there was an error with options[]. The third, const char *arg parameter in the argp_option struct must be provided, if the option has argument associated with it [source: GNU C: Argp Option Vectors].
static struct argp_option options[] = {
{"bool", 'b', 0, 0, "Simple boolean flag, works as I expected."},
{"int", 'i', "Numbah", 0, "Now everything works as expected, I get the correct key-value (key-arg) pair in the parse_opt function"},
{0}
};

parsing command option with default values and range constraints in C

I need to parse command line arguments in C. My arguments are basically
int or float with default values and range constrains.
I've started to implement something that look like this:
option_float(float* out, int argc, char* argv, char* name, description,
float default_val, int is_optional, float min_value, float max_value)
which I call for example with:
float* pct;
option_float(pct, argc, argv, "pct", "My super percentage option", 50, 1,
FALSE, 0, 100)
However I don't want to reinvent the wheel!
My objective is to have error checking of range constraints, throw an error when
the option is not optional and is not set. And generate the help message usually
given by usage() function.
The usage text would look like this:
--pct My super percentage option (default : 50). Should be in [0, 100]
I've started with getopt but it is too limited for what I want to do and I feel it still
requires me to write too much code for a simple use case like this.
What alternatives would you recommend?
Assuming you are coding for Linux...
Try getopt_long (man 3 getopt_long) for the double-dash options.
Also, try making the validators to be generic functions and let getopt/getopt_long to the hard part of the parsing and checking required arguments to options.
In any case, if you want to use your functions as defined, your example call will not work as defined.
A simplified example:
int main( int argc, char **argv )
{
float pct = 0.0
if( !GetArgs(argc, argv, &pct) )
DoStuff(pct)
}
int GetArgs( int argc, char **argv, float *thePct )
{
extern char *optarg;
int rc = 0;
(*thePct) = 50.0 /* default val */
while( (opt = getopt(argc, argv, "hp:")) != -1 )
{
switch( opt )
{
case 'p':
(*thePct) = atof( optarg );
break;
case 'h':
MyUsage(); /* Explain everything */
rc = -1;
break;
}
}
if( !rc )
{
rc = ValidatePct( (*thePct), /* value to check */
0.0, /* low pct val */
100.0 ); /* hi pct val */
/* Other validations here */
if( !rc )
MyUsage();
}
}
This will allow a call like:
$ myprogram -p 45.0
If you stick to the parsers getopt and getopt_long, you can also make command lines that take options followed by N number of other arguments like grep does, for instance:
grep -in -e "SomeRegex" file1, file2, ..., fileN
Out of sheer curiosity, you aren't a PERL programmer, are you?

Way to pass argv[] to CreateProcess()

My C Win32 application should allow passing a full command line for another program to start, e.g.
myapp.exe /foo /bar "C:\Program Files\Some\App.exe" arg1 "arg 2"
myapp.exe may look something like
int main(int argc, char**argv)
{
int i;
for (i=1; i<argc; ++i) {
if (!strcmp(argv[i], "/foo") {
// handle /foo
} else if (!strcmp(argv[i], "/bar") {
// handle /bar
} else {
// not an option => start of a child command line
break;
}
}
// run the command
STARTUPINFO si;
PROCESS_INFORMATION pi;
// customize the above...
// I want this, but there is no such API! :(
CreateProcessFromArgv(argv+i, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
// use startup info si for some operations on a process
// ...
}
I can think about some workarounds:
use GetCommandLine()
and find a substring corresponding to argv[i]
write something similar to ArgvToCommandLine() also mentioned in another SO question
Both of them lengthy and re-implement cumbersome windows command line parsing logic, which is already a part of CommandLineToArgvW().
Is there a "standard" solution for my problem? A standard (Win32, CRT, etc.) implementation of workarounds counts as a solution.
It's actually easier than you think.
1) There is an API, GetCommandLine() that will return you the whole string
myapp.exe /foo /bar "C:\Program Files\Some\App.exe" arg1 "arg 2"
2) CreateProcess() allows to specify the command line, so using it as
CreateProcess(NULL, "c:\\hello.exe arg1 arg2 etc", ....)
will do exactly what you need.
3) By parsing your command line, you can just find where the exe name starts, and pass that address to the CreateProcess() . It could be easily done with
char* cmd_pos = strstr(GetCommandLine(), argv[3]);
and finally: CreateProcess(NULL, strstr(GetCommandLine(), argv[i]), ...);
EDIT: now I see that you've already considered this option. If you're concerned about performance penalties, they are nothing comparing to process creation.
The only standard function which you not yet included in your question is PathGetArgs, but it do not so much. The functions PathQuoteSpaces and PathUnquoteSpaces can be also helpful. In my opinion the usage of CommandLineToArgvW in combination with the with GetCommandLineW is what you really need. The usage of UNICODE during the parsing of the command line is in my opinion mandatory if you want to have a general solution.
I solved it as follows: With your Visual Studio install you can find a copy of some of the standard code used to create the C library. In particular if you look in VC\crt\src\stdargv.c you will find the implementation of "wparse_cmdline" function which creates argc and argv from the result of GetCommandLineW API. I created an augmented version of this code which also created a "cmdv" array of pointers which pointed back into the original string at the place where each argv pointer begins. You can then act on argv arguments as you wish, and when you want to pass the "rest" on to CreateProcess you can just pass in cmdv[i] instead.
This solution has the advantages that is uses the exact same parsing code, still provides argv as usual, and allows you to pass on the original without needing to re-quote or re-escape it.
I have faced the same problems with you. The thing is, we don't need to parse the whole string, if we can separate the result of GetCommandLine(), then you can put them together afterwards.
According to Microsoft's documentation, you should consider only backslashes and quotes.
You can find their documents here.
And, then, you can call Solve to get the next parameter start point.
E.g.
"a b c" d e
First Part: "a b c"
Next Parameter Start: d e
I solved the examples in Microsoft documentation, so do worry about the compatibility.
By calling the Solve function recursively, you can get the whole argv array.
Here's the file test.c
#include <stdio.h>
extern char* Solve(char* p);
void showString(char *str)
{
char *end = Solve(str);
char *p = str;
printf("First Part: ");
while(p < end){
fputc(*p, stdout);
p++;
}
printf("\nNext Parameter Start: %s\n", p + 1);
}
int main(){
char str[] = "\"a b c\" d e";
char str2[] = "a\\\\b d\"e f\"g h";
char str3[] = "a\\\\\\\"b c d";
char str4[] = "a\\\\\\\\\"b c\" d e";
showString(str);
showString(str2);
showString(str3);
showString(str4);
return 0;
}
Running result are:
First Part: "a b c"
Next Parameter Start: d e
First Part: a\\b
Next Parameter Start: d"e f"g h
First Part: a\\\"b
Next Parameter Start: c d
First Part: a\\\\"b c"
Next Parameter Start: d e
Here's all the source code of Solve function, file findarg.c
/**
This is a FSM for quote recognization.
Status will be
1. Quoted. (STATUS_QUOTE)
2. Normal. (STATUS_NORMAL)
3. End. (STATUS_END)
Quoted can be ended with a " or \0
Normal can be ended with a " or space( ) or \0
Slashes
*/
#ifndef TRUE
#define TRUE 1
#endif
#define STATUS_END 0
#define STATUS_NORMAL 1
#define STATUS_QUOTE 2
typedef char * Pointer;
typedef int STATUS;
static void MoveSlashes(Pointer *p){
/*According to Microsoft's note, http://msdn.microsoft.com/en-us/library/17w5ykft.aspx */
/*Backslashes are interpreted literally, unless they immediately precede a double quotation mark.*/
/*Here we skip every backslashes, and those linked with quotes. because we don't need to parse it.*/
while (**p == '\\'){
(*p)++;
//You need always check the next element
//Skip \" as well.
if (**p == '\\' || **p == '"')
(*p)++;
}
}
/* Quoted can be ended with a " or \0 */
static STATUS SolveQuote(Pointer *p){
while (TRUE){
MoveSlashes(p);
if (**p == 0)
return STATUS_END;
if (**p == '"')
return STATUS_NORMAL;
(*p)++;
}
}
/* Normal can be ended with a " or space( ) or \0 */
static STATUS SolveNormal(Pointer *p){
while (TRUE){
MoveSlashes(p);
if (**p == 0)
return STATUS_END;
if (**p == '"')
return STATUS_QUOTE;
if (**p == ' ')
return STATUS_END;
(*p)++;
}
}
/*
Solve the problem and return the end pointer.
#param p The start pointer
#return The target pointer.
*/
Pointer Solve(Pointer p){
STATUS status = STATUS_NORMAL;
while (status != STATUS_END){
switch (status)
{
case STATUS_NORMAL:
status = SolveNormal(&p); break;
case STATUS_QUOTE:
status = SolveQuote(&p); break;
case STATUS_END:
default:
break;
}
//Move pointer to the next place.
if (status != STATUS_END)
p++;
}
return p;
}
I think it's actually harder than you think for a general case.
See What's up with the strange treatment of quotation marks and backslashes by CommandLineToArgvW.
It's ultimately up to the individual programs how they tokenize the command-line into an argv array (and even CommandLineToArgv in theory (and perhaps in practice, if what one of the comments said is true) could behave differently than the CRT when it initializes argv to main()), so there isn't even a standard set of esoteric rules that you can follow.
But anyway, the short answer is: no, there unfortunately is no easy/standard solution. You'll have to roll your own function to deal with quotes and backslashes and the like.

getopt does not parse optional arguments to parameters

In C, getopt_long does not parse the optional arguments to command line parameters parameters.
When I run the program, the optional argument is not recognized like the example run below.
$ ./respond --praise John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame
You suck !
Here is the test code.
#include <stdio.h>
#include <getopt.h>
int main(int argc, char ** argv )
{
int getopt_ret, option_index;
static struct option long_options[] = {
{"praise", required_argument, 0, 'p'},
{"blame", optional_argument, 0, 'b'},
{0, 0, 0, 0} };
while (1) {
getopt_ret = getopt_long( argc, argv, "p:b::",
long_options, &option_index);
if (getopt_ret == -1) break;
switch(getopt_ret)
{
case 0: break;
case 'p':
printf("Kudos to %s\n", optarg); break;
case 'b':
printf("You suck ");
if (optarg)
printf (", %s!\n", optarg);
else
printf ("!\n", optarg);
break;
case '?':
printf("Unknown option\n"); break;
}
}
return 0;
}
Although not mentioned in glibc documentation or getopt man page, optional arguments to long style command line parameters require 'equals sign' (=). Space separating the optional argument from the parameter does not work.
An example run with the test code:
$ ./respond --praise John
Kudos to John
$ ./respond --praise=John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame=John
You suck , John!
The man page certainly doesn't document it very well, but the source code helps a little.
Briefly: you're supposed to do something like the following (though this may be a little over-pedantic):
if( !optarg
&& optind < argc // make sure optind is valid
&& NULL != argv[optind] // make sure it's not a null string
&& '\0' != argv[optind][0] // ... or an empty string
&& '-' != argv[optind][0] // ... or another option
) {
// update optind so the next getopt_long invocation skips argv[optind]
my_optarg = argv[optind++];
}
/* ... */
From among the comments preceding _getopt_internal:
...
If getopt finds another option character, it returns that character,
updating optind and nextchar so that the next call to getopt can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, getopt returns -1.
Then optind is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.) <-- a note from me:
if the 3rd argument to getopt_long starts with a dash, argv will not
be permuted
...
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in optarg. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in optarg, otherwise optarg is set to zero.
...
... though you have to do some reading between the lines. The following does what you want:
#include <stdio.h>
#include <getopt.h>
int main(int argc, char* argv[] ) {
int getopt_ret;
int option_index;
static struct option long_options[] = {
{"praise", required_argument, 0, 'p'}
, {"blame", optional_argument, 0, 'b'}
, {0, 0, 0, 0}
};
while( -1 != ( getopt_ret = getopt_long( argc
, argv
, "p:b::"
, long_options
, &option_index) ) ) {
const char *tmp_optarg = optarg;
switch( getopt_ret ) {
case 0: break;
case 1:
// handle non-option arguments here if you put a `-`
// at the beginning of getopt_long's 3rd argument
break;
case 'p':
printf("Kudos to %s\n", optarg); break;
case 'b':
if( !optarg
&& NULL != argv[optind]
&& '-' != argv[optind][0] ) {
// This is what makes it work; if `optarg` isn't set
// and argv[optind] doesn't look like another option,
// then assume it's our parameter and overtly modify optind
// to compensate.
//
// I'm not terribly fond of how this is done in the getopt
// API, but if you look at the man page it documents the
// existence of `optarg`, `optind`, etc, and they're
// not marked const -- implying they expect and intend you
// to modify them if needed.
tmp_optarg = argv[optind++];
}
printf( "You suck" );
if (tmp_optarg) {
printf (", %s!\n", tmp_optarg);
} else {
printf ("!\n");
}
break;
case '?':
printf("Unknown option\n");
break;
default:
printf( "Unknown: getopt_ret == %d\n", getopt_ret );
break;
}
}
return 0;
}
I recently came across this issue myself. I arrived at a similar solution to the one Brian Vandenberg and Haystack suggested. But to improve readability and avoid code duplication, you can wrap it all up in a macro like below:
#define OPTIONAL_ARGUMENT_IS_PRESENT \
((optarg == NULL && optind < argc && argv[optind][0] != '-') \
? (bool) (optarg = argv[optind++]) \
: (optarg != NULL))
The macro can be used like this:
case 'o': // option with optional argument
if (OPTIONAL_ARGUMENT_IS_PRESENT)
{
// Handle is present
}
else
{
// Handle is not present
}
break;
If you are interested, you can read more about how this solution works in a blog post I wrote:
https://cfengine.com/blog/2021/optional-arguments-with-getopt-long/
This solution is tested and is – at the time of this writing – currently used in CFEngine.
I also ran into the same problem and came here. Then I realised this .
You don't have much of a use case of "optional_argument" . If an option is required you check from program logic, if an option is optional then you need not do anything because at getopt level all options are optional , they are not mandatory, so there is no use case of "optional_argument". Hope this helps.
ps: for the above example i think the correct options are
--praise --praise-name "name" --blame --blame-name "name"

Resources