天天看點

《UNIX環境進階程式設計》--6系統資料檔案和資訊系統資料檔案和資訊

系統資料檔案和資訊

使用者配置檔案

1.

/etc/passwd

  1. UNIX密碼檔案

    /etc/passwd/

    是一個

    ASCII

    檔案,每一行包含很多字段,字段之間用冒号分隔。這些字段包含在

    <pwd.h>

    頭檔案定義的

    passwd

    ,該結構有如下成員:
    • char *pw_name

      :使用者名
    • char *pw_passwd

      :加密密碼
    • uid_t pw_uid

      :數值使用者ID
    • gid_t pw_gid

      :數值組ID
    • char *pw_gecos

      :注釋字段
    • char *pw_dir

      :初始工作目錄
    • char *pw_shell

      :初始

      shell

    • char *pw_class

      :使用者通路類
    • time_t pw_change

      :下次更改密碼時間
    • time_t pw_expire

      :賬戶有效期時間
    關于密碼檔案:
    • 通常有一個使用者名為

      root

      的登入項,其使用者ID是 0
    • 加密密碼字段包含一個占位符。現在加密密碼其實是放在

      /etc/shadow

    • 密碼檔案中某些字段可能為空。
      • 如果加密密碼字段為空,則說明該使用者沒有密碼,沒有密碼則不能登入
    • shell

      字段指定了初始

      shell

      • 若它為空,則取系統預設值(通常是

        /bin/sh

        )linux下為

        /bin/bash

      • 若它為

        /dev/null

        ,則會阻止任何人以該字段所在行記錄中的使用者名來登入系統
    • 使用者名如果是

      nobody

      ,則任何人都可以使用它登入系統,但是其使用者ID群組ID不提供任何特權。該使用者ID群組ID隻能通路人人皆可讀、可寫的檔案
    • Linux

      中,沒有

      pw_class,pw_change,pw_expire

      字段

注意如果要将一個使用者設為不能登入

1.可以将其shell設為

/bin/false

/bin/true

2.可以在

/etc/shadow

下将密碼字段前加

!!

*

  1. getpwuid/getpwnam

    函數:讀取密碼檔案:
    #include<pwd.h>
    
    struct passwd* getpwuid(uid_t uid);
    struct passwd* getpwnam(const char*name);
               
    • 參數:
      • uid

        :使用者ID
      • name

        :使用者名
    • 傳回值:
      • 成功:傳回

        passwd

        結構的指針
      • 失敗:傳回

        NULL

    注意:

    getpwuid/getpwnam

    函數傳回的

    struct passwd

    結構通常是函數内部的靜态變量,是以多次調用上面的函數,該靜态變量會被覆寫。
  2. 檢視整個密碼檔案,使用下面的函數:
    #include<pwd.h>
    
    struct passwd *getpwent(void);
    void setpwent(void);
    void endpwent(void);
               
    • getpwent

      傳回值:
      • 成功:傳回

        passwd

        結構的指針
      • 失敗:傳回

        NULL

      • 到達檔案尾端:傳回

        NULL

    用法:
    • 調用

      getpwent

      時,它傳回密碼檔案中的下一個記錄項
    傳回的

    struct passwd

    結構通常是函數内部的靜态變量,是以多次調用

    getpwent

    函數,該靜态變量會被覆寫
  3. 在第一次調用

    getpwent

    函數時,它會打開所使用的各個檔案
  4. getpwent

    對傳回的各個記錄項順序并沒有要求
  5. setpwent

    會反繞

    getpwent

    所使用的檔案到檔案起始處。即當調用

    setpwent

    之後,

    getpwent

    又會從頭開始讀取記錄項
  6. endpwent

    會關閉

    getpwent

    所使用的檔案。在調用

    getpwent

    讀取完密碼檔案後,一定要調用

    endpwent

    關閉這些檔案

    getpwent

    知道什麼時候應該打開它所使用的檔案(第一次被調用時),但是不知道何時應該關閉這些檔案
  7. 加密密碼是經單向加密算法處理過的使用者密碼副本。
    因為此算法是單向的,是以不能從加密密碼猜測到原始密碼
    現在的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

      不應該由一般使用者讀取。
      • 僅有少數幾個程式需要通路加密密碼,如

        login,passwd

        。這些程式通常是設定使用者ID為

        root

        的程式
      • 普通密碼檔案

        /etc/passwd/

        可以任由各使用者讀取
  8. 用于讀取陰影密碼檔案的函數為:
    #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

    函數,該靜态變量會被覆寫
  9. 調用

    getspent

    時,它傳回陰影密碼檔案中的下一個記錄項

    傳回的

    struct spwd

    結構通常是函數内部的靜态變量,是以多次調用

    getspent

    函數,該靜态變量會被覆寫
  10. 在第一次調用

    getspent

    函數時,它會打開所使用的各個檔案
  11. getspent

    對傳回的各個記錄項順序并沒有要求
  12. setspent

    會反繞

    getspent

    所使用的檔案到檔案起始處。即當調用

    setspent

    之後,

    getspent

    又會從頭開始讀取記錄項
  13. endspent

    會關閉

    getspent

    所使用的檔案。在調用

    getspent

    讀取完陰影密碼檔案後,一定要調用

    endspent

    關閉這些檔案

    getspent

    知道什麼時候應該打開它所使用的檔案(第一次被調用時),但是不知道何時應該關閉這些檔案
  14. UNIX 組檔案包含的字段定義在

    <grp.h>

    所定義的

    group

    結構中:
    • char *gr_name

      :組名
    • char *gr_passwd

      :加密密碼
    • int gr_gid

      :組ID
    • char **gr_mem

      :指向各使用者名指針的數組
    它是一個指針數組,其中每個指針指向一個屬于該組的使用者名。該數組以

    null

    指針結尾
  15. 《UNIX環境進階程式設計》--6系統資料檔案和資訊系統資料檔案和資訊
  16. getgrgid/getgrnam

    函數:檢視組檔案:
    #include<grp.h>
    
    struct group* getgrgid(gid_t gid);
    struct group* getgrnam(const char* name);
               
    • 參數:
      • gid

        :組ID
      • name

        :組名
    • 傳回值:
      • 成功:傳回

        group

        結構的指針
      • 失敗:傳回

        NULL

    注意:

    getgrgid/getgrnam

    函數傳回的

    struct group

    結構通常是函數内部的靜态變量,是以多次調用上面的函數,該靜态變量會被覆寫。
  17. 檢視整個組檔案,使用下面的函數:
    #include<grp.h>
    
    struct group *getgrent(void);
    void setgrent(void);
    void endgrent(void);
               
    • getgrent

      傳回值:
      • 成功:傳回

        group

        結構的指針
      • 失敗:傳回

        NULL

      • 到達檔案尾端:傳回

        NULL

    用法:
    • 調用

      getgrent

      時,它傳回組檔案中的下一個記錄項
    傳回的

    struct group

    結構通常是函數内部的靜态變量,是以多次調用

    getgrent

    函數,該靜态變量會被覆寫
  18. 在第一次調用

    getgrent

    函數時,它會打開所使用的各個檔案
  19. getgrent

    對傳回的各個記錄項順序并沒有要求
  20. setgrent

    會反繞

    getgrent

    所使用的檔案到檔案起始處。即當調用

    setgrent

    之後,

    getgrent

    又會從頭開始讀取記錄項
  21. endgrent

    會關閉

    getgrent

    所使用的檔案。在調用

    getgrent

    讀取完組檔案後,一定要調用

    endgrent

    關閉這些檔案

    getgrent

    知道什麼時候應該打開它所使用的檔案(第一次被調用時),但是不知道何時應該關閉這些檔案
  22. 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

        :填入

        grouplist

        數組的附屬組ID的最大數量
        若該值為0,則函數隻傳回附屬組ID數,而不修改

        grouplist

        數組
      • grouplist

        :存放附屬組ID的數組
    • 對于

      setgroups

      函數:
      • ngroups

        grouplist

        數組中元素個數

        數量不能太大,不能超過

        NGROUPS_MAX

      • grouplist

        :待設定的附屬組ID的數組
    • 對于

      initgroups

      函數:
      • username

        :使用者名
      • basegid

        :使用者的

        base

        組ID(它就是在密碼檔案中,使用者名對于的組ID)
    傳回值:
    • 對于

      getgroups

      函數:
      • 成功:傳回附屬組ID的數量
      • 失敗:傳回 -1
    • 對于

      setgroups/initgroups

      函數:
      • 成功:傳回 0
      • 失敗:傳回 -1
    用法:
    • getgroups

      函數将程序所屬使用者的各附屬組ID填寫到

      grouplist

      中,填入該數組的附屬組ID數最多為

      gidsetsize

      個。實際填寫到數組中的附屬組ID數由函數傳回
    • setgroups

      函數可由超級使用者調用以便為調用程序設定附屬組ID表。
    • 由于

      initgroups

      函數會在内部調用

      setgroups

      函數,是以它也必須由超級使用者調用
  23. 除了密碼檔案群組檔案之外,系統中還有很多其他重要的資料檔案。UNIX對于這些系統資料檔案提供了對應的類似的API。對于每種資料檔案,至少有三個函數:
    • get

      函數:讀下一個記錄。如果需要還會打開該檔案。
      • 此種函數通常傳回一個指向某個結構的指針。
      • 當已到達檔案尾端時,傳回空指針
      • 大多數

        get

        函數傳回指向一個靜态存儲類結構的指針,如果需要儲存其内容,則需要複制該結構
    • set

      函數:打開相應資料檔案(如果尚未打開),然後反繞該檔案
      • 如果希望在相應檔案起始處開始處理,則調用該函數
    • end

      函數:關閉相應資料檔案。在結束了對相應資料檔案的讀、寫操作後,總應該調用此函數以關閉所有相關檔案

    另外如果資料檔案支援某種形式的鍵搜尋,則也提供搜尋具有指定鍵的記錄的函數

    下面是各個重要的資料檔案:

    說明 資料檔案 頭檔案 結構 附加的鍵搜尋函數
    密碼 /etc/passwd passwd getpwnam,getpwuid
    /etc/group group getgrnam,getgrgid
    陰影 /etc/shadow

時間和日期

  1. UNIX核心提供的基本時間服務是自 UTC 1970-01-01 00:00:00 這一特定時間以來經過的秒數。
    • 這個時間稱作月曆時間,用資料類型

      time_t

      表示(它包括了時間和日期)
    • UNIX 提供若幹個時間函數來轉換月曆時間
  2. time

    函數:傳回目前的月曆時間
    #include<time.h>
    
    time_t time(time_t *calptr);
               
    • 參數:
      • calptr

        :如果該指針不是

        NULL

        ,則傳回的月曆時間也存放在

        calptr

        指向的記憶體中
    • 傳回值:
      • 成功:傳回目前月曆時間的值
      • 失敗:傳回 -1
  3. 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

          :擷取不帶負跳數的實時系統時間
        • CLOCK_PROCESS_CPUTIME_ID

          :調用程序的CPU時間
        • CLOCK_THREAD_CPUTIME_ID

          :調用線程的CPU時間
      • tsp

        :存放擷取時間的

        timespec

        結構(它把時間表示為秒和納秒)的指針
    • 傳回值:
      • 成功: 傳回 0
      • 失敗: 傳回 -1
  4. 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

    參數對應的始終精度
  5. 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

    函數對特定的時鐘設定時間。但是:
    • 某些始終是不能修改的
    • 需要适當的權限來修改時鐘值
  6. gettimeofday

    函數:更高精度的擷取目前時間(但是目前已經棄用)
    #include<sys/time.h>
    
    int gettimeofday(struct timeval *restrict tp,void *restrict tzp);
               
    • 參數:
      • tp

        :存放目前時間的

        timeval

        結構(将目前時間表示為秒和微秒)的指針
      • tzp

        :唯一合法值是

        NULL

        。其他任何值都産生未定義的結果
    • 傳回值:總是傳回 0
  7. 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

    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
    }
               
    其中秒可以超過 59 的理由是表示潤秒

    gmtime/localtime

    函數的差別:
    • gmtime

      :将月曆時間轉換成統一協調的年月日時分秒周日分解結構
    • localtime

      :将月曆時間轉換成本地實際(考慮本地市區和夏令時标志),由

      TZ

      環境變量指定

    TZ

    環境變量影響

    localtime/mktime/strftime

    這三個函數:
    • 如果定義了

      TZ

      環境變量:則這些函數将使用

      TZ

      的值代替系統預設時區
    • 如果

      TZ

      定位為空

      TZ=

      ,則使用

      UTC

      作為時區
  8. mktime

    函數:以本地時間的年月日等作為參數,将其變化成

    time_t

    值:
    #include<time.h>
    
    time_t mktime(struct tm*tmptr);
               
    • 參數:

      tmptr

      :指向

      struct tm

      結構的指針
    • 傳回值:
      • 成功: 傳回月曆時間
      • 失敗: 傳回 -1
    所謂的本地實際的”本地“:由

    TZ

    環境變量指定
  9. 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

      長度足夠存放格式化結果以及一個

      null

      終止符,則這兩個函數才有可能順利轉換;否則空間不夠,這兩個函數傳回0,表示轉換失敗
    • strftime_l

      運作調用者将區域指定為參數;而

      strftime

      使用通過

      TZ

      環境變量指定的區域
    • format

      參數控制時間值的格式。如同

      printf

      ,轉換說明的形式是百分号之後跟随一個特定的字元,而

      format

      中的其他字元則按照原樣輸出:
      • %a

        :縮寫的周日名,如

        Thu

      • %A

        :周日名,如

        Thursday

      • %b

        :縮寫的月名:如

        Jan

      • %B

        :全月名,如

        January

      • %c

        :日期和時間,如

        Thu Jan 19 21:24:25 2012

      • %C

        :年的最後兩位,範圍是(00~99),如

        20

      • %d

        :月日,範圍是 (01~31),如

        19

      • %D

        日期(MM/DD/YY),如

        01/19/12

      • %e

        月日(一位數字前加空格)(1~31),如

        19

      • %F

        :ISO 8601 日期格式 (YYYY-MM-DD),如

        2012-01-19

      • %g

        :ISO 8601 年的最後2位數(00~99),如

        12

      • %G

        :ISO 8601 的年,如

        2012

      • %h

        :與

        %b

        相同,縮寫的月名
      • %H

        :小時(24小時制)(00~23)
      • %I

        :小時(12小時制)(01~12)
      • %j

        :年日(001~366),如

        019

      • %m

        :月(01~12),如

        01

      • %M

        :分(00~59),如

        24

      • %n

        :換行符
      • %p

        AM/PM

      • %r

        :本地時間(12小時制),如

        09:24:52 PM

      • %R

        :與

        %H:%M

        相同
      • %S

        :秒(00~60),如

        52

      • %t

        :水準制表符
      • %T

        :同

        %H:%M:%S

        相同,如

        21:24:52

      • %u

        :ISO 8601 周幾(1~7,1為周一)
      • %U

        :一年的星期日周數(00~53)
      • %V

        :ISO 8601 周數(01~53)
      • %w

        :周幾:(0~6,周日為0)
      • %W

        :一年的星期一周數(00~53)
      • %x

        :本地日期,如

        01/19/12

      • %X

        :本地時間,如

        21:24:52

      • %y

        :年的最後兩位(00~99)
      • %Y

        :年,如

        2012

      • %z

        :ISO 8601 格式的UTC偏移量,如

        -0500

      • %Z

        :時區名,如

        EST

      • %%

        :百分号
  10. 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

      :任何空白