Q1: who命令能做些什么?
$ who
xxx :0 yyyy-mm-dd hh:mm (:0)
xxx pts/0 yyyy-mm-dd hh:mm (:0)
这是在CentOS7上的输出结果,who的版本为8.22。每一行代表一个已经登陆的用户,第一列是用户名,第二列是终端名,第三列是登录时间。
可以通过阅读手册详细查看who命令。
$ man who
Q2: who命令是如何工作的?
首先我们先阅读联机帮助:
DESCRIPTION
Print information about users who are currently logged in.
If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is common. If ARG1 ARG2 given, -m presumed: ‘am i‘ or ‘mom likes‘ are usual.
通过描述得知已登录用户的信息一般会在/var/run/utmp或/var/log/wtmp中。
utmp文件中保存的是当前正在本系统中的用户的信息。wtmp文件中保存的是登录过本系统的用户的信息。
现在关注utmp文件,who通过读取该文件获得信息。使用带有-k命令可以根据关键字搜索联机帮助:
$ man -k utmp
注意观察描述,有一行包含可能有用的信息:
utmpx (5) - login records
接着使用man查看联机帮助:
$ man 5 utmp
浏览手册,发现该文件结构定义在头文件中,首先去/usr/include/目录下寻找:
$ find /usr/include/utmp.h
/usr/include/utmp.h
然后用more或者cat命令查看该文件:
$ more /usr/include/utmp.h
浏览发现该文件并不是声明原始数据结构的头文件:
/* Get system dependent values and data structures. */
#include
接着再到下一层目录bits当中查看,这里注意在C源文件中不能include,仍然是include。
$ more /usr/include/bits/utmp.h
通过浏览代码,获取到结构体:
/* The structure describing an entry in the user accounting database. */
struct utmp
{
short int ut_type;/* Type of login. */
pid_t ut_pid;/* Process ID of login process. */
char ut_line[UT_LINESIZE];/* Devicename. */
char ut_id[4];/* Inittab ID. */
char ut_user[UT_NAMESIZE];/* Username. */
char ut_host[UT_HOSTSIZE];/* Hostname for remote login. */
struct exit_status ut_exit;/* Exit status of a process marked
as DEAD_PROCESS. */
/* The ut_session and ut_tv fields must be the same size when compiled
32- and 64-bit. This allows data files and shared memory to be
shared between 32- and 64-bit applications. */
#ifdef __WORDSIZE_TIME64_COMPAT32
int32_t ut_session;/* Session ID, used for windowing. */
struct
{
int32_t tv_sec;/* Seconds. */
int32_t tv_usec;/* Microseconds. */
} ut_tv;/* Time entry was made. */
#else
long int ut_session;/* Session ID, used for windowing. */
struct timeval ut_tv;/* Time entry was made. */
#endif
int32_t ut_addr_v6[4];/* Internet address of remote host. */
char __unused[20];/* Reserved for future use. */
};
观察当中的变量,可以获取到who所使用的成员变量ut_type(who用来过滤空白而留下当前用户)、ut_line(显示设备名,即用户的终端)、ut_user(用户名)、ut_host(远程登录用户名,(:0)显示)、ut_time(时间)。
所以who命令其实是打开utmp文件,读取记录,显示记录,然后关闭utmp文件。
Q3: 如何编写who?
根据以上分析得知who命令按照打开文件,读取记录,显示记录,关闭文件的流程工作。打开文件用open,读取用read,显示printf,关闭close。其中printf就不用介绍了。另外三个具体如下:
open
目标
打开一个文件
头文件
#include
函数原型
int fd = open(char *name, int how)
参数
name 文件名
how O_RDONLY, O_WRONLY, O_RDWR
返回值
-1 遇到错误
int 成功返回