在who命令的基本实现(上)这一篇博文介绍了who命令的基本原理,所以我们可以尝试着编写自己的who命令。
who1.c:
#include
#include
#include
#include
#include
#define SHOWHOST /* include remote machine on output */
void show_info (struct utmp*);
int main () {
struct utmp current_record; /* read info into this variable */
int utmpfd; /* just a file descriptor */
int reclen = sizeof(current_record);
if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1) {
perror(UTMP_FILE); /* UTMP_FILE is in utmp.h */
exit(1);
}
while (read(utmpfd, ¤t_record, reclen) == reclen) {
show_info(¤t_record);
}
close(utmpfd);
return 0;
}
void show_info (struct utmp* utbufp) {
printf("%-8.8s", utbufp->ut_name);
printf(" ");
printf("%-8.8s", utbufp->ut_line);
printf(" ");
printf("%10ld", utbufp->ut_time);
printf(" ");
#ifdef SHOWHOST
printf("(%s)", utbufp->ut_host);
#endif
printf("\n");
}
用以下命令将上述文件编译、运行:
cc who1.c -o who1
./who1 //在who1所在目录下运行这条命令
使用who1命令得到的结果为:
可以看到它能显示出:用户名、终端名、从登陆开始到目前为止的秒数、远程主机名。
我们的who1有两个不足:
①无法正确的显示时间;
②
但与系统自带的who命令作对比可以发现:
系统中登陆的用户其实只有wzh这一个用户,这是因为utmp文件实际上包含所有终端的信息,包括那些尚未被用到的终端的信息也存放在utmp中。
who2.c:
1.
(使用man -k utmp命令可以看到以下两张图片的信息)
utmp结构体中有个ut_type属性。以下是ut_type可以有的一些值:
当ut_type的值为7时,表示这是一个已经登录的用户。因此,对程序作出修改:
void show_info (struct utmp* utbufp) {
if (utbufp->ut_type != USER_PROCESS) return;
printf("%-8.8s", utbufp->ut_name);
printf(" ");
printf("%-8.8s", utbufp->ut_line);
printf(" ");
printf("%10ld", utbufp->ut_time);
printf(" ");
#ifdef SHOWHOST
printf("(%s)", utbufp->ut_host);
#endif
printf("\n");
}
主要是添加上面代码片段中加粗的那条语句。
从who命令的基本实现(上)可以知道用户登录时间ut_time其实被定义为ut_tv结构体中的tv_sec变量,而tv_sec变量的类型为int32_t。
而我在utmp.h文件中是没发现int32_t的实际类型是什么:
但是我在utmp.h文件中发现它include了一个头文件。我猜想int32_t的实际类型可能会在这个头文件中定义。进一步查看可以知道int32_t的实际类型为int类型:
使用如下命令查看关于时间的联机帮助:
man -k time
更好的过滤方法是:
man -k time | grep transform
或
man -k time | grep -i convert
这里使用的是ctime(3)来将表示时间的整数值转换成人们日常所使用的时间形式。
通过man 3 ctime命令查看可以发现下面这两段信息:
其中这篇博文介绍了追踪time_t实际类型的方法,time_t实际类型为long int。
这就表示ctime这个函数可以将指向用户登录时间ut_time的指针作为参数,然后该函数返回一个上图中显示的字符串。
系统为32位ubuntu的int,long,long int的字节数: