who功能
用man who
来查看who命令的功能:
who命令用于显示系统中有哪些使用者正在上面,显示的资料包含了使用者 ID、使用的终端机、从哪边连上来的、上线时间、呆滞时间、CPU 使用量、动作等等。
相关参数
-H 或 --heading:显示各栏位的标题信息列;
-i 或 -u 或 --idle:显示闲置时间,若该用户在前一分钟之内有进行任何动作,将标示成"."号,如果该用户已超过24小时没有任何动作,则标示出"old"字符串;
-m:此参数的效果和指定"am i"字符串相同;
-q 或--count:只显示登入系统的帐号名称和总人数;
-s:此参数将忽略不予处理,仅负责解决who指令其他版本的兼容性问题;
-w 或-T或--mesg或--message或--writable:显示用户的信息状态栏;
--help:在线帮助;
--version:显示版本信息。
who功能原理
who的原理便是读取/var/run/utmp
部分文件内容,输出到屏幕。所以我们考虑使用系统调用,调用utmp函数,来实现显示使用者系统的信息。
utmp
输入man utmp
,查看utmp的具体功能:
还可以看到utmp结构体的结构:
可以发现utmp可以显示登陆者的pid、登陆设备、登陆者的名字、登录主机的名字、退出状态等等,其中,登录时间被保存在tu_tv中。
利用utmp系统调用(#include<utmp.h>
),编写mywho代码,实现与who命令一样的功能:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#define SHOWOST
void showinfo(struct utmp *utbufp);
long showtime(long timeval);
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,¤t_record,reclen)==reclen)
showinfo(¤t_record);
close(utmpfd);
return 0;
}
void showinfo(struct utmp *utbufp){
if(utbufp->ut_type!=USER_PROCESS)
return;
else{
printf("%-8.8s",utbufp->ut_name);
printf(" ");
printf("%-8.8s",utbufp->ut_line);
printf(" ");
showtime(utbufp->ut_time);
printf(" ");
printf("(%s)",utbufp->ut_host);
printf(" ");
}
}
long showtime(long timeval)
{
struct tm *cp;
cp = gmtime(&timeval);
printf(" ");
printf("%d-%d-%d %d:%d ",cp->tm_year+1900,cp->tm_mon+1,cp->tm_mday,(cp->tm_hour+8)%24,cp->tm_min);
}
- main函数使用系统调用open,read,close对utmp文件进行操作。
- 使用showtime()函数,调用tm结构体完成对时间的输出
tm结构体的内容如下:
struct tm
{
int tm_sec; /* 秒–取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值从1900开始 */
int tm_wday; /* 星期–取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
int tm_yday; /* 从每年的1月1日开始的天数–取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负。*/
long int tm_gmtoff; /*指定了日期变更线东面时区中UTC东部时区正秒数或UTC西部时区的负秒数*/
const char *tm_zone; /*当前时区的名字(与环境变量TZ有关)*/
};
tm结构体是在Linux编程中较为常用的结构体,通过观察tm结构体的类型可以看出调用tm可以输出年月日、时分秒等,
-
utbufp->ut_time是一个时间数据,其储存的是从1970年1月1日0:00开始到现在所经过的秒数。
-
C 库函数
struct tm *gmtime(const time_t *timer)
使用 timer 的值来填充 tm 结构,并用协调世界时(UTC)也被称为格林尼治标准时间(GMT)表示。用cp = gmtime(&timeval);
来获取当前时间,通过gmtime可以将这个数据转换为结构体tm。 -
需要注意的是tm结构体中tm_year年份数值是减去了1900年,所以输出时需要加上1900。
printf("%d-%d-%d %d:%d ",cp->tm_year+1900,cp->tm_mon+1,cp->tm_mday,(cp->tm_hour+8)%24,cp->tm_min);