您的位置:首页 > 运维架构 > Linux

Linux编程实践——代码实现ac命令

2011-10-24 13:37 501 查看
ac命令是什么?

man ac命令后的解释是‘打印用户连接时间的统计数据’。
附带的两个常用的命令参数:

-d 日统计
-p 每个用户的统计

ac命令运行结果

进入命令行,依次敲下命令,输出结果比较了然:

$ ac
total 312.64
$ ac -d
Oct 8 total 48.11
Oct 9 total 74.71
Oct 12 total 86.85
Oct 14 total 58.57
Today total 44.82
$ ac -p
lizh 313.09
total 313.09

统计结果单位为小时。
要统计出这些系统信息,需要查询那些文档呢?那么把我们的问题列出个清单来对症下药即可:

ac的登陆时间和注销时间日志记录在哪个文件?

何时会写入登陆和注销日志记录?

日志记录的格式是什么?

统计时间的算法是什么?

姑且只有这些问题吧,由此查阅我们需要的文档。

我们需要什么?

首先要做的是分析实现过程,我们需要以下工具作为参考:

ac文档手册:man ac;
wtmp文档手册:man 5 wtmp;
dump-utmp工具查看wtmp;
login(3):写utmp和wtmp入口;
logout(3):写utmp和wtmp入口;

编程我们借助《Unix\Linux编程实践教程》acc.c

#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include "utmplib.c"

#define RECORDSIZE 256

struct utmp_record{
short ut_type;                 //type
char ut_user[UT_NAMESIZE];     // user name
char ut_line[UT_LINESIZE];    //tty
int32_t login_sec;           //登陆时间
int32_t logout_sec;          //注销时间
double diff;                 //登陆时间与注销时间的时间差
};
struct utmp_record record[RECORDSIZE];
int num_rd = 0;  //整理日志后的记录数量

void show_wtmp(struct utmp*);  //打印wtmp内容
void showtime(long);         //打印时间(按照时间格式)
void show_sorted();
void  show_totaltime();    //打印总连接时间
double sec2hour(double );  //秒换算成小时

int  main(int ac, char* av[]){
int wtmpfd;
struct utmp* utbuf=utmp_next();
int i;
if(utmp_open(WTMP_FILE) == -1){
perror(WTMP_FILE);
return -1;
}

memset(&record[0],0,sizeof(struct utmp_record)*RECORDSIZE);
while((utbuf=utmp_next()) != ((struct utmp*)NULL))
{
// show_wtmp(utbuf);
if((utbuf->ut_type == USER_PROCESS))
{

for(i=0; i < num_rd; i++)
{
if( (strcmp(record[i].ut_user,utbuf->ut_user)==0)&&
(record[i].login_sec == utbuf->ut_time))
{
break;
}

}
if(i == num_rd)
{
record[num_rd].ut_type = utbuf->ut_type;
memcpy(record[num_rd].ut_user,utbuf->ut_user,UT_NAMESIZE);
memcpy(record[num_rd].ut_line,utbuf->ut_line,UT_LINESIZE);
record[num_rd].login_sec = utbuf->ut_time;
num_rd++;
}
}
else if(utbuf->ut_type == DEAD_PROCESS){
for(i=0; i < num_rd; i++){
if(record[i].ut_type == USER_PROCESS
&& strcmp(record[i].ut_line,utbuf->ut_line)==0
&& utbuf->ut_time > record[i].login_sec)
{
record[i].logout_sec = utbuf->ut_time;
record[i].ut_type = DEAD_PROCESS;
record[i].diff = difftime(record[i].logout_sec,record[i].login_sec);//计算时间差
}
}
}
else if((utbuf->ut_type == RUN_LVL && strncmp(utbuf->ut_user,"shutdown",8)==0)
|| (utbuf->ut_type == BOOT_TIME && strncmp(utbuf->ut_user,"reboot",6)==0)){
for(i=0; i < num_rd; i++){
if(record[i].ut_type == USER_PROCESS
&& utbuf->ut_time > record[i].login_sec ){
record[i].logout_sec = utbuf->ut_time;
record[i].ut_type = utbuf->ut_type;
record[i].diff = difftime(record[i].logout_sec, record[i].login_sec);
}
}
}
}

//  show_sorted();
utmp_close();
if(ac == 1 ){ //不带参数的ac令命
show_totaltime();
}
else if (ac == 2){
//..带参数的ac命令,例如:
//ac -p 按照用户名统计
//ac -d 按照日期统计
}
return 0;

}

/*
*      show info()
*                      displays the contents of the utmp struct
*                      in human readable form1
*                      * displays nothing if record has no user name
*/
void show_wtmp( struct utmp *utbufp)
{
//  if ( utbufp->ut_type != USER_PROCESS )
//    return;

printf("%-8.8s", utbufp->ut_name);      /* the logname  */
printf("");                            /* a space      */
printf("|%-8.8s", utbufp->ut_line);      /* the tty      */
printf("");                            /* a space      */
printf("|%d", utbufp->ut_type);
printf("");
showtime( utbufp->ut_time );            /* display time */
#ifdef SHOWHOST
if ( utbufp->ut_host[0] != '\0' )
printf(" (%s)", utbufp->ut_host);/* the host    */
#endif
printf("\n");                          /* newline      */
}
void show_sorted(){
int i = 0;
for(i=0; i < num_rd; i++){
printf("%-8.8s",record[i].ut_name);
printf("");
printf("|%-8.8s",record[i].ut_line);
printf("|%d",record[i].ut_type);
printf("");
printf("%d",record[i].login_sec);
printf("");
showtime(record[i].login_sec);
printf("");
printf("%d",record[i].logout_sec);
printf("");
showtime(record[i].logout_sec);
printf("");
printf("|%f",record[i].diff);
printf("\n");
}
}
void show_totaltime()
{
int i=0;
double total =0.0;
time_t now_t = time(NULL);
for(i=0; i < num_rd;i++){
if(record[i].ut_type != USER_PROCESS){
total += record[i].diff;
}
else {
record[i].diff = difftime(now_t,record[i].login_sec);
total += record[i].diff;
}
}
printf("   total    %.2f\n",sec2hour(total));
}

void showtime( long timeval )
/*
*      displays time in a format fit for human consumption
*      uses ctime to build a string then picks parts out of it
*      Note: %12.12s prints a string 12 chars wide and LIMITS
*      it to 12chars.
*/
{
char    *cp;                    /* to hold address of time      */

cp = ctime(&timeval);           /* convert time to string       */
/* string looks like            */
/* Mon Feb  4 00:46:40 EST 1991 */
/* 0123456789012345.            */
printf("|%15.15s",cp+4 );       /* pick 12 chars from pos 4     */
}
double sec2hour(double secs){
double hours = (secs/60.0/60.0);
return hours;
}


对于当前用户的登陆时间计算,是采用执行acc时取当前时间然后与登陆时间做差的方法。

该程序只是一定程度上实现了ac工具,并不完美:

为了便于编程,整理后的数据结构数组个数,用的宏RECORDSIZE直接定义;

带参数执行未实现,像-p、-d参数,可在目前程序基础上再做扩展;

用户更改系统时间时对执行结果的影响,未作作相应处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: