有了上篇关于ac的实现,对于这个last的实现过程就是很简单了。首先 man 1 last。
描述中写着last looks through the file wtmp (which records all logins/logouts) and prints information about connect times of users.
也就是还是读的wtmp这个文件。
所以代码的实现就很简单了,我参照大犇的ac写了个last。代码如下:
#include <stdio.h>
#include <utmp.h>
#include <string.h>
#include <sys/utsname.h>
struct acc{
short ut_type;
char ut_name[UT_NAMESIZE];
char ut_line[UT_LINESIZE];
char ut_host[UT_HOSTSIZE];
int32_t login_sec;
int32_t logout_sec; /* 0 still in,-1 down*/
int diff; /* logout_sec - login_sec */
} record[1024];
static int num_rd;
#define STILL_IN 0
#define DOWN -1
void output_ans(void);
char *format_time(int t);
int main(int ac,char *av[])
{
struct utmp *utbufp,*utbufp_next(void);
int utmp_open(char *filename);
void utmp_close(void);
int i;
if(utmp_open(WTMP_FILE) == -1){
perror(WTMP_FILE);
exit(1);
}
num_rd = 0;
while(utbufp = utmp_next()){
switch(utbufp->ut_type){
case USER_PROCESS:
case BOOT_TIME:
record[num_rd].login_sec = utbufp->ut_time;
record[num_rd].logout_sec = STILL_IN;
record[num_rd].ut_type = utbufp->ut_type;
strcpy(record[num_rd].ut_name,utbufp->ut_name);
strcpy(record[num_rd].ut_line,utbufp->ut_type == USER_PROCESS ? utbufp->ut_line : "system");
strcpy(record[num_rd].ut_host,utbufp->ut_host);
++num_rd;
break;
case DEAD_PROCESS:
for(i = 0; i < num_rd; ++i){
if(record[i].ut_type == USER_PROCESS && !strcmp(record[i].ut_line,utbufp->ut_line)){
record[i].logout_sec = utbufp->ut_time;
record[i].ut_type = DEAD_PROCESS;
record[i].diff = record[i].logout_sec - record[i].login_sec;
break;
}
}
break;
case RUN_LVL:
/* utbufp->ut_time > record[num_rd - 1].login_sec guarantee that can record boot time normally */
if(!strcmp("runlevel",utbufp->ut_name) && utbufp->ut_time > record[num_rd - 1].login_sec)
for(i = 0; i < num_rd; ++i)
if(record[i].ut_type == USER_PROCESS ||
record[i].ut_type == BOOT_TIME){
record[i].logout_sec = utbufp->ut_time;
record[i].diff = record[i].logout_sec - record[i].login_sec;
if(record[i].ut_type == USER_PROCESS)
record[i].logout_sec = DOWN; /* quit because shutdown */
record[i].ut_type = DEAD_PROCESS;
}
break;
}
}
output_ans();
utmp_close();
return 0;
}
void output_ans(void)
{
int i;
time_t now_t = time(NULL);
struct utsname buf;
uname(&buf);
for(i = num_rd - 1; i >= 0; --i){
if(record[i].ut_type == BOOT_TIME){
record[i].logout_sec = (int32_t)now_t;
record[i].diff = record[i].logout_sec - record[i].login_sec;
}
printf("%-8.8s ",record[i].ut_name);
printf("%-6.6s ",record[i].ut_line);
if(!strcmp(record[i].ut_line,"system")){
printf("%-5.5s ","boot");
printf("%-16.16s ",buf.release); /* 4.2.0-27-generic */
}else{
printf("%-5.5s ","");
printf("%-16.16s ",record[i].ut_host);
}
printf("%-16.16s ",asctime(localtime(&record[i].login_sec)));
switch(record[i].logout_sec){
case STILL_IN:
printf(" %-5.5s ","still");
break;
case DOWN:
printf("- %-5.5s ","down");
break;
default:
printf("- %-5.5s ",asctime(localtime(&record[i].logout_sec)) + 11);
break;
}
if(record[i].ut_type == USER_PROCESS)
printf("logged in\n");
else
printf(" (%s)\n",format_time(record[i].diff));
}
}
char *format_time(int t)
{
static char buf[10];
int h;
int m;
t /= 60;
m = t % 60;
h = t / 60;
sprintf(buf,"%.2d:%.2d",h,m);
return buf;
}
用到的utmp缓存:
#include <utmp.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFMAX 10
#define UTSIZ sizeof(struct utmp)
static int fd = -1;
static int utCur;
static int utSum;
struct utmp utmpBuf[BUFMAX];
struct utmp *utmp_reload(void);
struct utmp *utmp_next(void)
{
if(fd == -1)
return NULL;
if(utCur == utSum)
return utmp_reload();
return &utmpBuf[utCur++];
}
struct utmp *utmp_reload(void)
{
int bytes_read = read(fd,utmpBuf,sizeof(utmpBuf));
utCur = 0;
utSum = bytes_read / UTSIZ;
return utSum > 0 ? &utmpBuf[utCur++] : NULL;
}
int utmp_open(char *filename)
{
utCur = utSum = 0;
return fd = open(filename,O_RDONLY);
}
void utmp_close(void)
{
if(fd != -1)
close(fd);
}
效果:
原文链接:/bash/392806.html