今天介绍一种解析utmp文件获取系统中用户信息的方法。有关utmp的介绍可以看我之前的文章《utmp文件》。此方法是使用python实现,大致如下:
$ vi utmp.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import struct
UTMP_STRUCT = 'hi32s4s32s256shhIII4i20x'
UTMP_STRUCT_SIZE = struct.calcsize(UTMP_STRUCT)
with open("/var/run/utmp", 'rb') as fd:
while True:
bytes = fd.read(UTMP_STRUCT_SIZE)
if not bytes:
break
data=struct.unpack(UTMP_STRUCT, bytes)
#repr可以看出原始的数据内容
#print(repr(data))
#直接将unpack的tuple转换为字符串,字符串以‘\0’结尾,所以只保留\0前的内容
data = [(lambda s: str(s).split("\0", 1)[0])(item) for item in data]
print(data)
运行结果
$ python utmp.py
['2', '0', '~', '~~', 'reboot', '2.6.32-358.el6.x86_64', '0', '0', '0', '1559633400', '826864', '0', '0', '0', '0']
['1', '53', '~', '~~', 'runlevel', '2.6.32-358.el6.x86_64', '0', '0', '0', '1559633400', '845284', '0', '0', '0', '0']
['8', '3588', 'pts/0', 'ts/0', '', '', '0', '0', '0', '1561434852', '892300', '1023453376', '0', '0', '0']
['7', '27146', 'pts/1', 'ts/1', 'root', '127.0.0.10', '0', '0', '0', '1561944111', '653687', '1023453376', '0', '0', '0']
以上输出了四组数据,也就是四条用户信息。以最后一组数据为例,对应struct utmp的字段为:
类型:ut_type, ut_pid, ut_line, ut_id, ut_user, ut_host, _, _, _, tv_sec, tv_usec, ut_session, _, _, _
数据:['7', '27146', 'pts/1', 'ts/1', 'root', '127.0.0.10', '0', '0', '0', '1561944111', '653687', '1023453376', '0', '0', '0']
如果想知道系统中所有正在登录的终端,可以找第一个项为'7'(struct utmp中ut_type为USER_PROCESS宏定义)的数据项,其中第三个项保存的就是此终端的名字,如上面的数据可以看出pts/1是当前正在登录的终端。
代码中使用struct.calcsize计算出每条用户信息的大小,每次从文件中读出一条用户的信息,然后按照UTMP_STRUCT(hi32s4s32s256shhIII4i20x)格式进行转化。UTMP_STRUCT为struct utmp在struct中对应的格式。struct详细的对应格式可以查看:https://docs.python.org/2/library/struct.html