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. C#生成注册码

    string t = DateTime.Now.Ticks.ToString(); t = DESKey.DESEncrypt(t, DESKey.DesKeyStr); string[] strid ...

  2. [转]三大WEB服务器对比分析(apache ,lighttpd,nginx)

    原博文地址:http://www.blogjava.net/daniel-tu/archive/2008/12/29/248883.html 一.软件介绍(apache  lighttpd  ngin ...

  3. Tableau——BI software

    Tableau 8权威指南 (权威的数据可视化实战手册,中国传媒大学教授沈浩.北京大学研究员袁晓如 联袂推荐) 触手可及的大数据分析工具——Tableau案例集 写给专业数据分析师的丛书,无门槛的大数 ...

  4. 利用iframe实现无刷新上传处理

    继上一篇对上传异常进行处理之后,当上传异常的时候的错误体验并不是很好,这里介绍用iframe来进行错误提示 拦截错误 @ExceptionHandler(MaxUploadSizeExceededEx ...

  5. Mysql查询阻塞初探

    第一次值班,报警打电话给我说,数据库复制延时一个多小时,那个时候是半夜啊,但我还是很清醒的起来,开机.vpn.登录.show processlist,结果发现情况是这样的: 红线框表示的是当前每个线程 ...

  6. 这是经典的"百马百担"问题,有一百匹马,驮一百担货,大马驮3担,中马驮2担,两只小马驮1担,问有大,中,小马各几匹?

  7. 举例讲解Linux系统下Python调用系统Shell的方法

    有时候难免需要直接调用Shell命令来完成一些比较简单的操作,比如mount一个文件系统之类的.那么我们使用Python如何调用Linux的Shell命令?下面来介绍几种常用的方法:1. os 模块 ...

  8. 理解 OpenStack + Ceph (4):Ceph 的基础数据结构 [Pool, Image, Snapshot, Clone]

    本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成: (1)安装和部署 (2)Ceph RBD 接口和工具 (3)Ceph 物理和逻辑结构 (4)Ceph 的基础数据结构 ...

  9. Java Web之Filter

    Filter被称为过滤器或者拦截器,基本功能就是对调用servler过程的拦截,在servlet进行响应和处理前后实现一些特殊功能.其实,Filter过滤器就是一个实现了javax.servlet.F ...

  10. bzoj-4517 4517: [Sdoi2016]排列计数(组合数学)

    题目链接: 4517: [Sdoi2016]排列计数 Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 846  Solved: 530[Submit][ ...