• 用系统调用实现who命令mywho


    查看who命令的功能
    image

    使用man who查看详细内容
    image

    可以看到,who命令用于显示目前登录系统的用户信息。

    输入man -k utmp,可以看到
    image

    输入man utmp,可以看到utmp的结构
    image

    点击查看代码
    `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 */
               };`
    
               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 */
           };`
    

    这是utmp结构体的定义,从注释中可以了解到:ut_line保存设备名,即用户的终端类型;ut_user保存登录名;ut_host保存用户用于登录的远程计算机的名字;用户的登录时间被保存在ut_tv结构体中。

    who的原理便是读取/var/run/utmp部分文件内容,输出到屏幕。
    编写mywho

    点击查看代码
    #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,&current_record,reclen)==reclen)
                    showinfo(&current_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("\n");
            }
    }
    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函数

    main函数使用系统调用open,read,close对utmp文件进行操作
    showinfo函数

    用来保存数据的结构体中数据不断读出,但是在utmp中,系统对每种用户都给了标示符:

    而我们需要打印的是标识符为7的USER_PROCESS
    showtime函数

    我调用了头文件time.h,其中的储存时间的结构体内容如下所示:

    点击查看代码
    `struct tm {
        int tm_sec;    /* Seconds (0-60) */
        int tm_min;    /* Minutes (0-59) */
        int tm_hour;   /* Hours (0-23) */
        int tm_mday;   /* Day of the month (1-31) */
        int tm_mon;    /* Month (0-11) */
        int tm_year;   /* Year - 1900 */
        int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
        int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
        int tm_isdst;  /* Daylight saving time */
    };`
    

    utbufp->ut_time是一个时间数据,其储存的是从1970年1月1日0:00开始到现在所经过的秒数。

    通过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);

    最终结果
    image
    image

  • 相关阅读:
    IT人必看的9个故事
    Word中如何隐藏菜单栏
    Delphi MaskEdit用法
    看看哪家银行缩写最牛!
    Delphi TRzButtonEdit的用法
    vagrant box镜像百度下载地址
    Python全国二级等级考试(2019)
    使用Vagrant配置本地开发环境
    Vagrant 如何调整虚拟机的内存大小?
    全国计算机等级考试二级教程2019年版——Python语言程序设计参考答案
  • 原文地址:https://www.cnblogs.com/1482156703optimus/p/16779311.html
Copyright © 2020-2023  润新知