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

查看who命令的功能

使用man who查看详细内容


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

输入man -k utmp,可以看到

输入man utmp,可以看到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 */
           };

这是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);
}
                                                              45,1         底端

main函数

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

showinfo函数

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

#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 (seeinit(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 */

而我们需要打印的是标识符为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);

最终结果

版权声明:本文为blingblingXY原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/blingblingXY/p/13912082.html