5 系统数据文件和信息

5.1 口令文件

        口令文件包含了下表中所示的各字段,这些字段包含在<pwd.h>中定义的passwd结构中。

/etc/passwd文件中的字段
说 明struct passwd 成员
用户名char *pw_name
加密口令char *pw_passwd
数值用户IDuid_t pw_uid
数值组IDgid_t pw_gid
注释字段char *pw_gecos
初始工作目录char *pw_dir
初始shell(用户程序)char *pw_shell

        口令文件是/etc/passwd,而且是一个文本文件。每一行包含上表中所示的 7个字段,字段之间用冒号相分隔。例如,该文件中可能有下列三行:

root:jheVopR58x9Fx:0:1:The superuser:/:/bin/sh
nobody:*:65534:65534::/:
stevens:3hKVD8R58r9Fx:224:20:Richard Stevens:/home/stevens:/bin/ksh

关于这些登录项请注意下列各点:

  • 通常有一个登录项,其用户名为root,其用户ID是0 (超级用户)。
  • 加密口令字段包含了经单向密码算法处理过的用户口令副本。因为此算法是单向的,所 以不能从加密口令猜测到原来的口令。
  • 口令文件中的某些字段可能是空。如果密码口令字段为空,这通常就意味着该用户没有口令。nobody有两个空白字段:注释字段和初始shell字段。空白注释字段不产生任何影响。空白shell字段则表示取系统默认值,通常是/bin/sh。

        定义了两个存取口令文件中信息的函数。在给出用户登录名或数值用户ID后,这两个函数就能查看相关记录。

#include <sys/types.h>
#include <pwd.h>

//两个函数返回:若成功则为指针,若出错则为NULL
struct passwd *getpwuid(uid_t uid) ;
struct passwd *getpwnam(const char *name) ;

        如果要查看的只是一个登录名或用户ID,那么这两个函数能满足要求,但是也有些程序要查看整个口令文件。下列三个函数则可用于此。

#include <sys/types.h>
#include <pwd.h>

//返回:若成功则为指针,若出错或到达文件尾端则为NULL
struct passwd *getpwent(void);

void setpwent(void);
void endpwent(void);

5.2 组文件

        组文件包含了下表中所示字段。这些字段包含在<grp.h> 中所定义的group结构中。

/etc/group文件中的字段
说 明struct group 成员
组名char *gr_name
加密口令char *gr_passwd
数字组IDint gr_gid
指向各用户名指针的数组char **gr_mem

字段gr_mem是一个指针数组,其中的指针各指向一个属于该组的用户名。该数组以null结尾。

        可以用下列两个函数来查看组名或数值组ID。

#include <sys/types.h>
#include <grp.h>

//两个函数返回:若成功则为指针,若出错则为NULL
struct group *getgrgid(gid_t gid) ;
struct group *getgrnam(const char * name) ;

如同对口令文件进行操作的函数一样,这两个函数通常也返回指向一个静态变量的指针,在每次调用时都重写该静态变量。

        如果需要搜索整个组文件,则须使用另外几个函数。下列三个函数类似于针对口令文件的三个函数。

#include <sys/types.h>
#include <grp.h>

//返回:若成功则为指针,若出错或到达文件尾端则为NULL
struct group *getgrent(void);

void setgrent(void);
void endgrent(void);

        setgrent打开组文件(如若它尚末被打开)并反绕它。getgrent从组文件中读下一个记录,如若该文件尚未打开则先打开它。endgrent关闭组文件。

5.3 添加组ID

        为了存取和设置添加组I D提供了下列三个函数:

#include <sys/types.h>
#include <unistd.h>

//返回:若成功则为添加的组ID数,若出错则为-1
int getgroups(int gidsetsize, gid_t grouplist[]) ;

//两个函数返回:若成功则为 0,若出错则为-1
int setgroups(int ngroups, const gid_t grouplist[]) ;
int initgroups(const char *username, gid_t basegid) ;

5.4 其它数据文件

        UNIX系统还使用很多其他文件。例如, BSD网络软件有一个记录各网络服务器所提供的服务的数据文件 (/etc/services ),有一个记录协议信息的数据文件(/etc/protocols),还有一个则是记录网络信息的数据文件(/etc/networks)。幸运的是,对于这些数据文件的界面都与上述对口令文件和组文件的相似。

        一般情况下每个数据文件至少有三个函数:

(1)get函数:读下一个记录,如果需要还打开该文件。此种函数通常返回指向一个结构的指针。当已达到文件尾端时返回空指针。大多数 get函数返回指向一个静态存储类结构的指针,如果要保存其内容,则需复制它。

(2)set函数:打开相应数据文件 (如果尚末打开),然后反绕该文件。如果希望在相应文件起始处开始处理,则调用此函数。

(3) end函数:关闭相应数据文件。正如前述,在结束了对相应数据文件的读、写操作后, 总应调用此函数以关闭所有相关文件。

5.5 登录会计

        大多数UNIX系统都提供下列两个数据文件:utmp文件,它记录当前登录进系统的各个用 户;wtmp文件,它跟踪各个登录和注销事件。

        包含下列结构的一个二进制记录写入这两个文件中:

struct utmp {
char ut_line[8]; /* tty line: "ttyh0", "ttyd0", "ttyp0", ... */
char ut_name[8]; /* login name */
long ut_time;    /* seconds since Epoch */
} ;

5.6 系统标识

        定义了uname函数,它返回与主机和操作系统有关的信息。

#include <sys/utsname.h>

//返回:若成功则为非负值,若出错则为- 1
int uname(struct utsname *name) ;
struct utsname {
char sysname[9]; /* name of the operating system */
char nodename[9]; /* name of this node */
char release[9]; /* current release of operating system */
char version[9]; /* current version of this release */
char machine[9]; /* name of hardware type */
} ;

        伯克利类的版本提供gethostname函数,它只返回主机名,该名字通常就是TCP/IP网络上主 机的名字。

#include <unistd.h>

//返回:若成功则为0,若出错则为-1
int gethostname(char *name, int namelen) ;

通过name返回的字符串以null结尾 (除非没有提供足够的空间 )。<sys/param.h>中的常数 MAXHOSTNAMELEN规定了此名字的最大长度(通常是64字节)。如果宿主机联接到TCP/IP网络中,则此主机名通常是该主机的完整域名。

5.7 时间和日期例程

        由UNIX内核提供的基本时间服务是国际标准时间公元 1970年1月1日00 : 00 : 00以来经过的秒数。这种秒数是以数据类型 time_t表示的。我们称它们为日历时间。日历时间包括时间和日期。UNIX在这方面与其他操作系统的区别是:

( 1 )以国际标准时间而非本地时间计时;

( 2 )可自动进行转换,例如变换到夏日制;

( 3 )将时间和日期作为一个量值保存。time函数 返回当前时间和日期。

#include <time.h>

//返回:若成功则为时间值,若出错则为- 1
time_t time(time_t *calptr) ;

时间值作为函数值返回。如果参数非null,则时间值也存放在由calptr指向的单元内。

        一旦取得这种以秒计的很大的时间值后,通常要调用另一个时间函数将其变换为人们可读的时间和日期。下图中说明了各种时间函数之间的关系。(图中以虚线表示的四个函数localtime、mktime、ctime和strftime都受到环境变量T Z的影响。)

各个时间函数之间的关系

         两个函数localtime和gmtime将日历时间变换成以年、月、日、时、分、秒、周日表示的时 间,并将这些存放在一个tm结构中。

struct tm { /* a broken-down time */
    int tm_sec;   /* seconds after the minute: [0, 61] */
    int tm_min;   /* minutes after the hour: [0, 59] */
    int tm_hour;  /* hours after midnight: [0, 23] */
    int tm_mday;  /* day of the month: [1, 31] */
    int tm_mon;   /* month of the year: [0, 11] */
    int tm_year;  /* years since 1900 */
    int tm_wday;  /* days since Sunday: [0, 6] */
    int tm_yday;  /* days since January 1: [0, 365] */
    int tm_isdst; /* daylight saving time flag: <0, 0, >0 */
}
#include <time.h>

//两个函数返回:指向tm结构的指针
struct tm *gmtime(const time_t *calptr) ;
struct tm *localtime(const time_t *calptr) ;

localtime和gmtime之间的区别是: localtime将日历时间变换成本地时间 (考虑到本地时区和夏时 制标志),而gmtime则将日历时间变换成国际标准时间的年、月、日、时、分、秒、周日。

        函数mktime以本地时间的年、月、日等作为参数,将其变换成 time_t值。

#include <time.h>

//返回:若成功则为日历时间,若出错则为- 1
time_t mktime(struct tm *tmptr) ;

        asctime和ctime函数产生形式的26字节字符串,这与date(1)命令的系统默认输出形式类似:

Tue Jan 14 17:49:03 1992\n\0

#include <time.h>

//两个函数返回:指向null结尾的字符串
char *asctime(const struct tm *tmptr) ;
char *ctime(const time_t *calptr) ;

asctime的参数是指向年、月、日等字符串的指针,而 ctime的参数则是指向日历时间的指针。

        最后一个时间函数是strftime,它是非常复杂的printf类的时间值函数。

#include <time.h>

//返回:若有空间,则存入数组的字符数,否则为 0
size_t strftime(char *buf, size_t maxsize, const char * format, const struct tm *tmptr) ;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值