博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编写自己的who命令
阅读量:5369 次
发布时间:2019-06-15

本文共 4973 字,大约阅读时间需要 16 分钟。

今天偷看了一本书,书名叫做《unix/linux编程实践教程》。第三章讲的是文件读写内容,于是跟着他写了一个who命令。先记录于此,以备以后复习用。

在linux终端输入who命令,显示如下:

第一列是用户名

第二列是终端名

第三列是登陆时间

第四列是用户登陆地址

我用的是linux虚拟机,系统版本为ubuntu 10.10,IP地址为:10.201.18.2,显示当前共有两个用户登入到该虚拟机,其中ppxpp是在本地登陆,zhouhao是在远程登陆,其ip地址为10.201.18.5

但是who命令是如何实现这一功能的呢?

这与linux系统下的一个叫做utmp的文件有关。

utmp文件记录了每个用户的登陆信息,由一系列utmp记录组成,而utmp记录的结构定义位于utmp.h中: 

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(8) */               /* 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 */           };

 

编写程序从utmp文件中读取出该结构体内容,并打印:  

 

//打印struct utmp的内容void showUtmp(struct utmp* pUtmp){    printf("%-13.13s", pUtmp->ut_user);    printf("%-8.8s", pUtmp->ut_line);    printf("%-14.10ld", pUtmp->ut_tv.tv_sec);   printf("(%s)", pUtmp->ut_host);    printf("\n");}

 

 

int main(int ac, char **avs){    int utmpfd;//read utmp file    struct utmp curtUsr;    //一个记录的长度    int len = sizeof(struct utmp);    //在我的系统中,utmp文件位于/var/run/utmp    char *fPath = "/var/run/utmp";    if(-1 == (utmpfd = open(fPath, O_RDONLY)))    {        perror("open utmp file failed!\n");        exit(-1);    }    while( read(utmpfd, &curtUsr, len) ==len)    {        showUtmp(&curtUsr);    }    close(utmpfd);    return 0;}

 

使用gcc编译:gcc -o m_who who.c,运行:

第一列为用户名,第二列为终端号,第三列为登陆时间,第四列为用户登陆地址

咋一看,打印的都是神马玩意!!

第一:显然比标准的who命令多显示了LOGIN,reboot和runlevel。他们到底是何方神圣暂且不论(其实我现在也还不知道,慢慢学习吧),反正与标准的who命令就是不同,说明我们的程序还有某个地方有疏漏。

第二:时间显示也与who命令不一样

好吧,继续改进吧,先解决第一个问题。

使用man  utmp命令查看utmp相关信息,发现有下述描述:

 很显然,我们需要使用ut_type字段判断当前的记录属于什么类型,我们在showUtmp函数中增加打印ut_type的语句:

printf("%-5d", pUtmp->ut_type);

 

 结果显示如下:

可知,为了正确显示当前登录的用户列表,我们只需要打印出ut_type == USER_PROCESS的记录就可以了,修改main函数如下:

int main(int ac, char **avs){    int utmpfd;//read utmp file    struct utmp curtUsr;    //一个记录的长度    int len = sizeof(struct utmp);    //在我的系统中,utmp文件位于/var/run/utmp    char *fPath = "/var/run/utmp";    if(-1 == (utmpfd = open(fPath, O_RDONLY)))    {        perror("open utmp file failed!\n");        exit(-1);    }    while( read(utmpfd, &curtUsr, len) ==len)    {        //增加判断条件        if(curtUsr.ut_type == USER_PROCESS)            showUtmp(&curtUsr);    }    close(utmpfd);    return 0;}

 

 编译运行如下:

嗯,不错不错,看起来更像是标准who命令的打印结果了。着手解决时间显示不正确的问题。

我们在打印时间的时候直接使用

printf("%-14.10ld", pUtmp->ut_tv.tv_sec);语句。这个ut_tv,tv_sec是什么呢?

从前文可知,ut_tv是一个struct timeval结构体类型,其定义如下:

struct timeval {   time_t      tv_sec;    //表示秒   suseconds_t tv_usec;   //表示微妙};

 strct timeval表示一个时间点,该时间点从1970年1月1日0点0分0秒开始计时。若linux系统时间为1970年1月1日0点0分1秒,

则linux内核返回的时间时间可以用该类型变量time表示,且time.tv_sec = 1,time.tv_usec = 0。

上面打印结果zhouhao那一栏的时间 1364285795 即表示zhouhao这个用户登陆系统时,距离1970年1月1日0点0分0秒已经过去1364285795秒了。

我们可以使用其他函数将这一串数字转变成我们能够看懂的文字表示方式,修改showUtmp()函数如下:

 

//打印struct utmp的内容void showUtmp(struct utmp* pUtmp){    printf("%-13.13s", pUtmp->ut_user);    printf("%-8.8s", pUtmp->ut_line);    //显示时间    char* time_str = (char*)malloc(32 * sizeof(char));    strftime(time_str, 32 * sizeof(char), "%Y-%m-%d %H:%M", localtime(&(pUtmp->ut_tv.tv_sec)));      printf("%-20s", time_str);    printf("(%s)", pUtmp->ut_host);    printf("\n");    //释放内存    free(time_str);}

 

编译运行,结果如下:

至此,一个自己的who命令就算是完成了,至于其他拓展参数,还是有时间在写吧。。。。

转载于:https://www.cnblogs.com/zhouhao/archive/2013/03/26/2982729.html

你可能感兴趣的文章
流程图怎么画?分享绘制流程图简单方法
查看>>
squid的处理request和reply的流程
查看>>
硬件_陀螺仪
查看>>
三、winForm-DataGridView操作——DataGridView 操作复选框checkbox
查看>>
SSIS的部署和配置
查看>>
计算机内存管理介绍
查看>>
POJ 2761 Feed the dogs 求区间第k大 划分树
查看>>
mysql中间件研究(Atlas,cobar,TDDL)[转载]
查看>>
ASP.NET应用程序与页面生命周期
查看>>
Linux--多网卡的7种Bond模式
查看>>
Oracle命令(一):Oracle登录命令
查看>>
业务建模 之 业务用例图
查看>>
EasyUI基础入门之Pagination(分页)
查看>>
一次PHP代码上线遇到的问题
查看>>
显示密码
查看>>
实现one hot encode独热编码的两种方法
查看>>
ubuntu中文英文环境切换
查看>>
[sql]mysql启停脚本
查看>>
[elk]Mutate filter plugin增删改查字段
查看>>
Java内功心法,行为型设计模式
查看>>