Linux文件操作实践:实现who命令解析

张开发
2026/4/27 1:16:13 15 分钟阅读

分享文章

Linux文件操作实践:实现who命令解析
Linux文件操作实践实现who命令的完整解析1. 项目概述1.1 学习目标本项目通过分析Linux系统中的who命令实现原理深入讲解Linux文件操作的基础知识。主要学习目标包括理解Linux用户登录信息的存储机制掌握Linux文件读写的基本系统调用学习时间数据的转换与显示方法实现一个简化版的who命令1.2 实验环境操作系统Ubuntu 18.04 LTS编译器gcc 7.5.0开发语言C语言2. who命令原理分析2.1 who命令功能who命令用于显示当前登录系统的用户信息输出格式通常包含用户名终端名称登录时间登录来源IP或显示服务器2.2 数据来源分析who命令通过读取系统文件获取用户登录信息主要涉及两个文件/var/run/utmp记录当前登录用户的信息/var/log/wtmp记录历史登录信息本项目暂不涉及2.3 utmp文件结构utmp文件实际上是一个结构体数组每个元素都是utmp类型的结构体定义在/usr/include/utmp.h头文件中。关键结构定义如下struct utmp { short ut_type; // 记录类型 pid_t ut_pid; // 进程ID char ut_line[UT_LINESIZE]; // 终端设备名 char ut_id[4]; // 终端ID后缀 char ut_user[UT_NAMESIZE]; // 用户名 struct exit_status ut_exit; // 进程退出状态 long ut_session; // 会话ID struct timeval ut_tv; // 时间记录 int32_t ut_addr_v6[4]; // 远程IP地址 char __unused[20]; // 保留字段 };其中ut_type字段特别重要当值为7USER_PROCESS时表示这是一个有效的用户登录记录。3. 关键系统调用3.1 文件操作三件套实现who命令需要掌握三个基本系统调用3.1.1 open() - 打开文件#include sys/types.h #include sys/stat.h #include fcntl.h int open(const char *pathname, int flags);pathname文件路径flags打开模式O_RDONLY、O_WRONLY、O_RDWR返回值成功返回文件描述符失败返回-13.1.2 read() - 读取数据#include unistd.h ssize_t read(int fd, void *buf, size_t count);fd文件描述符buf数据缓冲区count期望读取的字节数返回值实际读取的字节数0表示EOF-1表示错误3.1.3 close() - 关闭文件#include unistd.h int close(int fd);fd要关闭的文件描述符返回值0表示成功-1表示错误3.2 时间处理函数#include time.h struct tm *localtime(const time_t *timep);将time_t类型的时间戳转换为本地时间的tm结构体包含年、月、日等分解时间信息。4. 代码实现4.1 基础版本实现#include stdio.h #include utmp.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include stdlib.h #define SHOWHOST void show_info(struct utmp *utbufp); int main() { struct utmp current_record; int utmpfd; int reclen sizeof(current_record); if ((utmpfd open(UTMP_FILE, O_RDONLY)) -1) { perror(UTMP_FILE); exit(1); } while (read(utmpfd, current_record, reclen) reclen) { show_info(current_record); } close(utmpfd); return 0; } void show_info(struct utmp *utbufp) { printf(%-8.8s, utbufp-ut_name); printf( ); printf(%-8.8s, utbufp-ut_line); printf(%10d, utbufp-ut_time); printf( ); #ifdef SHOWHOST printf((%s), utbufp-ut_host); #endif printf(\n); }4.2 优化版本实现针对基础版本的不足进行改进过滤非用户进程记录优化时间显示格式#include time.h void show_time(time_t timeval) { struct tm *info NULL; info localtime(timeval); printf(%4d-%02d-%02d %02d:%02d, (info-tm_year 1900), (info-tm_mon 1), info-tm_mday, info-tm_hour, info-tm_min); } void show_info(struct utmp *utbufp) { if (utbufp-ut_type ! USER_PROCESS) { return; } printf(%-8.8s, utbufp-ut_name); printf( ); printf(%-8.8s, utbufp-ut_line); show_time(utbufp-ut_time); printf( ); #ifdef SHOWHOST printf((%s), utbufp-ut_host); #endif printf(\n); }5. 编译与测试5.1 编译命令gcc who.c -o who5.2 测试结果对比优化后的输出与系统who命令基本一致user :0 2021-11-01 09:12 (:0) user pts/2 2021-11-01 18:41 (192.168.0.104)6. 工程实践要点6.1 错误处理每次系统调用后都应检查返回值使用perror()输出错误信息适当使用exit()终止程序6.2 性能考虑使用合适大小的缓冲区及时关闭文件描述符避免不必要的内存拷贝6.3 可移植性使用标准头文件处理不同系统的utmp结构差异考虑字节序问题7. 扩展思考如何实现who命令的-h参数功能怎样处理utmp文件的并发访问如何优化大量用户登录时的显示效率考虑实现whoami命令的类似功能

更多文章