Linux下who命令之C语言实现

Step1:前期准备

  • 首先要有一个清楚的认识:linux中一切皆文件

  • 实现who命令,who命令也是Linux中的一个文件,那我们怎么找到它呢?我们可以“找男人”(man),终端下执行命令:man who

  • 此处我装了汉译版的man手册,查看到这样一段提示如下:

  • 所以退出man手册,执行命令:info who

  • 找到如下图相关信息:

  • 也可以找到下面这样的一段话,也就是说:who命令可以这样实现,读取utmp里边的内容,然后显示记录,最后关闭utmp,who命令就是一个很简单的体现吧,打开文件,保存文件id,根据文件id读取用户的登陆信息,显示在终端。

  • 我们尝试地打开一下/var/run/utmp这个文件得到如下画面,发现是一串乱码,但还是能看出相关who的信息的

  • 既然不清楚utmp是干嘛的,我们可以使用man -k来检索一下相关信息,得到信息如下

  • 经过筛选,发现只有utmpx(5)是符合我们要求的,其中后面显示的是login records,而who命令不就是用来输出登录信息的;man的第五个类型表示的是文件格式和规范,说明此处可能存储了登录记录的数据结构

  • 使用指令:man 5 utmpx,可以得到如下有用信息:

  • 也可以使用输出重定向指令man 5 utmpx > utmp.txt,得到文本格式的utmp数据结构体如下:

struct utmp {
short ut_type; /* Type of record */
pid_t ut_pid; /* PID of login process */
char ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */
char ut_id[4]; /* Terminal name suffix,
or inittab(5) ID */
char ut_user[UT_NAMESIZE]; /* Username */
char ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or
kernel version for run-level
messages */
struct exit_status ut_exit; /* Exit status of a process
marked as DEAD_PROCESS; not
used by Linux init (1 */
/* The ut_session and ut_tv fields must be the same size when
compiled 32- and 64-bit. This allows data files and shared
memory to be shared between 32- and 64-bit applications. */
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
int32_t ut_session; /* Session ID (getsid(2)),
used for windowing */
struct {
int32_t tv_sec; /* Seconds */
int32_t tv_usec; /* Microseconds */
} ut_tv; /* Time entry was made */
#else
long ut_session; /* Session ID */
struct timeval ut_tv; /* Time entry was made */
#endif int32_t ut_addr_v6[4]; /* Internet address of remote
host; IPv4 address uses
just ut_addr_v6[0] */
char __unused[20]; /* Reserved for future use */
};
  • 此时万里长征已走一半,对比系统who命令,发现该结构体中并没有直接给出用户登录时间的成员变量,而是内嵌了一个ut_tv的时间结构体,其中成员变量tv_sec才是我们需要的。

  • 如果耐心地看完该帮助文档,可以在下面一段代码中有新的发现:

  • 此处定义了一个ut_time的宏,指向的就是ut_tv.ut_sec,而我们需要用到的不是这样一个以秒为单位的格林威治标准时间,所以才后面需用到ctime()函数

  • 在这儿用的就是刚刚说的linux的一个思想,一切事物都是文件。

Step2:其余头文件的准备

  • time.h:将格林威治标准时间(GMT)长整形的数时间转化为我们所熟悉的时间表示,运用ctime()函数
  • string.h:调整输出格式,后面调试时会提到用处。
  • 其余头文件:因为要打开文件嘛,所以有些头文件必不可少,这个在我本周博客中有详细介绍:博客地址

Step3:编程思想

  • 查看UTMP_FILE宏:grep -nr UTMP_FILE /usr/include

  • 读取其结构体,将需要的变量提取出来并按照一定的格式输出

  • 其中,时间输出本来是一串格林威治标准时间(GMT)长整形的数,可以用ctime()将把日期和时间转换为字符串

Step4:代码实现

  • who代码
  • 其中等下需要修改的代码贴在此处:
void showtime(long timeval)
{
char* cp;
cp = ctime(&timeval);
printf("%s",cp+4); //+4是因为*cp所指的一串字符前4个字符表示为“星期”,可以忽略此信息
}

Step5:编译执行

  • 执行结果如下:

  • 发现“(:0)”被换行了,但是程序中并没有输出换行字符。经过一番思索后,猜想ctime()函数的返回值*cp可能自动在最后补了一个字符\n

Step6:调试代码

  • 那只要能回退一个字符就好了,比如输出一个\b(退格字符)
  • 编译再运行,发现输出格式仍是原样,最后经过了解\b确实是可以回退一个字符,但是并不能实现退到上行,也就是不能消除\n带来的影响
  • 百度之后,说可以通过输出\r\b来实现“退行”,但实践后发现也不可取
  • 最后考虑到直接修改*cp字符串中最后一个字符为\0,使输出达到与系统who命令一样的效果
  • 在输出语句前添加如下代码(需用到string.h):
    • cp[strlen(cp)-1] = '\0'
  • 最后编译执行效果,可以看出与who命令基本一致:

Linux下who命令之C语言实现的更多相关文章

  1. 20155212 C语言实现linux下pwd命令的两种方法

    20155212 C语言实现linux下pwd命令的两种方法 学习pwd命令 通过man pwd命令查看 pwd [OPTION],一般不加参数 -P显示当前目录的物理路径 -L显示当前目录的连接路径 ...

  2. Linux下ls命令显示符号链接权限为777的探索

    Linux下ls命令显示符号链接权限为777的探索 --深入ls.链接.文件系统与权限 一.摘要 ls是Linux和Unix下最常使用的命令之一,主要用来列举目录下的文件信息,-l参数允许查看当前目录 ...

  3. linux下的命令是如何运行的

    linux下的命令分为内建命令.可执行文件.脚本文件 shell终端里键入一个命令,如ls.cd.bash,shell会先查询一个环境变量PATH,它存了各种可执行文件的路径,输入$PATH可以打印变 ...

  4. Linux下ps命令详解 Linux下ps命令的详细使用方法

    http://www.jb51.net/LINUXjishu/56578.html Linux下的ps命令比较常用 Linux下ps命令详解Linux上进程有5种状态:1. 运行(正在运行或在运行队列 ...

  5. 例解 Linux 下 Make 命令

    Linux 下 make 命令是系统管理员和程序员用的最频繁的命令之一.管理员用它通过命令行来编译和安装很多开源的工具,程序员用它来管理他们大型复杂的项目编译问题.本文我们将用一些实例来讨论 make ...

  6. linux下history命令显示历史指令记录的使用方法

    Linux系统当你在shell(控制台)中输入并执行命令时,shell会自动把你的命令记录到历史列表中,一般保存在用户目录下的.bash_history文件中.默认保存1000条,你也可以更改这个值 ...

  7. linux下svn命令使用大全

    最近经常使用svn进行代码管理,这些命令老是记不住,得经常上网查,终于找了一个linux下svn命令使用大全:1.将文件checkout到本地目录 svn checkout path(path是服务器 ...

  8. Linux下rz命令使用的实例详解

    Linux中rz命令和sz命令都可用于文件传输,而rz命令主要用于文件的上传,下面将通过几个实例来给大家详细介绍下Linux下rz命令的用法,一起来学习下吧. rz命令可以批量上传文件,当然也可上传单 ...

  9. Linux下rar命令详解

    Linux下rar命令详解 用法: rar <命令> -<选项1> ….-<选项N> < 操作文档> <文件…> <@文件列表…> ...

随机推荐

  1. 更换mysql数据目录后出现ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) 的解决办法

    服务器上的mysql默认数据目录为/var/lib/mysql/,同时服务器的/空间不是很大,而近期又有大量的日志需要导入进行分析,时常搞得/的空间捉襟见肘,晚上一狠心就想把mysql的数据目录转移到 ...

  2. 在Linux下使用gradle自动打包

    一.下载软件包 1.下载地址 wget https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz wget http://services ...

  3. java 重载、重写、构造函数详解

    方法重写 1.重写只能出现在继承关系之中.当一个类继承它的父类方法时,都有机会重写该父类的方法.一个特例是父类的方法被标识为final.重写的主要优点是能够定义某个子类型特有的行为. class An ...

  4. 磁盘配额-----quota

    为什么要使用磁盘配额:为了限制普通用户使用普通磁盘的空间与创建文件的个数等. 不至于个别人的浪费影响所有人的使用. 需要安装quota的软件包. mount -o usrquota,grpquota ...

  5. html特殊字符的html,js,css写法汇总

    ⇠  箭头类 符号 UNICODE 符号 UNICODE HTML JS CSS HTML JS CSS ⇠ &#8672 \u21E0 \21E0 ⇢ &#8674 \u21E2 \ ...

  6. javaSE ---OOP总结

    面向对象编程(Object Oriented Programming,OOP)是当前最主流的编程范式之一,Java是一门纯面向对象的编程语言.我们常说C++是一门面向对象的编程语言,C++是C语言的一 ...

  7. 一个优秀的Unity3d开发者必备的几种设计模式

    Unity脚本编程 众所周知,unity的编程属于脚本化,脚本没有一个具体的概念跟架构, 导致在项目过程中,经常出现哪里需要实现什么功能,就随便添加脚本, 结果,就造成了一片混乱,不好管理. 更有甚者 ...

  8. VR可以用做除游戏外的哪些地方

    虚拟现实可以将你传送到平时不敢去的地方, 例如喜马拉雅山顶. 也可以将你带到人类几乎不可能到达的地方, 例如世界上最深处, 马里亚纳海沟.马里亚纳海沟最深处的水压可是达到惊人的110Mpa, 这个高压 ...

  9. WEB 业务测试中需要关注的问题

    汇总起来分为:    1.浏览器自身的一些操作,后退键,刷新键,样式兼容,多浏览器之间的一些操作 2.键盘快捷键的一些支持 3.所有前端校验,必须也在后端代码进行校验,验证后端是否校验可越过前端校验进 ...

  10. sturct2类型转化

    第三种struts2类型转换方式实例 1.convert.jsp <%@ page language="java" import="java.util.*" ...