linux系统中的数据文件有很多,在这一章里介绍的主要内容是和系统有关的一系列文件,包括passwd,shadow,group,utmp,wtmp以及一些系统的相关信息和时间的相关操作。
1.passwd文件(即口令文件)
口令文件就是存在于目录/etc/passwd文件,它用来存储系统中的用户名,密码,用户ID,所属组ID,注释,起始工作目录和默认的shell。密码在早期是记录在这个文件中的,并且使用单向加密算法把密码加密成13个可读的ascii字符集,也就是说不可以对这13个字符集进行逆运算得到原来的密码。但是,由于可以通过这个文件对密码进行猜测,这里的猜测是指,我们可以指定一个密码,按照这种加密算法加密后,和passwd文件中的加密后的密码进行对照。所以处于安全的考虑,现在的linux系统都将密码存储在另一个文件/etc/shadow中。这样就可以对shadow文件的存取权限进行限制,从而保证了系统的安全性。
我们通过如下两个函数可以得到passwd文件的信息,如下:
struct passwd* getpwnam(const char* name);
struct passwd* getpwuid(uid_t uid);
这两个函数都返回一个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 */
};
它包括了/etc/passwd文件中的各个字段。第一个函数指定用户名,第二个函数指定用户的ID。如果函数执行成功则返回一个指针,这个指针指向一个静态存储区域。否则如果函数执行失败,则返回NULL。
如果想要遍历passwd文件,需要使用三个函数:
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwent(void);
void setpwent(void);
void endpwent(void);
getpwent函数用来每次从/etc/passwd文件中读取一个passwd记录,并将它存储在一个静态的存储区域。每一次的调用都会重新填写该静态存储区域,也就是说,上次调用getpwent返回的值会被覆盖。如果调用getpwent时,/etc/passwd文件尚未打开,则会自动打开该文件。setpwent的作用是反绕该文件到passwd文件首,所以调用getpwent函数就会返回第一个记录,再次调用就会返回第二个记录,等等。endpwent函数用来关闭打开的/etc/passwd文件。这3个函数可以用来实现getpwnam和getpwuid。
2.group文件(即组文件)
组文件就是用来保存组的一些信息,这个文件就是/etc/group文件。这个文件中包括了组名,组密码,组ID和组成员列表。与对passwd的操作类似,对组的操作也有如下这些函数:
#include <sys/types.h>
#include <grp.h>
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
得到的group的信息将会存储在一个group结构体的静态存储区域中。这个结构体的结构如下:
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
第一个成员是组名,第二个成员是组密码,第三个成员是组ID,第四个成员是属于该组的成员。同样还有3个函数可以对group进行操作:
#include <sys/types.h>
#include <grp.h>
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
这三个函数与对passwd进行操作的3个函数极为相似,在这里就不说了。
添加组ID是用来给某一个用户添加一个组。对添加组ID所用到的操作包括:
#include <sys/types.h>
#include <unistd.h>
int getgroups(int size, gid_t list[]);
#include <grp.h>
int setgroups(size_t size, const gid_t *list);
3.utmp、wtmp和uname
utmp和wtmp这两个文件用来记录当前登录进系统的用户和系统的登录和注销事件。每次当一个用户登录系统时,就会填写一个utmp记录,并将这个记录写入到utmp文件和wtmp文件中,这个记录如下:
struct utmp
{
char ut_line[8];
char ut_name[8];
long ut_time;
}
utmp用来记录当前系统中的登录用户,而wtmp文件用来记录系统的登录和注销的历史记录。每次当注销时,就会将utmp文件中对应的用户名清除,并且将注销的用户信息添加到wtmp中。使用 who 命令可以查看当前系统中,登录的用户,使用 who /var/log/wtmp 可以查看系统中的登录和注销的事件,或者使用 last 命令也可以查看系统的登录和注销事件。
uname这个函数用来获取和系统相关的一些信息,它的函数原型如下:
#include <sys/utsname.h>
int uname(struct utsname *buf);
这个函数如果执行成功,则会将系统的信息填写到一个由参数buf指定的ustname结构体中。ustname结构体如下:
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
};
4.时间和日期
在linux中,时间的记录是从1970年1月1日0时0分0秒开始经过的秒数,这个称为日历时间。可以使用如下函数获取:
#include <time.h>
time_t time(time_t *t);
如果函数执行成功,会向参数指定的内从中填写这个日历时间,并且返回这个日历时间。对日历时间可以通过一些函数来进行转换,是我们可以读懂。例如: localtime 和 gmtime 可以将日历时间转换为以年月日时分秒表示的时间。关于时间的操作函数还有很多,所以这里就不列举了,只要在需要用到的时候会查阅手册就行了。