首页 > 其他分享 >第二章节C代码RUST实现

第二章节C代码RUST实现

时间:2024-06-15 15:54:24浏览次数:26  
标签:章节 std use u8 ut 代码 utmp let RUST

第二章节书中代码有如下内容


这些C语言代码大致实现了一个简单版的 who 命令。这个命令的功能是读取系统的 utmp 文件,并显示当前登录的用户信息。utmp 文件包含关于用户登录会话的信息,包括用户名、登录终端、登录时间等。以下是对上述所有代码实现功能的总结:

  • cp1:实现复制文件内容到另一指定文件的功能
  • who0.c:基本版本,读取并显示 utmp 文件中的所有记录。
  • who1.c:增加了对空记录的抑制功能,只显示有用户登录的记录。
  • who2.c:增加了时间格式化显示功能,使时间信息更易读。
  • who3.c:使用了缓冲读取,提高了读取效率,增加了对 utmplib 的支持。

实现过程

在linux虚拟机中实现

所有代码工程文件如下

代码约束 Cargo.toml文件

[package]
name = "who2"
version = "0.1.0"
edition = "2018"

[dependencies]
nix = "0.23.2"
chrono = "0.4"

cp1

use std::ffi::CString;
use std::process;
use libc::{open, read, write, close, O_RDONLY, O_CREAT, O_WRONLY, S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH};

const BUFFERSIZE: usize = 4096;
const COPYMODE: u32 = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

fn oops(s1: &str, s2: &str) {
    eprintln!("Error: {} {}", s1, s2);
    process::exit(1);
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 3 {
        eprintln!("usage: {} source destination", args[0]);
        process::exit(1);
    }

    let src = &args[1];
    let dest = &args[2];

    let src_cstr = CString::new(src.as_str()).expect("CString::new failed");
    let dest_cstr = CString::new(dest.as_str()).expect("CString::new failed");

    let in_fd = unsafe { open(src_cstr.as_ptr(), O_RDONLY) };
    if in_fd == -1 {
        oops("Cannot open", src);

utmplib

use std::ffi::CString;
use std::os::unix::io::RawFd;
use std::ptr;
use libc::{open, read, close, O_RDONLY};
use std::mem::size_of;

const NRECS: usize = 16;
const UTSIZE: usize = size_of::<libc::utmpx>();

static mut UTMPBUF: [u8; NRECS * UTSIZE] = [0; NRECS * UTSIZE];
static mut NUM_RECS: usize = 0;
static mut CUR_REC: usize = 0;
static mut FD_UTMP: RawFd = -1;

fn oops(s1: &str, s2: &str) {
    eprintln!("Error: {} {}", s1, s2);
    std::process::exit(1);
}

fn utmp_open(filename: &str) -> RawFd {
    let c_filename = CString::new(filename).expect("CString::new failed");
    unsafe {
        FD_UTMP = open(c_filename.as_ptr(), O_RDONLY);
        CUR_REC = 0;
        NUM_RECS = 0;
        if FD_UTMP == -1 {
            oops("Cannot open", filename);
        }
    }
    unsafe { FD_UTMP }
}

fn utmp_next() -> Option<libc::utmpx> {
    unsafe {
        if FD_UTMP == -1 {
            return None;
        }
        if CUR_REC == NUM_RECS && utmp_reload() == 0 {
            return None;
        }
        let recp = ptr::read(UTMPBUF.as_ptr().add(CUR_REC * UTSIZE) as *const libc::utmpx);
        CUR_REC += 1;
        Some(recp)
    }
}

fn utmp_reload() -> usize {
    unsafe {
        let amt_read = read(FD_UTMP, UTMPBUF.as_mut_ptr() as *mut libc::c_void, NRECS * UTSIZE);
        if amt_read < 0 {
            oops("Read error from", "utmp file");
        }
        NUM_RECS = amt_read as usize / UTSIZE;
        CUR_REC = 0;
        NUM_RECS
    }
}

fn utmp_close() {
    unsafe {
        if FD_UTMP != -1 {
            close(FD_UTMP);
            FD_UTMP = -1;
        }
    }
}

fn main() {
    let filename = "/var/log/wtmp"; // 替换为实际的utmp文件路径

    utmp_open(filename);

    while let Some(record) = utmp_next() {
        let user = unsafe { std::ffi::CStr::from_ptr(record.ut_user.as_ptr()) };
        println!("User: {}", user.to_str().unwrap());
    }

    utmp_close();
}

who0

use std::fs::File;
use std::io::{self, Read};
use std::mem::size_of;
use std::ptr;

// 定义与 C 语言中的 struct utmp 等价的结构体
#[repr(C)]
struct Utmp {
    ut_type: i16,
    ut_pid: i32,
    ut_line: [u8; 32],
    ut_id: [u8; 4],
    ut_user: [u8; 32],
    ut_host: [u8; 256],
    ut_exit: ExitStatus,
    ut_session: i32,
    ut_tv: TimeVal,
    ut_addr_v6: [i32; 4],
    unused: [u8; 20],
}

#[repr(C)]
struct ExitStatus {
    e_termination: i16,
    e_exit: i16,
}

#[repr(C)]
struct TimeVal {
    tv_sec: i32,
    tv_usec: i32,
}

fn main() -> io::Result<()> {
    let mut file = File::open("/var/run/utmp")?;
    let reclen = size_of::<Utmp>();

    let mut buffer = vec![0u8; reclen];
    while file.read_exact(&mut buffer).is_ok() {
        let utmp: Utmp = unsafe { ptr::read(buffer.as_ptr() as *const _) };
        show_info(&utmp);
    }

    Ok(())
}

fn show_info(utmp: &Utmp) {
    let user = String::from_utf8_lossy(&utmp.ut_user).trim_end_matches(char::from(0)).to_string();
    let line = String::from_utf8_lossy(&utmp.ut_line).trim_end_matches(char::from(0)).to_string();
    let host = String::from_utf8_lossy(&utmp.ut_host).trim_end_matches(char::from(0)).to_string();

    println!("User: {}, Line: {}, Host: {}", user, line, host);
}

who1

use std::fs::File;
use std::io::{self, Read};
use std::mem::size_of;
use std::ptr;
use std::time::{UNIX_EPOCH, Duration};

// 定义与 C 语言中的 struct utmp 等价的结构体
#[repr(C)]
struct Utmp {
    ut_type: i16,
    ut_pid: i32,
    ut_line: [u8; 32],
    ut_id: [u8; 4],
    ut_user: [u8; 32],
    ut_host: [u8; 256],
    ut_exit: ExitStatus,
    ut_session: i32,
    ut_tv: TimeVal,
    ut_addr_v6: [i32; 4],
    unused: [u8; 20],
}

#[repr(C)]
struct ExitStatus {
    e_termination: i16,
    e_exit: i16,
}

#[repr(C)]
struct TimeVal {
    tv_sec: i32,
    tv_usec: i32,
}

fn main() -> io::Result<()> {
    let mut file = File::open("/var/run/utmp")?;
    let reclen = size_of::<Utmp>();

    let mut buffer = vec![0u8; reclen];
    while file.read_exact(&mut buffer).is_ok() {
        let utmp: Utmp = unsafe { ptr::read(buffer.as_ptr() as *const _) };
        show_info(&utmp);
    }

    Ok(())
}

fn show_info(utmp: &Utmp) {
    let user = String::from_utf8_lossy(&utmp.ut_user).trim_end_matches(char::from(0)).to_string();
    let line = String::from_utf8_lossy(&utmp.ut_line).trim_end_matches(char::from(0)).to_string();
    let host = String::from_utf8_lossy(&utmp.ut_host).trim_end_matches(char::from(0)).to_string();
    let login_time = UNIX_EPOCH + Duration::new(utmp.ut_tv.tv_sec as u64, 0);

    println!("{:<8} {:<8} {:>10} ({})", user, line, login_time.duration_since(UNIX_EPOCH).unwrap().as_secs(), host);
}

who1bot

use std::fs::File;
use std::io::{self, Read};
use std::mem::size_of;
use std::ptr;
use std::time::{UNIX_EPOCH, Duration};

// 定义与 C 语言中的 struct utmp 等价的结构体
#[repr(C)]
struct Utmp {
    ut_type: i16,
    ut_pid: i32,
    ut_line: [u8; 32],
    ut_id: [u8; 4],
    ut_user: [u8; 32],
    ut_host: [u8; 256],
    ut_exit: ExitStatus,
    ut_session: i32,
    ut_tv: TimeVal,
    ut_addr_v6: [i32; 4],
    unused: [u8; 20],
}

#[repr(C)]
struct ExitStatus {
    e_termination: i16,
    e_exit: i16,
}

#[repr(C)]
struct TimeVal {
    tv_sec: i32,
    tv_usec: i32,
}

fn main() -> io::Result<()> {
    let mut file = File::open("/var/run/utmp")?;
    let reclen = size_of::<Utmp>();

    let mut buffer = vec![0u8; reclen];
    while file.read_exact(&mut buffer).is_ok() {
        let utmp: Utmp = unsafe { ptr::read(buffer.as_ptr() as *const _) };
        show_info(&utmp);
    }

    Ok(())
}

fn show_info(utmp: &Utmp) {
    let user = String::from_utf8_lossy(&utmp.ut_user).trim_end_matches(char::from(0)).to_string();
    let line = String::from_utf8_lossy(&utmp.ut_line).trim_end_matches(char::from(0)).to_string();
    let host = String::from_utf8_lossy(&utmp.ut_host).trim_end_matches(char::from(0)).to_string();
    let login_time = UNIX_EPOCH + Duration::new(utmp.ut_tv.tv_sec as u64, 0);

    println!(
        "{:<8} {:<8} {:>10} ({})",
        user,
        line,
        login_time.duration_since(UNIX_EPOCH).unwrap().as_secs(),
        host
    );
}

who1top

use std::io::{self, Read};
use std::mem::size_of;
use std::ptr;
use std::time::{UNIX_EPOCH, Duration};
use nix::fcntl::{open, OFlag};
use nix::unistd::{close, read};
use nix::sys::stat::Mode;

// 定义与 C 语言中的 struct utmp 等价的结构体
#[repr(C)]
struct Utmp {
    ut_type: i16,
    ut_pid: i32,
    ut_line: [u8; 32],
    ut_id: [u8; 4],
    ut_user: [u8; 32],
    ut_host: [u8; 256],
    ut_exit: ExitStatus,
    ut_session: i32,
    ut_tv: TimeVal,
    ut_addr_v6: [i32; 4],
    unused: [u8; 20],
}

#[repr(C)]
struct ExitStatus {
    e_termination: i16,
    e_exit: i16,
}

#[repr(C)]
struct TimeVal {
    tv_sec: i32,
    tv_usec: i32,
}

fn main() -> io::Result<()> {
    let utmp_path = "/var/run/utmp";
    let utmpfd = open(utmp_path, OFlag::O_RDONLY, Mode::empty())
        .expect("Failed to open utmp file");

    let reclen = size_of::<Utmp>();

    let mut buffer = vec![0u8; reclen];
    while read(utmpfd, &mut buffer).expect("Failed to read from utmp file") == reclen {
        let utmp: Utmp = unsafe { ptr::read(buffer.as_ptr() as *const _) };
        show_info(&utmp);
    }

    close(utmpfd).expect("Failed to close utmp file");
    Ok(())
}

fn show_info(utmp: &Utmp) {
    let user = String::from_utf8_lossy(&utmp.ut_user).trim_end_matches(char::from(0)).to_string();
    let line = String::from_utf8_lossy(&utmp.ut_line).trim_end_matches(char::from(0)).to_string();
    let host = String::from_utf8_lossy(&utmp.ut_host).trim_end_matches(char::from(0)).to_string();
    let login_time = UNIX_EPOCH + Duration::new(utmp.ut_tv.tv_sec as u64, 0);

    println!(
        "{:<8} {:<8} {:>10} ({})",
        user,
        line,
        login_time.duration_since(UNIX_EPOCH).unwrap().as_secs(),
        host
    );
}

who2

use std::io;
use std::mem::size_of;
use std::ptr;
use std::time::{UNIX_EPOCH, Duration, SystemTime};
use nix::fcntl::{open, OFlag};
use nix::unistd::{close, read};
use nix::sys::stat::Mode;
use chrono::prelude::*;

// 定义与 C 语言中的 struct utmp 等价的结构体
#[repr(C)]
struct Utmp {
    ut_type: i16,
    ut_pid: i32,
    ut_line: [u8; 32],
    ut_id: [u8; 4],
    ut_user: [u8; 32],
    ut_host: [u8; 256],
    ut_exit: ExitStatus,
    ut_session: i32,
    ut_tv: TimeVal,
    ut_addr_v6: [i32; 4],
    unused: [u8; 20],
}

#[repr(C)]
struct ExitStatus {
    e_termination: i16,
    e_exit: i16,
}

#[repr(C)]
struct TimeVal {
    tv_sec: i32,
    tv_usec: i32,
}

const USER_PROCESS: i16 = 7;

fn main() -> io::Result<()> {
    let utmp_path = "/var/run/utmp";
    let utmpfd = open(utmp_path, OFlag::O_RDONLY, Mode::empty())
        .expect("Failed to open utmp file");

    let reclen = size_of::<Utmp>();

    let mut buffer = vec![0u8; reclen];
    while read(utmpfd, &mut buffer).expect("Failed to read from utmp file") == reclen {
        let utmp: Utmp = unsafe { ptr::read(buffer.as_ptr() as *const _) };
        show_info(&utmp);
    }

    close(utmpfd).expect("Failed to close utmp file");
    Ok(())
}

fn show_info(utmp: &Utmp) {
    if utmp.ut_type != USER_PROCESS {
        return;
    }

    let user = String::from_utf8_lossy(&utmp.ut_user).trim_end_matches(char::from(0)).to_string();
    let line = String::from_utf8_lossy(&utmp.ut_line).trim_end_matches(char::from(0)).to_string();
    let login_time = UNIX_EPOCH + Duration::new(utmp.ut_tv.tv_sec as u64, 0);

    print!("{:<8} {:<8} ", user, line);
    showtime(login_time);

    // 注释掉未使用的 host 变量
    /*
    #[cfg(feature = "showhost")]
    if !host.is_empty() {
        print!(" ({})", host);
    }
    */
    println!();
}

fn showtime(system_time: SystemTime) {
    let datetime: DateTime<Local> = system_time.into();
    print!("{}", datetime.format("%b %e %H:%M"));
}

who3

use std::io;
use std::mem::size_of;
use std::ptr;
use std::time::{UNIX_EPOCH, Duration, SystemTime};
use nix::fcntl::{open, OFlag};
use nix::unistd::{close};
use nix::sys::stat::Mode;
use chrono::prelude::*;

// 定义与 C 语言中的 struct utmp 等价的结构体
#[repr(C)]
#[derive(Clone, Copy)]
struct Utmp {
    ut_type: i16,
    ut_pid: i32,
    ut_line: [u8; 32],
    ut_id: [u8; 4],
    ut_user: [u8; 32],
    ut_host: [u8; 256],
    ut_exit: ExitStatus,
    ut_session: i32,
    ut_tv: TimeVal,
    ut_addr_v6: [i32; 4],
    unused: [u8; 20],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct ExitStatus {
    e_termination: i16,
    e_exit: i16,
}

#[repr(C)]
#[derive(Clone, Copy)]
struct TimeVal {
    tv_sec: i32,
    tv_usec: i32,
}

const USER_PROCESS: i16 = 7;
const UTMP_FILE: &str = "/var/run/utmp";

fn main() -> io::Result<()> {
    if utmp_open(UTMP_FILE).is_err() {
        eprintln!("Failed to open utmp file");
        std::process::exit(1);
    }

    while let Some(utmp) = utmp_next() {
        show_info(&utmp);
    }

    utmp_close();
    Ok(())
}

fn show_info(utmp: &Utmp) {
    if utmp.ut_type != USER_PROCESS {
        return;
    }

    let user = String::from_utf8_lossy(&utmp.ut_user).trim_end_matches(char::from(0)).to_string();
    let line = String::from_utf8_lossy(&utmp.ut_line).trim_end_matches(char::from(0)).to_string();
    let host = String::from_utf8_lossy(&utmp.ut_host).trim_end_matches(char::from(0)).to_string();
    let login_time = UNIX_EPOCH + Duration::new(utmp.ut_tv.tv_sec as u64, 0);

    print!("{:<8} {:<8} ", user, line);
    showtime(login_time);

    #[cfg(feature = "showhost")]
    if !host.is_empty() {
        print!(" ({})", host);
    }
    println!();
}

fn showtime(system_time: SystemTime) {
    let datetime: DateTime<Local> = system_time.into();
    print!("{}", datetime.format("%b %e %H:%M"));
}

static mut UTMP_BUFFER: Option<Vec<Utmp>> = None;
static mut INDEX: usize = 0;

fn utmp_open(file: &str) -> Result<(), io::Error> {
    let utmpfd = open(file, OFlag::O_RDONLY, Mode::empty())?;
    let reclen = size_of::<Utmp>();
    let mut buffer = Vec::new();
    let mut temp_buffer = vec![0u8; reclen];
    
    while let Ok(n) = nix::unistd::read(utmpfd, &mut temp_buffer) {
        if n == 0 { break; }
        if n == reclen {
            let utmp: Utmp = unsafe { ptr::read(temp_buffer.as_ptr() as *const _) };
            buffer.push(utmp);
        }
    }
    
    unsafe {
        UTMP_BUFFER = Some(buffer);
        INDEX = 0;
    }

    close(utmpfd)?;
    Ok(())
}

fn utmp_next() -> Option<Utmp> {
    unsafe {
        if let Some(ref buffer) = UTMP_BUFFER {
            if INDEX < buffer.len() {
                let record = buffer[INDEX].clone();
                INDEX += 1;
                return Some(record);
            }
        }
    }
    None
}

fn utmp_close() {
    unsafe {
        UTMP_BUFFER = None;
        INDEX = 0;
    }
}

who3top

use std::io;
use std::mem::size_of;
use std::ptr;
use std::time::{UNIX_EPOCH, Duration, SystemTime};
use nix::fcntl::{open, OFlag};
use nix::unistd::{close};
use nix::sys::stat::Mode;
use chrono::prelude::*;

// 定义与 C 语言中的 struct utmp 等价的结构体
#[repr(C)]
#[derive(Clone, Copy)]
struct Utmp {
    ut_type: i16,
    ut_pid: i32,
    ut_line: [u8; 32],
    ut_id: [u8; 4],
    ut_user: [u8; 32],
    ut_host: [u8; 256],
    ut_exit: ExitStatus,
    ut_session: i32,
    ut_tv: TimeVal,
    ut_addr_v6: [i32; 4],
    unused: [u8; 20],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct ExitStatus {
    e_termination: i16,
    e_exit: i16,
}

#[repr(C)]
#[derive(Clone, Copy)]
struct TimeVal {
    tv_sec: i32,
    tv_usec: i32,
}

const USER_PROCESS: i16 = 7;
const UTMP_FILE: &str = "/var/run/utmp";

fn main() -> io::Result<()> {
    if utmp_open(UTMP_FILE).is_err() {
        eprintln!("Failed to open utmp file");
        std::process::exit(1);
    }

    while let Some(utmp) = utmp_next() {
        show_info(&utmp);
    }

    utmp_close();
    Ok(())
}

fn show_info(utmp: &Utmp) {
    if utmp.ut_type != USER_PROCESS {
        return;
    }

    let user = String::from_utf8_lossy(&utmp.ut_user).trim_end_matches(char::from(0)).to_string();
    let line = String::from_utf8_lossy(&utmp.ut_line).trim_end_matches(char::from(0)).to_string();
    let host = String::from_utf8_lossy(&utmp.ut_host).trim_end_matches(char::from(0)).to_string();
    let login_time = UNIX_EPOCH + Duration::new(utmp.ut_tv.tv_sec as u64, 0);

    print!("{:<8} {:<8} ", user, line);
    showtime(login_time);

    #[cfg(feature = "showhost")]
    if !host.is_empty() {
        print!(" ({})", host);
    }
    println!();
}

fn showtime(system_time: SystemTime) {
    let datetime: DateTime<Local> = system_time.into();
    print!("{}", datetime.format("%b %e %H:%M"));
}

static mut UTMP_BUFFER: Option<Vec<Utmp>> = None;
static mut INDEX: usize = 0;

fn utmp_open(file: &str) -> Result<(), io::Error> {
    let utmpfd = open(file, OFlag::O_RDONLY, Mode::empty())?;
    let reclen = size_of::<Utmp>();
    let mut buffer = Vec::new();
    let mut temp_buffer = vec![0u8; reclen];
    
    while let Ok(n) = nix::unistd::read(utmpfd, &mut temp_buffer) {
        if n == 0 { break; }
        if n == reclen {
            let utmp: Utmp = unsafe { ptr::read(temp_buffer.as_ptr() as *const _) };
            buffer.push(utmp);
        }
    }
    
    unsafe {
        UTMP_BUFFER = Some(buffer);
        INDEX = 0;
    }

    close(utmpfd)?;
    Ok(())
}

fn utmp_next() -> Option<Utmp> {
    unsafe {
        if let Some(ref buffer) = UTMP_BUFFER {
            if INDEX < buffer.len() {
                let record = buffer[INDEX].clone();
                INDEX += 1;
                return Some(record);
            }
        }
    }
    None
}

fn utmp_close() {
    unsafe {
        UTMP_BUFFER = None;
        INDEX = 0;
    }
}

标签:章节,std,use,u8,ut,代码,utmp,let,RUST
From: https://www.cnblogs.com/lizhuotong/p/18249383

相关文章