Unix/Linux编程实践教程–ac在Ubuntu 14.04的实现
环境:Ubuntu 14.04 32位 为什么这回不写在OS x上的实现了?因为OS X使用的是utmpx,然后我用 默认没有带 好的,开始我们的节目。 那我们就 然后就可以开始尝试写代码了,初版可能是这样的。 /* ubuntu 14.04 */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <utmp.h>
#include <string.h>
void utmpOut(struct utmp *p);
int main(void)
{
int fd;
struct utmp utmpBuf;
int siz = sizeof(struct utmp);
if((fd = open(WTMP_FILE,O_RDONLY)) == -1){
perror("ac_ubuntu");
exit(1);
}
while(read(fd,&utmpBuf,siz) == siz)
utmpOut(&utmpBuf);
close(fd);
return 0;
}
void utmpOut(struct utmp *p)
{
//if(strcmp(p->ut_user,"superxc"))
// return ;
printf("%dt%st%st%s",p->ut_type,p->ut_user,p->ut_line,asctime(localtime(&p->ut_time)));
}
运行一下看看wtmp里都写啥了。 1 shutdown ~ Mon May 29 09:11:18 2017
2 reboot ~ Sun Jun 4 18:46:09 2017
1 runlevel ~ Sun Jun 4 18:46:09 2017
6 LOGIN tty4 Sun Jun 4 18:46:09 2017
6 LOGIN tty5 Sun Jun 4 18:46:09 2017
6 LOGIN tty2 Sun Jun 4 18:46:09 2017
6 LOGIN tty3 Sun Jun 4 18:46:09 2017
6 LOGIN tty6 Sun Jun 4 18:46:09 2017
6 LOGIN tty1 Sun Jun 4 18:46:09 2017
7 superxc tty1 Sun Jun 4 18:46:42 2017
7 superxc pts/0 Sun Jun 4 18:57:52 2017
7 superxc pts/2 Sun Jun 4 18:58:07 2017
1 runlevel ~ Sun Jun 4 19:03:16 2017
8 tty4 Sun Jun 4 19:03:17 2017
8 tty5 Sun Jun 4 19:03:17 2017
8 tty2 Sun Jun 4 19:03:17 2017
8 tty3 Sun Jun 4 19:03:17 2017
8 tty6 Sun Jun 4 19:03:17 2017
8 pts/0 Sun Jun 4 19:03:17 2017
8 pts/2 Sun Jun 4 19:03:17 2017
1 shutdown ~ Sun Jun 4 19:03:17 2017
1 shutdown ~ Sun Jun 4 19:03:17 2017
2 reboot ~ Mon Jun 5 08:21:34 2017
1 runlevel ~ Mon Jun 5 08:21:34 2017
6 LOGIN tty4 Mon Jun 5 08:21:34 2017
6 LOGIN tty5 Mon Jun 5 08:21:34 2017
6 LOGIN tty2 Mon Jun 5 08:21:34 2017
6 LOGIN tty3 Mon Jun 5 08:21:34 2017
6 LOGIN tty6 Mon Jun 5 08:21:34 2017
6 LOGIN tty1 Mon Jun 5 08:21:34 2017
7 superxc pts/0 Mon Jun 5 08:22:25 2017
7 superxc pts/2 Mon Jun 5 08:22:38 2017
7 root tty1 Mon Jun 5 09:05:05 2017
8 tty1 Mon Jun 5 09:07:35 2017
6 LOGIN tty1 Mon Jun 5 09:07:35 2017
我这里只截取了6月4日和6月5日的记录,再拿 superxc 0.45 Jun 4 total 0.45 superxc 2.47 root 0.04 Today total 2.51 这里的Today 指的是6月5日,可以看到6月4日,superxc总共连接了0.45个小时。怎么算的呢?注意看wtmp的输出。关于superxc用户的登录有三条,分别是: 7 superxc tty1 Sun Jun 4 18:46:42 2017 7 superxc pts/0 Sun Jun 4 18:57:52 2017 7 superxc pts/2 Sun Jun 4 18:58:07 2017 退出的话,注意刚才文档里写的那句话,也就是我标重点的部分,如果用户名为空的话,说明用户在对应的终端上退出了,所以可以找到下面这两行,就是退出的记录。 8 pts/0 Sun Jun 4 19:03:17 2017 8 pts/2 Sun Jun 4 19:03:17 2017 这里要注意到tty1没有退出,直接就关机了,所有没有对应的记录。 同一个用户在三个终端登录,时间是怎么算的?由计算得知是累加的。 (63 - 46 + (17 - 42)/60 + /* tty1 */
63 - 57 + (17 - 52)/60 + /* pts/0 */
63 - 58 + (17 - 07)/60 /* pts/2 */
)/60 = 0.45277
刚好和ac的结果一致。 wtmp文件中有些记录是我们并不需要的,ut_type为6? 2? 1的不需要,但是ut_type为1且ty_user为shutdown为需要保留(用于作为关机时没有退出的用户的退出时间)。 所以ac的实现大概是这样的: 所以代码可能是这样的: /* ubuntu 14.04 */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <utmp.h>
#include <string.h>
#include <time.h>
#define UTMPSIZ sizeof(struct utmp)
void utmpOut(struct utmp *p);
int cntTime(int fd,struct utmp *p);
int main(void)
{
int fd;
struct utmp utmpBuf;
int sum = 0; /* seconds */
if((fd = open(WTMP_FILE,UTMPSIZ) == UTMPSIZ){
sum += cntTime(fd,&utmpBuf);
// utmpOut(&utmpBuf);
}
close(fd);
printf("%d seconds => %f hoursn",sum,sum / (60.0 * 60));
return 0;
}
void utmpOut(struct utmp *p)
{
//if(strcmp(p->ut_user,asctime(localtime(&p->ut_time)));
}
int cntTime(int fd,struct utmp *p)
{
char line[256];
struct utmp utmpBuf;
int cnt = 0; /* forward how many time */
int flag = 0;
int t1,t2;
if(p->ut_type != USER_PROCESS) /* USER_PROCESS 7 */
return 0;
strcpy(line,p->ut_line);
t1 = (int)p->ut_time;
/* printf("user %s login on %s at %s",asctime(localtime(&p->ut_time))); */
while(read(fd,UTMPSIZ) == UTMPSIZ){
++cnt;
/* DEAD_PROCESS 8,RUN_LVL 1 */
/* printf("test record: "); */
/* utmpOut(&utmpBuf); */
if((utmpBuf.ut_type == DEAD_PROCESS && strcmp(line,utmpBuf.ut_line) == 0)
|| (utmpBuf.ut_type == RUN_LVL && strcmp("shutdown",utmpBuf.ut_user) == 0)){
flag = 1;
/* printf("find!n"); */
break;
}
}
t2 = flag ? utmpBuf.ut_time : (int)time(NULL);
/* if(flag){ printf("log out at %s",asctime(localtime(&utmpBuf.ut_time))); }else{ printf("log out at nown"); } printf(" tabkes %d secondsn",t2 - t1); */
lseek(fd,-cnt * UTMPSIZ,SEEK_CUR); /* roll back */
return t2 - t1;
}
代码中使用了lseek进行回滚指针,本程序并没有使用缓存,有兴趣的可以自己加上,还有比如 执行效果: 有个大犇的实现做得比我好多了,可以很大程序减少系统调用,时间开销比较小,而且能结合缓冲,可扩展性也挺好。链接 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |