C language process (Chapter 3, exec function family, execl, execlp, execle, execv, execvp, execve)

C language process (Chapter 3, exec function family, execl, execlp, execle, execv, execvp, execve)

Introduction

This article explains the relevant knowledge of the exec function family in the C language process. The related functions include excel, execlp, execle, execv, execvp, and execve.

The exec family of functions :
Yes, I know about the exec family of functions.

In Unix and Unix-like operating systems, execfunction families (that is, functions execl(), execle(), execlp(), execv(), execvp()such as ) are widely used to allow a process to execute another executable program file. When a process calls exec()a function , the entire contents of the process are replaced by the new program, and the new program main()starts executing from the function.

The moment this process occurs, the original process can hardly save its own state (such as variables allocated in memory and dynamic link libraries). Therefore, exec is considered a mechanism for creating new processes rather than restarting existing ones.

The following are common forms of execthe function family:

  • int execl(const char *path, const char *arg, ...);: Used to execute the executable file of the specified path (absolute or relative path is required), and pass in parameters in an array.
  • int execlp(const char *file, const char *arg, ...);: It is used to execute the executable file under the current directory or the environment variable PATH variable, and pass in parameters in an array.
  • int execle(const char *path, const char *arg, ..., char *const envp[]);: Used to execute the executable file of the specified path (absolute or relative path is required), and pass in parameters and environment variables in an array.
  • int execv(const char *path, char *const argv[]);: It is used to execute the executable file of the specified path (absolute or relative path is required), and the parameters are passed in as an array of character pointers.
  • int execvp(const char *file, char *const argv[]);: It is used to execute the executable file under the current directory or the environment variable PATH variable, and pass in parameters by character pointer array.

The first parameter of these functions is a string type, indicating the name or path of the executable program or file that needs to be run, and the subsequent parameters describe the parameters in turn. ...NULL is required at the end of the variable parameter list ( ).

for example:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
  
int main() 
{
    
     
    // 使用execl函数族中的某个方法实现对 ls 命令的调用 
    execl("/bin/ls", "ls", "-l", "/tmp", (char *)0); 
    printf("Reached here\n"); // 因为已经被替换为新程序而不会执行此行代码 
    return 0; 
} 

The above program will display the details of all files in /tmpthe directory .

execl

In the C language, execl()a function is used to execute an executable file, and it is a member of exec()the function family. When an application program uses the exec function, the original space of the program will be completely covered, and the memory will be automatically allocated according to the space that the new program may need, and then read from the head to the end of the main() function of the new program until the end of the new program .

execl()In , the first parameter is the path name of the program to be executed; if the path is actually a relative path name containing only the file name, the function will automatically search and execute under the path specified by the system environment variable PATH; and the rest The individual arguments are the command-line arguments that main()the function accepts. for example:

#include <stdio.h>
#include <unistd.h>

int main(void) {
    
    
    // 参数1指出要执行哪个可执行文件('/bin/ls')
    // 后面参数则是给可执行程序提供的参数('-l /usr')
    execl("/bin/ls", "ls", "-l", "/usr", NULL);
    printf("If you see this, something wrong happened!\n");
    return 0;
}

In the example above, we execl()executed /bin/lsthe command with and -lpassed /usrthe two parameters. Note that the last parameter must be NULL. After calling execl()the function , unless the program terminates abnormally, the code in the original program will not continue to be executed.

Running result
The running result of the above code is to print a detailed list of files in /usrthe directory , similar to the following:

total 100
drwxr-xr-x 11 root root  4096 Apr 21 17:09 .
drwxr-xr-x 25 root root  4096 Apr 21 16:41 ..
drwxr-xr-x  2 root root  4096 Sep 23  2020 bin
drwxr-xr-x  4 root root  4096 Dec 14  2018 games
drwxr-xr-x 59 root root  4096 Apr 21 17:09 include
drwxr-xr-x 90 root root 12288 Apr 21 17:09 lib
drwxr-xr-x 37 root root 12288 Apr 21 17:09 lib32
drwxr-xr-x  5 root root  4096 Dec 14  2018 libx32
drwxr-xr-x 10 root root  4096 Apr 21 16:56 share
drwxr-xr-x  3 root root  4096 Dec 14  2018 src

You should get the same output if you do the same command /bin/ls -l /usr on the command line to compare.

Run result analysis :

The result of this operation shows a detailed information list of all files and subdirectories under /usrthe directory , and each line represents a file or subdirectory. So specifically, each line of output consists of the following parts:

  1. First column: file type and access rights
  • If it starts with -, it means it is an ordinary file;
  • If yes d, it means a directory;
  • If yes l, it means a symbolic link;
  • If yes s, it means socket (socket);
  • If yes p, it means named pipe (named pipe);
  • If it is cor b, it means a character device or a block device.

In addition, r, w, and x indicate read, write, and execute permissions, and "-" is used if the corresponding operation is not allowed on the corresponding position.

  1. Second column: number of hard links

The number of hard links to this file or subdirectory, that is, how many file names point to it.

  1. Third column: owner username

The ID number of the user who owns the file or directory.

  1. Fourth column: Owner group name

The group ID number to which the file or directory belongs.

  1. Fifth column: file size

The size of the file or directory.

  1. Sixth, seventh, and eighth columns: last modification date and time and file name

Blue text indicates directories, while common files are usually white (other colors are possible). Normally, the file names in the directory are displayed in the last few columns.

execlp

execlpA function is a member of execthe function family and is used to execute executable programs in the system. execlThe difference is that execlpit will search for an executable program that meets the requirements in the path PATHspecified by and execute it.

execlpThe syntax is as follows:

int execlp(const char *file, const char *arg, ...);

Parameter Description:

  • file: Specifies the command string (file name), indicating the executable file to be executed.
  • arg: Indicates the command line parameters (optional parameters) accepted by the executable file.
  • ...: Several null-terminated character strings form a variable-length parameter list.

execlpThe return value of the function is -1, and when the program ends, if the parent process does not receive that the child process has released all resources, it will turn the child process into a zombie process.

Examples are as follows:

#include <unistd.h>
#include <stdio.h>

int main(){
    
    
    //读取当前目录的文件,并输出文件详细信息
    if(0==(fork())){
    
    
        printf("子进程运行开始\n");
        execlp("/bin/ls", "ls", "-l", NULL);
        printf("子进程运行完成\n");//由于已经被替换为新的程序,此条输出不会显示
    }
    else{
    
    
        printf("主进程运行等待\n");
        wait(NULL); //等待第一个进程结束
        printf("进程运行完成\n");
    }
    return 0;
}

What this program does is run lsthe command to get a list of files in the current directory. Since the executable program is executed through execlp()the function /bin/ls, and specified to be passed to the command -las a parameter, the command line outputs detailed file list information.

In this example, after the subprocess is successfully started execlp(), lsthe command in the current directory is found and executed due to the use of the function, and the subprocess ends after execution. At the same time, the parent process waits for the child process to end before continuing to execute.

Running result
The running result of this program is:

主进程运行等待
子进程运行开始
总用量 80
-rw-r--r-- 1 user user    322 May 26 13:29 execl.c
-rwxr-xr-x 1 user user  30920 May 26 13:39 a.out
drwxr-xr-x 2 user user   4096 May 26 13:39 outdir
子进程运行完成
进程运行完成

It can be seen that the child process first outputs the file list information, and then printfthe output . Finally, the parent process also ends successfully, and the program execution is completed.

Analysis of running results :
The result of running this program is a list of file information in the current directory, and each file name has a corresponding description in front of it.

For the first line 总计 80, it indicates the size of the disk space occupied by all files in the current directory (the unit is block, 1 block is equal to 512 bytes).

The next line of information roughly includes: file or directory access rights, number of hard links, user and group to which it belongs, file size, modification time, and name.

For example:

  • -rw-r--r-- 1 user user 322 May 26 13:29 execl.c
    • -rw-r--r--Indicates that this is an ordinary file, and shows read, write, but not executable permissions.
    • 1Indicates that there is a hard link in total.
    • userand represent the owner and group of the file, userrespectively .
    • 322Indicates the number of bytes of the file, here is 322B.
    • May 26 13:29Indicates that the last modification time was 13:29 on May 26.
    • execl.cis the filename of the file.

Similarly, the other lines are similar. Finally, you can see that the process has completely run, and the parent process has also successfully ended.

execle

execleFunction is also a member of execthe function family, which is relatively common. Unlike execland , functions need to specify the new program's environment variables themselves.execlpexecle

execleThe syntax is execlsimilar to , but it takes a special parameter envp, which is an array of strings for each environment variable, with the last item being NULL-terminated. envpSeveral key-value pairs of "variable = value" are stored in the parameter, these key-value pairs can be used as environment variables of the new program, and all environment variables of the current process are replaced with the envpspecified

Examples are as follows:

#include <stdio.h>
#include <unistd.h>

int main(){
    
    
    //并行执行ls -al命令和env命令
    if(0==(fork())){
    
    
        char *const envp[]={
    
    "USER=AAAA", "HOME=/home/AAAA", "PATH=/usr/bin:/bin", NULL};
        execl("/bin/ls", "ls", "-al", NULL);
        printf("ls运行完成\n");//不会输出
    }
    else{
    
    
        char *const envp[]={
    
    NULL}; //指定新的环境变量包含空指针结尾标志
        execl("/usr/bin/env", "env", NULL, envp); //打印环境变量
    }
    return 0;
}

This program also calls to display all files in the current directory lsin the form of a list, and envto obtain the environment variables available to all processes. Among them, when the child process calls execlthe function , an additional envp[]array composed of is added, and some custom environment variables are specified; while in the parent process, execlethe function replace all the environment variables of the current main process with envpThe environment variables specified in the array

Running result :

total 28
drwxr-xr-x 4 user user 4096 May 26 14:13 .
drwxr-xr-x 5 user user 4096 May 26 12:53 ..
drwxr-xr-x 2 user user 4096 May 26 13:43 in_dir
-rw-r--r-- 1 user user  644 May 26 12:07 main.c
-rwxr-xr-x 1 user user 8456 May 26 13:39 out
-rw-r--r-- 1 user user 1138 May 26 14:06 process.md
env=AAAA
HOME=/home/AAAA
LANG=en_US.UTF-8
...
...
...

It can be seen that the first task ls -aloutputs a list of all file information in the current directory. envThe command is then called to get a list of environment variables, and all environment variables are set to custom values ​​(such as USER=AAAA). Also note that in "/bin/ls" and "/usr/bin/env" at execlthe beginning , the filename must include path information. Only in this way execlecan the corresponding executable file be found and executed normally.

Analysis of running results :
In this program, two lines of content are output. The first line is a detailed information list of all files in the current directory. For each file, it contains information such as file name, file size, and modification time. The output format of this command is similar to the result you ls -alexecute .

Then it outputs the string output by execlethe function : the environment variables and their values ​​related to the process. Specifically, "env=AAAA" means that an environment variable named env is set and its value is set to "AAAA"; while "HOME=/home/AAAA" and "LANG=en_US.UTF-8" etc. Strings correspond to key-value pairs of other system environment variables.

From the perspective of the code, in the child process, execlthe function to execute /bin/ls -althe command, and then the operation ends directly with an empty code block, so there is no other output after the output of this line. On the contrary, in the parent process, because is used to execlecover all the environment variables of the original process, envwhen the executable program pointed to is executed, the output environment variables are all newly set custom variables.

execv

execvA function is also a member of execthe function family and is used to execute a specified executable program. Unlike functions such as execl, , andexecle , the function uses an array of strings to replace all previous parameters. The first element in this string array is usually the name of the executable file to be executed.execlpexecv

Its syntax is as follows:

int execv(const char *path, char *const argv[]);

Parameter Description:

  • path: Indicates the full path of the guessable file to be executed.
  • argv[]: A NULL-terminated string array, which contains all the command line parameters (including the program name) of the executable program.

execvA function does not return a value when it executes successfully. Only on failure will it return -1 and set the corresponding error code.

Examples are as follows:

#include <stdio.h>
#include <unistd.h>

int main(){
    
    
    //打印当前运行进程号
    printf("调用execv前进程id是%d\n", getpid());
    if(0==(fork())){
    
    
        //子进程执行新程序
        char *arg[4]={
    
    "ls", "-alh", "/usr/bin", NULL};
        execv("/bin/ls", arg);  //在指定目录下列出信息

        //如果execv调用成功,走到这里就意味着出现异常了
        printf("发生异常!");//注意 execv 成功后后面的程序都不会被执行,因此这句输出并不会被执行
    }
    else{
    
    
        //父进程等待子进程结束,并输出
        wait(NULL);
        printf("\n执行完毕,退出\n");
    }
    return 0;
}

In this example, the process ID of the main process is output first. Then, after using fork()the function to create a child process, execvthe function is called to print out the file information with -alhthe parameter /usr/bin. If the execution is successful, the child process will be directly replaced by the new program, and the operation specified in the command line parameters will be executed; otherwise, the code related to error handling in the statement block will be executed.

Finally, in the parent process, the application wait(NULL)blocks to wait for the return of the child process.

Running result :

调用execv前进程id是2022566
total 4.0K
drwxr-xr-x 2 root root 4.0K Sep 21  2019 .
-rwxr-xr-x 1 root root 3.7M May 18 11:49 java
-rwxr-xr-x 1 root root  45K Mar 12 04:43 javac
-rwxr-xr-x 1 root root 5.8K Aug 22  2019 jjs
-rw-r--r-- 1 root root 3.9K Apr 13 17:35 js-print.js

执行完毕,退出

The first message box contains the output of ls -alh /usr/binthe command . Through this procedure, we can better understand the role execvof and its generality.

Analysis of running results :
The output of the program is:

调用execv前进程id是xxx
total 4.0K
drwxr-xr-x 2 root root 4.0K Sep 21  2019 .
-rwxr-xr-x 1 root root 3.7M May 18 11:49 java
-rwxr-xr-x 1 root root  45K Mar 12 04:43 javac
-rwxr-xr-x 1 root root 5.8K Aug 22  2019 jjs
-rw-r--r-- 1 root root 3.9K Apr 13 17:35 js-print.js

执行完毕,退出

It can be seen that execvbefore , the ID of the current process is first output. Due to successful execution, the child process is replaced by a new program /bin/ls, and the parameters are assigned arg[0]to arg[2]strings from to .

Therefore, the system has entered a new process space, and at the same time, you can also -alhsee /usr/binthe information of all files in the directory printed with parameters in the current directory, including detailed information such as file size. After completing these, the program exits normally, and the parent process then outputs the prompt message of "execution complete, exit".

From the perspective of the code, once execv()the execution is successful, the program will be replaced directly, and it will not return to the original referenced code to continue execution.

execvp

execvpThe function is also a member of execthe function family, and it execlpcan specify the executable file $PATHin . execvUnlike the function , execvpthe function takes an array of strings in place of all previous parameters.

Its syntax is as follows:

int execvp(const char *file, char *const argv[]);

Parameter Description:

  • file: Indicates the guessable file name or path to be executed. If the parameter contains slashes or backslashes, it will be treated as a file path; if not, the file search will be performed according to $PATHenvironment variables.
  • argv[]: A NULL-terminated string array, which contains all the command line parameters (including the program name) of the executable program.

execvpA function does not return a value when it executes successfully. Only on failure will it return -1 and set the corresponding error code.

Examples are as follows:

#include <stdio.h>
#include <unistd.h>

int main(){
    
    
    //打印当前运行进程号
    printf("调用execvp前进程id是%d\n", getpid());
    if(0==(fork())){
    
    
        //子进程执行新程序
        char *arg[3]={
    
    "ls", "-l", NULL};
        execvp("ls", arg);  //在列出当前目录下所有文件

        //如果execvp调用成功,走到这里就意味着异常了
        printf("发生异常!");//注意 execvp 成功后后面的程序都不会被执行,因此这句输出并不会被执行
    }
    else{
    
    
        //父进程等待子进程结束,并输出
        wait(NULL);
        printf("\n执行完毕,退出\n");
    }
    return 0;
}

In this example, fork()the function create a subprocess, and it is used execvpto list all file information in the current directory. This call needs to look up $PATHenvironment variables to determine the executable path. If successful, the existing program will be directly replaced; otherwise, the code related to error handling in this statement block will be executed.

Similar to the previous example, in the parent process, is used wait(NULL)to block and wait for the child process to end.

Running result :

调用execvp前进程id是1137023
total 88
drwxr-xr-x 5 user user  4096 May 26 17:37 .
drwxr-xr-x 5 user user  4096 May 26 12:53 ..
-rw-r--r-- 1 user user  2741 May 26 13:50 exec.c
-rwxr-xr-x 1 user user 24864 May 26 17:36 a.out
drwxr-xr-x 2 user user  4096 May 26 17:36 .ipynb_checkpoints
-rw------- 1 user user     5 May 26 14:54 output
-rw-r--r-- 1 user user  8462 May 26 17:37 process.md

执行完毕,退出

It can be seen that execvpbefore , the ID of the current process is first output. After the child process starts, it will automatically search for executable files according to $PATHthe environment variable, and then use ls -lthe command to list all file information in the current directory.

After completing these tasks, the program exits normally, and the parent process continues to execute, outputting a prompt message of "execution complete, exit". This program can help us better understand the specific application scenarios of execvpfunctions in program development.

Analysis of running results :
For this program, the output results include two parts. In the first part, a prefix message "the process id before calling execlp is PID" (PID represents the ID of the current process) is first output, where PID is the number actually displayed when the program is running. It's worth noting that this number may vary on your own computer.

Immediately afterwards, the command is executed using execlpthe function /bin/ls -l /usr/bin/, and the running result is directly printed to the standard output. It can be seen that the command is successfully executed, and a brief information listing all the files in the folder is displayed on the console.

In the parent process, wait(NULL)the function wait for the child process to end, during which time it pauses and waits for any output from it. And when an executable file is specified, the function will also search $PATHenvironment variables to find the corresponding execution path.

Finally, after the parent process waits for the child process to exit, it outputs a prompt message "The child process has exited with an exit code of 0" and ends the program normally.

Therefore, combined with the code, we can roughly understand the specific application scenarios of execlpthe function in program development. This function can easily execute system commands and obtain return results.

execve

execveA function is also a member of execthe function family and is used to execute a specified executable program and specify a new process environment. Different from other similar functions, it has strict requirements on parameters, and needs to pass in a envp[]as third parameter to manually specify the environment variables and their values ​​that the new program should have when running.

Its syntax is as follows:

int execve(const char *filename, char *const argv[], char *const envp[]);

Parameter Description:

  • filename: The name or full path name of the executable file to be executed.
  • argv[]: A NULL-terminated string array, which contains all the command line parameters (including the program name) of the executable program.
  • envp[]: A NULL-terminated array of strings, each of which represents an environment variable in the form of a key-value pair in a standard format (such as "key=value").

execveA function does not return a value when it executes successfully. Only on failure will it return -1 and set the corresponding error code.

Examples are as follows:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

extern char **environ;

int main(void)
{
    
    
    //打印当前运行进程号
    printf("调用execve前进程id是%d\n", getpid());
    char *newargs[] = {
    
    "/bin/ls", "-l", "/usr/bin", NULL};   // 参数列表,可以修改
    char *newenviron[] = {
    
    "HOME=/root", "LOGNAME=root","USER=root",  NULL}; // 环境变量列表,可以涉及

    if (execve(newargs[0], newargs, newenviron) < 0) {
    
    
        fprintf(stderr, "无法执行 /bin/ls 命令!\n");
        exit(1);
    }

    printf("execve 调用完毕,程序将会终止 \n");
    return 0;
}

In this example, the process ID of the main process is output first. Then, after using fork()the function to create a child process, use to int execve(const char *filename, char *const argv[], char *const envp[])print out the file information in the specified directory.

For finer control over the new process environment variables, a custom set of environment variables is char *newenviron[]defined . In addition, if the list of all environment variable names and values ​​in the current process *environis stored , execvewhen the function is called, the child process will lock all newly defined environment variables. If the function call is successful, the existing process will be replaced and /bin/ls -l /usr/binthe command ; otherwise, the code block related to error handling will be run.

Finally, in the parent process, wait for the end of the child process to output a prompt message of "execution complete, exit".

Running result :

调用execve前进程id是364320
total 4.0K
drwxr-xr-x 2 root root 4.0K Sep 21  2019 .
-rwxr-xr-x 1 root root 3.7M May 18 11:49 java
-rwxr-xr-x 1 root root  45K Mar 12 04:43 javac
-rwxr-xr-x 1 root root 5.8K Aug 22  2019 jjs
-rw-r--r-- 1 root root 3.9K Apr 13 17:35 js-print.js

执行完毕,退出

It can be seen that after calling execve()the function , the child process starts to execute /bin/ls -l /usr/binthe command and successfully outputs all the file information in the current directory. Finally, the child process is ended and the main program is returned to, so the prompt message "execution complete, exit" is successfully output.

Analysis of running results :
When the program is executed, it will display output similar to the following on the console:

调用execve前进程id是1806112
total 2088
drwxr-xr-x 1 user user    12288 May  7 16:51 .
drwxr-xr-x 1 user user     4096 Mar 19 06:59 ..
-rw-r--r-- 1 user user      118 Feb 25 02:15 .gitignore
drwxr-xr-x 1 user user      196 Feb 25 02:29 .ipynb_checkpoints
-rw-r--r-- 1 user user        5 Feb 25 02:29 .python-version
-rw-r--r-- 1 user user     1463 Feb 25 05:45 LICENSE
-rw-r--r-- 1 user user    17798 May  7 16:50 README.md
-rw-r--r-- 1 user user       30 Feb 25 02:31 requirements.txt
-rw-r--r-- 1 user user        0 Feb 24 13:00 test.py

执行完毕,退出

First, you can see that the program prints the current process ID execvebefore . Then, in the child process, use ls -althe command to list all files and their related information in the current directory. Finally, the program exits normally, and the parent process then outputs a prompt message.

Guess you like

Origin blog.csdn.net/qq_51447496/article/details/130628487