02 who——open、read、close

1、who能做什么

who命令可以显示出当前系统中已经登录的用户信息,输入who命令,就可以知道有谁正在使用系统。

who命令每一行代表一个已经登录的用户,第1列是用户名,第2列是终端名,第3列是登录时间,第4列是用户的登录地址。

2、who是如何实现的

在联机帮助中描述了who的功能和用法,所以通过联机帮助可以学习who任何实现与工作的。

  • 阅读联机帮助:man who,在描述部分写了已登录用户的信息是放在/var/adm/utmp文件中,who就是通过读该文件获得信息。
  • 搜索联机帮助:man -k utmp,然后通过搜索联机帮助来了解/var/adm/utmp文件的结构信息
  • 阅读.h文件:搜索到/var/adm/utmp文件,然后通过命令man 5 utmp查看该帮助内容,就可以看到utmp.h文件内容,可以看到utmp结构保存了登录记录,ut_user保存登录名,ut_line保存设备名也就是用户终端类型,ut_time保存登录时间,ut_host保存用户用于登录的远程计算机的名字。

open、read和close系统调用:

  • open():打开一个文件,fd=open(char *name,int how),打开文件name,以模式how方式打开,how的三种打开模式:O_RDONLY、O_WRONLY、O_RDWR,最后返回文件描述符fd。
  • read():把数据读取到缓冲区,numread=read(int fd,void *buf,size_t qty),从fd所指定的文件中读取qty字节数据,存放在buf所指定的内存空间中,如果成功返回读取数据的字节数numread。
  • close():关闭一个文件,result=close(int fd),关闭进程和文件fd直接的连接。

who的工作原理:通过阅读who和utmp的联机帮助,以及头文件utmp.h,who通过读文件来获得需要的信息,而每个登录的用户在文件中都有对应的记录。who的流程打开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(8) */
               /* 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 */
           };

3、自己编写一个who

who使用了open、read、close三个系统调用,open这个系统调用在进程和文件之间建立一条连接,这个连接称为文件描述符,是用来唯一标识这个连接的,它像一条由进程通向内核的管道,然后内核提供打开文件服务。

who1.c

#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#define SHOWHOST
void show_info(struct utmp *utbufp)
{
    printf("%-8.8s",utbufp->ut_name);
    printf(" ");
    printf("%-8.8s",utbufp->ut_line);
    printf(" ");
    printf("%10ld",utbufp->ut_time);
    printf(" ");
#ifdef SHOWHOST
    printf("(%s)",utbufp->ut_host);
#endif
    printf("\n");
}
int main()
{
    struct utmp current_record;
    int fd;
    int recordlen=sizeof(current_record);
    if((fd=open(UTMP_FILE,O_RDONLY))==-1)
    {
        perror(UTMP_FILE);
	exit(1);
    }
    while(read(fd,&current_record,recordlen)==recordlen)
        show_info(&current_record);
    close(fd);
    return 0;
}

who2.c

改进:清除空白记录和正确显示登录时间

#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
#define SHOWHOST
void showtime(long timeval)
{
    char *cp;
    cp=ctime(&timeval);
    printf("%12.12s",cp+4);

}
void show_info(struct utmp *utbufp)
{
    if(utbufp->ut_type!=USER_PROCESS)
        return;
    printf("%-8.8s",utbufp->ut_name);
    printf(" ");
    printf("%-8.8s",utbufp->ut_line);
    printf(" ");
    showtime(utbufp->ut_time);
    printf(" ");
#ifdef SHOWHOST
    printf("(%s)",utbufp->ut_host);
#endif
    printf("\n");
}
int main()
{
    struct utmp current_record;
    int fd;
    int recordlen=sizeof(current_record);
    if((fd=open(UTMP_FILE,O_RDONLY))==-1)
    {
        perror(UTMP_FILE);
	exit(1);
    }
    while(read(fd,&current_record,recordlen)==recordlen)
        show_info(&current_record);
    close(fd);
    return 0;
}

who3.c

在who中运用缓冲技术,用utmplib来缓冲main函数调用utmplib.c中的函数来取得下一条utmp记录,utmplib.c中定义的函数每次从文件中读取16条记录放入数组中,当数组中16条记录都被取走后,才调用内核服务重新读取数据。

用一个能容纳16个utmp结构的数组作为缓冲区,编写utmp_next函数来从缓冲区中取得下一个utmp结构的数据,通过调用utmp_next来取得数据,当缓冲区的数据都被取走后,utmp_next会调用read,通过内核再次获得16条记录充满缓冲区。用这种方法可以使read的调用次数减少到原来的1/16。

utmplib.c

#include<stdio.h>
#include<fcntl.h>
#include<sys/types.h>
#include<utmp.h>
#define NRECS 16
#define NULLUT ((struct utmp*)NULL)
#define UTSIZE (sizeof(struct utmp))
static char utmpbuf[NRECS*UTSIZE];
static int num_recs;
static int cur_rec;
static int fd_utmp=-1;
int utmp_open(char *filename)
{
    fd_utmp=open(filename,O_RDONLY);
    cur_rec=num_recs=0;
    return fd_utmp; 
}
struct utmp *utmp_next()
{
    struct utmp *recp;
    if(fd_utmp==-1)
        return NULLUT;
    if(cur_rec==num_recs && utmp_reload()==0)
        return NULLUT;
    recp=(struct utmp*)&utmpbuf[cur_rec*UTSIZE];
    cur_rec++;
    return recp;
}
int utmp_reload()
{
    int amt_read;
    amt_read=read(fd_utmp,utmpbuf,NRECS*UTSIZE);
    num_recs=amt_read/UTSIZE;
    cur_rec=0;
    return num_recs;
}
void utmp_close()
{
    if(fd_utmp!=-1)
        close(fd_utmp);
}

who3.c

#include<stdio.h>
#include<utmp.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
#include "utmplib.c"
#define SHOWHOST
void showtime(long timeval)
{
    char *cp;
    cp=ctime(&timeval);
    printf("%12.12s",cp+4);

}
void show_info(struct utmp *utbufp)
{
    if(utbufp->ut_type!=USER_PROCESS)
        return;
    printf("%-8.8s",utbufp->ut_name);
    printf(" ");
    printf("%-8.8s",utbufp->ut_line);
    printf(" ");
    showtime(utbufp->ut_time);
    printf(" ");
#ifdef SHOWHOST
    printf("(%s)",utbufp->ut_host);
#endif
    printf("\n");
}
int main()
{
    struct utmp *utbufp;
    if(utmp_open(UTMP_FILE)==-1)
    {
	perror(UTMP_FILE);
	exit(1);
    }
    while((utbufp=utmp_next())!=((struct utmp*)NULL))
	show_info(utbufp);
    utmp_close();
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值