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的系统数据文件及时间日期的认识,能够调用系统函数获取系统相关数据。

  • 相关阅读:
    Hdu 1094 A+B for Input-Output Practice (VI)
    Hdu 1091 A+B for Input-Output Practice (III)
    Hdu 1092 A+B for Input-Output Practice (IV)
    Hdu 1087 Super Jumping! Jumping! Jumping!
    scala学习笔记2(类,继承,抽象类)
    scala学习笔记1(表达式)
    把以前写的几个Linux Framebuffer小工具放到github上了,直接去下吧,别找我要了
    一位台湾朋友刚建的一个FTK的论坛,欢迎加入讨论
    Linux高端内存的由来
    read系统调用深度剖析
  • 原文地址:https://www.cnblogs.com/Anker/p/2819038.html
Copyright © 2011-2022 走看看