Getting infinite loop on execvp() - c

I am learning about how fork() works and I am running into an infinite loop when calling execvp(argh[0], argv);
Here is my program:
int main (int argc, char *argv[])
{
pid_t pid;
pid = fork();
if (pid < 0) { // error occurred
printf("Something went wrong!\n");
exit(-1);
} else if (pid == 0) { // child process
printf("Child process. ");
if(argc == 1 || argc == 0) {
printf("No arguments provided. Terminating child.\n");
exit(0);
} else if(argc == 2) {
printf("One argument provided.\n");
execlp(argv[1], argv[1], NULL);
} else {
printf("More than one argument\n");
execvp(argv[0], argv); // *** It's right here ***
}
} else { // parent process
printf("PARENT started with pid=%d.\n", pid);
int status = 0;
pid_t wait(int *status);
printf("PARENT resumed with status code: %i. Now terminating parent.\n", status);
exit(0);
}
return 0;
}
I'm trying to perform the operation (and arguments) that are passed into the function, with this code execvp(argv[0], argv), but I'm getting an infinite loop when I do ./arguments ls -l. How should I be calling execvp? Or should I call another method?
Thanks for any help
---Update---
I made the change suggested in an answer which was to call execvp(argv[1], argv); (change the arguv[0] to arguv[1]) and I now get cannot access ls: No such file or directory rather than an infinite loop.

When you do ./arguments ls -l, your code is executing execvp("./arguments", {"./arguments", "ls", "-l"}). Your program is forking and calling itself infinitely: you have made fork-bomb. :)
This is because argv[0] is your executable file (i.e. ./arguments).
You should use argv[1] instead, like this:
execvp(argv[1], &argv[1]);
Note you have to change both the first and the second argument.
When executed, that line will be equivalent to: execvp("ls", {"ls", "-l"}).

Related

execl is suceeding - however exit(1) is being called

I'm trying to better understand exec() - so I have the following script in testing.c
#include <stdio.h>
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
if(argc < 2) {
fprintf(stderr,"Error:: Expecting an Argument!\n");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid==0) {
execlp("./testing","testing",NULL);
fprintf(stderr, "I want to get to here...\n");
exit(-1);
}
wait(NULL);
printf("Parent and child done\n");
return 0;
}
The block below is the output after I execute with ./testing one:
Error:: Expecting an Argument!
Parent and child done
In reading how exec() works, I was expecting to be able to fprintf after my execlp call since it should be returning -1, I'm wondering if I need to be setting an errno or something or being more explicity about throwing something so that execlp recoginize the error?
If the execlp function successfully starts the given program, it does not return. The current program image gets replaced with the program image of the new program. So even if the new program exits with status -1, it still doesn't go back to the program that called execlp.
If you want to get the exit status of the child process, pass the address of an int to wait and read that:
int main(int argc, char ** argv)
{
if(argc < 2) {
fprintf(stderr,"Error:: Expecting an Argument!\n");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid == -1 {
perror("fork failed");
exit(-1);
} else if (pid == 0) {
execlp("./testing","testing",NULL);
perror("execlp failed");
exit(-1);
}
int status;
wait(&status);
printf("child exit status: %d\n", WEXITSTATUS(status));
printf("Parent and child done\n");
return 0;
}
The output:
Error:: Expecting an Argument!
Parent and child done
is from
(first line) child process tries to run but no command line parameter.
(second line) parent process finishes

Exec won't call my second program

I created a test file to see if I could run a second program, but the code doesn't run the actual file even though it seems to compile. Is my syntax for exec incorrect?
coordinator.c
int main(int argc, char *argv[])
{
// Creates 2^n processes for n amount of values.
pid_t child = fork();
if(child < 0) //parent process
{
perror("fork() system call failed.");
exit(-1);
}
else if(child == 0) //Child Process, worker will be called here.
{
execl("/worker", "worker", "Hello", NULL);
printf("I'm the child %d, my parent is %d\n", getpid(), getpid());
}
else
{
printf("I'm the parent %d, my child is %d\n", getpid(), child);
wait(NULL); // wait for child process to catch up
}
}
worker.c
int main(int argc, char *argv[])
{
printf("Hi, I'm the worker file!");
return 0;
}
The problem is in the PATH argument you're passing to execl().
In fact, if you do insert a / at the beginning of the string passed as the first argument, the function is going to seek the program at the root of your file system.
To let it look for the worker executable in your current directory, just specify the name of it, thus execl("worker", ... ), or execl("./worker", ... )
Take a look here to understand how the function works https://www.systutorials.com/docs/linux/man/3-execl/
Let's say worker executable is in the same directory where you are running the main(coordinator) process then in child process while doing exec you should do ./worker instead of /worker, that shows current working directory.
see then man pages of exec() for other argument, it says
int execl(const char *path, const char *arg, ...);
child process should be like below
else if(child == 0) //Child Process, worker will be called here.
{
printf("I'm the child %d, my parent is %d\n", getpid(), getpid());
//execl("/worker", "worker", "Hello", NULL);/** It's wrong, check the below one **/
execl("./worker", "./worker", NULL);
}
IF worker is in different directory then set the PATH variable, it seems it's in same directory because you are trying to do /worker instead of ./worker.
EDIT :
How to compile & execute :
coordinator.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
pid_t child = fork();
if(child < 0){
perror("fork() system call failed.");
exit(-1);
}
else if(child == 0) {
printf("I'm the child %d, my parent is %d\n", getpid(), getpid());
execl("./worker", "./worker", NULL);
}
else {
printf("I'm the parent %d, my child is %d\n", getpid(), child);
wait(NULL); // wait for child process to catch up
}
}
worker.c
int main(int argc, char *argv[])
{
printf("Hi, I'm the worker file!");
return 0;
}
First create the worker executable/binary as
gcc -Wall worker.c -o worker
Next, create the main executable and run it
gcc -Wall coordinator.c
./a.out

execvp in C not going through ar

I'm trying to use exec to execute a list of commands given as arguments.
Example input when In run the program would be ./assn2 ls date.
When I do this only the first command is executed.
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main(int argc, char *argv[])
{
int args = argc-1;
pid_t childpid = fork();
// error
if (childpid < 0)
{
perror("fork() error");
exit(-1);
}
// parent process
if (childpid != 0)
{
printf("Parent Process started, now waiting for ID: %d\n", childpid);
wait(NULL);
printf("Parent Process resumeed. Child exit code 0. Now terminating\n");
exit(0);
}
// child process
if (args > 0)
{
printf("Child process has begun. %d argument/s provided\n", args);
int i;
for (i = 1; i <= argc; i++)
{
execlp(argv[i], argv[i], NULL);
}
execvp(argv[1], argv);
}
else
{
printf("No arguments provided, terminating child\n");
}
return 0;
}
Once the first child process execs (and succeeds), the for loop no longer continues because the an execlp would just replace the current process image with the command being exec'ed.
What you want to do is to loop over the command line arguments in the parent process and exec once for each of the command. Something like is probably what you're after:
for(int i = 1; i < argc; i++) {
pid_t pid = fork();
if (pid == 0) {
execlp(argv[i] ,argv[i], (char*)0);
perror("exec");
} else if (pid > 0) {
wait(NULL);
} else {
perror("fork");
exit(1);
}
}
What are you trying to achieve with the sequential calls to execlp() and execvp()? These functions are not meant to return. I think you should read the ref:
The exec() family of functions replaces the current process image with a new process image. [..] The exec() functions only return if an error has occurred.
As a result you cannot execute them one after another in the same process.
Read about fork():
fork() creates a new process by duplicating the calling process.
Moreover, here:
for(i = 1; i <= argc; i++)
you go out of bounds, since argv starts indexing from 0, and ends at argc - 1.
Chnage it to:
for(i = 1; i < argc; i++)

Custom shell stops working after dup2

I am writing a function to my shell where I need to redirect output to file. For example user write: ls -l >> file and ls -l should be written to file. Almost all things are correct but after first calling my function program stop and I can't write anything else. Below I present my function and I would appreciate any clues to resolve the problem:
void execute2(char *command, char **argv, char **argv2)
{
pid_t pid;
int status;
if ((pid = fork()) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
else if (pid == 0)
{
close(1);
parse(command, argv, argv2);
int output = open(*argv2, O_APPEND | O_WRONLY);
dup2(output,1);
if (strcmp(argv[0], "exit") == 0)
exit(0);
if (execvp(*argv, argv) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
close(output);
}
else
{
while (wait(&status) != pid);
}
}
command is command getting from user, argv is part of instruction and parameters and argv2 is the output file.
#Jonathan Leffler I checked this and I think it doesn 't resolve problem. I suggest that when I call first time execute2 it works as well as I want but I never finish that proces. Or I don 't undestand something

Creating a UNIX Shell, confused about fork and child pids?

Here is my code for the evaluate function, which is called in the main.
void eval(char *cmdline)
{
char *argv[MAXARGS]; /* argv for execve() */
int bg; /* should the job run in bg or fg? */
pid_t pid; /* process id */
bg = parseline(cmdline, argv);
struct job_t tempJob;
if (builtin_cmd(argv) == 0)
{
if ((pid = fork()) == 0)
{ /* child runs user job */
if (execve(argv[0], argv, environ) < 0)
{
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
}
if (!bg)
{ /* parent waits for fg job to terminate */
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else /* otherwise, don’t wait for bg job */
{
printf("%d %s", pid, cmdline);
}
}
return;
}
Now when I run a background job, I expect that the pid of the job get printed twice twice, once in parent and once for child.I just need to understand what is going on in the code. It works the way it is supposed to but why?
Both the parent and child return from fork, but the condition == 0 is true only for the child:
if ((pid = fork()) == 0)
Thus only the child runs this:
if (execve(argv[0], argv, environ) < 0)
execve replaces the current process, and thus does not return if there is no error, i.e., the child's execution of this program ends either here or at the exit(0); that follows from the error condition.
The rest of the function is run only by the parent in all cases.

Resources