目录
[单刷APUE系列]第一章——Unix基础知识[1]
[单刷APUE系列]第一章——Unix基础知识[2]
[单刷APUE系列]第二章——Unix标准及实现
[单刷APUE系列]第三章——文件I/O
[单刷APUE系列]第四章——文件和目录[1]
[单刷APUE系列]第四章——文件和目录[2]
[单刷APUE系列]第五章——标准I/O库
[单刷APUE系列]第六章——系统数据文件和信息
[单刷APUE系列]第七章——进程环境
[单刷APUE系列]第八章——进程控制[1]
[单刷APUE系列]第八章——进程控制[2]
[单刷APUE系列]第九章——进程关系
[单刷APUE系列]第十章——信号[1]
口令文件
使用过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然后获得函数返回值来使用。
原著中也讲到了指定时间的获取,但是非常不幸,苹果系统又没有这些方法,所以这里也只能不提及了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。