I'm working on a C program with some system calls and I'm saving variables as follows:
int inhandle,outhandle,bytes,read_while_writing_nhandle;
char source[128],target[128];
Right now my program prompts the user with
printf("enter source file name\n");
scanf("%s",source);
How can I change it so a user can just type "run sourceName targetName"
aka, storing them as argv[1] and argv[2]?
I also use the inputs (target and source)
in handles like:
inhandle=open(source,O_RDONLY);
My main issue is conversion since I'm storing target and source as char. I could use something like strcpy.
It would just be very much appreciated if someone could help me out with it. Hope this was clear. Thank you.
*********EDIT: I apologize, I probably wasn't clear enough...
I tried doing the int main(int argc, char *argv[]) and then including:
if(argc==3)
{ source = argv[1]; target = argv[2]; }
else{ printf("Syntax error.\n");
return -1;
But I'd get conversion errors since I can't store them that way. And if I do store them as pointers (like *target=argv[2]) I'm worried they won't work when I call the handles.. (ex: outhandle=open(target...) works but I can't do open(*target..)
Use int main(int argc, char **argv);
And then assign source to argv[1] and target to argv[2]
Change to:
if(argc==3)
{
strcpy(source, argv[1]);
strcpy(target, argv[2]);
}
Also, read up on the dangers of strcpy, and consider strncpy.
But using strcpy will get you started at least...
Related
I'm studying C in order to start doing some fun low-level code stuff, and I've stumbled into a scenario which I can't wrap my head around, and I'm sure it's because I don't have a lot of experience with it.
Currently my code is very simple: it takes some arguments, and gets the first parameter passed to main, and stores it as a path string. The first question that came to mind, was whether it would be correct to store the main params as char *args[] or char **args, and I decided to go with char **args since according to this question there could be some scenarios where the first would not be accessible, and I just wanted to make a code that would be as complete as possible, and learn the whys on the process.
Here's is the code:
int main(int argc, char **args) {
if (args[1] == NULL) return 1;
// Get path of input file
char *path = &*args[1];
fputs(path, stdout);
return 0;
}
Given the code above, what would be a better way of fetching the value stored in *args[1]? It seems very cryptic when I look at it, and it took me a while to get to it as well.
My understanding is that char **args, is a pointer, to an array of pointers. Thus, if I'm to store a string or any other value for later use in one of the indexes of args, I would have to assign a new pointer to a memory location (*path), and assign the value of the given index to it (&*args[i]). Am I over complicating things? Or is this thought process correct?
For starters these two function declarations
int main(int argc, char **args)
and
int main(int argc, char *args[])
are fully equivalent because the compiler adjusts the parameter that has an array type to pointer to the array element type.
In the initializer expression of this declaration
char *path = &*args[1];
applying the two operators & and * sequentially is redundant. So you may just write
char *path = args[1];
Also in general instead of the condition in the if statement
if ( args[1] == NULL) return 1;
it will be more safer to write
if ( argc < 2 ) return 1;
You can simply write:
char *path = args[1];
& and * operators are inverses of each other, so &* or *& can simply be removed from an expression.
I'm trying to write a LD_PRELOADable library that prevents processes from removing itself from this variable (to make sure children inherit it).
So far I sucessfully wrapped putenv,setenv and clearenv, but execve gives me issues.
My code so far:
int (*real_execve)(const char *filename, char *const argv[], char *const envp[]);
int execve(const char *filename, char *const argv[], char *const envp[]){
real_execve = dlsym(RTLD_NEXT,"execve");
char *path = getenv("LD_PRELOAD");
fprintf(stderr, "INTERCEPTED execve, env:\n");
int i;
for(i=0;envp[i]!=NULL;i++);
char *nenvp[i+1];
nenvp[i]=NULL;
for(i=0;envp[i]!=NULL;i++){
char *string = envp[i];
char *buf = malloc((strlen(string)+1)*sizeof(char));
strcpy(buf,string);
char *name = strtok(buf,"=");
char *value = strtok(NULL,"=");
if(0==strcmp(name,"LD_PRELOAD")){
fprintf(stderr," FIXING '%s'\n",string);
char * nstring = malloc((strlen(name)+strlen(path)+strlen(value)+3)*sizeof(char));
strcpy(nstring,name);
strcat(nstring,"=");
strcat(nstring,path);
strcat(nstring,":");
strcat(nstring,value);
nenvp[i]=nstring;
fprintf(stderr," TO '%s'\n",nenvp[i]);
free(string);
}else{
nenvp[i]=envp[i];
fprintf(stderr," LEFT '%s'\n",nenvp[i]);
}
free(buf);
}
fprintf(stderr, " CALLING %s\n", filename);
return real_execve(filename,argv,nenvp);
}
I'm encountering 2 issues:
it logs things like:
FIXING 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1'
TO 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1:/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1'
instead of the expected prepending of the path to self, so I guess I somehow messed up the strtok.
I get a lot of errors like those:
Error in 'sh': munmap_chunk(): invalid pointer: 0x00007fff3888af4a
which to me sounds like I'm freeing too much probably, but I can't find the culprit.
I hope this doesn't sound too much like a "hey fix this for me" post but I'm kinda hitting a wall here and any help would be very appreciated.
You cannot assume that an individual string in envp was allocated with malloc so free(string) could be Undefined Behaviour. It is virtually impossible to call exec* with a completely empty heap and the entire image will be replaced anyway, so it's not worth worrying about.
Your second strtok call should supply NULL as its first argument. See man strtok for an explanation and examples.
Do this straight forward:
Create a new pointer array with the size necessary to hold the new env/ var/s
strdup() all elements you need from the old to the new array.
Add new stuff as necessary.
Make sure the last pointer in the array is NULL.
Pass the new pointer array to the original execve().
Do not modify or even (try to) free() entries of the old environment.
int main(int argc, char *argv[])
{
char *line, buffer[1024];
char *token, *setValue, *pointer;
FILE *fp = fopen("file", "r");
if(fp == NULL)
{
printf("File was unable to be opened.\n");
}
fgets(buffer,1024,fp);
printf("%s\n", buffer);
while(fgets(buffer,1024,fp) != NULL)
{
strcpy(token, strsep(&buffer, ","));
printf("%s\n", token);
}
return 0;
}
I'm having a bit of trouble understanding how strsep works.. I've looked up tutorials for it, but when I try different methods, it keeps just not being able to compile.. It'd be appreciated if someone helped me understand the syntax and the way it works. Thank you.
**EDIT: 'Buffer' contains "I,was,in,the,school"
****EDIT x2: I'm trying to parse a csv file, and using the basic 'Buffer' I created on my desktop as an example. I want to separate the different words by the respective comma.
regarding:
strcpy(token, strsep(&buffer, ","));
the variable token is ONLY a pointer, it has not been set to point to any memory that the application owns. Therefore, it will contain what ever trash was on the stack at the location of the variable.
The result is undefined behavior and it can lead to a seg fault event.
Suggest declare token as
char token[ 1024 ];
so it is large enough to hold a maximum length string (I.E. the length of buffer[]
as it the above wasn't bad enough:
the posted code is missing the statement: #include <string.h> so as to expose the prototype for the function strsep() so the compiler will make the assumption that the parameters and returned value are int rather than their actual types.
The posted code is also missing the statement: #include <stdio.h> so the parameter and return types for the functions: fopen(), fgets(), printf()and even the struct type forFILEare assumed to beint` rather than their actual types.
I'm just trying to check the commandline arguments and see if it works in the command line. It works fine if I execute './a.out hello' but when I do './a.out' I get the error.
#include <stdio.h>
int main(int argc, char * argv[]){
printf("Test");
printf("\n%s",argv[0]);
printf("\n%s",argv[1]);
return 0;
}
The reason why I'm doing this is because I'm going to take that string and compare it later on. I don't understand why something this simple is causing an error.
You're not checking the length of argv before dereferencing the second argument. If argv only has one element argv[1] is a null reference, which causes your fault.
With C everything needs to be done carefully. To answer your question, yes, an if statement is the right approach if you want to handle the command line yourself. The argc parameter to main() is provided for exactly this purpose.
#include <stdio.h>
int main(int argc, char * argv[]){
printf("Test");
if (argc > 0) {
printf("\n%s", argv[0]);
if (argc > 1) {
printf("\n%s", argv[1]);
}
}
return 0;
}
Theoretically argv[0] is always populated with the application name so the first if is redundant but with C caution is your friend.
However, don't take this path. For everything except trivial applications you should use a parameter parsing library such as http://www.gnu.org/software/libc/manual/html_node/Getopt.html, check Christian's excellent answer here https://stackoverflow.com/a/24479532/2381157 for more options.
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.