深入理解linux下的last命令及其数据源



深入了解linux下的last命令及其数据源

last
数据源
: /var/log/wtmp(默认 记录每个用户的登录次数和持续时间等信息)和/var/log/btmp(详细,包括登录失败请求)
数据源格式:二进制(可以通过dump-utmp 命令进行阅读)
last [-adRx][-f ][-n ][帐号名称...][终端机编号...]

linux下的last命令及其数据源_第1张图片

                                              图1 last 命令格式
参数说明:
  -a  把从何处登入系统的主机名称或IP地址,显示在最后一行。
  -d  将IP地址转换成主机名称。
  -f <记录文件>  指定记录文件,默认是显示/var/log目录下的wtmp文件的记录,但/var/log目录下得btmp能显示的内容更丰富,可以显示远程登录,例如ssh登录 ,包括失败的登录请求。
  -n <显示列数>或-<显示列数>  设置列出名单的显示列数。
  -R  不显示登入系统的主机名称或IP地址。
  -x  显示系统关机,重新开机,以及执行等级的改变等信息。
       -i 显示特定ip登录的情况

      -t  显示YYYYMMDDHHMMSS之前的信息

实例1

last

linux下的last命令及其数据源_第2张图片

                                                                                       图2 last
正常命令重启显示为down,而电源强制重启为crash

   字段介绍:

           第一列:用户名

           第二列:终端位置

           第三列:登录ip或者内核

           第四列:开始时间

           第五列:结束时间(still login in 还未退出  down 直到正常关机 crash 直到强制关机)

           第六列:持续时间

实例2

last -x

linux下的last命令及其数据源_第3张图片

                                                图3 last -x

实例3

 last  -n

linux下的last命令及其数据源_第4张图片

                                                      图4 last -x -n

实例4

last -f /var/log/btmp | head -100

linux下的last命令及其数据源_第5张图片

                                             图5 last -f /var/log/btmp | head -100

实例5

 last -t  20130819090800

显示2013-08-19 09:09:00之前的登录信息

linux下的last命令及其数据源_第6张图片

                                       图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  directly; use  instead."
#endif

#include 
#include 
#include 
#include 


#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 

#include 


__BEGIN_DECLS

/* Get system dependent values and data structures.  */
#include 

/* 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 

#include 

#include 

#include 



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

运行

./mywho

                              图7 mywho运行结果

 

在上面的程序中增加下面一条语句,就可以读取曾经登录过本系统的用户信息

utmpname(_PATH_WTMP); /* #define _PATH_WTMP "/var/log/wtmp" */

#include 

#include 

#include 

#include 



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

运行

./mywho
linux下的last命令及其数据源_第7张图片

                                          图8 mywho运行结果(所以用户登录信息)

在上面那些函数是非线程安全的,不可重入的,因为它们将返回结果保存在一个static变量中,可以被后面相同的调用所覆盖。
对应可重入的版本如下(/usr/include/utmp.h):

#define _GNU_SOURCE /* or _SVID_SOURCE or _BSD_SOURCE */

#include 



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);




原文“http://www.myexception.cn/linux-unix/1407251.html