who命令实现

who命令实现

1.who命令

1.1who命令实践

在linux环境中使用who命令,可以打印当前登录系统中的用户。

root@ubuntu:~# who
ye       tty7         2017-05-12 22:07 (:0)
ye       pts/4        2017-06-04 13:40 (192.168.1.5)
ye       pts/21       2017-06-04 13:55 (192.168.1.5)

1.2 who命令解释

WHO(1) User Commands NAME
       who - show who is logged on
SYNOPSIS
       who [OPTION]... [ FILE | ARG1 ARG2 ]
DESCRIPTION
       Print information about users who are currently logged in.

If FILE is not specified, use /var/run/utmp.  /var/log/wtmp as FILE is common.  If ARG1 ARG2 given, -m presumed: 'am i' or 'mom likes' are usual.

​ 由解释可知,该who命令查询的是一个/var/run/utmp文件来获取当前系统的登录用户信息。

2. utmp文件

  • utmp maintains a full accounting of the current status of the system, system boot time (used by uptime), recording user logins at which terminals, logouts, system events etc.
  • wtmp acts as a historical utmp
  • btmp records failed login attempts

linux下文件路径:

/var/run/utmp
/var/log/wtmp
/var/log/btmp

​ These files are not regular text files, but rather a binary format which needs to be edited by specially crafted programs. The implementation and the fields present in the file differ depending of the system or the libc version, and are defined in the utmp.h header file.

3. utmp.h文件

3.1 utmp结构体

#define UT_LINESIZE      32
#define UT_NAMESIZE      32
#define UT_HOSTSIZE     256

struct exit_status {              /* Type for ut_exit, below */
               short int e_termination;      /* Process termination status */
               short int e_exit;             /* Process exit status */
           };
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 */
           };

  /* Backward compatibility hacks */
#define ut_name ut_user
#ifndef _NO_UT_TIME
#define ut_time ut_tv.tv_sec
#endif
#define ut_xtime ut_tv.tv_sec
#define ut_addr ut_addr_v6[0]

3.2 ut_type 值

​ 可根据此值变化判断某个登录用户是否活跃。

    /* Values for ut_type field, below */

           #define EMPTY         0 /* Record does not contain valid info (formerly known as UT_UNKNOWN on Linux) */
           #define RUN_LVL       1 /* Change in system run-level (see init(8)) */
           #define BOOT_TIME     2 /* Time of system boot (in ut_tv) */
           #define NEW_TIME      3 /* Time after system clock change (in ut_tv) */
           #define OLD_TIME      4 /* Time before system clock change (in ut_tv) */
           #define INIT_PROCESS  5 /* Process spawned by init(8) */
           #define LOGIN_PROCESS 6 /* Session leader process for user login */
           #define USER_PROCESS  7 /* Normal process */
           #define DEAD_PROCESS  8 /* Terminated process */
           #define ACCOUNTING    9 /* Not implemented */

    The first entries ever created result from init(1) processing inittab(5).  Before an entry is processed, though,init(1) cleans up utmp by setting ut_type to DEAD_PROCESS, clearing ut_user, ut_host, and ut_time with null  bytes for  each  record which ut_type is not DEAD_PROCESS or RUN_LVL and where no process with PID ut_pid exists.  If no empty record with the needed ut_id can be found, init(1) creates a new one.It  sets  ut_id  from  the  inittab,ut_pid and ut_time to the current values, and ut_type to INIT_PROCESS.
    mingetty(8)  (or  agetty(8)) locates the entry by the PID, changes ut_type to LOGIN_PROCESS, changes ut_time, sets ut_line, and waits for connection to be established.
    login(1), after  a  user  has  been  authenticated,  changes ut_type  to  USER_PROCESS, changes ut_time, and sets ut_host and ut_addr.  Depending on mingetty(8) (or agetty(8)) and login(1), records may be located by ut_line instead of the preferable ut_pid.
    When init(1) finds that a process has exited, it locates its utmp entry by ut_pid, sets ut_type  to  DEAD_PROCESS,and clears ut_user, ut_host and ut_time with null bytes.

3.3 登录时间值

#define ut_time ut_tv.tv_sec

其中:
struct utmp ut;
struct timeval tv;
/* gettimeofday((struct timeval *) &ut.ut_tv, NULL); */
gettimeofday(&tv, NULL);
ut.ut_tv.tv_sec = tv.tv_sec;
ut.ut_tv.tv_usec = tv.tv_usec;

DESCRIPTION  
    The functions gettimeofday and settimeofday can get and set the time as  
    well as a timezone. The tv argument is a timeval struct, as specified  
    in <sys/time.h>:  
    struct timeval {  
          time_t       tv_sec;     /* seconds */  
          suseconds_t   tv_usec; /* microseconds */  
    };  

time_t存的是197011000 秒算起至今的UTC时间所经过的秒数
time_t是long int类型.

​ 想清晰得得到现在的年月日信息,就不能通过这个time_t了,需要用struct tm来显示,而将time_t和struct tm转换的函数就是localtime(time_t*),返回一个struct tm*类型,注意是指针类型。然后可以得到tm中的成员.

查询关于时间转换的函数:

root@ubuntu:/var/run# man -k time | grep transform
asctime (3)          - transform date and time to broken-down time or ASCII
asctime_r (3)        - transform date and time to broken-down time or ASCII
ctime (3)            - transform date and time to broken-down time or ASCII
ctime_r (3)          - transform date and time to broken-down time or ASCII
gmtime (3)           - transform date and time to broken-down time or ASCII
gmtime_r (3)         - transform date and time to broken-down time or ASCII
localtime (3)        - transform date and time to broken-down time or ASCII
localtime_r (3)      - transform date and time to broken-down time or ASCII
mktime (3)           - transform date and time to broken-down time or ASCII

root@ubuntu:/var/run# man 3 localtime
       #include <time.h>

       struct tm *localtime(const time_t *timep);
       struct tm *localtime_r(const time_t *timep, struct tm *result);

        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;      /* 从每年的11日开始的天数 – 取值区间为[0,365],其中0代表11日,1代表12日
        };

4 实例代码

/*who01.c文件*/
#include <stdio.h>
#include <utmp.h>
#include <string.h>
#include <time.h>
/* 文件路径 */
#define FILE_PATH "/var/run/utmp"
#define SHOWHOST

/*
函数名称:show_info
函数功能:打印登录用户信息
输入参数:struct utmp *utmpfp
输出参数:无
备注:
*/
void show_info(struct utmp *utmpfp)
{
    /* 时间值转换 */
    time_t timelong = utmpfp->ut_time;
    struct tm *localnow=localtime(&timelong);
   /* 根据当前用户的状态值,判断是否为当前登录用户 */
    if(utmpfp->ut_type == USER_PROCESS)
    {
        printf("%8s\t",utmpfp->ut_name);
        printf("%12s\t",utmpfp->ut_line);
        printf("%d-%d-%d %d:%d ",localnow->tm_year+1900,localnow->tm_mon+1,localnow->tm_mday,localnow->tm_hour,localnow->tm_min); //登录时间

        #ifdef SHOWHOST
            printf("(%s)",utmpfp->ut_host);
        #endif  
        printf("\n");
    }
}

/*
函数名称:main()
函数功能:主函数
输入参数:无
输出参数:无
备注:
*/
int main()
{
    struct utmp current_record;
    FILE *utmpfd = NULL;

    int reclen = sizeof(current_record);
    /* 打开登录信息记录文件 */
    if((utmpfd = fopen(FILE_PATH,"r"))==NULL)
    {
        printf("file open error!\n");
        return 0;
    }   
    printf("file open success!\n");
    memset(&current_record,0x00,reclen);
    /*循环读取*/
    while(fread(&current_record,sizeof(char),reclen,utmpfd)==reclen)
    {
        //read success
        show_info(&current_record);
        memset(&current_record,0x00,reclen);
    }
   /* 关闭文件 */
    fclose(utmpfd);
    return 0;
}

程序测试:

root@ubuntu:/work/shell_cmd/1_code# gcc -g -Wall who01.c -o main
root@ubuntu:/work/shell_cmd/1_code# ./main
file open success!
      ye            tty7    2017-5-12 22:7 (:0)
      ye           pts/4    2017-6-4 13:40 (192.168.1.5)
      ye          pts/21    2017-6-4 13:55 (192.168.1.5)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值