第2章 用户、文件操作与联机帮助:编写who命令

一 介绍

who命令会显示系统中活动用户的情况。

二 关于命令who

Unix系统中,几乎所有的命令都是人为编写的程序。在Unix系统中增加新命令方法:将程序的可执行文件放到以下任意一个目录:

/bin
/usr/bin
/usr/local/bin

三 问题1:who命令做些什么

who命令的输出格式如下:

用户名  终端名  登录时间   用户登录地址

可通过man命令查看联机帮助:
在这里插入图片描述

四 问题2:who命令是如何工作的

已登录用户的信息放在文件/var/adm/utmp中,who通过读改文件获得信息。
使用带有选项-k的man命令可以根据关键字搜索联机帮助,例如:man -k utmp
在这里插入图片描述
在这里插入图片描述

可以得出:who要读取utmp这个文件,进一步,utmp文件里保存的是结构数组,数组元素是utmp类型的结构,可以在utmp.h中找到定义,该文件在/usr/include目录中。
在这里插入图片描述
在这里插入图片描述

在CentOS6.5中,结构体定义在/usr/include/bits/utmp.h头文件中:
在这里插入图片描述

  • ut_user数组:保存登录名
  • ut_line数组:保存设备名
  • ut_hose数组:保存用户用于登录的远程计算机名

由此可见,who的工作流程可如下图表示:
在这里插入图片描述

五 如何编写who

1.如何从文件中读取数据结构

(1)打开一个文件:open

open()系统调用在进程和文件之间建立一条连接,这个连接被称为文件描述符,基本用法如下:

系统调用open
目标打开一个文件
头文件<fcntl.h>
函数原型int fd=open(char* name,int how)
name文件名
howO_RDONLY,O_WRONLY,O_RDWR
返回值-1:遇到错误,int 成功返回

Unix并不禁止一个文件同时被多个进程访问。
如果文件被顺利打开,内核会返回一个正整数值,叫做文件描述符。如果同时打开好几个文件,它们所对应的文件描述符是不同的,如果将一个文件打开多次,对应的文件描述符也不相同。必须通过文件描述符对文件进行操作

(2)从文件读取数据:read

用法如下:

系统调用read
目标将数据读到缓冲区
头文件<unistd.h>
函数原型ssize_t numread=read(int fd,void* buf,size_t qty)
fd文件描述符
buf用于存放数据的目的缓冲区
qty要读取的字节数
返回值-1:遇到错误,numread 成功读取

(3)关闭文件:close

用法如下:

系统调用close
目标关闭一个文件
头文件<unistd.h>
函数原型int result=close(int fd)
fd文件描述符
返回值-1:遇到错误,0: 成功关闭

(4)编写who1.c

/* who1.c - a first version of the who program
 *          open,read UTMP file,and show results
 */
 
 #include<fcntl.h>
 #include<utmp.h>
 #include<stdio.h>
 #include<unistd.h>
 
 #define SHOWHOST
 
 void show_info(struct utmp* utbufp);
 
 int main()
 {
	 struct utmp current_record;
	 int utmpfd;
	 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,&current_record,reclen)==reclen)
		 show_info(&current_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(" ");
 #ifndef SHOWHOST
	 printf("(%s)",utbufp->ut_host);
 #endif
	printf("\n");
 }

运行结果如下:
在这里插入图片描述

系统who命令结果如下:
在这里插入图片描述

可见,相比系统who命令,有两处需要完善:

  • 清除空白记录
  • 正确显示登录时间

(5)编写who2.c

1)清除空白记录

实际上utmp包含所有终端的信息,甚至那些尚未被用到的终端信息。
/usr/include/bits/utmp.h文件中有如下记录:
在这里插入图片描述

可以看出,utmp结构中有一个成员ut_type,当其值为7(USER_PROCESS)时,表示这是一个已经登录的用户名。根据这一点,进行如下修改:

 void show_info(struct utmp* utbufp)
 {
	 if(utbufp->ut_type!=USER_PROCESS)
		 return;
	 printf("%-8.8s",utbufp->ut_name);
	 ..........................
}
2)以可读的方式显示登录时间

Unix存储时间的方式:time_t数据类型。时间是用一个整数表示,它的值是从1970.01.01 00:00:00开始所经过的秒数。
将time_t显示出来::ctime
在命令行中输入:

man -k time | grep transform

在这里插入图片描述
很多记录提到了ctime,ctime将表示时间的整数值转换成日常所用的时间形式
在这里插入图片描述
在这里插入图片描述
可见,ctime()函数要输入一个指向time_t的指针,返回如下格式的字符串:

Wed Jun 30 21:49:08 1993.\n

对上述字符串进行处理,即可得到需要的日期。
由此得到who的第二个版本:

/* who2.c - a first version of the who program
 *          open,read UTMP file,and show results
 */
 
 #include<fcntl.h>
 #include<utmp.h>
 #include<stdio.h>
 #include<unistd.h>
 #include<time.h>
 
 /*#define SHOWHOST*/
 
 void show_info(struct utmp* utbufp);
 void showtime(long timeval);
 
 int main()
 {
	 struct utmp utbuf;
	 int utmpfd;
	 
	 if((utmpfd=open(UTMP_FILE,O_RDONLY))==-1)
	 {
		 perror(UTMP_FILE);                     /*UTMP_FILE is in utmp.h*/
		 exit(1);
	 }
	 while(read(utmpfd,&utbuf,sizeof(utbuf))==sizeof(utbuf))
		 show_info(&utbuf);
	 close(utmpfd);
	 return 0;
 }
 
 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(" ");
	 showtime(utbufp->ut_time);
 #ifdef SHOWHOST
	 printf("(%s)",utbufp->ut_host);
 #endif
	printf("\n");
 }
 
 void showtime(long timeval)
 {
	 char *cp;
	 cp=ctime(&timeval);
	 printf("%12.12s",cp+4);
 }

编译后执行结果如下:
在这里插入图片描述
在这里插入图片描述
可见二者基本相似。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值