who命令的编写


一.who的功能

 查看当前哪些用户正在使用系统

二.who的工作流程:

 从 /var/run/utmp 文件中读取已登录用户的信息,然后输出

                            (注意:我的操作环境是ubuntu11.10 ,有些地方与其他系统不同)

                              如在我的ubuntu11.10中utmp.h在   /usr/include   和    /usr/include/i386-linux-gnu/bits  中

三.内容详解

/usr/include中的/utmp.h有:

#include <bits/utmp.h>
/* Compatibility names for the strings of the canonical file names.  */
#define UTMP_FILE   _PATH_UTMP 

path.h中有:           

#define _PATH_UTMP             "/var/run/utmp"     
则 UTMP_FILE    就是文件路径/var/run/utmp

/usr/include/i386-linux-gnu/bits/utmp.h中包含信息:

#ifndef _UTMP_H
# error "Never include <bits/utmp.h> directly; use <utmp.h> instead."
#endif

#include <paths.h>
#include <sys/time.h>
#include <sys/types.h>
#include <bits/wordsize.h>


#define UT_LINESIZE	32
#define UT_NAMESIZE	32
#define UT_HOSTSIZE	256


/* The structure describing an entry in the database of
   previous logins.  */
struct lastlog
  {
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
    int32_t ll_time;
#else
    __time_t ll_time;
#endif
    char ll_line[UT_LINESIZE];
    char ll_host[UT_HOSTSIZE];
  };


/* The structure describing the status of a terminated process.  This
   type is used in `struct utmp' below.  */
struct exit_status
  {
    short int e_termination;	/* Process termination status.  */
    short int e_exit;		/* Process exit status.  */
  };


/* The structure describing an entry in the user accounting database.  */
struct utmp
{
  short int ut_type;		/* Type of login.  */
  pid_t ut_pid;			/* Process ID of login process.  */
  char ut_line[UT_LINESIZE];	/* Devicename.  */
  char ut_id[4];		/* Inittab ID.  */
  char ut_user[UT_NAMESIZE];	/* Username.  */
  char ut_host[UT_HOSTSIZE];	/* Hostname for remote login.  */
  struct exit_status ut_exit;	/* Exit status of a process marked
				   as DEAD_PROCESS.  */
/* 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, used for windowing.  */
  struct
  {
    int32_t tv_sec;		/* Seconds.  */
    int32_t tv_usec;		/* Microseconds.  */
  } ut_tv;			/* Time entry was made.  */
#else
  long int ut_session;		/* Session ID, used for windowing.  */
  struct timeval ut_tv;		/* Time entry was made.  */
#endif

  int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
  char __unused[20];		/* Reserved for future use.  */
};

/* Backwards compatibility hacks.  */
#define ut_name		ut_user
#ifndef _NO_UT_TIME
/* We have a problem here: `ut_time' is also used otherwise.  Define
   _NO_UT_TIME if the compiler complains.  */
# define ut_time	ut_tv.tv_sec
#endif
#define ut_xtime	ut_tv.tv_sec
#define ut_addr		ut_addr_v6[0]


/* Values for the `ut_type' field of a `struct utmp'.  */
#define EMPTY		0	/* No valid user accounting information.  */

#define RUN_LVL		1	/* The system's runlevel.  */
#define BOOT_TIME	2	/* Time of system boot.  */
#define NEW_TIME	3	/* Time after system clock changed.  */
#define OLD_TIME	4	/* Time when system clock changed.  */

#define INIT_PROCESS	5	/* Process spawned by the init process.  */
#define LOGIN_PROCESS	6	/* Session leader of a logged in user.  */
#define USER_PROCESS	7	/* Normal process.  */
#define DEAD_PROCESS	8	/* Terminated process.  */

#define ACCOUNTING	9

/* Old Linux name for the EMPTY type.  */
#define UT_UNKNOWN	EMPTY


/* Tell the user that we have a modern system with UT_HOST, UT_PID,
   UT_TYPE, UT_ID and UT_TV fields.  */
#define _HAVE_UT_TYPE	1
#define _HAVE_UT_PID	1
#define _HAVE_UT_ID	1
#define _HAVE_UT_TV	1
#define _HAVE_UT_HOST	1

struct utmp结构保存登录信息

四.自己写的who命令的代码(版本一):

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

#define SHOWHOST

void showtime(long);
void show_info(struct utmp *utbufp);
int main()
{
    struct utmp  utbuf;        // read info into here
    int          utmpfd;       // read from this descriptor

    if( (utmpfd = open(UTMP_FILE,O_RDONLY)) == -1)
    {
    	perror(UTMP_FILE);     //UTMP_FILE is in utmp.h
    	exit(1);
    }
    while( read( utmpfd,&utbuf,sizeof(utbuf)) ==sizeof(utbuf))
    	show_info(&utbuf);
    close(utmpfd);
    return 0;
}
void show_info(struct utmp *utbufp)
{
	if(utbufp->ut_type != USER_PROCESS) //ut_type==USER_PROCESS时,表示已经登录的用户
		return ;
    printf("%-8.8s",utbufp->ut_user);
    printf(" ");
    printf("%-8.8s",utbufp->ut_line);
    printf(" ");
    showtime( utbufp->ut_time);
   // printf("%12.12s",ctime(&(utbufp->ut_tv).tv_sec)+4);
    printf(" ");
#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);
}

五.运用缓冲技术的who命令代码(版本二):

        在版本一中,每次只能读取一个数据,因此需要不停的读取,所以导致效率低下。可以加入缓冲机制提高程序的运行效率。缓冲技术的主要思想是一次读入大量的数据放入缓冲区,需要的时候从缓冲区取得数据。

        程序使用一个 utmplib.c文件实现缓冲算法,在main函数中只要调用 utmplib.c中相应函数即可。在 utmplib.c中用一个能容纳16个utmp结构的数组作为缓冲区。utmp_next 函数来从缓冲区取得下一个utmp结构的数据。

       修改原来的main 函数,通过调用utmp_next 来取得数据,当缓冲区的数据都被取出后,utmp_next会调用read,通过内核再次获得16条记录充满缓冲区,用这种方法可以是read的调用次数减少到原来的 1/16 。

utmplib.c 代码如下:

#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<sys/types.h>

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

static char utmpbuf[NRECS * UTSIZE]; //一次可以存储16个utmp结构的数组
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;
}
/*
 *  utmp_reload返回值是缓冲区的数据个数
 */
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 ;
}
/*
 *   utmp_next 返回指向结构的指针
 */
struct utmp *utmp_next()
{
	struct utmp *recp;
	if( fd_utmp == -1)
		return NULLUT;
	if( cur_rec == num_recs && utmp_reload() == 0)
		return NULLUT;
	// recp指向下一个数据
	recp = (struct utmp *)&utmpbuf[cur_rec * UTSIZE];
	cur_rec++;
	return recp;
}

void utmp_close()
{
	if(fd_utmp != -1)
		close(fd_utmp);
}

who.c中只更改main函数,其余不变,main函数代码如下:

int main()
{
    struct utmp  *utbufp,
            *utmp_next();

    if( (utmp_open(UTMP_FILE)) == -1)
    {
    	perror(UTMP_FILE);     //UTMP_FILE is in utmp.h
    	exit(1);
    }
    while(( utbufp = utmp_next()) != ((struct utmp *) NULL))
    	show_info(utbufp);
    utmp_close();
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值