Why is my execv() not working with 'ls' command in linux - c

I'm trying to execute the command by execv() in child process (using fork()) and test the result by simple 'ls' command in linux.
However, execv does not return error(-1) but not printing anything when I input 'ls' command. I can't understand what is wrong. There are few files in directory with the c file it self containing the code so there should be some output for 'ls'
`
if ((pid = fork()) == 0) {
command(argv);
if (execv(argv[0], argv) < 0) {
fprintf(stderr,"%s: Command not found.\n", argv[0]);
exit(0);
}
exit(0);
}
argc = 0;
char* ptr = strtok(buf, " ");
while (ptr!=NULL) {
argv[argc++] = ptr;
ptr = strtok(NULL, " ");
}
argv[argc] = NULL;
if (!strcmp(argv[0],"ls") || !strcmp(argv[0], "man") ||
!strcmp(argv[0], "grep")
|| !strcmp(argv[0], "sort") || !strcmp(argv[0], "awk") ||!strcmp(argv[0], "bc")) {
strcat("/bin/", argv[0]);
`
I tried changing strcat for adding /bin/ to sprintf, strcpy, but I don't think it is problem for argv[0] because execv understand the command.
may be it is error with argv but there is only /bin/ls in it. What can go wrong?

execv() system call (execv() man page) has the signature:
int execv(const char *path, char *const argv[]);
so it needs two arguments: 1) the path of the command to execute, 2) the arguments of the command to execute.
The issues in your code are:
argv[0]. You're using argv[0] but, instead you may want to use argv[1], since argv[0] is the name of your executable file, while argv[1] is the first argument from the command line. Thus, the path of the command to pass to execv() is argv[1].
The argument passed to execv() since you're passing all the command line parametes that are different to the parametes you need to send to the execv() function.
To fix your code use these lines:
char* arg[] = {"ls", "-l", NULL};
if ((pid = fork()) == 0) {
if (execv(argv[1], arg) < 0) {
...
}
}

Related

c programming using execvp

I'm working on a side project where I want to spawn 5 children processes then execvp into a second program called isEven which will tell if the number passed to it is even or not. However, the execvp call keeps failing as I ran it in gdb and it doesn't execute.
Args and load(args) are both called in another function.
Thanks in advance!!!
//Code to load binary
void load(char* args[])
{
execvp("./isEven", args);
printf("ERROR\n");
}
//args being passed in
char *args[] = {"./isEven", number, NULL};
load(args);
Here is a smaller program I wrote which does the same thing I'm trying to do right now. Gdb says I am getting a segmentation fault.
int main(int argc, char *argv[])
{
int returnCode = fork();
if(returnCode == 0)
{
char *args[] = {"./isEven", 12345, NULL};
execvp("./isEven", args);
printf(errno);
printf("ERROR: execvp failed\n");
exit(-1);
}
else if(returnCode < 0)
{
fprintf(stderr, "fork failed\n");
}
else
{
//i am the parent
printf("I am the parent");
}
return 1;
}
The main problem is with this line:
char *args[] = {"./isEven", 12345, NULL};
The args passed to execvp must be an array of char*. Having 12345 as an argument makes it interpret it as address and it's unlikely to be a valid address. In any case, that's not what you wanted to pass. So do:
char *args[] = {"./isEven", "12345", NULL};
You need to convert number into a string. For example:
int number = 12345;
char num_str[256];
snprintf(num_str, sizeof num_str, "%d", number);
char *args[] = {"./isEven", num_str, NULL};
execvp("./isEven", args);
perror("exec");
In your modified example, you are printing errno as:
printf(errno);
This will fail because printf expects a string as its first argument. You can use perror() to print the error as shown above.

How to execute shell command with arguments in C

I'm unable to execute the command alone, with arguments is working. How can I make it work both ways.
char command[256];
char args[10][256];
char buffer[256] __attribute__((aligned(4096)));
Funcion is handling command and arguments and I'm sure they are correct, however I can't find a way to execute it.
pid = fork();
if (pid == -1)
{
printf("Failed forming fork\n");
return;
}
else if (pid == 0)
{
strcpy( cmd , "/usr/bin/");
strcat( cmd, command);
execl(cmd, command, args, NULL);
}else{
wait(NULL);
}
And in general how can I stop fork bombs, how to check for them and avoid them?

execvp fails when a command has an option

So I am reading commands from a file that has a line of commands, each separated by a delimiter which is a semi colon. I got these commands into an array and I am basically executing them one by one. Everything works fine until I have a command that has an option and execvp fails and I don't know how to fix this.
Here is my code:
int main(int argc, char *argv[])
{
char delim[] = ";"; // the semicolon is the commands separator
FILE* batchFile;
char oneLine[512];
batchFile = fopen("myfile.txt", "r");
int numOfCommands = 0;
char *commands[100];
char *oneCommand;
pid_t childPid;
int child_status;
if(batchFile == NULL)
{
perror("Error opening file ... exiting !");
exit(1);
}
if(fgets(oneLine,512,batchFile) != NULL)
{
//puts(mystring);
fclose(batchFile);
}
printf("The command is: %s \n", oneLine);
oneCommand = strtok(oneLine,delim);
commands[numOfCommands++] = strdup(oneCommand);
while((oneCommand=strtok(NULL, delim))!=NULL)
{
commands[numOfCommands++] = strdup(oneCommand);
}
commands[numOfCommands] = NULL;
for(int i = 0;i < numOfCommands;i++)
{
printf("The command is: %s \n",commands[i]);
}
for(int i =0;i < numOfCommands;i++)
{
childPid = fork();
if(childPid == 0)
{
execvp(commands[i], argv);
perror("exec failure");
exit(1);
}
else
{
wait(&child_status);
}
}
return 1;
}
and some commands like exit, cd will not work, I guess maybe because they are not in /bin ??
and how could this be fixed ?
My file has the following line
ls;date;cal;pwd;cd;ls -l;
and when I run my program it outputs the following.
If you look at the output, it fails for cd. This is expected because cd is a shell built-in, not a command. For cd, you have to use chdir(2) instead of execv().
ls -l fails because there's no such command. You need to split the command again before passing them to execvp().
Basically, the command you pass has to be in the form:
char *cmd[] = {"ls", "-l", 0};
execvp(cmd[0], cmd);

execvp not working with command line argument

I am working on this program to run the shell command given via command line argument using system calls execvp() and fork(). Here arglist is a 2D array which contains the command name and its argument list. I am passing command name as the first argument and the arglist array as the second argument. But it is not working. man page of execvp() says that it will look for the given command by default in the directories defined by PATH variable, that is why I am passing just command name.
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
void executeCommand(char *command,char **arglist){
int pid;
int status;
pid=fork();
printf("%s %s\n",command,arglist[1]);
if(pid == -1){
printf("fork failed\n");
exit(1);
}
else if(pid==0){
if(execvp(command,arglist) == -1){
printf("execution of command failed\n");
exit(1);
}
exit(0);
}
else {
while(wait(&status) != pid);
printf("Parent Exiting\n");
exit(0);
}
}
int main(int argc,char **argv){
char **arglist,*com;
int i,k=1;
if(argc>2){
arglist = (char**)malloc(sizeof(char*)*(argc));
for(i=0;i<argc-1;i++){
arglist[i] = (char*)malloc(sizeof(char)*1024);
}
com = (char*)malloc(sizeof(char)*strlen(argv[1]));
strcpy(com,argv[1]);
for(i=1;i<=(argc-1);i++,k++){
strcpy(arglist[k],argv[i]);
}
arglist[k] = NULL ;
for(i=0;i<argc;i++){
printf("%s\n",argv[i]);
}
executeCommand(argv[1],arglist);
}
//printf("%d\n",argc);
return 0;
}
You are not allocating enough space for the command when you do
com = (char*)malloc(sizeof(char)*strlen(argv[1]));
since it doesn't make space for the terminator, you need to add one to the result of strlen as in
com = (char*)malloc(sizeof(char)*(1+strlen(argv[1])));
Even easier would be to use strdup instead of malloc/strcpy. Then you just need to say
com = strdup(argv[1]);
and
arglist[k] = strdup(argv[i]);
and remove all of the mallocs except the one creating the space for arglist itself.

Call mkdir syscall with execve in C

I am very new to C and am in an OS class where I need to write a basic shell in C (yay). It's actually been going halfway decently, I am just trying to learn C basics while getting through the work.
I am trying to use exec after forking and call, for now, mkdir. The arguments required through me off a little, but I've been trying to figure it out and was hoping someone could tell me where I've gone wrong.
} else {
//fork exec
int pid = fork();
if (pid == 0) {
printf("%s",my_argv[0]);
execve("/bin/mkdir",my_argv,0);
} else wait(NULL);
}
This is the portion where I am responding to the mkdir call. Right now, I have a line[] that is input from the user, the command is taken with
command = strtok(line, DELIMITERS);
The arg is :
arg = strtok(0,DELIMITERS);
my_argv[0] = arg;
Everything compiles fine but the mkdir never works. Printing my_argv[0] gives the correct argument that I expect. I'm sure this is something stupid but any tips would be appreciated.
All Code:
int main(int argc, char *argv[])
{
char *command;
char line[MAXLINE];
char *arg = NULL;
char *my_argv[];
while(1) {
printf(PROMPT);
if (fgets(line,MAXLINE,stdin) != NULL) {
//take out \n
line[strlen(line)-1] = '\0';
}
//looks for first delimiter, saves as the command
command = strtok(line, DELIMITERS);
//start looking at what command it is by comparing
if (strcmp(command,"cd")==0) {
//if they equal zero, they match
//this is a cd command, must have following arg
if (argv[1] == NULL) chdir("/");
else chdir(argv[1]);//chdir is the system call for cd
} else if (strcmp(command,"exit")==0) {
break;
} else if (strcmp(command,"mkdir")==0){
arg = strtok(0,DELIMITERS);
my_argv[0] = arg;
my_argv[1] = NULL;
if (!arg) {
printf("Usage: mkdir missing arg\n");
} else {
//fork exec
int pid = fork();
if (pid == 0) {
printf("%s",my_argv[0]);
//mkdir(arg);
execve("/bin/mkdir",my_argv,0);
} else wait(NULL);
}
}
}
return 0;
}
argv[0] contains the name of the program
argv[1] is the first argument
argument list must be NULL terminated
You could use the mkdir syscall instead of execve

Resources