zoukankan      html  css  js  c++  java
  • Linux下who命令之C语言实现

    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可能自动在最后补了一个字符

    Step6:调试代码

    • 那只要能回退一个字符就好了,比如输出一个(退格字符)
    • 编译再运行,发现输出格式仍是原样,最后经过了解确实是可以回退一个字符,但是并不能实现退到上行,也就是不能消除 带来的影响
    • 百度之后,说可以通过输出 来实现“退行”,但实践后发现也不可取
    • 最后考虑到直接修改*cp字符串中最后一个字符为,使输出达到与系统who命令一样的效果
    • 在输出语句前添加如下代码(需用到string.h):
      • cp[strlen(cp)-1] = ''
    • 最后编译执行效果,可以看出与who命令基本一致:
  • 相关阅读:
    在Centos 7下编译openwrt+njit-client
    开博随笔
    Chapter 6. Statements
    Chapter 4. Arrays and Pointers
    Chapter 3. Library Types
    Chapter 2.  Variables and Basic Types
    关于stm32不常用的中断,如何添加, 比如timer10 timer11等
    keil 报错 expected an identifier
    案例分析 串口的地不要接到电源上 会烧掉
    案例分析 CAN OPEN 调试记录 进度
  • 原文地址:https://www.cnblogs.com/20145221GQ/p/6060420.html
Copyright © 2011-2022 走看看