last
数据源: /var/log/wtmp(默认 记录每个用户的登录次数和持续时间等信息)和/var/log/btmp(详细,包括登录失败请求)
数据源格式:二进制(可以通过dump-utmp 命令进行阅读)
last [-adRx][-f ][-n ][帐号名称...][终端机编号...]
图1 last 命令格式
参数说明:
-a 把从何处登入系统的主机名称或IP地址,显示在最后一行。
-d 将IP地址转换成主机名称。
-f <记录文件> 指定记录文件,默认是显示/var/log目录下的wtmp文件的记录,但/var/log目录下得btmp能显示的内容更丰富,可以显示远程登录,例如ssh登录 ,包括失败的登录请求。
-n <显示列数>或-<显示列数> 设置列出名单的显示列数。
-R 不显示登入系统的主机名称或IP地址。
-x 显示系统关机,重新开机,以及执行等级的改变等信息。
-i 显示特定ip登录的情况
-t 显示YYYYMMDDHHMMSS之前的信息
实例1
last
图2 last
正常命令重启显示为down,而电源强制重启为crash
字段介绍:
第一列:用户名
第二列:终端位置
第三列:登录ip或者内核
第四列:开始时间
第五列:结束时间(still login in 还未退出 down 直到正常关机 crash 直到强制关机)
第六列:持续时间
实例2
last -x
图3 last -x
实例3
last -n
图4 last -x -n
实例4
last -f /var/log/btmp | head -100
图5 last -f /var/log/btmp | head -100
实例5
last -t 20130819090800
显示2013-08-19 09:09:00之前的登录信息
图6 last -t 20130819090800
深入了解-晋级
结构
utmp文件中保存的是当前正在本系统中的用户的信息。
wtmp文件中保存的是登录过本系统的用户的信息。
/var/log/wtmp 文件结构和/var/run/utmp 文件结构一样,都是引用/usr/include/bits/utmp.h 中的struct utmp
/* The `struct utmp' type, describing entries in the utmp file. GNU version. Copyright (C) 1993, 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #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
而读取和修改这些文件的函数如下(/usr/include/utmp.h):
/* Copyright (C) 1993, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _UTMP_H
#define _UTMP_H 1
#include <features.h>
#include <sys/types.h>
__BEGIN_DECLS
/* Get system dependent values and data structures. */
#include <bits/utmp.h>
/* Compatibility names for the strings of the canonical file names. */
#define UTMP_FILE _PATH_UTMP
#define UTMP_FILENAME _PATH_UTMP
#define WTMP_FILE _PATH_WTMP
#define WTMP_FILENAME _PATH_WTMP
/* Make FD be the controlling terminal, stdin, stdout, and stderr;
then close FD. Returns 0 on success, nonzero on error. */
extern int login_tty (int __fd) __THROW;
/* Write the given entry into utmp and wtmp. */
extern void login (__const struct utmp *__entry) __THROW;
/* Write the utmp entry to say the user on UT_LINE has logged out. */
extern int logout (__const char *__ut_line) __THROW;
/* Append to wtmp an entry for the current time and the given info. */
extern void logwtmp (__const char *__ut_line, __const char *__ut_name,
__const char *__ut_host) __THROW;
/* Append entry UTMP to the wtmp-like file WTMP_FILE. */
extern void updwtmp (__const char *__wtmp_file, __const struct utmp *__utmp)
__THROW;
/* Change name of the utmp file to be examined. */
extern int utmpname (__const char *__file) __THROW;
/* Read next entry from a utmp-like file. */
extern struct utmp *getutent (void) __THROW;
/* Reset the input stream to the beginning of the file. */
extern void setutent (void) __THROW;
/* Close the current open file. */
extern void endutent (void) __THROW;
/* Search forward from the current point in the utmp file until the
next entry with a ut_type matching ID->ut_type. */
extern struct utmp *getutid (__const struct utmp *__id) __THROW;
/* Search forward from the current point in the utmp file until the
next entry with a ut_line matching LINE->ut_line. */
extern struct utmp *getutline (__const struct utmp *__line) __THROW;
/* Write out entry pointed to by UTMP_PTR into the utmp file. */
extern struct utmp *pututline (__const struct utmp *__utmp_ptr) __THROW;
#ifdef __USE_MISC
/* Reentrant versions of the file for handling utmp files. */
extern int getutent_r (struct utmp *__buffer, struct utmp **__result) __THROW;
extern int getutid_r (__const struct utmp *__id, struct utmp *__buffer,
struct utmp **__result) __THROW;
extern int getutline_r (__const struct utmp *__line,
struct utmp *__buffer, struct utmp **__result) __THROW;
#endif /* Use misc. */
__END_DECLS
#endif /* utmp.h */
utmpname()函数设定utmp文件所在的路径,默认的路径为宏 _PATH_UTMP,该宏定义在/usr/include/paths.h中
#define _PATH_UTMP "/var/run/utmp"
setutent()函数打开文件utmp,并且将文件指针指向文件的最开始。
getutent()函数从文件utmp中,每次读取一个struct utmp的结构体。读取失败返回NULL。
endutent()函数关闭文件utmp。
pututline()函数将一个struct utmp结构体写进文件utmp中。
下面根据这些知识写一个模仿Linux下的who命令的小程序(mywho.c).
#include <stdio.h>
#include <stdlib.h>
#include <utmp.h>
#include <time.h>
int main()
{
struct utmp *p_utent;
long t;
setutent(); /* rewinds the file pointer to the beginning of the utmp file */
while((p_utent = getutent()) != NULL){
if(p_utent->ut_type != USER_PROCESS)
continue;
printf("%s\t", p_utent->ut_user);
printf("%s\t", p_utent->ut_line);
t = p_utent->ut_tv.tv_sec;
printf("%.20s\t", ctime(&t) + 4);
printf("(%s)\n", p_utent->ut_host);
}
endutent(); /* closes the utmp file. */
return 0;
}
编译
gcc -o mywho mywho.c
运行
图7 mywho运行结果
在上面的程序中增加下面一条语句,就可以读取曾经登录过本系统的用户信息
utmpname(_PATH_WTMP); /* #define _PATH_WTMP "/var/log/wtmp" */
#include <stdio.h> #include <stdlib.h> #include <utmp.h> #include <time.h> int main() { struct utmp *p_utent; long t; utmpname(_PATH_WTMP); /* #define _PATH_WTMP "/var/log/wtmp" */ setutent(); /* rewinds the file pointer to the beginning of the utmp file */ while((p_utent = getutent()) != NULL){ if(p_utent->ut_type != USER_PROCESS) continue; printf("%s\t", p_utent->ut_user); printf("%s\t", p_utent->ut_line); t = p_utent->ut_tv.tv_sec; printf("%.20s\t", ctime(&t) + 4); printf("(%s)\n", p_utent->ut_host); } endutent(); /* closes the utmp file. */ return 0; }
编译
gcc -o mywho mywho.c
运行
图8 mywho运行结果(所以用户登录信息)
在上面那些函数是非线程安全的,不可重入的,因为它们将返回结果保存在一个static变量中,可以被后面相同的调用所覆盖。
对应可重入的版本如下(/usr/include/utmp.h):
#define _GNU_SOURCE /* or _SVID_SOURCE or _BSD_SOURCE */ #include <utmp.h> int getutent_r(struct utmp *ubuf, struct utmp **ubufp); int getutid_r(struct utmp *ut, struct utmp *ubuf, struct utmp **ubufp); int getutline_r(struct utmp *ut, struct utmp *ubuf, struct utmp **ubufp);