LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   the difference of using fork() and exec() with system() (https://www.linuxquestions.org/questions/programming-9/the-difference-of-using-fork-and-exec-with-system-558172/)

jaepi 05-31-2007 10:12 PM

the difference of using fork() and exec() with system()
 
Hello there. Is there someone kind enough to please explain to me the difference of using fork() and exec() with system() in invoking a process. I just want to know their difference according to well experienced with processes here. And what is the most efficient in invoking a process between the two. Thanks.

jaepi 05-31-2007 10:31 PM

I'm a bit confused. In order to spawn a new process, you must first use fork()to make a copy of the current process, then exec() to transform one of these processes into an instance of the program you want to spawn. I have here a test program. I used fork and exec to execute the command in Linux "switch user" or the "su" command. I was surprised to see two outputs. It executed two "su" commands. Here's the code.

Code:


      #include <iostream>
 
      #include <unistd.h>
 
     
 
      using namespace std;
 
   
 
      int main(){
 
      const char* command = "su";
 
      pid_t child_p;
 
 
      child_p = fork();
 
     
 
      execvp(command, NULL);
 
      return 0;
 
      }

Question:

Quote:

you must first use fork()to make a copy of the current process
-What was the process that the fork in my test program copied?
-Why is it that it produced two instances of the "su" command?

Dark_Helmet 06-01-2007 12:13 AM

You received two "su" commands because you executed it twice.

Your original process (the "master") called fork(). A second process (the "slave") was created--a mirror image of the master. Then both processes continued execution. The next instruction for both processes was the execvp() call.

If you want only one process to execute execvp(), then you need to build an if statement around it, and check the return result of fork(). The fork() function's return value indicates whether the process was originally the master or the slave. Read the man page to understand what the return value should be in each case.

culin 06-01-2007 12:23 AM

Hi jaepi,
let me answer ur first question,
exec family will replace the current execution of the process context with the image that u have specified....so always exec calls is used with the fork().. i.e. after forking... fork will create another instance of the process.. so the from the next statement of forking everything is duplicated...fork returns the child pid to the parent and the 0 to the child process.. so after forking there will be a child and parent.. normally in child we will exec..(execvp u have used there is a blocking call it wont return untill there is some error in execvp, since u have used fork() it has executed that twice...) fork() and exec wont invoke the shell...
where as system() it creates a shell and executes the command what u have given inside the system in the shell...
for further clarifications read the man pages..
cheers
culin...:)

jaepi 06-01-2007 12:37 AM

@Dark_Helmet and culin - Thank you sirs! :)

Quote:

You received two "su" commands because you executed it twice.
@Dark_Helmet - How come I executed the "su" command twice?

Dark_Helmet 06-01-2007 01:14 AM

Quote:

Originally Posted by Dark_Helmet
Your original process (the "master") called fork(). A second process (the "slave") was created--a mirror image of the master. Then both processes continued execution. The next instruction for both processes was the execvp() call.

Both the master and the slave executed the execvp() function. Two processes--two calls to execvp()--two invocations of "su".

jaepi 06-01-2007 01:20 AM

Ahh. So the parent process (the main program) was split into two, producing the child process and the parent process. Now here, the execvp() function invoked both process that's why I end up producing two "su" commands. How do I filter that the child process will be the one executing the "su" command?

Dark_Helmet 06-01-2007 11:49 AM

Quote:

Originally Posted by Dark_Helmet
If you want only one process to execute execvp(), then you need to build an if statement around it, and check the return result of fork(). The fork() function's return value indicates whether the process was originally the master or the slave. Read the man page to understand what the return value should be in each case.

Store the return value of fork() in a variable (which you already do), and use an if statement to decide whether to call execvp() based on fork()'s return value.

jlliagre 06-01-2007 12:58 PM

Quote:

Originally Posted by jaepi
I just want to know their difference according to well experienced with processes here.

system is a standard library function, fork and exec are system calls, i.e. lower level.
Quote:

And what is the most efficient in invoking a process between the two.
There should be no difference in performance, system is using fork and exec (and waitpid) under the hood anyway.

jaepi 06-03-2007 07:49 PM

Thank you very much. :)

ta0kira 06-04-2007 08:21 AM

Quote:

Originally Posted by culin
...
execvp u have used there is a blocking call it wont return untill there is some error in execvp, since u have used fork() it has executed that twice
...

'execvp' is just 'execv' that searches PATH for the command.

The main reason to use 'system' is when you have a command line as a string, such as "ls -ld". That will not 'execv' because there is no program "ls -ld"; just the "ls" program.

'su' will use the 'system' call when using '-c' since the entire command must be in 1 argument. The 'exec' built-in in bash, however, can take the entire command line and build an 'execv' call.

'system' uses the default shell to evaluate the argument, whereas 'execv' actually inserts the 'char*[]' argument into 'argc' and 'argv' of the program given by the 'char*' argument.

Since 'system' returns rather than replacing the process, you can emulate 'execv' by doing 'exit( system("ls -ld") );'. Normally 'system' is used when a program needs the assistance of an outside command, whereas 'execv' is used when a lengthy process or daemon needs communication with the parent outside of just command line arguments.

You should also check out 'pipe', 'dup2', and 'fcntl' to make full use of 'fork' and 'execv'. If you need some help putting it all together let us know.
ta0kira

PS To make 'fork' more clear: In the parent process the function returns a positive number (the process ID of the child) if successful and a negative number if unsuccessful. In the child process it will return 0. You can therefore do this:
Code:

pid_t child = 0;

if ( !(child = fork()) )
{
char *command[] = { "ls", "-ld", NULL };
exit( execvp(command[0], command) ); //use 'exit' in case there is a problem with 'execvp'
}

else if (child < 0) exit(1);

//...parent program continues...


culin 06-05-2007 03:56 AM

good info ta0kira, but i have a clarification..
but , we can as well use execvp to accomplish "ls -ld" but we need to pass "-ld" as the argument to the execvp..
Quote:

Originally Posted by ta0kira
The main reason to use 'system' is when you have a command line as a string, such as "ls -ld". That will not 'execv' because there is no program "ls -ld"; just the "ls" program.

see the code below and execute that.
Code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int spawn(char *program, char** arg_list);
int main (int argc , char *argv[])
{
        int child_pid,child_pid3;
        int *status;
        //pid_t child_pid1,child_pid2,child_pid3;
        //int i=2;
        char* arg_list1[] =
        {
                "ls", // argv[0], the name of the program.
                "-ld",
                "/home/naren/Proj_conf",
                NULL // The argument list must end with a NULL.
        };
        child_pid=spawn("ls",arg_list1);
        printf("the first child pid is %d\n\n ",child_pid);
        return 0;
}

int spawn(char *program, char** arg_list)
{
                        int child_pid,*status;
                        child_pid=fork();
                        if (child_pid != 0)
                        return child_pid;
                        else
                        {
                                execvp(program, arg_list);
                                fprintf (stderr, "\nan error occurred in execvp\n\n\n");
                        }

}


ta0kira 06-05-2007 07:14 AM

Yes, I understand that. It is nearly the same in the example I give. The distinction I was making was that sometimes you only have an unparsed command line, such as from the environment or from user input. Rather than parsing input into a command and arguments, you can use 'system' to parse it into "ls" and "-ld" using the default shell.
ta0kira


All times are GMT -5. The time now is 09:13 PM.