What arguments does a c application like snmpget take? - c

I want to call snmpget.c from another c program in the same project. For that reason I have changed the main() into a function say get_func() which takes the same arguments. But i an not sure how to give the arguments namely argv[0]
My arguments look something like this:
char *argstr[]=
{
"v",
"1",
"c",
"public",
"-Ovq",
"192.168.1.1",
"ifInOctets.7",
"ifOutOctets.7",
NULL
};
And then
i = get_func(10, argstr);
1.Should argv[0] be the app name or path?
2.Is using char *argstr[] correct for c?
3.snmpget is not taking these arguments correctly. What could the reason be?
It works correctly with the same args in command.

Your get_func expects the arguments starting at argv[1], so your argstr argument should not start with "v" but with something else (e.g. the programme name or just an empty string if get_func doesn’t use it).
Yes. But be aware that your argstr contains non-modifiable strings, if get_func wants to modify them, you can use compound literals
char *argstr[]=
{
(char []){ "v" },
(char []){ "1" },
/* etc */
NULL
};
See 1. and 2. Additionally, argc is incorrect (must be sizeof argstr/sizeof *argstr - 1, which is 8 in your case, not 10).
Not directly an answer to your question, but consider redesigning this (depends on what exactly you’re currently doing, however). For example, write a function accepting a structure where the different options are stored (already parsed and validated) and change the old main from snmpget.c to a function only scanning and validating arguments, initializing such a structure object, and calling this function. And then, perhaps split your files into snmpget.c, snmpget_main.c, another_c_file.c (with better names, of course) and link both user interface implementations against the object file of snmpget.c.

Yes, if your main uses it. If not, just pass NULL is enough >o<
Sure, it's array of pointers. char *argstr[9] is equal to
typedef char *pchar;
pchar argstr[9];
Well, I assume you don't give appropriate argc and don't pass the app name by argv[0] because the argc is 10, but the number of content of argv is 8. (I've counted excluding NULL, but the NULL is required yet - argv[argc] should be NULL.)
To reduce mistakes, I suggest to use sizeof(argstr) / sizeof(argstr[0]) - 1 instead of calculating argc yourself.
See live example. Code:
#include <stdio.h>
int test(int argc, char *argv[]);
int main()
{
char *argstr[] = {
"test.exe",
"--opt-1",
"--output",
"test.txt",
NULL
};
int argcount = sizeof(argstr) / sizeof(argstr[0]) - 1;
return test(argcount, argstr);
}
int test(int argc, char *argv[])
{
int i;
printf("argc: %d\n", argc);
printf("program name: %s\n", argv[0]);
for (i = 1; argv[i] != NULL; i++)
{
printf("argument %d is: %s\n", i, argv[i]);
}
return 0;
}
Output:
argc: 4
program name: test.exe
argument 1 is: --opt-1
argument 2 is: --output
argument 3 is: test.txt

Related

finding the size of an string array that saves integers C

I am currently working on a project where I am manipulating command line data, but I can't seem to get it work if I initialize the size of the array before.
char* len2[50]; // will store "1","2","3" from command line args
int size_arr = sizeof(len2) / sizeof(len2[0]);
printf("%d", size_arr);
this will input 50 when I am looking for it to input 3. How would I be able to find the size?
int size_arr = sizeof(len2) / sizeof(len2[0]);
sizeof(len2) asks for the total allocated size of len2 in bytes. This only works because C knows how many you allocated at compile time and turns it into a constant. It doesn't tell you which ones you've filled in. C does not keep track of that; you have to.
Because len2 is an array of pointers, you can mark the end with a null pointer. The term for this is a sentinel value. First, be sure to initialize the array to null.
// This will initialize the entire array to NULL
char* len2[50] = {NULL};
Now you can find how many elements are in the array by looking for the first null, or by hitting the allocated size.
size_t len2_size = sizeof(len2) / sizeof(len2[0]);
int size = 0;
for( ; len2[size] != NULL && size < len2_size; size++ );
printf("size: %d\n", size);
This is, incidentally, basically how C strings work. The end of the string is marked with a 0.
Alternatively, you can store the allocated size and number of elements in a struct and keep track, but that's another question.
Finally, if you're just reading command line arguments, use argc and argv. argc is the size of argv. argv[0] is the name of the program, and the rest are the command line arguments.
int main( const int argc, const char **argv) {
printf("%d arguments in argv\n", argc-1);
}
And argv is also terminated with a NULL pointer so it's easy to iterate through.
// Because argv[0] is the name of the program,
// start at 1 and read until you hit a null pointer.
for( int i = 1; argv[i] != NULL; i++ ) {
printf("argv[%d] = %s\n", i, argv[i]);
}
From the comments:
I guess what I'm trying to find is the number of items. Since there are 3 numbers I'll be getting from the command line, I want to be able to manipulate the array using 3 for a for or while loop for example.
According to the standard you have two versions of main function available (while the implementation defining further ones is legal):
int main();
int main(int, char**);
The second form gets the command line parameters passed to directly while the first form can be used if command line parameters are irrelevant.
Typically (but not necessarily) these two arguments get named argc and argv with argc containing the total number of command line arguments and argv a null-terminated array to the actual arguments. First one of is always the name that has been used to call the programme (which can differ in some cases from the actual executable name, e.g. if symbolic links are involved) which you might want to skip.
So a programme simply iterating over all arguments and printing them back to console might look like this:
int main(int argc, char* argv[])
{
for(++argv; *argv; ++argv)
{
printf("%s\n", *argv);
}
return 0;
}
with first ++argv skipping the programme name, *argv profiting from and testing for the null-terminator of the array and second ++argv being the normal loop post operation.
If you want to see the programme name as well you might just skip very first pointer increment:
for(;*argv;++argv)
Alternative variants might use an integer to count up to argc – just a matter of personal taste...

Is it possible to add an argument to main by scanf?

I tried to add an argument to main by scanf. But it didn't work. The following is my program. My question is: what's wrong with this program? And is it possible to add an argument to main by scanf() instead of in the command line?
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]){
/*check if there is no argument, that is, argc!=2*/
if(argc != 2){
puts("Please enter an argument: ");
scanf("%s", &argv[1]);
printf("\nYou've entered argument: %s\n", argv[1]);
return 1;
}
printf("\nYou've entered argument: %s\n", argv[1]);
return 0;
}
Yes, code can effectively add arguments.
"The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination." C11dr §5.1.2.2.1 2
So this allows code to change argc and argv and change argv[0][0] (if argc > 0) - but wait, there's more...
Can code change the original elements of argv[], like argv[1], etc? That is an open question still hanging in SO here. So let us avoid that.
The way to change the contents of argv[] is to first create an alternate set argv_alt[] array and then assign argv_alt --> argv.
#include <stdio.h>
int main(int argc, char *argv[]) {
// Assume argc == 1
printf("%d '%s'\n", argc, argv[0]);
char a[3][10] = { "abc", "def", "fgh" };
char *argv_alt[] = { a[0], a[1], a[2], NULL };
argc = 3;
argv = argv_alt;
printf("%d '%s' '%s' '%s'\n", argc, argv[0], argv[1], argv[2]);
return 0;
}
Argv is allocated by the system when the user types in her arguments. If there wasn't arguments you cannot use the position 1 on that array. Although, as pointed out on the comments, you shouldn't do the way you are willing to, you could scanf arguments if you declare your own local variable.
The %s specifier in scanf expects that you pass in a pointer which points to space that has already been allocated and is big enough to hold whatever will be read.
Instead you pass in a pointer which points to an area where another pointer is stored. This causes undefined behaviour because the pointer you pass in has the wrong type.
It's not possible to extend the length of the argv array. In fact, writing to argv[n] probably causes undefined behaviour anyway.
Instead you should just read into a variable inside main.

C execve() parameters [spawn a shell example]

I have to fill the parameters for:
int execve(const char *filename, char *const argv[], char *const envp[]);
If I execute this program:
#include <unistd.h>
int main() {
char *args[2];
args[0] = "/bin/sh";
args[1] = NULL;
execve(args[0], args, NULL);
}
the shell is spawned correctly as expected.
My problem is that the shell is spawned correctly also if I pass a NULL as second parameter like that:
#include <unistd.h>
int main() {
char *args[2];
args[0] = "/bin/sh";
args[1] = NULL;
execve(args[0], NULL, NULL);
}
So what's the purpose to use the args vector (with the "/bin/sh" + NULL) as second parameter instead of a NULL?
In this line: execve(args[0], NULL, NULL); you are simply using the first element of args array. You could also use something like char* command="/bin/sh". You have to pass something, because that's how execve() was defined. In your case you pass NULL because you don't need to pass anything.
The point of the second argument of execve() is to pass arguments to the command you are spawning. Suppose that instead of shell you simply want to execute ls, you could then pass f.e. these arguments:
#include <unistd.h>
int main() {
char *args[2];
args[0] = "/bin/ls";
args[1] = "-lh";
execve(args[0], args, NULL);
}
Also, quoting man execve:
argv is an array of argument strings passed to the new program. By
convention, the first of these strings should contain the filename
associated with the file being executed. envp is an array of
strings, conventionally of the form key=value, which are passed as
environment to the new program.
If you pass a null pointer as the second, or the third, argument of execve, your program is incorrect according to POSIX; both of these arguments are required to be non-null. (This is not all that clearly stated in the specification of execve, but it's in there.) I am currently typing this on an operating system that treats passing null pointers,
execve("executable", 0, 0);
as equivalent to passing empty arrays, e.g.
execve("executable", (char *[]){0}, (char *[]){0});
but it would not surprise me to learn that other operating systems would fire a segmentation fault or return -1 with errno set to EFAULT or EINVAL.
Passing empty arrays for these arguments is allowed, but the newly executed program will receive zero arguments in argc/argv if the second argument is an empty array, and/or zero environment variables in envp/environ if the third argument is an empty array. Many programs will malfunction under these conditions. For instance, it is very common to see things like
int main(int argc, char **argv)
{
if (argc != 4) {
fprintf(stderr, "usage: %s one two three\n", argv[0]);
return 2;
}
// ...
}
where the program implicitly assumes that argv[0] will always be non-null.
So, you should always provide non-empty arrays for both arguments. The usual convention is that if you don't have anything else to do, you use
execve(program, (char *[]){program, 0}, environ);
which supplies the program's own name as argv[0] and no further arguments, and the same set of environment variables you got from your own parent.

String compare function properly

I am writing a program that has to use the strcmp function using a pointer in the main. There cannot be any user input. There is no menu, it must execute the arguments as parameters in the main function. my question is am I calling the strcmp function proper?
int main(int n, char **p, char **choice)
{
int i, x, A[100];
if (strcmp(*choice, "mode")==0){
Your code will compile and is grammatically correct, but I'm not certain that the logic is what you want it to be.
Typically main has 2 or 3 arguments, usually written as int argc, char **argv, char ** envp (if there are only 2, it's the first 2). It's ok to rename them as you did, to n, p, and choice, but you need to know what each of them mean.
argc ("n") is the number of strings in the argv array, 0 indexed. There will always be at least 1 argument - the name of the program. Arguments passed on the command line start at argv[1].
argv is all of the arguments, including the program name. The array will go from 0 to argc - 1
envp is an array of strings listing all of the environment settings. It is terminated with a NULL entry as its final one.
If you're tasked with executing the arguments as parameters, you're likely to be interested in looping through the strings in argv. You'll want something like this:
int i = 1;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "mode") == 0) {
Of course, if you want to keep your variable names, just replace them:
int i = 1;
for (i = 1; i < n; ++i) {
if (strcmp(p[i], "mode") == 0) {
So, yes. Your use of strcmp was syntactically acceptable. But it likely doesn't do what you want.
Good luck!
Incidentally, if you ever need to loop through envp, you'd do so as follows:
int i = 0;
while (envp[i] != NULL) {
if (strcmp(envp[i], "mode") == 0) { // or whatever else you needed to do.

C application error on run

I've built a C application, and when I build it, it shows no errors, but when I run it, it gives me the error "Segmentation Fault: 11".
If it helps, here is the code I am using:
#include <stdio.h>
int main(char *argv[]) {
printf("The project path is: ./Projects/%c", argv[1]);
return 0;
}
The correct main prototyped syntax is
int main(int argc, char *argv[]) { ... }
Also %c conversion specification in printf prints a character, to print a string use %s.
You have a number of problems:
The signature for main is an argument count followed by an array of C strings.
You should always check the count before using the array.
The array is of strings so you need %s to print them.
This should work:
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc < 2)
fprintf (stderr, "Wrong number of arguments\n");
else
printf ("The project path is: ./Projects/%s\n", argv[1]);
return 0;
}
Change the signature to int main(int, char*[]);
What arguments are you passing to the process? If you're not passing any argv[1] is out of range
In addition to the other suggestions, you may need to revisit your printf format. %c is used to print a single character, and argv[1] is char *. Either use argv[1][0] or some such, or use the string format specifier, %s.
First, change your main to:
int main(int argc, char *argv[])
Second, you have a mismatch between what you're passing to printf, and what you've told it you're going to pass. argv[1] is a pointer to characters, not a character. You need/want to use the %s conversion to print it out:
printf("The project path is: ./Projects/%s", argv[1]);
In this specific case, it's not really mandatory to check for enough arguments, because even if you don't pass any command line arguments, argv will contain at least argv[0] followed by a null pointer. As such, using argv[1] is safe, but if you haven't passed a command line argument, may print as something like (null).
Nonetheless, you generally want to check the value of argc before using argv. In this case, you can get away with it, but only more or less by accident. Trying to use argv[2] the same way could give undefined behavior.

Resources