linux环境c语言实现who,Linux下who命令之C语言实现

本文详细介绍了如何使用C语言从Linux的utmp文件中读取登录信息,通过理解utmpx数据结构,包括ut_tv时间戳,实现了类似who命令的功能,并处理了时间格式转换。通过代码实例展示了如何编译和调试,最终达到与系统who命令一致的输出。
摘要由CSDN通过智能技术生成

Linux下who命令之C语言实现

Step1:前期准备

首先要有一个清楚的认识:linux中一切皆文件

实现who命令,who命令也是Linux中的一个文件,那我们怎么找到它呢?我们可以“找男人”(man),终端下执行命令:man who

此处我装了汉译版的man手册,查看到这样一段提示如下:

7fe3a5822822ca1e00f7c92219c418d0.png

所以退出man手册,执行命令:info who

找到如下图相关信息:

bd5ee3ad13c4b96c85c42c2708183767.png

也可以找到下面这样的一段话,也就是说:who命令可以这样实现,读取utmp里边的内容,然后显示记录,最后关闭utmp,who命令就是一个很简单的体现吧,打开文件,保存文件id,根据文件id读取用户的登陆信息,显示在终端。

f566bfb37d286efd7e2db62da1f623ac.png

我们尝试地打开一下/var/run/utmp这个文件得到如下画面,发现是一串乱码,但还是能看出相关who的信息的

05a24275feb1bad48f56b74122345874.png

既然不清楚utmp是干嘛的,我们可以使用man -k来检索一下相关信息,得到信息如下

fb837d494e2f2d2a11373b68d93d8921.png

经过筛选,发现只有utmpx(5)是符合我们要求的,其中后面显示的是login records,而who命令不就是用来输出登录信息的;man的第五个类型表示的是文件格式和规范,说明此处可能存储了登录记录的数据结构

使用指令:man 5 utmpx,可以得到如下有用信息:

9047781c3029209ea389a313ed70d9b2.png

也可以使用输出重定向指令man 5 utmpx > utmp.txt,得到文本格式的utmp数据结构体如下:struct utmp {

short ut_type; /* Type of record */

pid_t ut_pid; /* PID of login process */

char ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */

char ut_id[4]; /* Terminal name suffix,

or inittab(5) ID */

char ut_user[UT_NAMESIZE]; /* Username */

char ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or

kernel version for run-level

messages */

struct exit_status ut_exit; /* Exit status of a process

marked as DEAD_PROCESS; not

used by Linux init (1 */

/* The ut_session and ut_tv fields must be the same size when

compiled 32- and 64-bit. This allows data files and shared

memory to be shared between 32- and 64-bit applications. */

#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32

int32_t ut_session; /* Session ID (getsid(2)),

used for windowing */

struct {

int32_t tv_sec; /* Seconds */

int32_t tv_usec; /* Microseconds */

} ut_tv; /* Time entry was made */

#else

long ut_session; /* Session ID */

struct timeval ut_tv; /* Time entry was made */

#endif

int32_t ut_addr_v6[4]; /* Internet address of remote

host; IPv4 address uses

just ut_addr_v6[0] */

char __unused[20]; /* Reserved for future use */

};

此时万里长征已走一半,对比系统who命令,发现该结构体中并没有直接给出用户登录时间的成员变量,而是内嵌了一个ut_tv的时间结构体,其中成员变量tv_sec才是我们需要的。

如果耐心地看完该帮助文档,可以在下面一段代码中有新的发现:

0d3638d6fdba0b31b112f3dbfa9ec2e2.png

此处定义了一个ut_time的宏,指向的就是ut_tv.ut_sec,而我们需要用到的不是这样一个以秒为单位的格林威治标准时间,所以才后面需用到ctime()函数。

在这儿用的就是刚刚说的linux的一个思想,一切事物都是文件。

Step2:其余头文件的准备

time.h:将格林威治标准时间(GMT)长整形的数时间转化为我们所熟悉的时间表示,运用ctime()函数

string.h:调整输出格式,后面调试时会提到用处。

其余头文件:因为要打开文件嘛,所以有些头文件必不可少,这个在我本周博客中有详细介绍:博客地址

Step3:编程思想

查看UTMP_FILE宏:grep -nr UTMP_FILE /usr/include

0d38d4357e9fb0ddb75f3f350c5a7a99.png

读取其结构体,将需要的变量提取出来并按照一定的格式输出

其中,时间输出本来是一串格林威治标准时间(GMT)长整形的数,可以用ctime()将把日期和时间转换为字符串

Step4:代码实现

其中等下需要修改的代码贴在此处:void showtime(long timeval)

{

char* cp;

cp = ctime(&timeval);

printf("%s",cp+4); //+4是因为*cp所指的一串字符前4个字符表示为“星期”,可以忽略此信息

}

Step5:编译执行

执行结果如下:

ca248cc343ac3e3641b1ac4aa35531ed.png

发现“(:0)”被换行了,但是程序中并没有输出换行字符。经过一番思索后,猜想ctime()函数的返回值*cp可能自动在最后补了一个字符\n。

Step6:调试代码

那只要能回退一个字符就好了,比如输出一个\b(退格字符)

编译再运行,发现输出格式仍是原样,最后经过了解\b确实是可以回退一个字符,但是并不能实现退到上行,也就是不能消除\n带来的影响

百度之后,说可以通过输出\r\b来实现“退行”,但实践后发现也不可取

最后考虑到直接修改*cp字符串中最后一个字符为\0,使输出达到与系统who命令一样的效果

在输出语句前添加如下代码(需用到string.h):

cp[strlen(cp)-1] = '\0'

最后编译执行效果,可以看出与who命令基本一致:

e053d06e57fe7412a08e2500c0f61266.png

来源:http://www.cnblogs.com/20145221GQ/p/6060420.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值