APUE学习笔记4——第六章——系统数据文件和信息

来源:互联网 发布:js点击效果 编辑:程序博客网 时间:2024/05/22 06:42

APUE学习笔记4——第六章——系统数据文件和信息


学号:16340043
中山大学
本博客为《UNIX环境高级编程》的学习笔记,希望能对大家有所帮助


1.前面的废话

今天写了两篇(这两篇都没那么长),一起放上来吧,相当于把明天的份给做了。明天要处理一堆习题QAQ


2.笔记正文

6.1 引言

由于历史原因,UNIX系统大量的数据文件1都是ASCII文本文件。
对于这些数据文件的可移植性接口是本章的主题。
本章也包括了系统标识函数、时间和日期函数。

6.2 口令文件

UNIX系统口令文件包含以下字段,这些字段包含在<pwd.h>定义的passwd结构中:

说明 struct passwd成员 用户名 char *pw_name 加密口令 char *pw_passwd 数值用户ID uid_t pw_uid 数值组ID gid_t pw_gid 注释字段 char *pw_gecos 初始工作目录 char *pw_dir 初始shell char *pw_shell 用户访问类 char *pw_class 下次更改口令时间 time_t pw_change 账户有效期时间 time_t pw_expire

有关事项:

  • 1)通常用户名为root的登陆项,其用户ID为0。
  • 2)加密口令字段包含了一个占位符。
  • 3)口令文件项中的某些字段可能为空。若加密口令字段为空,这通常意味着该用户没有口令
  • 4)shell字段包含了一个可执行程序名,它被用作该用户的登陆shell

某些系统提供finger命令打印用户信息,提供vipw命令允许管理员编辑口令文件

POSIX.1定义了两个获取口令文件项的函数(这两个函数按书上的意思好像只能查看用户登录名和数值用户ID,给其中一个查看到另一个,书上讲的不是很清楚)

#include <pwd.h>struct passwd *getpwuid(uid_t uid);struct passwd *getpwnam(const char *name);
  • uid:数值用户ID
  • name:用户登录名
  • 返回值:若成功,返回指针;若出错,返回NULL

若要查看全部口令文件,需用下列3个函数:

#include <pwd.h>struct passwd *getpwent(void);                //返回值:若成功,返回指针;若出错或达到文件尾端,返回NULLvoid setpwent(void);void endpwent(void);
  • 调用getpwend时,它打开它所使用的各个文件(第一次调用时才打开),返回口令文件中的下一个记录项
  • 函数setpwend反绕它所使用的文件
  • 函数endpwend关闭这些文件

6.3 阴影口令

加密口令是经过单向加密算法处理过的用户口令副本,不能由加密口令反推回明文口令。但是,可以对口令进行猜测,将猜测的口令经单向算法变换成加密形式,然后将其与用户的加密口令进行比较来判断猜测的口令是否正确。

为使原始资料难以通过枚举的方式得到,现在,某些系统将加密口令放在通常称为阴影口令的文件中

阴影口令文件不是一般用户可以读取的。只有少数几个设置用户ID为root的程序2需要访问

有一组函数可以访问阴影口令文件:

#include <shadow.h>struct spwd *getspnam(const char *name);struct spwd *getspent(void);                //两个函数的返回值:若成功,返回指针;若出错或达到文件尾端,返回NULLvoid setspent(void);void endspent(void);

6.4 组文件

UNIX组文件包含了以下字段,这些字段包含在<grp.h>所定义的group结构中:

说明 struct group成员 组名 char *gr_name 加密口令 char *gr_passwd 数值组ID int gr_gid 指向各用户名指针的数组3 char **gr_mem

下列两个函数可查看组名或数值组:

#include <grp.h>struct group *getgrgid(gid_t gid);struct group *getgrnam(const char *nam);
  • 返回值:若成功,返回指针;若出错,返回NULL

如果要搜索整个组文件,则需使用另外几个函数:

#include <grp.h>struct group *getgrent(void);                //返回值:若成功,返回指针;若出错或达到文件尾端,返回NULLvoid setgrent(void);void endgrent(void);

用法与口令文件的那三个一致

6.5 附属组ID

一个用户只属于一个组,有了附属组ID,便不用频繁地修改用户所在的组(一个用户参与多个项目时,可能需要同时属于多个组)

为了获取和设置附属组ID,提供了以下3个函数:

#include <unistd.h>int getgroups(int gidsetsize, gid_t grouplist[]);                //返回值:若成功,返回附属组ID填写成功的数量;若出错,返回-1#include <grp.h>    /*Linux*/int setgroups(int ngroups, const gid_t grouplist[]);int initgroups(const char *username, gid_t basegid);                //返回值:若成功,返回0;若出错,返回-1
  • getgroups将附属组ID填写到数组grouplist中,最多填写gidsetsize个(特殊情况,若getgidsize为0,则返回附属组ID数)
  • grouplist:组ID数组
  • ngroups:数组中的元素数
  • basegid:username在口令ID中的组ID

6.6 实现区别

(不同系统对这一套东西的实现区别,我先不关注了)

6.7 其他数据文件

还有好多好多其他数据文件

一般情况下,对于每个数据文件至少有3个函数:

  • 1)get函数:读下一个记录,如果需要,还会打开该文件。
  • 2)set函数:打开相应数据文件(若未打开),然后反绕该文件(到达文件开始处)。
  • 3)end函数:关闭相应数据文件。
  • 另外,如果数据文件支持某种形式的键搜索,则也提供搜索具有指定键的记录的例程。

6.8 登录账户记录

大多数UNIX系统都支持以下两个数据文件:

  • 1)utmp文件记录当前登录到系统的各个用户
  • 2)wtmp文件跟踪各个登陆和注销事件

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

struct utmp{    char ut_line[8];    char ut_name[8];    long ut_time;}

后来UNIX版本提供last命令,它读utmp文件并打印所选择的记录

6.9 系统标识

uname函数返回与主机和操作系统有关的信息:

#include <sys/utsname.h>int uname(struct utsname *name);                //若成功,返回非负值,若出错,返回0//utsname结构:struct utsname {    char sysname[];    char nodename[];    char release[];    char version[];    char machine;};
  • 该函数会填写utsname结构

还有个函数只填写主机名:

#include <unistd.h>int gethostname(char *name, int namelen);                //若成功,返回0;若出错,返回-1

超级用户还有个类似的函数 sethostname 来设置主机名(用法大概一样)

6.10 时间和日期例程

由UNIX系统提供的基本时间服务是计算自 协调世界时 公元1970年1月1日00:00:00 这一特定时间以来经过的秒数,这种秒数是以数据类型time_t表示的,我们称它为日历时间。

time函数返回当前时间和日期:

#include <time.h>time_t time(time_t *calptr);                //返回值:若成功,返回时间值;若出错,返回-1
  • 时间值存放在calptr所指的单元内

clock_gettime函数可用于获取指定时钟的时间,返回的时间在4.2节介绍的timespec结构中:

#include <sys/time.h>int clock_gettime(clockid_t clock_id, struct timespec *tsp);                //若成功:返回0;若出错,返回-1
  • clock_id为指定时间类型的标识:
标识符 说明 CLOCK_REALTIME 实时系统时间 CLOCK_MONOTONIC 不带负跳数的实时系统时间 CLOCK_PROCESS_CPUTIME_ID 调用进程的CPU时间 CLOCK_THREAD_CPUTIME_ID 调用线程的CPU时间

clock_getres把参数tsp指向的timespec结构初始化为与clock_id参数对应的时间精度:

#include <sys/time.h>int clock_getres(clockid_t clock_id, struct timespec *tsp);                //若成功:返回0;若出错,返回-1

设置时间可用clock_settime函数:

#include <sys/time.h>int clock_settime(clockid_t clock_id, const struct timespec *tsp);                //若成功:返回0;若出错,返回-1

两个函数localtime和gmtime将日历时间转换成分解的时间,并将这些时间存放在一个tm结构中:

#include <time.h>struct tm *gmtime(const time_t *calptr);struct tm *localtime(const time_t *calptr);struct tm {    int tm_sec;                 //seconds after the minute:[0 - 60]    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 since January:[0 -11]    int tm_year;                //year since 1990    int tm_wday;                //day since sunday:[0 - 6]    int tm_yday;                //day since January 1:[0 - 365]    int tm_isdst;               //daylight saving time flag: <0, 0, >0};
  • 秒可以超过59秒的原因是可以表示润秒
  • localtime将日历时间转化为本地时间,gmtime将日历时间转化为协调统一时间

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

#include <time.h>time_t mktime(struct tm *tmptr);                //出错返回-1

函数strftime是个类似于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);                //两个函数的返回值:若有空间,返回存入数组的字符数;否则,返回0
  • tmptr:要格式化的时间值,格式化结果存在一个长度为maxsize个字符的数组中
  • format:控制时间值的格式,像printf一样,转换说明的形式是百分号后跟一个特定的字符。(有37个转换说明,不列出来了…有兴趣的上网查吧)

strptime函数是strftime函数倒过来的版本,将字符串时间转换成分解时间:

#include <time.h>char *strptime(const char *restrict buf, const char *restrict format,                struct tm *restrict tmptr);                //返回指向上次解析的字符的下一个字符的指针;否则,返回NULL

(这个也有一张大表,不列出来了)

6.11 小结

这章讲了读口令文件和组文件的各种函数,还有与时间相关的各种函数。


  1. 例如口令文件/etc/passwd和组文件/etc/group ↩
  2. 如login和passwd ↩
  3. 该数组以null指针结尾 ↩
0 0
原创粉丝点击