Using fork and execvp in c causing error - c

I am attempting to use fork/execvp to execute another program from within my C program. It is working, however before ls outputs the contents of my directory I am getting several hundred lines of:
ls: cannot access : No such file or directory
Followed by the correct listing of the files in the directory. I am passing to execvp:
char **argv = {"ls", "/home/school/"};
char *command = "ls";
For some reason when I use the path "/home/school" it cannot find the directory. Does anyone know why that is happening and why ls is saying it cannot access?
PID = fork();
i = 0;
if(i == numArgs) { doneFlag = 1; }
if (PID == 0){//child process
execvp(command, argv);//needs error checking
}
else if(PID > 0){
wait(PID, 0, 0);//wait for child process to finish execution
}
else if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}

The execv and execvp functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program.
The first argument should point to the file name associated with the file being executed.
The array of pointers must be terminated by a NULL pointer. Append a 0 or NULL at the end of argv*.

The char** argument passed in execvp() must be terminated by NULL.

Related

exit(1) does not give me 1 as an exit value?

Why when i execute this code inside a function in c
int Pandoc(char *file)
{
//printf("Pandoc is trying to convert the file...\n");
// Forking
pid_t pid;
pid = fork();
if (pid == -1)
{
perror("Fork Error");
}
// child process because return value zero
else if (pid == 0)
{
//printf("Hello from Child!\n");
// Pandoc will run here.
//calling pandoc
// argv array for: ls -l
// Just like in main, the argv array must be NULL terminated.
// try to run ./a.out -x -y, it will work
char *output = replaceWord(file, ".md", ".html");
//checking if the file exists
char *ls_args[] = {"pandoc", file, "-o", output, NULL};
// ^
// use the name ls
// rather than the
// path to /bin/ls
// Little explaination
// The primary difference between execv and execvp is that with execv you have to provide the full path to the binary file (i.e., the program).
// With execvp, you do not need to specify the full path because execvp will search the local environment variable PATH for the executable.
if(file_exist(output)){execvp(ls_args[0], ls_args);}
else
{
//Error Handeler
fprintf(stdout, "pandoc should failed with exit 42\n");
exit(42);
printf( "hello\n");
}
}
return 0;
}
I get 0 as a returned value?
EDIT:
Edit:
So here i changed the return value of the main to 5.
The exit value for my function above to 42 (idk why tho)
It gives me 5 as an output.. no idea whats hapening.
I shouldve mentionned that i use fork() in my code.. Maybe its the reason.
I think that my exit shut off the child process but the main continiues.. so thats why its giving me the returned value inside of my main and not the exit one.
Your child process exits with an exotic value, but your main process always exits with 0, and that's what determines $?.
If you want $? to be the exit value of the child process, you'll have to wait() for it, retrieve the child's exit code, and then exit your main process with it.

Child process not exiting with fork()

I am creating a simple Linux command shell in C. I am having trouble understanding where my code is having problems. "commands" is a list of strings of Linux commands that I want to be executed concurrently as the children processes of one parent. When all are done executing, I want the parent to exit the function. However, when I call exit(0), the for loop continues and parses the current command again, causing the args to be executed again in execvp. Am I using fork() and wait() correctly here? I have tried using waitpid() as well with no luck.
void executeShell(char** commands){
char **arr = commands;
char *c;
pid_t pid, wpid;
int status = 0;
for (c = *arr; c; c=*++arr){
// printf("%d-\n", strcmp(command, "exit"));
if (strcmp(c, "exit") == 0){
EXIT = 1;
return;
}
printf("Running command \'%s\'...\n", c);
char** args = parseStringToTokenArray(c, " ");
free(args);
/* fork and execute the command */
pid = fork();
if(pid < 0){
perror("fork() error\n");
return;
}
/* child process executes command */
else if (pid == 0){
/* 'cd' is not a part of /bin library so handle it manually */
if (strcmp(args[0], "cd") == 0){
changeDirectory(args[1]);
}
else if (strcmp(args[0], "sdir") == 0){
searchDirectory(args[1]);
}else{
/* parse commands with arguments */
execvp(args[0], args);//execute the command
}
exit(0);// <-----command is finished, so why no exit?
}
}
/* wait for children to complete */
while((wpid = wait(&status)) > 0);
}
If execvp succeeds, the entire child process address space is replaced by the program invoked by execvp(). This means that the exit(0) will only ever be invoked following your two special cases i.e. cd and sdir. As far as your code is concerned execvp() should never return, unless there is an error.
A further problem is that you free args immediately after allocating it and then go on to use it in your child processes. This is undefined behaviour.
The only problem I see with your wait code is that, if any of the children block waiting for user input, the parent will block waiting for the child to exit.
The cd code, has no effect on any process except the child in which it is executed. The parent's current directory is not affected. As you state in the comments, this can bet fixed by handling cd in the parent without forking.

exec() is not throwing an error, but not running the other executable. Syntax error?

I'm trying to use fork() and exec() to run another program that resides in the same directery. The compiler is not complaining, but the program I am trying to call using execl() is not being run. Any tips? Thank you!
pid = fork();
if (pid == -1) {
fprintf (stderr, "Error\n");
exit(1);
}
else if (pid > 0) {
wait(&status);
}
else {
execl("./expo.c", "./expo", x, n, (char*) NULL);
_exit(EXIT_FAILURE);
}
I have tried a few different versions of exec() as well and none have worked.
EDIT:
I have changed to execl("expo","expo",&x,&n,(char*)NULL); , though I am still unsure why this works based on the man pages. The man page says the first argument should be a path, not just the executable. Also, why do I not need ./ for the second argument if I would need that to run that executable in the terminal?
I have got everything working correctly, here is what I changed. Instead of casting the arguments (x and n) into ints then passing them to the child, I passed them as chars and then casted them as ints in the child process.
if(pid==-1){
fprintf (stderr, "Error\n");
exit(1);
}
else if(pid>0){
wait(&status);
}
else{
const char *x=argv[1];
const char *n=argv[2];
execl("expo","expo",x,n,(char*)NULL);
perror("execl() failure!\n");
exit(EXIT_FAILURE);
}

What might be possible reasons that I get "Cannot Allocate Memory" error on forking()?

I am creating a simple Unix shell in C. I use the fork() to clone the process and exec to execute a new one. It works fine when you are inputting data for the first time in the shell. But when it comes the second iteration fork returns -1.
e.g
...>ls -l /
/results here/
...>ls -l /
forking failed
here is a part of the code:
int execute(char path[80],char *args[]){
pid_t pid;
if((pid=fork())<0){
printf("forking failed"); // The forking failed due to Cannot allocate memory error
exit(0);
}else if(pid==0){
execv(path,args);
}else{
wait(NULL);
}
return 0
}
where path is "bin/ls" and args "ls",NULL
the main is looks like
int main(){
while(1){
//read from keyboard
//find the program path
//fill args
execute(path,args);
}
}
Change your first if branch to this:
if((pid=fork())<0){
perror("forking failed");
exit(0);
}
This will tell you what went wrong.

C execlp() not correctly parsing parameters string

I'm building a shell for an Operating Systems class that must use exec() or one of its variants to execute external commands. Currently, I'm using execlp(command,command_parameters, (char *) NULL). This runs the command just fine (e.g. ls returns a standard directory listing), but doesn't seem to parse any of the parameters (e.g. running mkdir hello throws an error "hello: missing operand... Try 'hello --help' for more information). What am I missing?
else // Try to handle an external command
{
char *command_parameters = malloc(sizeof(raw_command)-sizeof(command));
strcpy(command_parameters, raw_command+strlen(command)+1);
pmesg(1, "Command is %s.\n", command);
pmesg(1, "The command parameters are %s.\n", command_parameters);
pid_t pid = fork();
pmesg(1, "Process forked. ID = %i. \n", pid);
int status;
if (fork < 0)
{
printf("Could not fork a process to complete the external command.\n");
exit(EXIT_FAILURE);
}
if (pid == 0) // This is the child process
{
pmesg(1, "This is the child process, running execlp.\n");
if (execlp(command, command_parameters, (char *) NULL) < 0)
{
printf("Could not execute the external command.\n");
exit(EXIT_FAILURE);
}
else { pmesg(1, "Executed the child process.\n"); }
}
else {while(wait(&status) != pid); } // Wait for the child to finish executing
pmesg(1, "The child has finished executing.\n");
}
(pmesg is a debug tag that prints the statement given a certain debug level).
Thanks!
A couple of issues here:
execlp( const char *file, const char *arg, ...) expects the arguments to be split up and passed separately, not as one big string.
The first arg (after const char *file) is by convention, the name of the executable you're running, which gets put into argv[0] in the called program. The first parameter, thus, will need to go after that.
e.g.:
execlp( command, command, arg1, arg2, ..., (char *)NULL );
With what you have, doing it like:
execlp( command, command, command_parameters, (char *)NULL );
will probably, as-is, take care of your issue with "mkdir", "hello", but you're still not splitting the command_parameters string up, so it won't work without modification for commands with more than one argument.
EDIT: P.S. Your line
if (fork < 0)
should be
if (pid < 0)

Resources