程序替換和exec函式族
阿新 • • 發佈:2019-01-25
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;
}
執行結果:
可以看到,打印出的引數正是我們傳過去的引數,而環境變數也是如此。
——完!