Rust系统日志处理库utmp-classic-raw的使用:高效解析和处理Unix/Linux utmp日志文件

Rust系统日志处理库utmp-classic-raw的使用:高效解析和处理Unix/Linux utmp日志文件

utmp-classic-raw介绍

utmp-classic-raw是一个用于读取原始Unix utmp文件的Rust库。需要注意的是,所有类Unix系统(包括所有GNU/Linux发行版、MacOS和除OpenBSD外的所有BSD系统)都使用较新的utmpx文件格式,尽管它们仍称之为utmp。这个库仅适用于原始的Unix utmp文件格式,据我所知只有OpenBSD还在使用这种格式。

如果你需要在除OpenBSD外的其他系统上使用,你可能需要寻找一个utmpx库,尽管大多数库都自称是utmp库。

示例运行

库的根目录中包含了一个示例utmp文件,你可以通过以下命令运行示例:

cargo run --package utmp-classic --example dump-utmp tests/samples/basic.utmp

历史背景

这个库是对utmp-rs(由upsuper开发)的修改版本。它被更新为适用于OpenBSD仍在使用的经典AT&T Unix v1风格的utmp文件。

完整示例代码

以下是使用utmp-classic-raw库解析utmp文件的完整示例:

use std::fs::File;
use std::io::Read;
use utmp_classic_raw::UtmpEntry;

fn main() -> std::io::Result<()> {
    // 打开utmp文件
    let mut file = File::open("/var/run/utmp")?;
    
    // 读取文件内容
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;
    
    // 解析utmp条目
    let entries = UtmpEntry::from_bytes(&buffer)?;
    
    // 打印每个条目信息
    for entry in entries {
        println!("User: {:?}", entry.user);
        println!("Terminal: {:?}", entry.line);
        println!("Host: {:?}", entry.host);
        println!("Login Time: {:?}", entry.time);
        println!("------------------------");
    }
    
    Ok(())
}

代码说明

  1. 首先打开并读取utmp文件内容到缓冲区
  2. 使用UtmpEntry::from_bytes方法解析二进制数据为UtmpEntry结构
  3. 遍历所有条目并打印相关信息,包括:
    • 用户名
    • 终端设备
    • 主机信息
    • 登录时间

安装方法

在你的项目中运行以下Cargo命令:

cargo add utmp-classic-raw

或者在Cargo.toml中添加:

utmp-classic-raw = "0.1.3"

注意事项

  • 该库主要针对OpenBSD系统,其他系统可能需要使用utmpx格式的库
  • 解析前需要确保有足够的权限读取utmp文件
  • 时间字段可能需要额外处理转换为可读格式

1 回复

Rust系统日志处理库 utmp-classic-raw 使用指南

完整示例代码

下面是一个综合使用 utmp-classic-raw 库的完整示例,展示了如何读取系统登录信息并生成统计报告:

use utmp_classic_raw::{UtmpEntry, UtmpReader};
use std::error::Error;
use std::collections::HashMap;

fn main() -> Result<(), Box<dyn Error>> {
    // 1. 读取当前登录用户
    let current_users = get_current_users()?;
    println!("当前登录用户: {:?}", current_users);

    // 2. 分析登录历史
    analyze_login_history()?;

    // 3. 生成登录统计
    generate_login_stats()?;

    Ok(())
}

/// 获取当前登录用户列表
fn get_current_users() -> std::io::Result<Vec<String>> {
    let mut users = Vec::new();
    let reader = UtmpReader::open("/var/run/utmp")?;
    
    for entry in reader.entries() {
        if let Ok(UtmpEntry::UserProcess(entry)) = entry {
            if let Some(user) = entry.user() {
                users.push(user.to_string());
            }
        }
    }
    
    Ok(users)
}

/// 分析登录历史记录
fn analyze_login_history() -> std::io::Result<()> {
    let mut reader = UtmpReader::open("/var/log/wtmp")?;
    let mut count = 0;
    
    println!("\n最近5次登录记录:");
    // 反向迭代获取最新记录
    for entry in reader.entries().rev().take(5) {
        match entry {
            Ok(UtmpEntry::UserProcess(entry)) => {
                println!(
                    "[{}] 用户: {:8} 终端: {:8} 来源: {:15} 时间: {}",
                    count + 1,
                    entry.user().unwrap_or("unknown"),
                    entry.line().unwrap_or("?"),
                    entry.host().unwrap_or("local"),
                    entry.time()
                );
                count += 1;
            }
            _ => {}
        }
    }
    
    Ok(())
}

/// 生成登录统计信息
fn generate_login_stats() -> std::io::Result<()> {
    let mut reader = UtmpReader::open("/var/log/wtmp")?;
    let mut stats = HashMap::new();
    let mut total_logins = 0;
    
    // 统计每个用户的登录次数
    for entry in reader.entries() {
        if let Ok(UtmpEntry::UserProcess(entry)) = entry {
            if let Some(user) = entry.user() {
                *stats.entry(user.to_string()).or_insert(0) += 1;
                total_logins += 1;
            }
        }
    }
    
    println!("\n登录统计:");
    println!("总登录次数: {}", total_logins);
    println!("各用户登录次数:");
    
    // 按登录次数排序输出
    let mut stats_vec: Vec<_> = stats.into_iter().collect();
    stats_vec.sort_by(|a, b| b.1.cmp(&a.1));
    
    for (user, count) in stats_vec {
        println!("{:>15}: {}", user, count);
    }
    
    Ok(())
}

代码说明

  1. get_current_users() 函数:

    • 读取 /var/run/utmp 文件
    • 返回当前登录系统的用户列表
  2. analyze_login_history() 函数:

    • 读取 /var/log/wtmp 文件
    • 显示最近5次登录记录
    • 包含用户名、终端、来源IP和时间信息
  3. generate_login_stats() 函数:

    • 统计所有历史登录记录
    • 计算每个用户的登录次数
    • 按登录次数排序输出统计结果

编译运行

  1. 在 Cargo.toml 中添加依赖:
[dependencies]
utmp-classic-raw = "0.1"
  1. 运行程序需要 root 权限:
sudo cargo run

输出示例

程序运行后可能的输出示例:

当前登录用户: ["alice", "bob"]

最近5次登录记录:
[1] 用户: alice    终端: pts/0    来源: 192.168.1.100   时间: 2023-01-01 10:30:00
[2] 用户: bob      终端: pts/1    来源: 192.168.1.101   时间: 2023-01-01 09:15:00
[3] 用户: alice    终端: pts/0    来源: 192.168.1.100   时间: 2023-01-01 08:45:00
[4] 用户: charlie  终端: tty2     来源: local           时间: 2023-01-01 08:30:00
[5] 用户: alice    终端: pts/0    来源: 192.168.1.100   时间: 2023-01-01 08:15:00

登录统计:
总登录次数: 42
各用户登录次数:
          alice: 20
           bob: 15
       charlie: 5
         dave: 2

这个示例展示了 utmp-classic-raw 库的综合应用,包括读取当前登录用户、分析登录历史和生成统计报告等功能。

回到顶部