1. 程式人生 > >程序替換和exec函式族

程序替換和exec函式族

fork 建立的子程序一般不會執行和父程序相同的程式碼段,而是呼叫 exec 相關函式,將該程序的使用者空間程式碼和資料完全替換,子程序從替換的新程式啟動執行。exec僅僅是替換程式碼和資料,並不會建立新程序,所以被替換的程序 id 和子程序 id 相等。

如下圖:
這裡寫圖片描述

新程序從呼叫程序繼承了下列屬性:

  • 程序 ID 和父 ID,實際使用者 ID 和實際組 ID
  • 附屬組 ID,程序組 ID,回話 ID
  • 控制終端
  • 鬧鐘尚預留的時間
  • 當前工作目錄
  • 根目錄
  • 檔案模式建立遮蔽字
  • 檔案鎖
  • 程序訊號遮蔽字
  • 未處理訊號
  • 資源限制
  • nice值
  • tms_utime, tms_stime, tms_cutime, tms_cstime

exec函式族

函式 引數格式 是否帶路徑 是否使用當前環境變數
int execl(const char * path,const char * arg, …); list 不帶
int execlp(const char * file,const char * arg, …); list
int execle(const char * path,const char * arg, … char const *envp[]); list 不帶 需自己組裝環境變數
int execv(const char * path,char* const argv[]); array 不帶
int execvp(const char * file,char* const argv[]); array
int execve(const char * path,char* const argv[], char const *envp[]); array 不帶 需自己組裝環境變數

引數:

  • 根據命名可以看出,名字中的 l 表示新程序的引數通過exec可變引數列表傳過去,因此帶 l 的函式引數列表都有 ... 代表可變引數;
  • 而帶 v 的函式,新程序的引數則是通過 一個字串陣列傳過去;
  • 名字中帶 p 的代表會自動到環境變數PATH 中搜索新程序,而不帶 p 的,則第一個引數必須是相對路徑或者絕對路徑;
  • 對於帶 e 的代表可以自己組裝一份環境變數,通過引數3傳遞給新程序。

返回值:

替換成功,則從新程序開始執行,不會返回,失敗返回-1,;所以該函式只要返回,就說明程序替換失敗。

事實上這些函式最終都調了系統呼叫 execve, 如下圖:
這裡寫圖片描述

看下面這個例子:
hello.c

#include <stdio.h>

int main(int argc, char *argv[], char *env[])
{
    int i = 0;
    for(; i < argc; i++){
        printf("argv[%d]: %s\n", i, argv[i]);
    }

    int j = 0;
    while(env[j]){
        printf("%s\n", env[j]);
        j++;
    }

    return 0;
}

exec.c

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

extern char **environ;

int main()
{
    const char *path= "./hello";
    char* const arg[] = {"aaa", "bbb", "ccc", NULL};
    char* const env[] = {"MYENV=myenv", NULL};
    execve(path, arg, env);

    return 0;
}

執行結果:
這裡寫圖片描述

可以看到,打印出的引數正是我們傳過去的引數,而環境變數也是如此。

——完!