• linux系统编程:自己动手写一个who命令


    who命令的作用用于显示当前有哪些用户登录到系统。

    这个命令执行的原理是读取了系统上utmp文件中记录的所有登录信息,直接显示出来的

    utmp文件在哪里呢?

    man who的时候,在手册下面有这么一段说明:意思就是不指定文件参数,那么读取的就是/var/run/utmp,到底是不是,验证下

    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.

    当我指定file参数为/var/run/utmp或者省略这个参数的时候,结果都是一样, 当我用一个错误的文件时,没有任何结果,从这里可以推断,who命令确实从/var/run/utmp中读取用户登录的信息

    ghostwu@ubuntu:~$ who
    ghostwu  tty7         2018-01-08 09:09 (:0)
    ghostwu  pts/18       2018-01-08 12:59 (:0)
    ghostwu  pts/19       2018-01-08 13:00 (:0)
    ghostwu  pts/20       2018-01-08 13:03 (:0)
    ghostwu@ubuntu:~$ who -b
             system boot  2018-01-08 09:08
    ghostwu@ubuntu:~$ who -b /var/run/utmp 
             system boot  2018-01-08 09:08
    ghostwu@ubuntu:~$ who -b /var/run/utmp2
    ghostwu@ubuntu:~$ who -b /var/run/utmp3

    那么utmp到底在哪里?

    利用man -k utmp 查找所有的可能:    推断--->  utmp (5) - login records  这里的可能性比较大,描述说,这里是记录登录信息的

    ghostwu@ubuntu:~$ man -k utmp
    endutent (3)         - access utmp file entries
    endutxent (3)        - access utmp file entries
    getutent (3)         - access utmp file entries
    getutent_r (3)       - access utmp file entries
    getutid (3)          - access utmp file entries
    getutid_r (3)        - access utmp file entries
    getutline (3)        - access utmp file entries
    getutline_r (3)      - access utmp file entries
    getutmp (3)          - copy utmp structure to utmpx, and vice versa
    getutmpx (3)         - copy utmp structure to utmpx, and vice versa
    getutxent (3)        - access utmp file entries
    getutxid (3)         - access utmp file entries
    getutxline (3)       - access utmp file entries
    login (3)            - write utmp and wtmp entries
    logout (3)           - write utmp and wtmp entries
    pututline (3)        - access utmp file entries
    pututxline (3)       - access utmp file entries
    sessreg (1)          - manage utmpx/wtmpx entries for non-init clients
    setutent (3)         - access utmp file entries
    setutxent (3)        - access utmp file entries
    systemd-update-utmp (8) - Write audit and utmp updates at bootup, runlevel ch...
    systemd-update-utmp-runlevel.service (8) - Write audit and utmp updates at bo...
    systemd-update-utmp.service (8) - Write audit and utmp updates at bootup, run...
    utmp (5)             - login records
    utmpdump (1)         - dump UTMP and WTMP files in raw format
    utmpname (3)         - access utmp file entries
    utmpx (5)            - login records
    utmpxname (3)        - access utmp file entries

    接下来,我们去 man 5 utmp 看下,会发现有这么一段提示:

    The file is a sequence of utmp structures, declared as follows in <utmp.h> (note that this
           is only one of several definitions around; details depend on the version of libc):

    意思是utmp文件的信息是一系列utmp结构体数据, 这个结构体定义在utmp.h文件中,  每个linux发行版可能不一样.

    接下来,我用强大的find命令查找到了2个目标:

    ghostwu@ubuntu:~$ find /usr/include -name "utmp.h"
    /usr/include/x86_64-linux-gnu/bits/utmp.h
    /usr/include/utmp.h

    结构体的定义就在这个文件中( /usr/include/x86_64-linux-gnu/bits/utmp.h  )

    这里有两个宏要注意下( ut_time和UTMP_FILE ), 下面的程序会用到

    #ifndef _NO_UT_TIME
    /* We have a problem here: `ut_time' is also used otherwise.  Define
       _NO_UT_TIME if the compiler complains.  */
    # define ut_time    ut_tv.tv_sec
    #endif
    ghostwu@ubuntu:~$ grep "UTMP_FILE" /usr/include/utmp.h 
    #define UTMP_FILE    _PATH_UTMP
    #define UTMP_FILENAME    _PATH_UTMP
    ghostwu@ubuntu:~$ grep "_PATH_UTMP" /usr/include/utmp.h
    #define UTMP_FILE    _PATH_UTMP
    #define UTMP_FILENAME    _PATH_UTMP
    ghostwu@ubuntu:~$ grep "_PATH_UTMP" /usr/include/x86_64-linux-gnu/bits/utmp.h 
    ghostwu@ubuntu:~$ grep "_PATH_UTMP" /usr/include/*.h
    /usr/include/paths.h:#define    _PATH_UTMP    "/var/run/utmp"
    /usr/include/utmp.h:#define UTMP_FILE    _PATH_UTMP
    /usr/include/utmp.h:#define UTMP_FILENAME    _PATH_UTMP
    /usr/include/utmpx.h:# define UTMPX_FILE    _PATH_UTMPX
    /usr/include/utmpx.h:# define UTMPX_FILENAME    _PATH_UTMPX
    ghostwu@ubuntu:~$

    UTMP_FILE的查找思路: 首先grep两个目录下面的文件utmp.h,在/usr/include/utmp.h找到一个宏定义 _PATH_UTMP,下一步就是确定 _PATH_UTMP到底是什么,利用grep "_PATH_UTMP" /usr/include/*.h

    最终在paths.h头文件中,发现了他的真面目

    who命令书写思路:

    1)从/var/run/utmp读取文件,每次读取一个struct utmp结构体这么大,如果长度每次都有这么大,继续读取

    2)格式化4个信息:用户名,主机,地址,时间

    3)只打印当前活动的用户(当前登录的用户)

    4)格式化时间( 小时,分钟,秒, >10的补0, <10的原样返回 )

    源代码

      1 /*================================================================
      2 *   Copyright (C) 2018 . All rights reserved.
      3 *   
      4 *   文件名称:mywho.c
      5 *   创 建 者:ghostwu(吴华)
      6 *   创建日期:2018年01月08日
      7 *   描    述:
      8 *
      9 ================================================================*/
     10 
     11 #include <stdio.h>
     12 #include <utmp.h>
     13 #include <sys/types.h>
     14 #include <sys/stat.h>
     15 #include <fcntl.h>
     16 #include <stdlib.h>
     17 #include <unistd.h>
     18 #include <time.h>
     19 #include <string.h>
     20 
     21 #ifndef UTMP_FILE
     22 #define UTMP_FILE "/var/run/utmp"
     23 #endif
     24 
     25 int count = 0;
     26 
     27 //格式化时间, <10 就补0, >10 原样返回
     28 char* format_time( char* s, const char *time ) {
     29     if( strlen( time ) < 2 ) {
     30         return strcat( s, time );
     31     }
     32     return strcpy( s, time );
     33 }
     34 
     35 void show_info( struct utmp* t_utmp ) {
     36     if ( t_utmp->ut_type != USER_PROCESS ) //不显示 非活跃的用户信息
     37       return;
     38 
     39     printf( "%-8.8s", t_utmp->ut_user ); 
     40     printf( " " );
     41     printf( "%-8.8s", t_utmp->ut_line );
     42     printf( " " );
     43 
     44     //printf( " " );
     45     //printf( "%12.12s", ctime( (time_t*)&(t_utmp->ut_time) ) + 4 ); //+4--->去除天(day)和后面的空格
     46     
     47     /*测试localtime用法
     48     //当前时间
     49     time_t now;
     50     struct tm* pNow;
     51     time( &now );
     52     pNow = localtime( &now );
     53     printf( "%d-%d-%d %d:%d", pNow->tm_year + 1900, pNow->tm_mon + 1, pNow->tm_mday, pNow->tm_hour, pNow->tm_min );
     54     */
     55 
     56     struct tm* ptm;
     57     time_t u_time = t_utmp->ut_time;
     58     ptm = localtime( &u_time );
     59     int ihour = ptm->tm_hour;
     60     int imin = ptm->tm_min;
     61 
     62     char hour[3] = "0";
     63     char hour2[3] = "0";
     64     sprintf( hour2, "%d", ihour );
     65     format_time( hour, hour2 );
     66 
     67     char min[3] = "0";
     68     char min2[3] = "0";
     69     sprintf( min2, "%d", imin );
     70     format_time( min, min2 );
     71 
     72     //printf( "%d-%d-%d %d:%d", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ihour, imin );
     73     printf( "%d-%d-%d %s:%s", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, hour, min );
     74 
     75     printf( " " );
     76     printf( "%-8.8s", t_utmp->ut_host );
     77 
     78     printf( "
    " );
     79 }
     80 
     81 int main(int argc, char *argv[])
     82 {
     83     struct utmp myutmp;
     84     int fd = -1;
     85     int reclen = sizeof( myutmp );
     86 
     87     fd = open( UTMP_FILE, O_RDONLY );
     88     
     89     if( -1 == fd ) {
     90         perror( "open utmp" );
     91         exit( -1 );
     92     }
     93 
     94     //printf( "fd = %d
    ", fd );
     95     
     96     while( read( fd, &myutmp, reclen ) == reclen ) {
     97         count++;
     98         show_info( &myutmp );    
     99     }
    100     printf( "文件读取的次数:%d
    ", count );
    101     close( fd );
    102 
    103 
    104     return 0;
    105 }
    View Code

    总结:

     一个非常小的功能,囊括以下知识点:

    1)文件读取

    2)man手册与系统命令使用技巧

    3)指针用法

    4)字符串函数用法

    5)时间函数用法

    6)宏与typedef的用法

       

  • 相关阅读:
    永无乡「HNOI2012」
    ruby基础知识之 class&module
    Linux命令集锦
    Ruby知识总结-一般变量+操作符+if+数组和哈希
    VMware通过VMnet8共享本地网络
    VMware Workstation 不可恢复错误 (vcpu-0)
    WIN10安装时msxml4.0提示2502、2503解决办法
    C# 委托知识总结
    request.servervariables参数
    判断MS SQLSERVER临时表是否存在
  • 原文地址:https://www.cnblogs.com/ghostwu/p/8243534.html
Copyright © 2020-2023  润新知