如何编写who命令

总结自书《Unix-Linux编程实践教程》

who命令

一、who命令能做什么

1.输入命令
在这里插入图片描述
显示用户名、终端名、登录时间等信息

**2.阅读手册 ** man who
NAME:命令名以及命令的简短说明
SYNOPSYS(概要):命令格式
DESCRIPTION:命令功能的详细阐述以及参数选项

二.who命令如何工作

1.阅读手册
了解到与utmp文件有关
wtmp与登录和注销有关,现在用不到
在这里插入图片描述

2.搜索联机帮助
man -k utmp
了解到可能与utmp(5)有关
在这里插入图片描述
man 5 utmp
了解到与utmp.h有关
在这里插入图片描述
●查找utmp.h
在这里插入图片描述
●查看utmp.h,发现utmp结构体中包含几个变量
ut_user保存登录名
ut_line保存设备名
ut_time保存时间
ut_host远程登录计算机名
在这里插入图片描述
●至此我们就知道了who的工作原理就是打开utmp文件并读取,然后关闭。

三、如何编写who命令

●需要做两件事:
1.从文件中读取数据
2.将数据合理的显示

为了完成第一件事,可以去搜索和读取文件有关的主题

man -k file|grep read

在这里插入图片描述
找到read命令并man 2 read 查看手册:
 size_t read(int fd,void *buf,size_t count)
 从fd(文件描述符)所指的文件传count个参数进入buf

类似的方法找到与打开关闭文件有关的open与close
 fd open(char *name,int how)
 int close(int fd)

完整代码

#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
void show_info(struct utmp *utbufp);
void showtime(long);
int main()
{
	struct utmp current_record;//read into
	int utmpfd;//read from
	int reclen=sizeof(current_record);
	if((utmpfd=open(UTMP_FILE,O_RDONLY))==-1){
		return -1;
	}
	while(read(utmpfd,&current_record,reclen)==reclen)
		show_info(&current_record);
	close(utmpfd);
	return 0;

}
void show_info(struct utmp *utbufp)
{
	if(utbufp->ut_type!=USER_PROCESS)
	//如果已经登陆,ut_type等于USER_PROCESS
			return ;
    printf("%-8.8s",utbufp->ut_name);//logname
    //printf(" ");
    printf("%-8.8s",utbufp->ut_line);//the tty
    //printf(" ");
    showtime(utbufp->ut_time);//调用showtime显示time_t类型
    //printf(" ");
    printf("(%s)",utbufp->ut_host);//the host
    //printf(" ");
    printf("\n"); //newline
}
void showtime(long timeval)
{
	char *cp;
	cp=ctime(&timeval);//ctime将秒数转换为日常使用的形式
	printf("%12.12s",cp+4);//从第4个字符开始打印12个字符
}

结果

四、如何提高效率

 系统调用在内核中,内核和用户来回切换消耗很多资源,加入缓冲机制可以提高程序的效率,用一个能容纳多个utmp结构的数组作为缓冲区,编写utmp_next函数获取下一个utmp结构的数据
在这里插入图片描述

utmplib.c

#include<stdio.h>
#include<fcntl.h>
#include<sys/types.h>//是Unix/Linux系统的基本系统数据类型的头文件
#include<utmp.h>
#include<unistd.h>
#define NRECS 16
#define NULLUT ((struct utmp*)NULL)
#define UTSIZE sizeof(struct utmp)
static char utmpbuf[NRECS*UTSIZE];
static int num_recs;
static int cur_rec;
static int fd_utmp=-1;

int utmp_open(char *filename)
{
	fd_utmp=open(filename,O_RDONLY);
	num_recs=0;
	cur_rec=0;
	return fd_utmp;
}

struct utmp* utmp_next()
{
	struct utmp* recp;
	if(fd_utmp==-1)//打开文件出错
		return NULLUT;
	if(cur_rec==num_recs&&utmp_reload()==0)//如果缓冲里没有也不能重装
		return NULLUT;
	recp=(struct utmp*)&utmpbuf[cur_rec*UTSIZE];//获取下一个记录的地址
	cur_rec++;
	return recp;
}
int utmp_reload()
{
	int amt_read;//读取的字节数
	amt_read=read(fd_utmp,utmpbuf,NRECS*UTSIZE);
	num_recs=amt_read/UTSIZE;//读取的utmp数据个数
	cur_rec=0;
	return num_recs;
}
void utmp_close()
{
	if(fd_utmp!=-1)
		close(fd_utmp);
}

main.c

#include<stdio.h>
#include<fcntl.h>
#include<utmp.h>
#include<sys/types.h>
#include<time.h>
#include<stdlib.h>
#include<unistd.h>
void show_info(struct utmp *);
void showtime(time_t);

int main()
{
	struct utmp *utbufp;
	if(utmp_open(UTMP_FILE)==-1)
	{
		perror(UTMP_FILE);
		exit(-1);
	}
	while((utbufp=utmp_next())!=(struct utmp*)NULL)//持续读取下一个
		show_info(utbufp);
	utmp_close();
	return 0;
}
void show_info(struct utmp *utbufp)
{
	if(utbufp->ut_type!=USER_PROCESS)
	//如果已经登陆,ut_type等于USER_PROCESS
			return ;
    printf("%-8.8s",utbufp->ut_name);//logname
    //printf(" ");
    printf("%-8.8s",utbufp->ut_line);//the tty
    //printf(" ");
    showtime(utbufp->ut_time);//调用showtime显示time_t类型
    //printf(" ");
    printf("(%s)",utbufp->ut_host);//the host
    //printf(" ");
    printf("\n"); //newline
}
void showtime(long timeval)
{
	char *cp;
	cp=ctime(&timeval);//ctime将秒数转换为日常使用的形式
	printf("%12.12s",cp+4);//从第4个字符开始打印12个字符
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值