APUE读书笔记 6--------- 系统数据文件和信息

来源:互联网 发布:华为大数据在贵州 编辑:程序博客网 时间:2024/05/18 10:33

一、口令文件和组文件

1、口令文件
(1)Linux系统的口令文件/ etc / passwd中的字段包含在passwd结构中,passwd的结构定义如下:
#include <pwd.h>/* The passwd structure.  */struct passwd{  char *pw_name;                /* Username.  */  char *pw_passwd;              /* Password.  */  uid_t pw_uid;                 /* User ID.  */  gid_t pw_gid;                 /* Group ID.  */  char *pw_gecos;               /* Real name.  */  char *pw_dir;                 /* Home directory.  */  char *pw_shell;               /* Shell program.  */};

其中 / etc / passwd 文件中的典型的一行显示为   root:x:0:0:root:/root:/bin/bash,分别对应passwd结构中的7个字段。

注意:    若要阻止某用户登到系统,可以将pw_shell设置为 /dev/null、/bin/false或者 /bin/true 。可以使用nobody用户名,这样任何用户都可以登录到该系统,不过只能访问人人可读、可写的文件。 在管理员的权限下,使用vipw命令可以修改口令文件。

(2)获取口令文件项的API
 获取单个口令文件项
#include <pwd.h>/* 若成功则返回指针,若出错,则返回NULL*/ //Search for an entry with a matching user ID.struct passwd *getpwuid ( uid_t uid);//Search for an entry with a matching username.struct passwd *getpwnam ( const char * name);

其中 getpwuid函数可以通过用户ID获得passwd结构,getpwnam函数可以通过用户名获得passwd结构。

获取整个口令文件

#include <pwd.h>//Rewind the password-file stream. void setpwent (void);//Close the password-file stream.void endpwent (void);//Read an entry from the password-file stream, opening it if necessary.struct passwd *getpwent (void);
其中setpwent函数将文件内偏移量设置在文件起始处;每调用一次getpwent函数便可以获取下一个口令文件项,通过while循环便可以获取整个文件的口令文件项;endpwent函数用来关闭口令文件。

注意:passwd结构是相关函数内的静态变量,如下示例:

// 探究passwd的静态性#include <stdio.h>#include <pwd.h>#include <stdlib.h>int main( int argc ,char *argv[] ){        struct passwd *sta_pass=getpwnam( "wang11chao01" );        printf( "username:%s \n userpass:%s \n userid:%d\n",sta_pass->pw_name,sta_pass->pw_passwd,sta_pass->pw_uid);        // 再次调用getpwnam函数,重写passwd结构        getpwnam( "root" );        printf("---------------------------------------"       "---------------------------------\n");        // sta_pass中的内容会修改        printf( "username:%s \n userpass:%s \n userid:%d\n",sta_pass->pw_name,sta_pass->pw_passwd,sta_pass->pw_uid);        exit( 0 );}
该程序执行结果为:

username:wang11chao01 

userpass:x 

userid:500

------------------------------------------------------------------------

username:root 

userpass:x 

userid:0

2、阴影口令

(1) 为了提高系统的安全性,防止一般用户获取用户的加密口令,通常将加密口令存放于阴影口令文件 /etc/shadow中,阴影口令项的字段存放于spwd结构中,spwd结构的定义为:

#include <shadow.h>/* Structure of the password file.  */struct spwd  {    char *sp_namp;              /* Login name.  */    char *sp_pwdp;              /* Encrypted password.  */    long int sp_lstchg;         /* Date of last change.  */    long int sp_min;            /* Minimum number of days between changes.  */    long int sp_max;            /* Maximum number of days between changes.  */    long int sp_warn;           /* Number of days to warn user to change                                   the password.  */    long int sp_inact;          /* Number of days the account may be                                   inactive.  */    long int sp_expire;         /* Number of days since 1970-01-01 until                                   account expires.  */    unsigned long int sp_flag;  /* Reserved.  */  };
(2)获取阴影口令文件项的API

#include <shadow.h>//Get shadow entry matching NAME.struct spwd *getspnam (const char *name);//Open database for reading.void setspent (void);//Close database.extern void endspent (void);//Get next entry from database, perhaps after opening the file./struct spwd *getspent (void);
该API使用方法与2(获取口令文件项的API)中方法相同。

3、组文件和附加组

(1)组文件/etc/group中的字段包含在结构体group中,group结构的定义如下:
#include <grp.h>struct group  {    char *gr_name;              /* Group name.  */    char *gr_passwd;            /* Password.    */    gid_t gr_gid;             /* Group ID.    */    char **gr_mem;              /* Member list. */  };

其中gr_mem是一个指针数组,每个指针指向一个指向一个属于该组的用户

(2)获取组文件项的API
#include <grp.h>//Search for an entry with a matching group ID.struct group *getgrgid (gid_t gid);//Search for an entry with a matching group name.struct group *getgrnam (const char *name);//Rewind the group-file stream.void setgrent (void);//Close the group-file stream.void endgrent (void);//Read an entry from the group-file stream, opening it if necessary.struct group *getgrent (void);

该API使用方法与2(获取口令文件项的API)中方法相同。

(3)每个用户除了可以属于口令文件项中组ID所对应的组,也可以属于其他的组 ------ 附加组 

获取附加组的API:

#include <unistd.h>/* If SIZE is zero, return the number of supplementary groups   the calling process is in.  Otherwise, fill in the group IDs   of its supplementary groups in LIST and return the number written.  */int getgroups (int size, gid_t list[]);
getgroups函数将附加组的ID数写到数组list中,其中数组list的最大长度未size,返回值为附加组ID数。若将size设为0,那么函数只返回附加组ID数

4、其他数据文件

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

  下表中列出了一些文件例程:

存取系统数据文件的类似例程说明数据文件头文件结构附加的关键字查找函数口令/etc/passwd<pwd.h>passwdgetpwnam 、getpwuid组/etc/group<grp.h>groupgetpwnam、getpwuid阴影/etc/shadow<shadow.h>spwdgetspnam主机/etc/hosts<netdb.h>hostentgethostbyname、gethostbyaddr网络/etc/networks<netdb.h>netentgetnetbyname、getnetbyaddr协议/etc/protocols<netdb.h>protoentgetprotobyname、getprotobyaddr服务/etc/services<netdb.h>serventgetservbyname、getservbyaddr

5、系统标识

(1)uname函数,返回当前主机和操作系统的有关信息,这些信息存放在结构utsname中,utsname结构的定义如下:

#include <sys/utsname.h>/* Structure describing the system and machine.  */struct utsname  {    /* Name of the implementation of the operating system.  */    char sysname[_UTSNAME_SYSNAME_LENGTH];    /* Name of this node on the network.  */    char nodename[_UTSNAME_NODENAME_LENGTH];    /* Current release level of this implementation.  */    char release[_UTSNAME_RELEASE_LENGTH];    /* Current version level of this release.  */    char version[_UTSNAME_VERSION_LENGTH];    /* Name of the hardware type the system is running on.  */    char machine[_UTSNAME_MACHINE_LENGTH];#if _UTSNAME_DOMAIN_LENGTH - 0    /* Name of the domain of this node on the network.  */# ifdef __USE_GNU    char domainname[_UTSNAME_DOMAIN_LENGTH];# else    char __domainname[_UTSNAME_DOMAIN_LENGTH];# endif#endif  };
获取utsname结构的API为:

#include <sys/utsname.h>//若成功则返回非负值,若出错则返回-1/* Put information about the system in NAME.  */int uname (struct utsname * name);
对系统进行简单的测试,代码为
// uname函数#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/utsname.h>int main( int argc,char *argv[] ){        struct utsname name;        if( uname( &name )==-1 ){                fputs("uname error",stdout);                exit( -1 );        }        printf( "The OS is %s \n The nodeName is %s \n"                "The release is %s \n The version is %s \n"                "The machine is %s \n ",                 name.sysname,name.nodename,name.release,name.version,name.machine );        exit( 0 );}

运行结果为:

The OS is Linux 
The nodeName is wang11chao01 
The release is 2.6.32-131.0.15.el6.x86_64 
The version is #1 SMP Sat Nov 12 15:11:58 CST 2011 
The machine is x86_64 

(2)gethostname函数

//若成功则返回0,若出错则返回-1#include <time.h>/* Put the name of the current host in no more than LEN bytes of NAME.   The result is null-terminated if LEN is large enough for the full   name and the terminator.  */int gethostname (char * name, size_t len);

二、时间与日期

1、各时间API的整体关系

其中localtime、mktime、ctime、strftime会受环境变量TZ的影响,若TZ定义为空串,则使用国际标准时间UTC。

2、获取日历时间 ---------- time_t
(1)分辨率为s的time函数API为
// 若成功则返回时间值,若出错则返回-1#include <time.h>/* Return the current time and put it in *TIMER if TIMER is not NULL.  */time_t time (time_t *timer);

若参数不为NULL,那么参数也存放返回的时间值

(2)分辨率为us的gettimeofday函数的API为

#include <sys/time.h>/* Get the current time of day and timezone information,   putting it into *TV and *TZ.  If TZ is NULL, *TZ is not filled.   Returns 0 on success, -1 on errors.   NOTE: This form of timezone information is obsolete.   Use the functions and variables declared in <time.h> instead.  */int gettimeofday (struct timeval *restrict  tv,                          timezone_ptr_t tz);
其中第一个参数timeval结构的定义如下:
#include <bits/time.h>/* A time value that is accurate to the nearest   microsecond but also has a range of years.  */struct timeval  {    time_t tv_sec;            /* Seconds.  */    suseconds_t tv_usec;      /* Microseconds.  */  };

其中tv_sec为日历时间的秒部分,tv_usec为日历时间的微妙部分,将两者相加即为日历时间。

gettimeofday函数的第二个参数标识指向时区的指针,若为NULL,则采用系统默认值。

3、将日历时间转换为人们可读的时间和日期------ tm结构

(1)当我们根据2中的函数获得以秒计的日历时间后,便可以将类型为time_t的日历时间转换成tm结构,其中tm结构的定义如下:

#include <time.h>/* Used by other time functions.  */struct tm{  int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */  int tm_min;                   /* Minutes.     [0-59] */  int tm_hour;                  /* Hours.       [0-23] */  int tm_mday;                  /* Day.         [1-31] */  int tm_mon;                   /* Month.       [0-11] */  int tm_year;                  /* Year - 1900.  */  int tm_wday;                  /* Day of week. [0-6] */  int tm_yday;                  /* Days in year.[0-365] */  int tm_isdst;                 /* DST.         [-1/0/1]*/#ifdef  __USE_BSD  long int tm_gmtoff;           /* Seconds east of UTC.  */  __const char *tm_zone;        /* Timezone abbreviation.  */#else  long int __tm_gmtoff;         /* Seconds east of UTC.  */  __const char *__tm_zone;      /* Timezone abbreviation.  */#endif};

将time_t转换成tm结构的API为

#include <time.h>/* Return the `struct tm' representation of *TIMER   in Universal Coordinated Time (aka Greenwich Mean Time).  */struct tm *gmtime (const time_t *timer);/* Return the `struct tm' representation   of *TIMER in the local timezone.  */struct tm *localtime (const time_t *timer);

其中gmtime函数与localtime函数的区别就是,gmtime将日历时间转换为国际标准时间,localtime函数将日历时间转换为本地时间

(2)我们也可以将tm结构重新转换为time_t结构,可以通过mktime函数,其定义如下:
// 若出错则返回-1#include <time.h>/* Return the `time_t' representation of TP and normalize TP.  */time_t mktime (struct tm *tp) ;

4、time_t和tm结构转换为字符串输出

(1)将time_t转换为字符串格式输出的ctime函数声明如下:

#include <time.h> /* Equivalent to `asctime (localtime (timer))'.  */char *ctime (const time_t *timer);
该函数返回类似下面格式的输出:2012年 07月 29日 星期日 19:06:14 CST

(2)将tm转换为字符串格式输出的asctime函数声明如下:

include <time.h>/* Return a string of the form "Day Mon dd hh:mm:ss yyyy\n"   that is the representation of TP in this format.  */char *asctime (const struct tm *tp) ;

返回日期的格式和ctime函数类似。

5、格式化日期输出函数strftime函数

strftime的函数声明如下:

#include <time.h>/* Format TP into S according to FORMAT.   Write no more than MAXSIZE characters and return the number   of characters written, or 0 if it would exceed MAXSIZE.  */size_t strftime (char *restrict s, size_t maxsize,                 const char *restrict format,                 const struct tm *restrict tp);
其中s用于存放格式化后的日期,maxsize表示s可以存放日期的最大长度,若实际的日期长度超过了maxsize,该函数返回0,否则返回日期的长度;

format表示输出日期的格式,tp表示用于转换的tm结构。

编写程序测试strftime的格式,程序如下:

#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAXSIZE 40int main( int argc,char *argv[] ){        char format[]="aAbBcCdDeEfFgGhHIjmMnprRStTuUVwWxXyYzZ%";        time_t now;        if( ( now=time( NULL ) )==-1 ){                fputs( "time error!",stdout );                exit( -1 );        }        struct tm *local;        if( ( local=localtime( &now ) )==NULL ){                fputs( "localtime error!",stdout );                exit( -1 );        }        char buf[ MAXSIZE ];        int i;        char form[3];        for( i=0;i<sizeof( format )/sizeof( char );++i ){                sprintf( form,"%%%c",format[i] );                if( strftime( buf,MAXSIZE,form,local )==0 ){                        fputs( "strftime error !",stdout );                        exit( -1 );                }                printf("The time using format %c is %s \n",format[i],buf );        }        exit( 0 );}
程序运行结果如下:The time using format a is Sun 

The time using format A is Sunday 
The time using format b is Jul 
The time using format B is July 
The time using format c is Sun Jul 29 19:44:04 2012 
The time using format C is 20 
The time using format d is 29 
The time using format D is 07/29/12 
The time using format e is 29 
The time using format E is %E 
The time using format f is %f 
The time using format F is 2012-07-29 
The time using format g is 12 
The time using format G is 2012 
The time using format h is Jul 
The time using format H is 19 
The time using format I is 07 
The time using format j is 211 
The time using format m is 07 
The time using format M is 44 
The time using format n is 
 
The time using format p is PM 
The time using format r is 07:44:04 PM 
The time using format R is 19:44 
The time using format S is 04 
The time using format t is      
The time using format T is 19:44:04 
The time using format u is 7 
The time using format U is 31 
The time using format V is 30 
The time using format w is 0 
The time using format W is 30 
The time using format x is 07/29/12 
The time using format X is 19:44:04 
The time using format y is 12 
The time using format Y is 2012 
The time using format z is +0800 
The time using format Z is CST 
The time using format % is %