zoukankan      html  css  js  c++  java
  • 《APUE》读书笔记—第六章数据系统文件和信息

      本章主要介绍了Unix系统的正常运行要使用的与系统有关的数据文件和信息。如:口令文件,阴影文件、组文件、附加组、系统标识、时间和日期历程。

      口令文件,即Unix系统用户数据库,存储在/etc/passwd中,是一个ASCII文件,包含的字段信息在<pwd.h>定义的passwd数据结构中。  

      struct passwd {
          char   *pw_name;       /* username */
          char   *pw_passwd;     /* user password */
          uid_t   pw_uid;        /* user ID */
          gid_t   pw_gid;        /* group ID */
          char   *pw_gecos;      /* user information */
          char   *pw_dir;        /* home directory */
          char   *pw_shell;      /* shell program */
      };

      获取口令文件函数,分别是根据用户ID和用户名。
      struct passwd *getpwuid(uid_t uid);   //根据用户ID
      struct passwd *getpwnam(const char *name);  //根据用户名
      查看整个口令文件,需要对口令文件进行遍历。有如下函数:
      struct passwd *getpwent(void); //返回口令文件中的下一个记录项
      void setpwent(void); //反绕文件,从文件头开始
      void endpwent(void); //关闭文件

      可以用getpwent来实现getpwuid和getpwnam函数。写个程序查看root用户的相关信息及查看口令文件中所有用户的用户名,程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <pwd.h>
     5 
     6 int main()
     7 {
     8     struct passwd *ppwd;
     9     struct passwd *ptr;
    10     //获取root用户信息
    11     ppwd = getpwnam("root");
    12     if(ppwd == NULL)
    13     {
    14         perror("getpwnam() error");
    15         exit(-1);
    16     }
    17     printf("root user information as follow:\n");
    18     printf("user_name is: %s\n",ppwd->pw_name);
    19     printf("user_passwd is: %s\n",ppwd->pw_passwd);
    20     printf("user_uid is: %d\n",ppwd->pw_uid);
    21     printf("user_gid is: %d\n",ppwd->pw_gid);
    22     printf("user_gecos is: %s\n",ppwd->pw_gecos);
    23     printf("user_dir is: %s\n",ppwd->pw_dir);
    24     printf("user_shell is: %s\n",ppwd->pw_shell);
    25     printf("*****************************\n");
    26     //反转口令文件,从文件头开始
    27     setpwent();
    28     printf("Print all user name:\n");
    29     //遍历读取口令文件
    30     while((ptr = getpwent())!= NULL)
    31     {
    32       printf("%s\t",ptr->pw_name);
    33     }
    34     putchar('\n'); 
    35     //关闭口令文件
    36     endpwent();
    37     return 0;
    38 }

    测试结果如下:

      阴影文件,存放加密口令,至少包含有用户名和加密口令。类似于口令文件,Unix在<shadow.h>都文件中针对阴影文件也提供类似的操作函数,但是只有超级用户(root)才能调用访问阴影文件的函数。阴影文件位于/etc/shadow文件中,文件结构及操作函数如下:

    struct spwd {
        char *sp_namp;     /* Login name */
        char *sp_pwdp;     /* Encrypted password */
        long  sp_lstchg;   /* Date of last change (measured in days since 1970-01-01 00:00:00 +0000 (UTC)) */
        long  sp_min;      /* Min # of days between changes */
        long  sp_max;      /* Max # of days between changes */
        long  sp_warn;     /* # of days before password expire to warn user to change it */
        long  sp_inact;    /* # of days after password expire until account is disabled */
        long  sp_expire;   /* Date when account expires (measured in days since 1970-01-01 00:00:00 +0000 (UTC)) */
        unsigned long sp_flag;  /* Reserved */
    };

    struct spwd *getspnam(const char *name);
    struct spwd *getspent(void);
    void setspent(void);
    void endspent(void);
    写个程序查看root用户的加密口令及所有用户的用户名及加密口令如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <shadow.h>
     5 
     6 int main()
     7 {
     8     struct spwd *pspwd;
     9     struct passwd *ptr;
    10     pspwd = getspnam("root");
    11     if(pspwd == NULL)
    12     {
    13         perror("getspnam() error");
    14         exit(-1);
    15     }
    16     printf("root user information as follow:\n");
    17     printf("user_name is: %s\n",pspwd->sp_namp);
    18     printf("user_passwd is: %s\n",pspwd->sp_pwdp);
    19     printf("*****************************\n");
    20     setspent();
    21     while((pspwd = getspent()) != NULL)
    22     {
    23         printf("user_name is: %s\n",pspwd->sp_namp);
    24         printf("user_passwd is: %s\n",pspwd->sp_pwdp);
    25     }
    26     endspent();
    27     return 0;
    28 }

    只能在超级用户下运行此程序,在普用户下提升权限不够。执行结果如下所示:

    组文件,即组数据库文件,存储在/etc/group中,结构及操作函数包含在<grp.h>头文件中。具体结构和操作函数如下:

    struct group {
        char   *gr_name;       /* group name */
        char   *gr_passwd;     /* group password */
        gid_t   gr_gid;        /* group ID */
        char  **gr_mem;        /* group members */
    };

    struct group *getgrnam(const char *name);
    struct group *getgrgid(gid_t gid);
    搜索整个文件组函数:
    struct group *getgrent(void);
    void setgrent(void);
    void endgrent(void);
    写个程序,打印出组id为0的组名称及遍历整个组文件,输出组名称及组id。程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <grp.h>
     5 #include <errno.h>
     6 
     7 int main()
     8 {
     9     struct group *pgrg;
    10     struct group *ptr;
    11     gid_t gid = 0;
    12     char *username = NULL;
    13     //根据gid进行查询
    14     pgrg = getgrgid(gid);
    15     if(pgrg == NULL)
    16     {
    17         perror("getgrgid() error");
    18         exit(-1);
    19     }
    20     printf("group name is: %s\n",pgrg->gr_name);
    21     printf("group passwd is: %s\n",pgrg->gr_passwd);
    22     printf("group gid is: %d\n",pgrg->gr_gid);
    23     setgrent();
    24     //遍历整个组文件
    25     while((ptr = getgrent()) != NULL)
    26     {
    27         printf("group name is: %s\t",ptr->gr_name);
    28         printf("group gid is: %d\n",ptr->gr_gid);
    29     }
    30     endgrent();
    31     return 0;
    32 }

    程序执行结果如下所示:

      附加组,一个用户可以属于多个组,这样可以参加多项工作,优点是不必显式地经常更改组。用户登录时候,系统按照口令文件记录项中的数值组ID,赋给实际组ID,可以在任何时候通过newgrp更改组ID。为了获取和设置附加组ID,提供操作函数如下:

    int getgroups(int size, gid_t list[]);  //将各个附加组ID填写到数组grouplist中
    int setgroups(size_t size, const gid_t *list); //由超级用户调用,以便为调用进程设置附加组ID表
    int initgroups(const char *user, gid_t group); //调用setgroups,确定其组的成员关系

      其他数据文件  除了口令文件和组文件外,Linux也使用很多其他文件,一般情况下,这些文件都至少支持三个函数:
    (1)get函数:读文件中的下一个记录项。
    (2)set函数:将文件偏移量设置到文件起始处。
    (3)end函数:关闭系统文件。
      如果该文件支持关键字检索,例如口令文件支持基于用户名和用户ID的检索,因此实现了接口getpwnam和getpwuid函数,就会支持相应的函数。

    存取系统数据文件的类似例程
    说明 数据文件 头文件 结构 附加的关键字查找函数
    口令 /etc/passwd <pwd.h> passwd getpwnam 、getpwuid
    /etc/group <grp.h> group getpwnam、getpwuid
    阴影 /etc/shadow <shadow.h> spwd getspnam
    主机 /etc/hosts <netdb.h> hostent gethostbyname、gethostbyaddr
    网络 /etc/networks <netdb.h> netent getnetbyname、getnetbyaddr
    协议 /etc/protocols <netdb.h> protoent getprotobyname、getprotobyaddr
    服务 /etc/services <netdb.h> servent getservbyname、getservbyad

      系统标识,uname函数返回与当前主机和操作系统有关的信息,函数字在<sys/utsname.h>头文件中定义。utsname结构信息和操作函数如下:

      struct utsname {
          char sysname[];    /* Operating system name (e.g., "Linux") */
          char nodename[];   /* Name within "some implementation-defined network" */
          char release[];    /* OS release (e.g., "2.6.28") */
          char version[];    /* OS version */
          char machine[];    /* Hardware identifier */
       #ifdef _GNU_SOURCE
          char domainname[]; /* NIS or YP domain name */
        #endif
      };

      int uname(struct utsname *buf);

    写个程序获取本机当前主机和操作系统信息,程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <sys/utsname.h>
     5 #include <errno.h>
     6 
     7 int main()
     8 {
     9     struct utsname  name;
    10     if(uname(&name) == -1)
    11     {
    12         perror("uname() error");
    13         exit(-1);
    14     }
    15     printf("system name is: %s\n",name.sysname);
    16     printf("node name is: %s\n",name.nodename);
    17     printf("release is: %s\n",name.release);
    18     printf("version is: %s\n",name.version);
    19     printf("machine is: %s\n",name.machine);
    20     return 0;
    21 }

    程序执行结果如下:

      时间和日期,Unix内核提供的基本时间服务是计算自国际标准时间公元1970年1月1日00:00:00以来经过的秒数,基本数据类型是time_t,称为日历时间,包括时间和日期,将时间和日期作为一个量值进行保存。类型定义如下:

    #ifndef __TIME_T
    #define __TIME_T     /* 避免重复定义 time_t */
    typedef long     time_t;    /* 时间值time_t 为长整型的别名*/
    #endif
    相关操作函数有:
    #include <time.h>

    time_t time(time_t *t);  //返回当前时间及日期

    #include <sys/time.h>

    int gettimeofday(struct timeval *tv, struct timezone *tz); //相比time提供更高的分辨率,微妙级

    int settimeofday(const struct timeval *tv, const struct timezone *tz);

    struct timeval {
        time_t      tv_sec;     /* seconds */
        suseconds_t tv_usec;    /* microseconds */
    };
    struct timezone {
        int tz_minuteswest;     /* minutes west of Greenwich */
        int tz_dsttime;         /* type of DST correction */
    };

    取得了这种以秒计的整型时间后,通常调用另外一个时间函数将其转化为人们可读的时间和日期。时间的结构及操作函数有:

    struct tm {
        int tm_sec;         /* seconds */
        int tm_min;         /* minutes */
        int tm_hour;        /* hours */
        int tm_mday;        /* day of the month */
        int tm_mon;         /* month */
        int tm_year;        /* year */
        int tm_wday;        /* day of the week */
        int tm_yday;        /* day in the year */
        int tm_isdst;       /* daylight saving time */
    };

    char *asctime(const struct tm *tm);
    char *ctime(const time_t *timep);
    struct tm *gmtime(const time_t *timep);  //转换为国际标准时间
    struct tm *localtime(const time_t *timep); //转换为本地实际
    time_t mktime(struct tm *tm);
    size_t strftime(char *s, size_t max, const char *format,const struct tm *tm); //对tm进行格式化输出到一个字符串
    函数之间的关系如下图:

    写一个程序巩固时间函数,程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <time.h>
     5 #include <errno.h>
     6 #include <string.h>
     7 
     8 int main()
     9 {
    10     time_t now;
    11     struct tm *ptime;
    12     char *ptstr;
    13     char timebuf[100];
    14     memset(timebuf,0,100);
    15    //获取时间,秒数
    16     now = time(&now);
    17     printf("Global time is:\n");
    18    //转化为国际时间
    19     ptime = gmtime(&now);
    20     ptime->tm_year += 1900;
    21     ptime->tm_mon += 1;
    22     printf("%d-%d-%d %d:%d:%d\n",ptime->tm_year,ptime->tm_mon,ptime->tm_mday,
    23            ptime->tm_hour,ptime->tm_min,ptime->tm_sec);
    24     printf("Local time is:\n");
    25     //转化为本地时间
    26     ptime = localtime(&now);
    27     ptime->tm_year += 1900;
    28     ptime->tm_mon += 1;
    29     printf("%d-%d-%d %d:%d:%d\n",ptime->tm_year,ptime->tm_mon,ptime->tm_mday,
    30            ptime->tm_hour,ptime->tm_min,ptime->tm_sec);
    31     //将tm结构转换为字符串
    32     ptstr = asctime(ptime);
    33     printf("tm time stirng is: %s",ptstr);
    34     //将time_t类型转换为字符串
    35     ptstr = ctime(&now);
    36     printf("time_t time string is: %s",ptstr);
    37     //date 格式化输出时间
    38     strftime(timebuf,100,"%YYear %mMonth %dDay %A %X",ptime);
    39     printf("time buf is:%s\n",timebuf);
    40     return 0;
    41 }

    程序执行结果如下所示:

     总结:加深对Unix的系统数据文件及时间日期的认识,能够调用系统函数获取系统相关数据。

  • 相关阅读:
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    冒泡排序和选择排序
  • 原文地址:https://www.cnblogs.com/Anker/p/2819038.html
Copyright © 2011-2022 走看看