exec族函式的詳細說明
簡介
我們知道fork()函式可以建立一個和父程序相同的程式,但是我們往往需要子程序執行另一個程式,這個時候就要呼叫一種exec函式以執行另一個程式。當程序呼叫exec函式時,該程序的使用者空間程式碼和資料完全被新的程式替換,從新的程式啟動例程開始執行。呼叫exec並不建立新程式,所以呼叫exec前後該程序的id並未改變。同樣,exec後的新程序會繼承子程序很多東西,包括檔案描述符表和檔案鎖。
exec函式有六種形式
int execl(const char *path,const char *arg,…)
int execlp(const char *file,const char *arg,…)
int execle(const char *path,const char *arg,…,char *const envp[])
int execv(const char *path,char *const arg[])
int execvp(const char *file,char *const arg[])
int execve(const char *path,char *const arg[],char *const envp[])
這六個以exec開頭的函式都是根據指定的檔名找到可執行檔案,並用它來取代呼叫程序的內容,換句話說,就是在呼叫程序內部執行一個可執行檔案。
前三個含有字母l,後三個含有字母v,帶有l的代表引數列表一一列舉在函式的引數中,並要求以NULL結尾;帶有v的代表引數列表放在一個以NULL結尾的指標陣列之中(即第二個引數)。
帶有字母p的代表2個以p結尾的函式execlp和execvp,看起來,和execl與execv的差別很小,事實也如此,它們的區別從第一個引數名可以看出:除 execlp和execvp之外的4個函式都要求,它們的第1個引數path必須是一個完整的路徑,如”/bin/ls”;而execlp和execvp 的第1個引數file可以僅僅只是一個檔名,如”ls”,這兩個函式可以自動到環境變數PATH指定的目錄裡去查詢。
帶有字母e的是指給可執行檔案指定環境變數。在全部6個函式中,只有execle和execve使用了char *envp[]傳遞環境變數,其它的4個函式都沒有這個引數,這並不意味著它們不傳遞環境變數,這4個函式將把預設的環境變數不做任何修改地傳給被執行的應用程式。而execle和execve用指定的環境變數去替代預設的那些。
注意
與其他系統呼叫比起來,exec很容易失敗,被執行檔案的位置,許可權等很多因素都能導致呼叫失敗。因此,使用exec函式族時,一定要加錯誤判斷語句。
exec函式族的函式執行成功後不會返回,因為呼叫程序的實體,包括程式碼段,資料段和堆疊等都已經被新的內容取代,只有程序ID等一些表面上的資訊仍保持原樣。呼叫失敗時,會設定errno並返回-1,然後從原程式的呼叫點接著往下執行。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main(int argc,char *argv[])
{
char* arg[] = {"pwd",NULL};
char* envp[] ={"PATH=/tmp","USER=lingdxuyan","STATUS=testing",NULL};
//execl函式
if(fork() == 0)
{
printf("execl\n");
if(execl("/bin/ls","ls","-a",NULL) == -1)
{
perror("execl error");
exit(1);
}
}
execv函式
if(fork() == 0)
{
printf("execv");
if(execv("/bin/pwd",arg))
{
perror("execv error");
exit(1);
}
}
//execlp函式
if(fork() == -1)
{
if(execlp("pwd","pwd",NULL) == -1)
{
perror("execp error");
exit(1);
}
}
//execvp函式
if(fork() == 0)
{
if(execvp("pwd",arg) == -1)
{
perror("execvp error");
exit(1);
}
}
//execle函式
if(fork() == 0)
{
if(execle("/bin/pwd",pwd,NULL,envp))
{
perror("execle error");
exit(1);
}
}
//execve函式
if(fork() == 0)
{
if(execve("/bin/pwd",arg))
{
perror("execve error");
exit(1);
}
}
}