实现who命令

59 篇文章 1 订阅

在看了《Linux/UNIX系统编程手册》和APUE前几章之后发现缺少相应的实践,如果只是单纯的了解API并没有太大意义,因此决定跟随《UNIX/Linux编程实践教程》将书中的例子调通与理解透。然后再去啃APUE,效果应该会好很多。
书中第二章给出了who实现的,由于书写与2004年,代码看上去有些“另类”,对于编译过程中发现的问题进行修改,在讲解代码前先记录如下用法:
grep -r命令

 -r, --recursive
              Read all files  under  each  directory,  recursively,  following symbolic  links only if they are on the command line.  Note that if  no  file  operand  is  given,  grep  searches  the   working directory.  This is equivalent to the -d recurse option.

-R, --dereference-recursive
              Read  all  files  under each directory, recursively.  Follow all symbolic links, unlike -r.

例如如下命令 grep -n -R ‘UTMP_FILE’ /usr/include
是在/usr/include目录下递归查找字符串UTMP_FILE.
-R 与-r的区别是针对符号链接时有所不同。

#include <stdio.h>
#include <stdlib.h>
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>

void showtime( long );
void show_info( struct utmp * utbufp );
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 )
        show_info( &current_record );
    close( utmpfd );
    return 0;
}

void show_info( struct utmp *utbufp )
{
    if ( utbufp->ut_type != USER_PROCESS )
        return;
    printf("%-8.8s ", utbufp->ut_name );
    printf("%-8.8s ", utbufp->ut_line );
    showtime( utbufp->ut_time );
#ifdef SHOWHOST
    if ( utbufp->ut_host[ 0 ] != '\0' )
        printf("(%s)", utbufp->ut_host);
#endif
    printf("\n");
}

void showtime( long timeval )
{
    char    *cp;
    cp = ctime( &timeval );

    printf("%12.12s", cp + 4 );
}

在上面的程序中UTMP_FILE通过grep查出来是_PATH_UTMP,使用grep用同样的方法可以知道其值为/var/run/utmp。
read:对于每个打开的文件系统内核会记录其文件偏移量,有时也将文件偏移量称为读写偏移量或指针。文件偏移量是指执行下一个read()或write()操作的文件或起始位置,会以相对于文件头部起始点的文件当前位置来表示。
ctime函数要输入一个指向time_t的指针,返回的时间字符串类似于以下格式:
Wed Jun 30 21:49:08 1993\n
由于who命令不需要指出星期几,所以在程序中输出从第4个字符开始输出。

运用缓冲技术

一次获取16条记录数据,用这种方法可以使read的调用次数减少到原来的1/16.

#include<stdio.h>
#include<stdlib.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
#define SHOWHOST /*include remote machine on output*/

#define NRECS 16
#define NULLUT ((struct utmp*) NULL)
#define UTSIZE (sizeof(struct utmp))

static char utmpbuf[NRECS* UTSIZE]; /*storage*/
static int  num_recs;               /*num stored*/
static int  cur_rec;                /*next to go */
static int  fd_utmp = -1;           /*read from*/

int utmp_open(char* filename)
{
    fd_utmp = open(filename,O_RDONLY);
    cur_rec = num_recs = 0;
    return fd_utmp;
}
int utmp_reload()
/*read next bunch of records into buffer*/
{
    int amt_read;
    amt_read = read(fd_utmp,utmpbuf,NRECS*UTSIZE);
    num_recs = amt_read/UTSIZE;
    cur_rec = 0;
    return num_recs;
}
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;
}
void utmp_close()
{
    if(fd_utmp!=-1)
        close(fd_utmp);
}

void showtime(long timeval)  
{
    char* cp;
    cp = ctime(&timeval);
    printf("%12.12s",cp+4);
}
void show_info(struct utmp* utbufp)
{
    /*USER_PROCESS indicate the user is active or not*/
    if(utbufp->ut_type!= USER_PROCESS)
        return ;

    printf("%-8.8s ",utbufp->ut_name); /*this logname */
    printf("%-8.8s ",utbufp->ut_line); /*the logtty*/
    showtime(utbufp->ut_time);
    #ifdef SHOWHOST
        if(utbufp->ut_host[0] != '\0')
            printf("( %s )",utbufp->ut_host);  /*the host*/ 
    #endif
        printf("\n");
}

int main()
{
    struct utmp *utbufp; /*read info into here*/
    int    utmpfd;              /*read from the descriptor*/
    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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值