Popen/system, understand the difference between these two functions and fork.

Source: Internet
Author: User


s under Linux we should try to avoid using system. Now let's look at a simple introduction to the system () function under Linux:




#include <stdlib.h>
int  system(const char* command)



The system () function calls/bin/sh to execute the specified command of a parameter,/bin/sh is typically a soft connection, pointing to a specific shell, such as the BASH,-C option, which tells the Shell to read the command from the String command, and during command execution, SIGCHLD is blocked, like in said, Hi, kernel, this will not send me sigchld signal, and so on I am busy to say; During this command, SIGCHLD and sigquit are ignored, meaning that the process receives both signals without any action.
Let's take a look at the return value of system:

Here we may not be able to understand the system () is in place, we need to understand the process of its execution, actually the system () function performed three operations:
1, fork a sub-process.
2. Call the EXEC function in the sub-process to execute the command;
3. Call wait in the parent process to wait for the child process to end; For fork failure, the system function returns 1, and if exec succeeds, that is, command executes successfully, the value returned by command via exit or return is returned. (Note that command execution does not execute successfully, such as command: "RM is not strong enough. txt", regardless of whether the file does not exist, the command is executed successfully) if Exec fails, that is, command is not executed smoothly, such as signal interruption, or command commands do not exist at all, the return value of the system function is 1. If command is null, the system function returns a value other than 0, typically 1.
I have five years to see the system of a section of source code:



1 #include <stdlib.h>
   2 #include <stdio.h>
   3 #include <errno.h>
   4
   5 int main(const char* cmdstring){//If cmdstring is empty, return a non-zero value, generally 1
   6 pid_t pid;
   7 int status;
   8 if(cmdstring==NULL){
   9 return (1);
  10}
  11 if((pid=fork())<0){
  12 status=-1;//Fork fails and returns -1
  13}
  14 else if(pid==-1){
  15 execl("/bin/sh","sh","-c",cmdstring,(char*)0);
  16 exit(127);//exec returns 127 if execution fails. Note that exec only returns to the current process when it fails. If it succeeds, the current process does not exist.
  17}
  18 else
  19 {
  20 while(waitpid(pid,&status,0)<0)
  twenty one         {
  22 if(errno != EINTR)
  23            {
  24 status=-1;//If waitpid is interrupted by a signal, it returns -1
  25 break;
  26}
  27}
  28}
  29 return status;//If waitpid waits successfully, it returns to the return status of the child process.
  30}
'


After reading this code, the simple implementation of the system () function, then the return value of the function is clear, then when the system () function returns a value of 0, only command commands return 0 o'clock.
Then how to monitor the system () function execution state
The system function is error-prone, the return value is too much, and the return value is easily confused with the command return value, here we recommend the Popen function instead of the simple use of the Popen function. Let's start with a brief introduction:
The advantage of the Popen () function compared to the system () function is that it is simple to use, and the Popen () function returns only two values. Successfully returns the status of the subprocess, using the wifexited-related macro to get the command return result; failure returns-1, we can use the Perro () function or the strerror () function to get useful error information.
The Popen function is provided in the standard I/O function library, which initiates another process to execute a shell command, where we call the process called Popen the parent process, and the process initiated by Popen is called a child process. The Popen function also creates a pipeline for communication between the parent and child, which either reads the information from the pipe or wants to write the information in the pipeline, whether it is read or write, depending on the arguments passed when the parent process calls the Popen function.


Function: Popen () will call fork () to produce the child process, and then call/bin/sh-c from the child process to execute the instruction of the parameter command, the parameter type edible "R" represents the Read, "W" represents the write. Depending on the value of this type, Popen establishes a standard output device or standard input device that the pipeline connects to the child process, and then returns a file pointer. The process can then use this file pointer to read the output device of the child process or to write to the child process's standard input device, return the value: If successful, return the file pointer, otherwise return NULL, the error reason exists in errno.

 



function function: the Pclose () function is used to close the pipes and file pointers created by Popen. The parameter stream is a pointer file returned by Popen () first.
Return value: If the shell's terminating state is successfully returned (that is, the terminating state of the child process), return 1 If an error occurs, and the cause of the error is in errno.
Let's take a look at the use of Popen:
If we want to get the number of files in the current directory, under the shell we can use:



ls | WC-  L


We can write this in the program:


1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <errno.h>
  4 #include <sys/wait.h>
  5 #include <string.h>
  6
  7 #define MAXLINE 1024
  8 
  9 int main()
 10 {
 11 char result_buf[MAXLINE],command[MAXLINE];
 12 int rc=0;//Used to receive command return value
 13 FILE* fp;
 14 //Write the command to be executed into buf
 15 snprintf(command,sizeof(command),"ls ./ |wc -l");
 16 //Execute the pre-set command and read the standard output of the command
 17 fp=popen(command,"r");
 18 if(NULL==fp){
 19 perror("Popen execution failed");
 20 exit(1);
 twenty one         }
 22 while(fgets(result_buf,sizeof(result_buf),fp)!=NULL)
 23 {
 24 if('\n'==result_buf[strlen(result_buf)-1]){
 25 result_buf[strlen(result_buf)-1]='\0';
 26}
 27 printf("Command [%s] output [%s]\r\n",command,result_buf);
 28}
 29 //Wait for the command to be executed and close the pipe and file pointer
 30 rc=pclose(fp);
 31 if(-1==rc){
 32 perror("Failed to close the file pointer");
 33 exit(1);
 34}
 35 else{
 36 printf("Command [%s] End status of child process [%d] Return value of command [%d]\r\n",command,rc,WEXITSTATUS(rc));
 37}
 38 return 0;
 39}


The above Popen just captures the command's standard output, and if the command command fails, the child process prints the wrong information to the standard error output. The parent process cannot be obtained, such as the command command is "LS nofile.txt", in fact we do not nofile.txt this file at all, when the shell will output "Ls:nofile.txt:No such file or directory". This output is on the output of the standard error. cannot be obtained through the above program.
Note: If you set the command in the above program to "LS Nofile.txt", compile the execution program and you will see the following result:

It is important to note that the first line of the output is not the output of the parent process, but the standard error output of the child process. Sometimes the error message of a child process is useful, so how does the parent process get the error message?
Here we can redirect the error output of the child process and redirect the error to standard output (2>&1) so that the parent process can catch the error message of the child process. For example: command "LS nofile.txt 2>&1"

Additional:
The terminating state of the child process is judged by the design to the macro, and the terminating state is status.
Wifexited (status) is a non-0 value if the child process ends normally.
Wexitstatus (status) Gets the end code returned by the child process exit (), typically using wifexited to determine whether the macro ends properly before it can be used.
wifsignaled (status) This macro value is true if the child process ends because of a signal.
Wtermsig (status) Gets the signal code that the child process terminates because of the signal, it is generally judged by wifsignaled before using this macro.
wifstopped (status) If the child process is paused, this macro value is true and is generally only available when wuntraced is used.
Wstosig (status) Gets the signal code that causes the child process to pause, which is generally judged by wifstopped before using the macro.
Summary:
Fork is used to create a child process A program calls the fork function, first, the system lets the new process and the old process use the same Code snippet, because their program is still the same, for the data segment and the stack segment, the system copies a copy to the new process, so that the parent process of all the data can be left to the child process, but once the child process began to run, Although it inherits all the data from the parent process, the data is actually separated and no longer affects each other, meaning that no data is shared between them. If two processes want to share what data, it is necessary to use a different set of functions (SHMGET,SHMAT,SHMDT, etc.) to operate. Now, there are two processes, for the parent process, the fork function returns the subroutine's process number, and for the subroutine, the fork function returns zero, so that for the program, as long as the return value of the fork function is determined, you know whether you are in the parent or child process.the system can be seen as fork + execl + waitpid. System () function,Powerful when the command that the system accepts is NULL, it is returned directly, otherwise fork out a subprocess, because fork is returned in two processes: parent process and child process, here to check that the returned Pid,fork returns 0 in the child process, the PID of the child process is returned in the parent process, The parent process uses WAITPID to wait for the child process to end, the child process is called Execl to start a program instead of itself, execl ("/bin/sh", "sh", "-C", Cmdstring, (char*) 0) is the calling shell, the path of the shell is/ Bin/sh, the subsequent strings are arguments, and then the subprocess becomes a shell process, and the shell parameter is cmdstring, which is the parameter that the system accepts. The shell in Windows is the command, and presumably everyone is familiar with what the shell has done after accepting the command.Popen () is also often used to execute a program
The Popen () function starts a process by creating a pipeline and invokes the shell. Because pipelines are defined as unidirectional, the type parameter can only be defined as read-only or write-only, not both, and the resulting stream is read-only or write-only. The command parameter is a string pointer to a string that ends with a null terminator that contains a shell command. This command is sent to/bin/sh with the-c parameter, which is executed by the shell. The type parameter is also a pointer to a string ending with a null terminator, which must be ' r ' or ' W ' to indicate whether it is read or write.
The return value of the Popen () function is a normal standard I/O stream that can only be closed with the pclose () function instead of the fclose () function. Writes to this stream are converted to standard input for command commands; The standard output of command commands is the same as calling Popen (), which is the same as the process of the function, unless it is changed by command. Conversely, reading a "Popen" stream is equivalent to reading the standard output of the command, while the command's standard input is the same as calling Popen, which is the same process as the function.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.