程式程式設計2 – Unix環境高階程式設計8章讀書筆記

ATField發表於2007-03-25

Process Control

1 Process Identifiers

1.     PID=0一般是排程程式,又稱為swapper

2.     PID=1一般是init程式,在引導過程之後啟動,負責啟動整個UNIX系統,所有Orphaned子程式都會自動成為init的子程式

3.     PID=2一般是頁面守護程式,負責將虛擬記憶體的換頁

4.     下面函式被用來獲得pid

#include <unistd.h>

 

pid_t getpid(void);

 

返回程式pid

 

pid_t getppid(void);

 

返回父程式的pid

 

uid_t getuid(void);

 

返回程式的user id

     

uid_t geteuid(void);

 

返回程式的effective user id

 

gid_t getgid(void);

 

返回程式的group id

 

gid_t getegid(void);

 

返回程式的effective group id

 

2 fork

fork函式原型如下:

#include <unistd.h>

 

pid_t fork(void);

 

在子程式中返回0,父程式中返回實際的子程式pid-1則出錯

1.     這個函式建立出一個和父程式相同的子程式,比較特別的是子程式也會從這個函式呼叫,和父程式只是返回值不同。

2.     子程式起初和父程式共享同樣的實體記憶體,當某個頁面被修改的時候,系統會給子程式分配新的空間給這個頁面。這個行為被稱為COW (Copy On Write)

3.     父程式還是子程式先繼續執行無法預測

4.     父程式的所有檔案描述符在子程式中都被呼叫dup函式複製,並且檔案offset是在子程式和父程式之中共享的

5.     子程式繼承了父程式的下列特性:

a.     File Descriptors

b.     Real user ID, real group ID, effective user ID, effective group ID

c.     Supplementary group IDs

d.     Process group ID

e.     Session ID

f.      Controlling terminal

g.     Set-user-ID & set-group-ID flags

h.     Working directory

i.      Root directory

j.      File mode creation mask

k.     Signal mask & dispositions

l.      The close-on-exec flag for any open file descriptions

m.    Environment

n.     Attached shared memory segments

o.     Memory mapping

p.     Resource limits

6.     子程式和父程式不同的地方有:

a.     fork函式的返回值

b.     Process ID

c.     Parent process ID

d.     tms_utime, tms_stime, tms_cutime, tms_cstime = 0

e.     File lock不被子程式繼承

f.      Pending alarm被清除

g.     Pending signal被清除

7.     fork失敗的可能性有:

a.     系統中的程式過多

b.     超過系統設定的limit

3 vfork

vfork的原型和返回值和fork相同,區別在於:

1.     建立的子程式和父程式共享同一個地址空間

2.     建立的子程式一般的作用是再呼叫exec建立一個新的程式,在某些系統上可能會有一些優化

4 exit

1.     當父程式先於子程式退出的時候,子程式會變成orphaned並被init程式“收養”,init成為這些子程式的新的父程式。

2.     當子程式先於父程式退出的時候,而且父程式也沒有用wait, waitpid函式等待子程式結束,則子程式的部分資訊會被儲存起來,如PID,退出狀態,CPU時間等,直到子程式被wait。處於這樣狀態的子程式被稱為zombie

3.     init程式inherit的子程式如果中止不會變成zombie,因為init會自動當程式結束的時候呼叫wait

5 wait & waitpid

1.     當子程式結束的時候,父程式會收到SIGCHLD通知

2.     程式可以呼叫wait / waitpid等待此Signal

a.     當所有子程式都在執行的時候,會block

b.     當某個子程式中止,成為zombie的時候,立刻返回

c.     如果沒有任何子程式,則返回錯誤

3.     waitwaitpid函式原型如下:

#include <unistd.h>

 

pid_t wait(void);

 

pid_t waitpid(pid_t pid, int *statloc, int options);

 

正常情況下返回pid,或者0waitpid在非block模式下才有可能返回),-1代表錯誤

 

4.     這兩個函式區別如下:

a.     Wait函式會因為等待子程式結束而block,而waitpid有一個option可以允許waitpid函式不block

b.     waitpid等待某個特定程式

5.     waitpid函式的statloc引數儲存了退出程式的狀態,當然也可以傳NULL。這個狀態通常和實現相關,不過可以用wait.h中定義的macro來檢測。

a.     WIFEXITED(status):返回值

b.     WIFSIGNALED(status):返回造成退出的signalnumber

c.     WIFSTOPPED(status):是否被stop,可以用WSTOPSIGstatus)來獲得具體的signal

d.     WIFCONTINUED(status):返回是否被continue

6.     waitpidpid引數:

a.     pid == -1:等待任意子程式,等價於wait

b.     pid > 0,等待pid指定的子程式

c.     pid == 0,等待和呼叫程式相同group id的任意子程式

d.     pid < -1,等待任意group id = pid的絕對值的子程式

7.     waitpidoptions引數可以是下面的組合:

a.     WCONTINUED:等待任何指定的子程式在stop之後被continue

b.     WNOHANG:如果還沒有退出,不block,返回0

c.     WUNTRACED:被stopped的程式

 

6 waitid

waitid函式在waitpid函式上提供了額外的靈活性:

#include <unistd.h>

 

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

 

成功返回0,錯誤返回-1

1.     idtype_t可以是下面的值之一:

a.     P_PID:等待某指定的子程式

b.     P_PGID:等待任意指定group id的子程式

c.     P_ALL:任意子程式,id會被忽略

2.     Options可以是下面的值:

a.     WCONTINUED:等待被stop並且被continue的程式

b.     WEXITED:等待退出的程式

c.     WNOHANG:如果沒有子程式需要等待則立刻返回

d.     WNOWAIT:不會將zombie子程式的退出狀態撤銷,下次呼叫wait系列函式的時候還可以繼續獲得這個退出狀態

e.     WSTOPPED:等待被stop的程式

3.     Infop指向一個siginfo_t結構,表示使得程式退出的signal的產生原因:

 

struct siginfo_t {

      int   si_signo;   /* signal */

      int   si_errno;   /* errrno */

      int   si_code;    /* 額外資訊,和具體signal相關 */

      pid_t si_pid;     /* 傳送signal程式的pid */

      uid_t si_uid;     /* 傳送signal的程式的uid */

      void  *si_addr;   /* 產生fault(SIG_SEGV)的地址 */

      int   si_status;  /* 退出值或者signal數值 */

      long  si_band;    /* SIGPOLLband數值 */

};

 

7 wait3 & wait4

這兩個函式的用處是返回額外的關於程式資源使用狀況的資訊,以struct rusage *rusage的形式返回

8 exec functions

之前提到了vfork可以建立一個並非是父程式copy的子程式,專門用來呼叫exec函式。exec系列函式的作用是呼叫一個新的程式在該程式中執行,PID不改變,也沒有建立新程式,只是replace當前的程式,該函式成功情況下不會返回。原型如下:

#include <unistd.h>

 

int execl(const char *pathname, const char *arg0, … /* (char *) 0 */ );

 

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

 

int execle(const char *pathname, const char *arg0, … /* (char *)0, char *const envp[] */);

 

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

 

int execlp(const char *filename, const char *arg0, … /* (char *)0 */ );

 

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

 

錯誤返回-1,成功不會返回

 

1.     前面4個是pathname,後面兩個則是filenameFilename如果有’/’字元,則被認為是pathname,否則認為是filename並會在PATH路徑指定的位置查詢

2.     execlpexecvp對於非可ELF執行檔案會認為是Shell指令碼來處理

3.     execl, execlp, execle需要每個引數單獨傳遞,NULL作為結束。而execv, execvp, execve則是傳入argv

4.     execle, execve可以傳入環境,其他四個函式則會使用environ變數中的內容

總結一下,各個字元代表的意義是:

1.     v:用argv傳入引數

2.     l:用每個引數作為argument傳入

3.     e:傳入環境,沒有的話則使用environ變數的值

4.     p:傳入的是filename,並會處理PATH的內容,否則是pathname

需要注意的是,exec呼叫之後程式的real user IDreal group ID不變,如果被執行的程式的set-user-ID位被設定,effective user ID被設定成owner ID。也就是說,如果一個normal userexec執行了一個ownersuperuser的程式,並且該程式的set-user-id被設定,那麼一旦該程式被執行,該程式的effective user id=super user,這可能是潛在的安全問題。

9 Change User IDs and Group IDs

1.     User ID & Group ID的意義如下:

ID

Description

real user ID

real group ID

真正的user IDgroup ID

effective user ID

effective group ID

supplementary group ID

用於檔案訪問許可權檢查

saved set-user-ID

saved set-group-ID

exec儲存起來。如果沒有提供這個feature(通過_POSIX_SAVED_IDS)可以判斷,則這些ID不存在

 

2.     setuid setgid函式用來設定User ID / Group ID,原型如下:

#include <unistd.h>

 

int setuid(uid_t uid);

 

int setgid(gid_t gid);

 

成功返回0,錯誤返回-1

 

3.     setuid的規則如下:

a.     有超級使用者的許可權的程式,setuid會修改real user id, effective user ID, & saved set-user-IDuid

b.     當程式沒有超級使用者許可權,並且uid = real user ID / saved set-user-ID的話,setuid會修改effective user IDuid

c.     否則,errno被設定為EPERM,返回-1

d.     上面這些規則也適用於setgid

4.     對於uid下面規則成立:

a.     只有超級使用者的程式才可以改變real user ID。一般情況下不會改變real user ID

b.     當程式的set-user-ID位被設定,exec才會設定effective user ID為程式的user ID,否則則不改變

c.     Saved set-user-IDexec所設定的effective user ID拷貝而來

5.     POSIX.1還提供了兩個函式seteuidsetegid,用來修改effective user ID / effective group ID

a.     對於一般使用者,只能設定effective user IDreal user ID或者saved set-user-ID,不能為其他值

b.     對於超級使用者,可以設定effective user ID為任意值

 

10 system

1.     System函式用於執行引數中給出的string,呼叫程式

2.     System函式的基本實現是呼叫fork,在子程式中呼叫exec執行/bin/sh或者其他shell,執行命令,父程式呼叫waitpid等待子程式的結束

3.     之前在討論exec的時候提到過, exec呼叫之後程式的real user IDreal group ID不變,如果被執行的程式的set-user-ID位被設定,effective user ID被設定成owner ID。也就是說,如果一個normal userexec執行了一個ownersuperuser的程式,並且該程式的set-user-id被設定,那麼一旦該程式被執行,該程式的effective user id=super user (real user ID不變)這可能是潛在的安全問題。這個問題同樣適用於system

11 User Identification

getlogin函式可以獲得使用者名稱:

#include <unistd.h>

 

char *getlogin(void);

 

成功返回具體name,錯誤返回NULL

 

12 Process Times

times函式可以獲得和程式相關的時間:

#include <sys/times.h>

 

clock_t times(struct tms *buf);

 

成功返回wall clock time,錯誤返回-1

tms結構如下:

struct tms {

      clock_t     tms_utime;        /* user CPU time */

      clock_t     tms_stime;        /* system CPU time */

      clock_t     tms_cutime;       /* user CPU time, terminated children */

      clock_t     tms_cstime;       /* system CPU time, terminated children */

};

 

作者:      ATField
Blog:     
http://blog.csdn.net/atfield

相關文章