转载

[单刷APUE系列]第六章——系统数据文件和信息

目录

[单刷APUE系列]第一章——Unix基础知识[1]

[单刷APUE系列]第一章——Unix基础知识[2]

[单刷APUE系列]第二章——Unix标准及实现

[单刷APUE系列]第三章——文件I/O

[单刷APUE系列]第四章——文件和目录[1]

[单刷APUE系列]第四章——文件和目录[2]

[单刷APUE系列]第五章——标准I/O库

[单刷APUE系列]第六章——系统数据文件和信息

口令文件

使用过Unix系统的朋友应该知道 /etc/passwd 文件,这就是Unix系统口令文件,在POSIX1.x规范中规定Unix系统必须存在用户数据库,这些用户数据库里每个用户都需要包含一些字段,具体需要查看 <pwd.h> 头文件。

struct passwd {         char    *pw_name;               /* user name */         char    *pw_passwd;             /* encrypted password */         uid_t   pw_uid;                 /* user uid */         gid_t   pw_gid;                 /* user gid */         __darwin_time_t pw_change;              /* password change time */         char    *pw_class;              /* user access class */         char    *pw_gecos;              /* Honeywell login info */         char    *pw_dir;                /* home directory */         char    *pw_shell;              /* default shell */         __darwin_time_t pw_expire;              /* account expiration */ };

在很多Unix系统中, passwd 是一个ASCII文件,每一行是一个用户,然后每个用户都包含这些字段,字段之间使用冒号分隔,但是在苹果系统中,则是使用 opendirectory 守护进程来存储用户数据库等数据。

系统提供了两个获取口令文件项的函数

struct passwd *getpwuid(uid_t uid); struct passwd *getpwnam(const char *login);

这两个函数都会返回passwd结构体,而且需要注意的是,这个结构体指针实际上是指向一块静态区域的指针,也就是说,不同通过保留指针来让后面使用。

struct passwd *getpwent(void);  void setpwent(void); void endpwent(void);

getpwent函数则是一项一项读取,然后将其以passwd结构体返回,非常适合需要读取全部内容的情况。setpwent和endpwent清理读取的缓存,其中endpwent则是关闭所有的文件,当使用getpwent后一定要使用endpwent关闭文件。

阴影口令

在最初的Unix系统实现中,密码是存放在 /etc/passwd 文件的第二个字段中,但是由于有很多程序读取这个文件,所以这个字段被专门移出来放在 /etc/shadow 中,通常情况下,只有root权限才能读取。在Solaris和Linux中,有一组函数用于访问阴影口令文件,但是,非常遗憾的是,苹果系统中没有,所以这里也就只能讲一讲,而不能列出实际的代码。

组文件

struct group {         char    *gr_name;               /* [XBD] group name */         char    *gr_passwd;             /* [???] group password */         gid_t   gr_gid;                 /* [XBD] group id */         char    **gr_mem;               /* [XBD] group members */ };

上面是苹果系统定义的 group 结构体

struct group *getgrgid(gid_t gid); struct group *getgrnam(const char *name);  struct group *getgrent(void); void setgrent(void); void endgrent(void);

就如同口令文件的函数一样,上面的函数用法也是一样的。

附属组ID

在早期Unix系统实现中,是不存在附属组的。直到后来BSD的一个版本引入了附属组ID的概念,这样在权限检查的时候也需要检查附属组ID的权限

int getgroups(int gidsetsize, gid_t grouplist[]);  int setgroups(int ngroups, const gid_t *gidset);  int initgroups(const char *name, int basegid);

getgroups 函数将进程所属用户的附属组ID放入grouplist参数中,groupsize参数用于确定放入的大小,但是实际上,我们可以将groupsize设置为0,然后函数会返回实际的附属组个数,然后就可以很方便的分配grouplist数组,用不着去猜测究竟应该分配多少。

setgroups 是一个root权限操作,用于为进程设置附属组ID。

initgroups 是一系列操作的集合,实际上用到的机会极少,如果有需要的朋友可以自行观看系统手册。

其他数据文件

除了上面讲到的两个文件以外,系统还有很多其他的文件,但是基本上都是提供了同样的接口(get,set,end),而且和前面的用法基本一样,所以这里也不再讲解。

登录账户记录

在实际的运维中,经常会需要查看用户的登录日志,所以系统也有相关的数据文件和接口函数用于开发使用。原著中讲解了utemp结构体的内容,这里不再多讲,但是在苹果系统中,实际上已经被utempx等结构体所取代

struct utmpx {         char ut_user[_UTX_USERSIZE];    /* login name */         char ut_id[_UTX_IDSIZE];        /* id */         char ut_line[_UTX_LINESIZE];    /* tty name */         pid_t ut_pid;                   /* process id creating the entry */         short ut_type;                  /* type of this entry */         struct timeval ut_tv;           /* time entry was created */         char ut_host[_UTX_HOSTSIZE];    /* host name */         __uint32_t ut_pad[16];          /* reserved for future use */ };  struct lastlogx {         struct timeval ll_tv;           /* time entry was created */         char ll_line[_UTX_LINESIZE];    /* tty name */         char ll_host[_UTX_HOSTSIZE];    /* host name */ };

其实,不光是苹果系统,其他的Unix系统的字段也已经被修改扩充了,而且其实这个并不重要,所以只需要了解即可。

系统标识

POSIX定义了uname函数,用于返回主机和操作系统相关的信息,uname命令就是使用了这个函数。

int uname(struct utsname *name);  struct  utsname {         char    sysname[_SYS_NAMELEN];  /* [XSI] Name of OS */         char    nodename[_SYS_NAMELEN]; /* [XSI] Name of this network node */         char    release[_SYS_NAMELEN];  /* [XSI] Release level */         char    version[_SYS_NAMELEN];  /* [XSI] Version level */         char    machine[_SYS_NAMELEN];  /* [XSI] Hardware type */ };

所有的成员都是以null字节结尾,并且BSD派生系统也提供了gethostname函数

int gethostname(char *name, size_t namelen);

实际上还有一个sethostname函数,但是这里也不多讲,除此以外,上面的一些函数实际上有一些已经被移到标准C库中了,所以也能作为跨平台开发使用。

日期和时间

Unix系统都使用的是Unix时间戳,也就是UTC时间1970年1月1日0时0分0秒以来的秒数,在前面我们提到过它,这个就是日历时间,并且是使用 time_t 类型存储的。

time_t time(time_t *tloc);

time函数就是很简单的获取日历时间,在一般的情况下,都是传入null然后获得函数返回值来使用。原著中也讲到了指定时间的获取,但是非常不幸,苹果系统又没有这些方法,所以这里也只能不提及了。

原文  https://segmentfault.com/a/1190000004419381
正文到此结束
Loading...