您的位置:首页 > 其它

who命令的编写

2013-01-10 15:06 148 查看

一.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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: