注:以下内容仅仅是who命令的初步编写,并未实现其余的命令行选项
1.Linux系统中who命令的用途:
打印已经登录系统用户的相关信息,如:
name tty7 2016-08-16 15:34 (:0)
name2 tty1 2016-8-16 15:35 (:0.0)
上述所列打印的信息中第一列为已经登录用户的用户名,第二列为终端名,第三列、第四列为登录时间,第五列为登录地址,两行分别代表目前所登录的两个不同用户
2.who命令的工作原理
用户的登录信息必然需要存储在某个文件中,当用who查看这些信息时,首先进入该文件读取相关的存储信息,再将该信息以一定的形式打印出来。
3.如何自己实现一个who命令
(1)首先需要确定存储相关信息的文件是什么
(2) 进入该文件读取信息
- 打开该文件(open)
- 读取信息(read)
- 关闭文件描述符(close)
(3) 打印在标准输出设备
4.具体实现
(1)如何确定存储信息的文件是哪个?
借助man命令查阅手册,查阅与who相关的信息(man who),可以看到出现了两个相关的文件名:“/var/run/utmp”,"/var/log/wtmp"
可以猜测应该与这个文件有关,再深入了解一下这两个文件的相关信息,根据关键字“utmp”查阅手册(man -k utmp:man + -k表示根据关键字查阅),可以看到出现的信
息中有一项是“utmp(5) login records”,猜测其与登录信息有关,进一步查阅utmp(man 5 utmp),可以看到一个结构体(struct utmp),该结构体的元素即登录信息
再看手册,可以发现该结构体在文件“utmp.h”中声明,而在/var/run/utmp中以该结构体的形式存储相关信息,因此写程序时包含头文件“utmp.h”,即可件“/var/run/utmp”中
读取信息。
(2)如何读取相关信息?
打开文件(open),读取(read),完成后关闭(close)
(3)需要改进的地方有哪些?
文件中所包含的信息不止已登录用户的登录信息,还包含其他信息,应该清除其余的空白记录(由结构体中的ut_type的值来进行筛选)
结构体中的登录时间用的是秒来表示,需转换成可阅读的形式来显示(ctime进行转换)
5.代码
注:在代码中对函数加入了出错检查,并写成了出错处理封装函数
(1)file.h
#include<stdio.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<stdlib.h>
void perr_exit(const char *str);
int Open(const char *pathname, int flags);
ssize_t Read(int fd, void *buf, size_t count);
int Close(int fd);
(2)file.c(出错处理封装函数)
#include"file.h"
void perr_exit(const char *str)
{
perror(str);
exit(-1);
}
int Open(const char *pathname, int flags)
{
int res;
if((res=open(pathname,flags))<0)
{
perr_exit("open");
}
else
return res;
}
ssize_t Read(int fd, void *buf, size_t count)
{
ssize_t res;
res=read(fd,buf,count);
if(res<0)
{
perr_exit("read");
}
else
return res;
}
int Close(int fd)
{
if(close(fd)<0)
{
perr_exit("close");
}
else
return 0;
}
(3)main.c(实现了登录信息的读取及打印)
#include"file.h"
#include<utmp.h>
#include<time.h>
void show_info(struct utmp buf)//用于实现时间形式的转换以及相关信息的打印
{
char *time=NULL;
time=ctime(&buf.ut_time);
if(time==NULL)
{
perr_exit("ctime");
}
printf("%-8.8s",buf.ut_name);
printf(" ");
printf("%-8.8s",buf.ut_line);
printf(" ");
printf("%-12.12s",time+4);
printf(" ");
//#ifdef SHOWHOST
printf("(%s)",buf.ut_host);
//#endif
printf("\n");
return;
}
int main(void)
{
int fd;
struct utmp buf;
fd=Open("/var/run/utmp",O_RDONLY);
while(Read(fd,&buf,sizeof(struct utmp))==sizeof(buf))
{
if(buf.ut_type!=USER_PROCESS)
continue;
else
show_info(buf);
}
Close(fd);
return 0;
}