第二章节C代码RUST实现

news/2024/10/5 13:22:21

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


这些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;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/44003.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

markdown图片管理教程

markdown图片管理教程 由于markdown对图片的支持不够友好,当文件分享给他人的时候经常会出现无法查看图片的情况,而且在博文上传到线上的时候也会出现无法访问图片的情况,因此需要将网上的图片下载到本地,之后再上传到博文中。 本文将会使用vscode的插件来帮助实现所需要的…

python爬虫获取百度热搜

注:本篇学习需要python基础 前言:在上篇中,我们学习了怎么用python发送网页请求来获取网站的源代码,在这篇中,我们将进一步学习 本篇目标:利用python爬虫获取百度热搜 第一步,用浏览器打开百度热搜网站 百度热搜网址 https://top.baidu.com/board?tab=realtime 页面如下…

CC2500和CC1101移植说明

CC1101,CC2500,CC1101模块,CC2500模块,移植说明主要通过如何移植、移植注意、关于芯片配置、如何生成导出配置四大步骤来说明CC2500和CC1101移植首先通过下图1这个宏进行选择 & 如何移植要移植的部分在 CC2500_hal.c 和 CC2500_hal.h中, 搜索 "//移植" 就可以定…

MyBatis的逆向工程详细步骤操作

1. MyBatis的逆向工程详细步骤操作 @目录1. MyBatis的逆向工程详细步骤操作2. 逆向工程配置与生成2.1 MyBatis3Simple:基础版,只有基本的增删改查2.1.1 第一步:在pom.xml 中添加逆向工程插件2.1.2 第二步:配置 generatorConfig.xml2.1.3 第三步:运行插件2.1.4 第四步:测试…

Vue微前端架构与Qiankun实践理论指南

这篇文章介绍了微前端架构概念,聚焦于如何在Vue.js项目中应用Qiankun框架实现模块化和组件化,以达到高效开发和维护的目的。讨论了Qiankun的原理、如何设置主应用与子应用的通信,以及如何解决跨域问题和优化集成过程,从而实现前端应用的灵活扩展与组织。title: Vue微前端架…

中小学电子教材课本下载(简单无脑)

前言 还记得读初中的时候,老是需要借高年级的课本,很是不方便,想要暑假提前预习一下也没资源。现在时代不同了,实用电子课本应该要方便一点。我去看过各类教材的官方网址,大部分电子教材只能在线阅读,不能下载,因此做了一个下载网页,可以直接下载。 简介 人教版电子教材…

Mac 修改默认 shell

Mac 修改默认 shell Mac 自 macOS Catalina 开始默认 shell 由原来的 Bash 改为 zsh 查看 Mac OS 系统版本: https://support.apple.com/zh-cn/109033 查看系统自带所有 shell $ cat /etc/shells # List of acceptable shells for chpass(1). # Ftpd will not allow users to c…

模拟集成电路学习笔记

模拟集成电路学习 MOS SPICE模型图中显示的是相关的参数表,其中需要了解部分参数的具体定义名称 需要注意单位,U0显示的单位是cm2,在计算时需要调整成m2电流公式二氧化硅的相对介电常数为3.9 真空的介电常数为其中有效沟道长度计算需要用沟道长度L-2*LD 参考题目:求解答案关…