/var/run/utmp -- database of currently logged-in users
/var/log/wtmp -- database of past user logins
utmp文件中保存的是当前正在本系统中的用户的信息。
wtmp文件中保存的是登录过本系统的用户的信息。
他们保存的信息是基于下面的结构体
struct utmp的(/usr/include/bits/utmp.h):
- /* 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. */
- };
/*
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
而读取和修改这些文件的函数如下:
utmpname()函数设定utmp文件所在的路径,默认的路径为宏 _PATH_UTMP,该宏定义在/usr/include/paths.h中:
- #include <utmp.h>
- struct utmp *getutent(void);
- struct utmp *getutid(struct utmp *ut);
- struct utmp *getutline(struct utmp *ut);
- struct utmp *pututline(struct utmp *ut);
- void setutent(void);
- void endutent(void);
- int utmpname(const char *file);
- #define _PATH_UTMP "/var/run/utmp"
setutent()函数打开文件utmp,并且将文件指针指向文件的最开始。
getutent()函数从文件utmp中,每次读取一个struct utmp的结构体。读取失败返回NULL。
endutent()函数关闭文件utmp。
pututline()函数将一个struct utmp结构体写进文件utmp中。
下面根据这些知识写一个模仿Linux下的who命令的小程序。
- #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;
- }
运行结果:
digdeep@ubuntu:~/uulp$ ./who2
digdeep
tty7
Sep 15 15:24:54 2011
(:0)
digdeep
pts/0
Sep 15 15:25:14 2011
(:0.0)
digdeep
pts/1
Sep 15 16:06:24 2011
(:0.0)
digdeep
pts/2
Sep 15 16:07:21 2011
(:0.0)
digdeep
pts/3
Sep 15 16:10:41 2011
(:0.0)
在上面的程序中增加一条语句,就可以读取曾经登录过本系统的用户信息:
- #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;
- }
上面红色的语句就是新增的。
运行结果如下:
digdeep
tty7
Sep 3 13:58:24 2011
(:0)
digdeep
pts/0
Sep 3 13:58:30 2011
(:0.0)
digdeep
tty7
Sep 3 22:00:31 2011
(:0)
digdeep
pts/0
Sep 3 22:00:41 2011
(:0.0)
digdeep
pts/1
Sep 3 22:13:42 2011
(:0.0)
digdeep
tty7
Sep 4 15:19:10 2011
(:0)
digdeep
pts/0
Sep 4 15:19:28 2011
(:0.0)
digdeep
pts/1
Sep 4 15:19:51 2011
(:0.0)
digdeep
tty7
Sep 5 10:31:59 2011
(:0)
digdeep
pts/0
Sep 5 10:32:05 2011
(:0.0)
digdeep
pts/1
Sep 5 14:47:23 2011
(:0.0)
digdeep
pts/2
Sep 5 16:47:00 2011
(:0.0)
... ...
在上面哪些函数是非线程安全的,不可重入的,因为它们
将返回结果保存在一个static变量中,可以被后面相同的调用所覆盖。
对应可重入的版本如下:
- #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);
Linux中utmp结构定义如下:
structutmp
{
short int ut_type; // 登录类型
pid_t ut_pid; // login进程的pid
char ut_line[UT_LINE_SIZE]; // 登录装置名,省略了"/dev/"
char ut_id[4]; // Inittab ID
char ut_user[UT_NAMESIZE]; // 登录账号
char ut_host[UT_HOSTSIZE]; // 登录账号的远程主机名称
struct exit_status ut_exit; // 当类型为DEAD_PROCESS时进程的结束状态
long int ut_session; // SessionID
struct timeval ut_tv; // 时间记录
int32_t ut_addr_v6[4]; // 远程主机的网络地址
char __unused[20]; // 保留未使用
};
ut_type有以下几种类型:
EMPTY
|
此为空的记录
|
RUN_LVL
|
记录系统run-level的改变
|
BOOT_TIME
|
记录系统开机时间
|
NEW_TIME
|
记录系统时间改变后的时间
|
OLD_TIME
|
记录当改变系统时间时的时间
|
INIT_PROCESS
|
记录一个由init衍生出来的进程
|
LOGIN_PROCESS
|
记录login进程
|
USER_PROCESS
|
记录一般进程
|
DEAD_PROSESS
|
记录一结束的进程
|
ACCOUNTING
|
目前尚未被使用
|
exit_status结构定义:
structexit_status
{
short int e_termination; //进程结束状态
short int e_exit; //进程退出状态
};