一、APUE這一章中的各種晦澀名詞 我在讀這一章時遇到了各種ID,根據名字完全不清楚什麼意思,幸好看到了這篇文章,http://blog.csdn.net/ccjjnn19890720/article/details/6990656,總結一下 每一個進程其實對應了6個以上的ID,它們分別是:實際用戶 ...
一、APUE這一章中的各種晦澀名詞
我在讀這一章時遇到了各種ID,根據名字完全不清楚什麼意思,幸好看到了這篇文章,http://blog.csdn.net/ccjjnn19890720/article/details/6990656,總結一下
每一個進程其實對應了6個以上的ID,它們分別是:實際用戶ID、實際組ID(我們實際上是誰,執行這個程式的用戶和組),有效用戶ID、有效組ID、附加組ID(用於文件訪問許可權檢查),保存設置用戶ID,保存設置組ID(由exec函數保存)
實際用戶ID/實際組ID:當前執行這個進程的ID,比如我現在是orlion用戶,那麼我執行foo程式,那麼這個foo進程的實際用戶ID就是orlion。組同理
有效用戶ID/有效組ID:這個ID是unix一直在使用的一個ID,因為即使你只是一個很簡單的訪問文件,那也是要通過這個有效用戶ID的,因為每一個文件都有一定的訪問許可權,而一個進程或者一個程式去訪問它,操作系統本身就是根據你的有效用戶ID給與一定的許可權.
實際用戶ID與有效用戶ID到底什麼區別?!:這兩個ID在一般情況下是相同的,比如當前用戶是orlion,那麼它的實際用戶ID是orlion,而有效用戶ID也是orlion。可是在不一般的情況下那麼這兩個ID就可能不一樣了,那麼什麼樣的情況下是不一樣的呢?那就是當一個用戶要進行一個合理的特權的時候就需要啦,那麼到底是怎麼樣的情況呢?
比如我們在Linux系統中的passwd這個命令或者這個passwd這個程式,一個用戶對自己進行修改密碼是一種很正常的事情,可是保存密碼的文件/etc/passwd卻是root用戶可寫的這樣的權利,那麼也就是用如果你要修改密碼,必須通過root用戶幫你修改
這個事情的處理是這樣的,讓用戶去運行passwd這個程式的時候,os給與root用戶的權利,然後用戶就可以修改自己的密碼。具體的講就是讓用戶去運行passwd這個程式的時候,unix將它的有效用戶ID變成了擁有passwd的用戶的ID,也就是root,所以就可以修改這個/etc/passwd這個文件。
保存設置用戶ID:這個ID是用來保存有效ID的副本,讓我們運行程式的過程其實就是os調用exec系列函數來調用我們程式的main函數,exec函數是kernel唯一執行程式的方法,或者那麼講不管什麼用戶程式的運行,其實也就是os的exec的調用過程。而exec在調用過程中會將這個程式的有效用戶ID拷貝給保存用戶ID。
文件的設置用戶ID位:每一個文件都有一個文件模式字(st_mode),這個字可以通過stat函數去獲取,而這個模式字包含了很多文件的屬性,包括文件的類型,以及文件的訪問許可權的,當然設置用戶ID位也在其中。通過設置這個位,就能當執行這個文件的時候,進程的有效ID設置為該文件本身的用戶,這裡這個文件可以認為是可執行文件,當運行這個文件的時候,進程會改變其有效用戶ID,變成這些文件本身的ID
終端中我們查看/usr/bin/passwd這個文件
$ ll /usr/bin/passwd -rwsr-xr-x. 1 root root 30768 2月 22 2012 /usr/bin/passwd
可以看到有一個s許可權,這就是設置了設置用戶ID位的標誌。
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> int main() { printf("real user ID = %d\n",getuid()); printf("effect user ID = %d\n",geteuid()); return 0; }
終端中執行: orlion$ ./main real user ID = 1000 effect user ID = 1000 orlion$ su root# chown root main root# chmod u+s main root# ll main -rwsr-xr-x 1 root orlion 9809 2016-12-21 22:20 main root# exit orlion$ exit orlion$ ./main real user ID = 1000 effect user ID = 0
從以上可以看到有效用戶id發生了變化
二、chmod和fchmod函數
這兩個函數使我們可以更改現存文件的存取許可權(許可權)
#include <sys/types.h> #include <sys/stat.h> int chmod(const char *pathname, mode_t mode); int fchmod(int fileds, mode_t mode); fileds即為文件句柄
返回值: 若成功則為0,若出錯則為-1
為了改變一個文件的許可權,進程的有效用戶ID必須等於文件的所有者,或者有root許可權
參數mode是下麵所示逐位或運算
mode 說明明 S_ISUID 執行時設置 -用戶-ID S_ISGID 執行時設置 -組-ID S_ISVTX 保存正文 S_IRWXU 用戶(所有者)讀、寫和執行 S_IRUSR 用戶(所有者)讀 S_IWUSR 用戶(所有者)寫 S_IXUSR 用戶(所有者)執行 S_IRWXG 組讀、寫和執行 S_IRGRP 組讀 S_IWGRP 組寫 S_IXGRP 組執行
S_IRWXO 其他讀、寫、和執行
S_IROTH 其他讀
S_IWOTH 其他寫
S_IXOTH 其他執行
實例:
#include <stdio.h> #include <sys/stat.h> int main(void) { struct stat statbuf; if (stat("foo", &statbuf) < 0) { fprintf(stderr, "stat error for foo\n"); } if (chmod("foo", (statbuf.st_mode & -S_IXGRP) | S_ISGID) < 0) { fprintf(stderr, "chmod error for foo\n"); } /* set absolute mode to "rw-r--r--" */ if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { fprintf(stderr, "chmod error for bar\n"); } return 0; }
三、 粘住位
上一小節中S_ISVTX位,UNIX早期版本中,有一位被稱為粘住位(sticky bit)。如果一個可執行程式文件的這一位被設置了,那麼在該程式第一次執行並結束時,該程式正文的一個文本被保存在交換區。 (程式的正文部分是機器指令部分。 )這使得下次執行該程式時能較快地將其裝入記憶體區。其原因是:在交換區,該文件是被連續存放的,而在一般的 U N I X文件系統中,文件的各數據塊很可能是隨機存放的。對於常用的應用程式,例如文本編輯程式和編譯程式的各部分常常設置它們所在文件的粘住位。後來的UNIX版本稱之為保存 -正文位( saved-text bit ),因此也就有了常數 S _ I S V T X。現今較新的UNIX系統大多數都具有虛存系統以及快速文件系統,所以不再需要使用這種技術。
S V R 4和4 . 3 + B S D中粘住位的主要針對目錄。如果對一個目錄設置了粘住位,則只有對該目錄具有寫許可權的用戶並且滿足下列條件之一,才能刪除或更名該目錄下的文件:
• 擁有此文件。
• 擁有此目錄。
• 是超級用戶。
目錄/tmp和/var/spool/uucppublic是設置粘住位的候選者 —,這兩個目錄任何用戶都可在其中創建文件。這兩個目錄對任一用戶 (用戶、組和其他 )的許可權通常都是讀、寫和執行。但是用戶不應能刪除或更名屬於其他人的文件,為此在這兩個目錄的文件方式中都設置了粘住位。
四、 chown、fchown和lchown函數
#include <sys/types.h> #include <unistd.h> int chown(const char *pathname, uid_t owner, gid_t group); int fchown(int filedes, uid_t owner, gid_t group); int lchown(const char *pathname, uid_t owner, gid_t group); 返回值:成功0,失敗-1.
lchown更改符號連接本身的所有者,而不是符號鏈接所指向的文件
根據_POSIX_CHOWN_RESTRICTED的值,POISX.1可以選擇只有超級用戶才能更改某個文件的所有者或者任何用戶都能修改他們所擁有的文件的所有者。
若_POSIX_CHOWN_RESTRICTED對指定的文件起作用,則
(1) 只有超級用戶進程能更改該文件的用戶 ID。
(2) 若滿足下列條件,一個非超級用戶進程可以更改該文件的組 ID:
(a) 進程擁有此文件(其有效用戶 ID等於該文件的用戶 ID)。
(b) 參數owner等於文件的用戶ID,參數group等於進程的有效組ID或進程的添加組ID之一。
這意味著,當 _ P O S I X _ C H O W N _ R E S T R I C T E D有效時,不能更改其他用戶的文件的用戶ID。你可以更改你所擁用的文件的組 ID,但只能改到你所屬於的組。
如果這些函數由非超級用戶進程調用,則在成功返回時,該文件的設置 -用戶-ID位和設置-組-ID位都被清除。
五、 文件長度
stat結構的成員st_size包含了以位元組為單位該文件的長度。此欄位只對普通文件、目錄、符號連接有意義。
對於目錄文件長度通常市一個數,例16或512的整數倍;
對於符號連接,文件長度是實際文件的長度。
六、 文件截短
有時我們需要在文件尾端截去一些數據以縮短文件,截短文件可以調用以下函數
#include <sys/types.h> #include <unistd.h> int truncate(const char *pathname, off_t length); int ftruncate(int filedes, off_t length); 返回值:成功0,失敗-1.
這兩個函數將文件的長度截短為length, 如果之前文件長度大於length,則超過length以外的數據就不再存取,如果以前的長度小於length,則其結果與系統有關。如果某個系統的處理是擴展該文件,則超過舊文件尾端與新文件尾端數據將讀作0。
七、 文件系統
傳統的UNIX系統V文件系統,可以將一個硬碟分為多個分區,每個分區可以包含一個文件系統
i節點是固定長度的記錄項,包含有關文件的信息。
- 上圖中有兩個目錄指向同一i節點。每個i節點中都有一個連接計數,其值是指向該i節點的目錄項數。只有當連接計數為0時才能刪除該文件(也就是可以釋放該文件所占的數據塊)。在stat結構中連接計數包含在st_nlink中,其基本系統數據類型是nlink_t。這種連接稱為硬連接。POSIX.1常數LINK_MAX指定了一個文件連接的最大值。
- 另外一種連接是符號連接(symbolic link)。對於這種連接,該文件的實際內容(在數據塊中)包含了該符號連接所指向的文件的名字。
- i節點包含了所有與文件有關的信息:文件類型、文件存取許可權位、文件長度和指向該文件所占用的數據塊的指針等。stat結構中大多數信息都取自i節點。只有兩項數據存放在目錄項中:文件名和i節點編號數。i節點編號數的數據類型是ino_t。
- 因為目錄項中的i節點編號數指向同一文件系統中的i節點,所以不能使一個目錄項指向另一個文件系統的i節點。(所以ln命令不能跨文件系統)
- 當在不更改文件系統的情況下為一個文件更名時,該文件的實際內容並未移動,只需構造一個指向現存i節點的新目錄項。
對於目錄文件的連接計數欄位:假如我們創建了一個testdir目錄:
$ mkdir testdir
下圖顯示了其結果,顯式的顯示了.和..目錄項
2549的i節點,其類型欄位表示它是一個目錄,其類型欄位表示它是一個目錄。而連接計數為2。任何一個葉目錄(不包含任何目錄(子目錄)的目錄)其連接計數總是2,數值2來自於命名該目錄(testdir)的目錄以及在該目錄中的.項。編號為1267的i節點,其類型欄位表示它是一個目錄,而其連接計數則大於或等於3。它大於等於3的原因是至少有三個目錄項指向它:一個是命名它的目錄項,一個是在該目錄中的.項,第三個是在自子目錄testdir中的..項。