1.3. popen and pclose Functions
The standard I/O Library provides two functions: popen and pclose. The two functions implement the following operations: Create an MPS queue, call fork to generate a sub-process, close the Non-Use end of the MPs queue, execute a shell to run the command, and wait until the command is terminated.
# Include <stdio. h>
File * popen (const char * character string, const char * type );
Int pclose (File * FP );
The function popen executes fork first, then calls exec to execute explain string, and returns a standard I/O file pointer. If the type is "r", the file pointer is linked to the standard output of struct string; if the type is "W", the file pointer is connected to the standard input of smdstring. If the type is "r", the returned file pointer chain is readable. If the type is "W", the returned file pointer chain is writable.
The function pclose closes the standard I/O Stream, waits for the command execution to end, and then returns the shell termination status. If the shell cannot be executed, the termination status returned by pclose is the same as that returned by the shell when exit (127) is executed.
The running string command is executed by the following columns of the Bourne shell:
Sh-C producer string
(The shell-C option tells the shell program to take the next command line parameter as the command input, rather than reading the command from the standard input or from a given file .)
Note: popen must not be called by a set user ID or set group ID program.
1.4. instance-Paging Program
Shell Command $ {Pager:-more} indicates that if the shell variable pager has been defined and its value is not empty, its value is used; otherwise, the string more is used.
# Include <sys/types. h> <br/> # include <signal. h> <br/> # include <stdlib. h> <br/> # include <unistd. h> <br/> # include <paths. h> <br/> # include <sys/Wait. h> <br/> # include <stdio. h> </P> <p> # define def_pager "$ {Pager:-more}"; </P> <p> int main (INT argc, char * argv []) <br/>{< br/> char line [maxline]; <br/> file * fpin; <br/> file * fpout; </P> <p> If (2! = Argc) <br/>{< br/> printf ("Usage :. /. out <pathname>/N "); <br/> return-1; <br/>}< br/> If (null = (fpin = fopen (argv [1], "R "))) <br/>{< br/> printf ("can't open % s/n", argv [1]); <br/> return-1; <br/>}< br/> If (null = (fpout = popen (PAGER, "W "))) <br/>{< br/> printf ("popen error/N"); <br/> return-1; <br/>}< br/>/* copy the file to the paging Program */<br/> while (fgets (line, maxline, fpin )! = NULL) <br/>{< br/> If (fputs (line, fpout) = EOF) <br/>{< br/> printf ("fputs error to pipe/N"); <br/> return-1; <br/>}< br/> // <br/> If (ferror (fpin )) <br/>{< br/> printf ("fgets error/N"); <br/> return-1; <br/>}< br/> If (pclose (fpout) =-1) <br/>{< br/> printf ("pclose error/N "); <br/> return-1; <br/>}< br/> exit (0); <br/>}
1.5. instance-Self-compiled popen and pclose functions.
When you call popen, remember the ID of the created sub-process and its file descriptor or file pointer. We choose to save the sub-process ID in the array child_pid and use the file descriptor as the subscript. Therefore, when pclose is called using the flle pointer as the parameter, we call the standard I/O function fileno to obtain the file descriptor, obtain the sub-process ID, and call waitpid as the parameter. Because a process may call popen multiple times, the length of the array of the dynamic child_pid array should be the maximum number of file descriptors. Posix.1 requires the sub-process to shut down the I/O Stream that was opened when the previous popen call was made and the loan is still being made.
# Include <sys/types. h> <br/> # include <signal. h> <br/> # include <stdlib. h> <br/> # include <unistd. h> <br/> # include <paths. h> <br/> # include <sys/Wait. h> <br/> # include <errno. h> <br/> # include <fcntl. h> </P> <p> static pid_t * child_pid = NULL; <br/> static int maxfd; </P> <p> file (const char * character string, const char * type) <br/>{< br/> int I; <br/> int PFD [2]; <br/> pid_t PID; <br/> file * FP; </P> <p> If (type [0 ]! = 'R' & type [0]! = 'W') | Type [1]! = 0) <br/>{< br/> // POSIX requirements <br/> errno = einval; <br/> return NULL; <br/>}< br/> If (child_pid = NULL) <br/>{< br/> maxfd = open_max (); <br/> If (child_pid = calloc (maxfd, sizeof (pid_t) = NULL) <br/>{< br/> return NULL; <br/>}</P> <p> If (pipe (PFD) <0) <br/>{< br/> return NULL; <br/>}</P> <p> If (pid = fork () <0) <br/>{< br/> return NULL; <br/>}< br/> else if (pid = 0) <br/> {<Br/> // sub-process <br/> If (* type = 'R') <br/> {<br/> close (PFD [0]); <br/> If (PFD [1]! = Stdout_fileno) <br/>{< br/> dup2 (PFD [1], stdout_fileno); <br/> close (PFD [1]); <br/>}< br/> else <br/> {<br/> close (PFD [1]); <br/> If (PFD [0]! = Stdin_fileno) <br/>{< br/> dup2 (PFD [0], stdin_fileno); <br/> close (PFD [0]); <br/>}< br/> for (I = 0; I <masfd; I ++) <br/>{< br/> If (child_pid [I]> 0) <br/>{< br/> close (I ); <br/>}</P> <p> execl ("/bin/sh", "sh", "-c", callback string, (char *) 0); <br/> _ exit (127 ); <br/>}< br/> // parent process <br/> If (* type = 'R ') <br/>{< br/> close (PFD [1]); <br/> If (FP = fdopen (PFD [0], type) = NULL) <br/> {<Br/> return NULL; <br/>}< br/> else <br/>{< br/> close (PFD [0]); <br/> If (FP = fdopen (PFD [1], type) = NULL) <br/>{< br/> return NULL; <br/>}< br/> // record the sub-process id <br/> child_pid [fileno (FP)] = PID; <br/> return FP; </P> <p >}</P> <p> int pclose (File * FP) <br/>{< br/> int FD, Stat; <br/> pid_t PID; </P> <p> // popen has never been called <br/> If (child_pid = NULL) <br/>{< br/> errno = einval; <br/> r Eturn-1; <br/>}</P> <p> // FD is not opened by popen <br/> FD = fileno (FP ); <br/> If (pid = child_pid [FD]) = 0) <br/>{< br/> errno = einval; <br/> return-1; <br/>}</P> <p> child_pid [FD] = 0; <br/> If (fclose (FP) = EOF) <br/>{< br/> return-1; <br/>}</P> <p> while (waitpid (PID, & stat, 0) <0) <br/>{< br/> If (errno! = Eintr) <br/>{< br/> return-1; <br/>}< br/> // return the termination status of the sub-process <br/> return Stat; <br/>}