exec函數族


title: exec函數族
date: 2019-06-15 18:32:38
tags:
- Linux
categories:
- Linux

進程的程序替換,exec 函數族。

fork 創建子進程後執行的是和父進程相同的程序,如果需要他執行不同的代碼分支,子進程旺旺需要調用一種 exec 函數以執行另一個程序。當進程調用一種 exec 函數時,該進程的用戶空間代碼的數據完全被新程序替換,從新程序的啓動例程開始執行。調用 exec 並不創建新的進程,所以調用 exec 前後該進程的 id 並未改變。

當前進程的 .text 和 .data 替換爲所需要加載的程序的 .text 和 .data,然後讓進程從新的 .text 第一條指令開始執行,進程的 id 不變,換核子不換殼子。

exec 函數族的一些參數有些不同,底層實現原理一樣。

SYNOPSIS
     #include <unistd.h>
     extern char **environ;
     int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
     int execle(const char *path, const char *arg0, ... /*, (char *)0, char *const envp[] */);
     int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
     int execv(const char *path, char *const argv[]);
     int execvp(const char *file, char *const argv[]);
     int execvP(const char *file, const char *search_path, char *const argv[]);
  • l(list) : 表示參數採用列表
  • v(vector) : 參數用數組
  • p(path) : 有p自動搜索環境變量PATH
  • e(env) : 表示自己維護環境變量

事實上,只有 execve 是真正的系統調用,其他五個函數最終都調用 execve,所以 execve 在 man 手冊第 2 節,其他函數在 man 手冊的第 3 節。這些函數之間的關係如下圖:

exec函數族,圖片來源於網絡

execl()

加載一個進程,通過 路徑+程序名 來加載。

int execl(const char *path, const char *arg0, ... /*, (char *)0 */);

**返回:**成功:無返回;失敗:-1。

**參數:**path:可執行程序的路徑,如/bin/ls。後面跟要傳給這個程序的參數。

有了這個函數就可以來加載一個自定義的程序了。

栗子:

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

int main(void) {
    pid_t ret = fork();
    if (ret == -1) {
        perror("fork error");
        exit(-1);
    } else if (ret == 0) {
        // 子進程
        execl("/bin/ls", "ls", "-a", NULL);
    } else {
        // 父進程
        sleep(1);
        printf("father process\n");
    }
    return 0;
}

execl_ls.c

execlp()

加載一個進程,藉助 PATH 環境變量。

int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);

**返回:**成功:沒有返回;失敗:-1。

**參數:**file:要加載的程序名。該函數需要配合 PATH 環境變量來使用,當 PATH 中所有目錄搜索後沒有參數 file 則返回出錯。後面跟傳給要執行程序的參數。

該函數通常用來調用系統程序。如:ls、date、cp、cat 等。

栗子:

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

int main(void) {
    pid_t ret = fork();
    if (ret == -1) {
        perror("fork error");
    } else if (ret == 0) {
        // 子進程
        execlp("ls", "ls", "-al", NULL); // 注意第二個參數 ls 對應到main函數的參數就是argv[0],傳給ls其實他並沒有使用這個參數
    } else {
        // 父進程
        sleep(1);
        printf("father process\n");
    }
    return 0;
}

execlp_ls.c

execle()

最後一個參數是一個數組,自己的環境變量數組,這個數組必須以 NULL 結尾。

int execle(const char *path, const char *arg0, ... /*, (char *)0, char *const envp[] */);

execv()

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

栗子:

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

int main(void) {
    pid_t ret = fork();
    if (ret == -1) {
        perror("fork error");
        exit(-1);
    } else if (ret == 0) {
        // 子進程
        char* argv[] = {"ls", "-a", NULL};
        execv("/bin/ls", argv);
    } else {
        // 父進程
        sleep(1);
        printf("father process\n");
    }
    return 0;
}

execv_ls.c


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章