【linux编程实践教程(Bruce Molay)】第二章 用户,文件操作与联机帮助:编写who命令

一 总概

  1. 内存中的系统空间存放系统相关的程序与数据;用户空间存放用户相关的程序与数据。
  2. 内存中的用户空间里的应用程序通过内核与外界(用户)进行通信(而内核与外界通讯时,还要通过一层shell)。
  3. bin目录下一般存放命令的二进制文件
  4. utmp文件中保存的是当前正在本系统中的用户的信息。
    wtmp文件中保存的是登录过本系统的用户的信息。
    --------如何保存?如何读取?--------未完待续
    参考博客:who命令编写的详细思路

二 查找who命令的来源

  1. 通过man who
    查找到who格式为:who [OPTION]... [ FILE | ARG1 ARG2 ]
    FILE为–指定从某文件中读取用户信息
    下面还有这样一行话:

If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is
common. If ARG1 ARG2 given, -m presumed: ‘am i’ or ‘mom likes’ are
usual.
意思是如果FILE没有指定,默认从 /var/run/utmp中读取用户数据(who一般情况下都是从这里读取用户数据)。

  1. 那么utmp文件在哪里呢,它的相关信息又该如何获取呢?
    依旧是man命令的使用:man -k utmp man的-k参数依据关键字模糊查找
    得到如下:在这里插入图片描述
    可以发现与登录记录有关的只有utmp(5)这个东西。那么这是个什么东西呢?
    其实就是linux的文件手册,utmp(5)代表utmp这本手册中的第5章节。
  2. 那么如何打开这一章节呢?
    依旧是man(manual缩写,该命令就是查找手册具体内容的)命令 :man 5 utmp 在这里插入图片描述
    可以发现,who命令就是从该utmp文件中读取用户信息的。
    在这里插入图片描述
    这里可以看出:这个utmp文件就是一个存储utmp结构体的数组(所以在读取该文件中用户信息时,自然想到要从该数组中读取,既然是从数组中读取,那思路就很清晰了,c语言读取结构体数组都理解原理吧,直接套用即可,每次读取定字节数(与utmp结构体大小一致)的数据长度赋给一个utmp结构体,就读取成功),而这个utmp结构体(存储用户的信息)又在utmp.h这个头文件中。
  3. 问题又来了,utmp.h文件在哪呢?
    通过查找文件的命令find:find /usr/include -name "utmp.h"在unix系统中,很多头文件都放在usr/include/中
    得到:
    在这里插入图片描述
    真正的结构体具体内容是定义在第一个文件里面的,外面的是更外层的声明
  4. 现在找到了utmp文件的手册,也知道了我们编写who命令是要从该文件中读取信息,那么该文件的地址在手册中有吗?当然!
    在这里插入图片描述
    第一个路径就是其绝对路径,在使用open()函数直接输入这个即可。
  5. 而在unix中这些很常用的路径一般都是已经封装好的宏定义,我们直接调用宏定义即可调用该地址,那么该地址又在哪里呢?
    一般都放在相关的头文件中,那么回到第4部,进入/usr/include/utmp.h中,发现:在这里插入图片描述
    canonical:标准的典型的;compatibility:兼容性
    在这中间有个UTMP_PATH宏定义很可能就是,那么接下来就是去查找_PATH_UTMP在哪个文件里面定义了。
    利用在文件中查找具体文本的命令grep:grep "_PATH_UTMP" /usr/include/*.h
    当不确定在哪个目录下时,也可使用:grep "_PATH_UTMP" /usr/*/*.h"—正则表达式的巧妙使用
    在这里插入图片描述
    双引号带不带无所谓,默认都是查找字符串
    可以发现在paths.h中有_PATH_UTNP宏定义以及其路径,查找成功!

三 who命令的编写

版本一:

#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
void show_info(struct utmp* pUtmp);
int main()
{
	int utmpfd;
	struct utmp cur_log_rcd;
	int rd_len = sizeof(struct utmp);
	if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1)//这里就是对UTMP_FILE的使用,它在tump.h头文件中被宏定义过一次。打开了utmp文件,文件描述符赋给了utmpfd
	{
		perror("sadasd");
		exit(1);
	}
	while (read(utmpfd, &cur_log_rcd, rd_len) == rd_len)
	{
		show_info(&cur_log_rcd);
	}
	close(utmpfd);
	return 0;

}
void show_info(struct utmp* pUtmp)
{
	printf("%-13.13s", pUtmp->ut_user);
	printf("%-8.8s", pUtmp->ut_line);
	printf("%-14.10ld", pUtmp->ut_tv.tv_sec);
	printf("(%s)", pUtmp->ut_host);
	printf("\n");
}

好,接下来问题来了。。。。。。。超难受的各种问题开始出现,花了七八小时午饭都没出就为了debug,详见博客:IT似海(和本文编写who命令没有大关系,不想看可直接跳过)。
版本二–

#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<time.h>
void show_info(struct utmp* pUtmp);
int main()
{
	int utmpfd;
	struct utmp cur_log_rcd;
	int rd_len = sizeof(struct utmp);   
	printf("sad!!!\n");
	if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1)
	{
		perror("sadasd\n");
		exit(1);
	}
	while (read(utmpfd, &cur_log_rcd, rd_len) == rd_len)
	{
		show_info(&cur_log_rcd);
	}
	close(utmpfd);
	//getchar();
	return 0;

}
void show_info(struct utmp* pUtmp)
{
	 time_t tm;    
    tm = time(NULL);//获取当前的总时间秒数
   	printf("%ld\n",tm);
	printf("%ld\n",pUtmp->ut_time);//打印用户登录时的总时间秒数
    printf("calendar times = %lu seconds\n", tm);    
    printf("localtime(&tm):\t%s", asctime(localtime(&tm)));
    printf("gmtime(&tm):\t%s",   asctime(gmtime(&tm)));
    printf("ctime:\t\t%s\n", ctime(&tm));
	//下面才为用户时间:
	if (pUtmp->ut_type != USER_PROCESS)
		return;
	printf("%-13.13s", pUtmp->ut_user);
	printf("%-8.8s", pUtmp->ut_line);
	char * ps;
	//下面这里,两种ps求得的时间秒数是不一样的,第二种是正确的,猜测可能是因为强制转换过程中出现了问题,需要深入探究一些
	//ps=ctime((time_t*)&(pUtmp->ut_time));
	tm=pUtmp->ut_time;
	//ps=asctime(localtime(&tm));
	printf("%14.19s",ps);
	printf("(%s)", pUtmp->ut_host);
	printf("\n");
}

四 总结回顾

  1. 对存储用户登录信息utmp结构体中各参数的认识
  2. 对一些头文件的位置以及内容有所了解—很多都在usr/include目录下
  3. 对查找某些文件以及某些文件内容的方法有了了解,利用find和grep命令
  4. 一些函数的认识与使用—open函数(注意与fopen的区别,见博客详细区别。open与read,write配合使用;fopen与fread,fwrite配合,open只能打开二进制文件,可见utmp文件就是二进制类型的),read函数,ctime,time
  5. 对who的工作原理有所认识,从utmp文件中读取用户信息,而utmp结构体是在utmp.h中定义的,注意区分
  6. 通过联机帮助,查询手册获得详细信息
  7. 强制类型转换对最后转换是否会有影响???
  8. vscode&远程链接&glibc库
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值