注:以下内容仅仅是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; }
