系統資料檔案和資訊
使用者配置檔案
1. /etc/passwd
/etc/passwd
- UNIX密碼檔案
是一個/etc/passwd/
檔案,每一行包含很多字段,字段之間用冒号分隔。這些字段包含在ASCII
頭檔案定義的<pwd.h>
,該結構有如下成員:passwd
-
:使用者名char *pw_name
-
:加密密碼char *pw_passwd
-
:數值使用者IDuid_t pw_uid
-
:數值組IDgid_t pw_gid
-
:注釋字段char *pw_gecos
-
:初始工作目錄char *pw_dir
-
:初始char *pw_shell
shell
-
:使用者通路類char *pw_class
-
:下次更改密碼時間time_t pw_change
-
:賬戶有效期時間time_t pw_expire
- 通常有一個使用者名為
的登入項,其使用者ID是 0root
- 加密密碼字段包含一個占位符。現在加密密碼其實是放在
中/etc/shadow
- 密碼檔案中某些字段可能為空。
- 如果加密密碼字段為空,則說明該使用者沒有密碼,沒有密碼則不能登入
-
字段指定了初始shell
shell
- 若它為空,則取系統預設值(通常是
)linux下為/bin/sh
/bin/bash
- 若它為
,則會阻止任何人以該字段所在行記錄中的使用者名來登入系統/dev/null
- 若它為空,則取系統預設值(通常是
- 使用者名如果是
,則任何人都可以使用它登入系統,但是其使用者ID群組ID不提供任何特權。該使用者ID群組ID隻能通路人人皆可讀、可寫的檔案nobody
- 在
中,沒有Linux
字段pw_class,pw_change,pw_expire
-
注意如果要将一個使用者設為不能登入
1.可以将其shell設為
/bin/false
或
/bin/true
2.可以在
/etc/shadow
下将密碼字段前加
!!
或
*
-
函數:讀取密碼檔案:getpwuid/getpwnam
#include<pwd.h> struct passwd* getpwuid(uid_t uid); struct passwd* getpwnam(const char*name);
- 參數:
-
:使用者IDuid
-
:使用者名name
-
- 傳回值:
- 成功:傳回
結構的指針passwd
- 失敗:傳回
NULL
- 成功:傳回
函數傳回的getpwuid/getpwnam
結構通常是函數内部的靜态變量,是以多次調用上面的函數,該靜态變量會被覆寫。struct passwd
- 參數:
- 檢視整個密碼檔案,使用下面的函數:
#include<pwd.h> struct passwd *getpwent(void); void setpwent(void); void endpwent(void);
-
傳回值:getpwent
- 成功:傳回
結構的指針passwd
- 失敗:傳回
NULL
- 到達檔案尾端:傳回
NULL
- 成功:傳回
- 調用
時,它傳回密碼檔案中的下一個記錄項getpwent
傳回的
結構通常是函數内部的靜态變量,是以多次調用struct passwd
函數,該靜态變量會被覆寫getpwent
-
- 在第一次調用
函數時,它會打開所使用的各個檔案getpwent
-
對傳回的各個記錄項順序并沒有要求getpwent
-
會反繞setpwent
所使用的檔案到檔案起始處。即當調用getpwent
之後,setpwent
又會從頭開始讀取記錄項getpwent
-
會關閉endpwent
所使用的檔案。在調用getpwent
讀取完密碼檔案後,一定要調用getpwent
關閉這些檔案endpwent
知道什麼時候應該打開它所使用的檔案(第一次被調用時),但是不知道何時應該關閉這些檔案getpwent
- 加密密碼是經單向加密算法處理過的使用者密碼副本。
因為此算法是單向的,是以不能從加密密碼猜測到原始密碼
現在的UNIX将加密密碼存放在一個稱作陰影密碼的檔案中(即檔案
)。該檔案至少應該包含使用者名和加密密碼。這些字段包含在/etc/shadow
頭檔案的<shadow.h>
結構中。相關的字段如下:struct spwd
-
:使用者登入名char *sp_namp
-
:加密密碼char *sp_pwdp
-
:上次更改密碼以來經過的時間int sp_lstchg
-
:經過多少天後允許修改密碼int sp_min
-
:經過多少天後必須修改密碼int sp_max
-
:經過多少天後如果未修改密碼則系統發出警告int sp_warn
-
:經過多少天後,該賬戶是int sp_inact
inactive
-
:經過多少天後,該賬戶過期int sp_expire
-
:保留字段unsigned int sp_flag
其中隻有使用者登入名和加密密碼這兩個字段是必須的。其他字段都是用于控制密碼更改的頻率。
注意:
- 陰影密碼檔案
不應該由一般使用者讀取。/etc/shadow
- 僅有少數幾個程式需要通路加密密碼,如
。這些程式通常是設定使用者ID為login,passwd
的程式root
- 普通密碼檔案
可以任由各使用者讀取/etc/passwd/
- 僅有少數幾個程式需要通路加密密碼,如
-
- 用于讀取陰影密碼檔案的函數為:
#include<shadow.h> struct spwd *getspnam(const char*name); struct spwd *getspent(void); void setspent(void); void endspent(void);
-
參數:getspnam
-
:使用者名name
-
-
傳回值:getspnam
- 成功:傳回
結構指針spwd
- 失敗:傳回
NULL
- 成功:傳回
-
傳回值:getspent
- 成功:傳回
結構指針spwd
- 失敗:傳回
NULL
- 到達檔案尾端:傳回
NULL
- 成功:傳回
- 調用
時,它傳回陰影密碼檔案中,對應使用者名的那一條記錄項getspnam
傳回的
結構通常是函數内部的靜态變量,是以多次調用struct spwd
函數,該靜态變量會被覆寫getspnam
-
- 調用
getspent
時,它傳回陰影密碼檔案中的下一個記錄項
傳回的
結構通常是函數内部的靜态變量,是以多次調用struct spwd
函數,該靜态變量會被覆寫getspent
- 在第一次調用
函數時,它會打開所使用的各個檔案getspent
-
對傳回的各個記錄項順序并沒有要求getspent
-
會反繞setspent
所使用的檔案到檔案起始處。即當調用getspent
之後,setspent
又會從頭開始讀取記錄項getspent
-
會關閉endspent
所使用的檔案。在調用getspent
讀取完陰影密碼檔案後,一定要調用getspent
關閉這些檔案endspent
知道什麼時候應該打開它所使用的檔案(第一次被調用時),但是不知道何時應該關閉這些檔案getspent
- UNIX 組檔案包含的字段定義在
所定義的<grp.h>
結構中:group
-
:組名char *gr_name
-
:加密密碼char *gr_passwd
-
:組IDint gr_gid
-
:指向各使用者名指針的數組char **gr_mem
它是一個指針數組,其中每個指針指向一個屬于該組的使用者名。該數組以
指針結尾null
-
-
函數:檢視組檔案:getgrgid/getgrnam
#include<grp.h> struct group* getgrgid(gid_t gid); struct group* getgrnam(const char* name);
- 參數:
-
:組IDgid
-
:組名name
-
- 傳回值:
- 成功:傳回
結構的指針group
- 失敗:傳回
NULL
- 成功:傳回
函數傳回的getgrgid/getgrnam
結構通常是函數内部的靜态變量,是以多次調用上面的函數,該靜态變量會被覆寫。struct group
- 參數:
- 檢視整個組檔案,使用下面的函數:
#include<grp.h> struct group *getgrent(void); void setgrent(void); void endgrent(void);
-
傳回值:getgrent
- 成功:傳回
結構的指針group
- 失敗:傳回
NULL
- 到達檔案尾端:傳回
NULL
- 成功:傳回
- 調用
時,它傳回組檔案中的下一個記錄項getgrent
傳回的
結構通常是函數内部的靜态變量,是以多次調用struct group
函數,該靜态變量會被覆寫getgrent
-
- 在第一次調用
函數時,它會打開所使用的各個檔案getgrent
-
對傳回的各個記錄項順序并沒有要求getgrent
-
會反繞setgrent
所使用的檔案到檔案起始處。即當調用getgrent
之後,setgrent
又會從頭開始讀取記錄項getgrent
-
會關閉endgrent
所使用的檔案。在調用getgrent
讀取完組檔案後,一定要調用getgrent
關閉這些檔案endgrent
知道什麼時候應該打開它所使用的檔案(第一次被調用時),但是不知道何時應該關閉這些檔案getgrent
- UNIX中還提供了附屬組ID。其中擷取和設定附屬組ID的函數為:
參數:#include<unistd.h> int getgroups(int gidsetsize,gid_t grouplist[]); #include<grp.h> //對Linux #include<unistd.h> //對 FreeBSD, Mac OS X, Solaris int setgroups(int ngroups,const gid_t grouplist[]); #include<grp.h> //對Linux #include<unistd.h> //對 FreeBSD, Mac OS X, Solaris int initgroups(const char *username, gid_t basegid);
- 對于
函數:getgroups
-
:填入gidsetsize
數組的附屬組ID的最大數量grouplist
若該值為0,則函數隻傳回附屬組ID數,而不修改
數組grouplist
-
:存放附屬組ID的數組grouplist
-
- 對于
函數:setgroups
-
:ngroups
grouplist
數組中元素個數
數量不能太大,不能超過
NGROUPS_MAX
-
:待設定的附屬組ID的數組grouplist
-
- 對于
函數:initgroups
-
:使用者名username
-
:使用者的basegid
組ID(它就是在密碼檔案中,使用者名對于的組ID)base
-
- 對于
函數:getgroups
- 成功:傳回附屬組ID的數量
- 失敗:傳回 -1
- 對于
函數:setgroups/initgroups
- 成功:傳回 0
- 失敗:傳回 -1
-
函數将程序所屬使用者的各附屬組ID填寫到getgroups
中,填入該數組的附屬組ID數最多為grouplist
個。實際填寫到數組中的附屬組ID數由函數傳回gidsetsize
-
函數可由超級使用者調用以便為調用程序設定附屬組ID表。setgroups
- 由于
函數會在内部調用initgroups
函數,是以它也必須由超級使用者調用setgroups
- 對于
- 除了密碼檔案群組檔案之外,系統中還有很多其他重要的資料檔案。UNIX對于這些系統資料檔案提供了對應的類似的API。對于每種資料檔案,至少有三個函數:
-
函數:讀下一個記錄。如果需要還會打開該檔案。get
- 此種函數通常傳回一個指向某個結構的指針。
- 當已到達檔案尾端時,傳回空指針
- 大多數
函數傳回指向一個靜态存儲類結構的指針,如果需要儲存其内容,則需要複制該結構get
-
函數:打開相應資料檔案(如果尚未打開),然後反繞該檔案set
- 如果希望在相應檔案起始處開始處理,則調用該函數
-
函數:關閉相應資料檔案。在結束了對相應資料檔案的讀、寫操作後,總應該調用此函數以關閉所有相關檔案end
另外如果資料檔案支援某種形式的鍵搜尋,則也提供搜尋具有指定鍵的記錄的函數
下面是各個重要的資料檔案:
說明 資料檔案 頭檔案 結構 附加的鍵搜尋函數 密碼 /etc/passwd passwd getpwnam,getpwuid 組 /etc/group group getgrnam,getgrgid 陰影 /etc/shadow -
時間和日期
- UNIX核心提供的基本時間服務是自 UTC 1970-01-01 00:00:00 這一特定時間以來經過的秒數。
- 這個時間稱作月曆時間,用資料類型
表示(它包括了時間和日期)time_t
- UNIX 提供若幹個時間函數來轉換月曆時間
- 這個時間稱作月曆時間,用資料類型
-
函數:傳回目前的月曆時間time
#include<time.h> time_t time(time_t *calptr);
- 參數:
-
:如果該指針不是calptr
,則傳回的月曆時間也存放在NULL
指向的記憶體中calptr
-
- 傳回值:
- 成功:傳回目前月曆時間的值
- 失敗:傳回 -1
- 參數:
-
函數:用于擷取指定的時鐘類型的時間:clock_gettime
#include<sys/time.h> int clock_gettime(clockid_t clock_id,struct timespec *tsp);
- 參數:
-
:時鐘類型。clock_id
-
:擷取實時系統時間。此時CLOCK_REALTIME
函數提供了與clock_gettime
函數類似的功能。不過在系統支援高精度時間值的情況下,time
可能比clock_gettime
函數得到更高精度的時間值。time
-
:擷取不帶負跳數的實時系統時間CLOCK_MONOTONIC
-
:調用程序的CPU時間CLOCK_PROCESS_CPUTIME_ID
-
:調用線程的CPU時間CLOCK_THREAD_CPUTIME_ID
-
-
:存放擷取時間的tsp
結構(它把時間表示為秒和納秒)的指針timespec
-
- 傳回值:
- 成功: 傳回 0
- 失敗: 傳回 -1
- 參數:
-
函數:時間精度調整clock_getres
#include<sys/time.h> int clock_getres(clockid_t clock_id,struct timespec *tsp);
- 參數:
-
:時鐘類型。clock_id
-
:存放時間的tsp
結構(它把時間表示為秒和納秒)的指針timespec
-
- 傳回值:
- 成功: 傳回 0
- 失敗: 傳回 -1
函數把參數clock_getres
指向的tsp
結構初始化為與timespec
參數對應的始終精度clock_id
- 參數:
-
函數:設定時間clock_settime
#include<sys/time.h> int clock_settime(clockid_t clock_id,const struct timepsec *tsp);
- 參數:
-
:時鐘類型。clock_id
-
:存放時間的tsp
結構(它把時間表示為秒和納秒)的指針timespec
-
- 傳回值:
- 成功: 傳回 0
- 失敗: 傳回 -1
函數對特定的時鐘設定時間。但是:clock_settime
- 某些始終是不能修改的
- 需要适當的權限來修改時鐘值
- 參數:
-
函數:更高精度的擷取目前時間(但是目前已經棄用)gettimeofday
#include<sys/time.h> int gettimeofday(struct timeval *restrict tp,void *restrict tzp);
- 參數:
-
:存放目前時間的tp
結構(将目前時間表示為秒和微秒)的指針timeval
-
:唯一合法值是tzp
。其他任何值都産生未定義的結果NULL
-
- 傳回值:總是傳回 0
- 參數:
-
函數:将月曆時間轉換成gmtime/localtime
結構:struct tm
#include<time.h> struct tm* gmtime(const time_t *calptr); struct tm* localtime(const time_t *calptr);
- 參數:
:指向月曆時間的指針calptr
- 傳回值:
- 成功:指向
結構的指針struct tm
- 失敗:傳回
NULL
- 成功:指向
其中秒可以超過 59 的理由是表示潤秒struct tm{ int tm_sec; //秒數,範圍是 [0~60] int tm_min; //分鐘數,範圍是 [0~59] int tm_hour; //小時數,範圍是 [0~23]。午夜12點是 0 int tm_mday; //一個月中的天數,範圍是 [1~31] int tm_mon; //月數,範圍是 [0~11] ,一月是 0 int tm_year; //年數,範圍是 [1900~],如果是16則表示 1916 int tm_wday; //一個星期中的天數,範圍是 [0~6] ,周日是0 int tm_yday; //一年中的天數,範圍是 [0~365],一月一号是 0 int tm_isdst; //daylight saving time flag }
函數的差別:gmtime/localtime
-
:将月曆時間轉換成統一協調的年月日時分秒周日分解結構gmtime
-
:将月曆時間轉換成本地實際(考慮本地市區和夏令時标志),由localtime
環境變量指定TZ
環境變量影響TZ
這三個函數:localtime/mktime/strftime
- 如果定義了
環境變量:則這些函數将使用TZ
的值代替系統預設時區TZ
- 如果
定位為空TZ
,則使用TZ=
作為時區UTC
- 參數:
-
函數:以本地時間的年月日等作為參數,将其變化成mktime
值:time_t
#include<time.h> time_t mktime(struct tm*tmptr);
- 參數:
:指向tmptr
結構的指針struct tm
- 傳回值:
- 成功: 傳回月曆時間
- 失敗: 傳回 -1
環境變量指定TZ
- 參數:
-
函數:類似strftime/strftime_l
的列印時間的函數。它們可以通過可用的多個參數來定制産生的字元串printf
#include<time.h> size_t strftime(char *restrict buf,size_t maxsize,const char*restrict format, const struct tm* restrict tmptr); size_t strftime_l(char *restrict buf,size_t maxsize,const char*restrict format, const struct tm* restrict tmptr,locale_t locale);
- 參數:
-
:存放格式化後的時間字元串的緩沖區的位址buf
-
:存放格式化後的時間字元串的緩沖區的大小maxsize
-
:時間的格式化字元串format
-
:存放時間的tmptr
結構的指針struct tm
函數:strftime_l
-
:指定的區域locale
-
- 傳回值:
- 成功:傳回存入
的字元數buf
- 失敗: 傳回 0
- 成功:傳回存入
- 如果
長度足夠存放格式化結果以及一個buf
終止符,則這兩個函數才有可能順利轉換;否則空間不夠,這兩個函數傳回0,表示轉換失敗null
-
運作調用者将區域指定為參數;而strftime_l
使用通過strftime
環境變量指定的區域TZ
-
參數控制時間值的格式。如同format
,轉換說明的形式是百分号之後跟随一個特定的字元,而printf
中的其他字元則按照原樣輸出:format
-
:縮寫的周日名,如%a
Thu
-
:周日名,如%A
Thursday
-
:縮寫的月名:如%b
Jan
-
:全月名,如%B
January
-
:日期和時間,如%c
Thu Jan 19 21:24:25 2012
-
:年的最後兩位,範圍是(00~99),如%C
20
-
:月日,範圍是 (01~31),如%d
19
-
日期(MM/DD/YY),如%D
01/19/12
-
月日(一位數字前加空格)(1~31),如%e
19
-
:ISO 8601 日期格式 (YYYY-MM-DD),如%F
2012-01-19
-
:ISO 8601 年的最後2位數(00~99),如%g
12
-
:ISO 8601 的年,如%G
2012
-
:與%h
相同,縮寫的月名%b
-
:小時(24小時制)(00~23)%H
-
:小時(12小時制)(01~12)%I
-
:年日(001~366),如%j
019
-
:月(01~12),如%m
01
-
:分(00~59),如%M
24
-
:換行符%n
-
:%p
AM/PM
-
:本地時間(12小時制),如%r
09:24:52 PM
-
:與%R
相同%H:%M
-
:秒(00~60),如%S
52
-
:水準制表符%t
-
:同%T
相同,如%H:%M:%S
21:24:52
-
:ISO 8601 周幾(1~7,1為周一)%u
-
:一年的星期日周數(00~53)%U
-
:ISO 8601 周數(01~53)%V
-
:周幾:(0~6,周日為0)%w
-
:一年的星期一周數(00~53)%W
-
:本地日期,如%x
01/19/12
-
:本地時間,如%X
21:24:52
-
:年的最後兩位(00~99)%y
-
:年,如%Y
2012
-
:ISO 8601 格式的UTC偏移量,如%z
-0500
-
:時區名,如%Z
EST
-
:百分号%%
-
- 參數:
-
函數:它是strptime
的逆向過程,把時間字元串轉換成strftime
時間struct tm
#include<time.h> char *strptime(const char*restrict buf,const char*restrict format, struct tm*restrict tmptr);
- 參數:
-
:存放已經格式化的時間字元串的緩沖區的位址buf
-
:給出了format
緩沖區中的格式化時間字元串的格式buf
-
:存放時間的tmptr
結構的指針struct tm
-
- 傳回值:
- 成功:傳回非
NULL
- 失敗:傳回
NULL
- 成功:傳回非
的格式化說明與strptime
的幾乎相同,但是下列會有差別strftime
-
:縮寫或者完整的周日名%a
-
:同%A
%a
-
:縮寫或者完整的月名%b
-
:同%B
%b
-
:任何空白%n
-
:任何空白%t
- 參數: