一、who命令
who命令用于查看当前系统中已经登陆过的用户信息
chanxiaoxi@ubuntu:~$ who
chanxiaoxi tty7 2013-06-01 09:38 (:0)
chanxiaoxi pts/1 2013-06-01 10:09 (:0)
chanxiaoxi pts/2 2013-06-01 10:12 (:0)
chanxiaoxi pts/3 2013-06-01 11:14 (:0)
chanxiaoxi pts/4 2013-06-01 11:22 (:0)
二、who命令的实现原理
通过查看联机手册可以知道,who命令的实现原理是,通过查找记录登陆信息的文件来获取系统中登陆过用户的信息。一般,系统将该文件存放在 /var/adm/utmp 或/var/run/utmp
这些可以通过查看手册可知
/* 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
chanxiaoxi@ubuntu:~$ more /usr/include/paths.h | grep _PATH_UTMP
#define _PATH_UTMP "/var/run/utmp"
但是utmp文件保存的是结构数组,数组元素是utmp类型的结构
struct utmp {
short ut_type; /* Type of record */
pid_t ut_pid; /* PID of login process */
char ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */
char ut_id[4]; /* Terminal name suffix,
or inittab(5) ID */
char ut_user[UT_NAMESIZE]; /* Username */
char ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or
kernel version for run-level
messages */
struct exit_status ut_exit; /* Exit status of a process
marked as DEAD_PROCESS; not
used by Linux init(8) */
/* 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 (getsid(2)),
used for windowing */
struct {
int32_t tv_sec; /* Seconds */
int32_t tv_usec; /* Microseconds */
} ut_tv; /* Time entry was made */
#else
long ut_session; /* Session ID */
struct timeval ut_tv; /* Time entry was made */
#endif
int32_t ut_addr_v6[4]; /* Internet address of remote
host; IPv4 address uses
just ut_addr_v6[0] */
char __unused[20]; /* Reserved for future use */
};
三、自己编写一个who命令
1、open、read、close
根据who命令的原理,我们的程序要能够打开存放登录记录的文件,然后还要能从中读取信息,最后关闭它并获得这些信息。
open
Given a pathname for a file, open() returns a file descriptor, a small,
nonnegative integer for use in subsequent system calls (read(2),
write(2), lseek(2), fcntl(2), etc.). The file descriptor returned by a
successful call will be the lowest-numbered file descriptor not cur‐
rently open for the process.
int fd=open(char * filename,int how)
这个系统调用会在进程和文件之间建立一条链接,该链接用descriptor来标志。如果打开成功,会返回一个nonnegative integer(descriptor),如果打开失败,会返回-1
打开文件时必须指定文件名和打开方式,打开方式有三种:O_RDONLY、O_WRONLY、O_RDWR
read
read() attempts to read up to count bytes from file descriptor fd into
the buffer starting at buf.
If count is zero, read() returns zero and has no other results. If
count is greater than SSIZE_MAX, the result is unspecified.
ssize_t numread=read(int fd,void * buf,size_t qty)
请求用户从fd所指定的文件中读取qty字节的数据并存放在buf中,读取成功则返回读取的字数,否则返回-1
close
close() closes a file descriptor, so that it no longer refers to any
file and may be reused. Any record locks (see fcntl(2)) held on the
file it was associated with, and owned by the process, are removed
(regardless of the file descriptor that was used to obtain the lock).
int result=close(int fd)
若错误,返回-1
2、代码实现
/* who1.c - a first version of the who program
* open,read UTMP file,and show results
*/
#include<stdio.h>
#include<stdlib.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#define SHOWHOST
int main(){
struct utmp current_record;
int utmpfd; /*read from this descriptor*/
int reclen=sizeof(current_record);
if((utmpfd=open(UTMP_FILE,O_RDONLY))==-1){ /*if failed return -1 */
perror(UTMP_FILE); /*print out error message */
exit(1);
}
while(read(utmpfd,¤t_record,reclen)==reclen) {
show_info(¤t_record);
}
close(utmpfd);
return 0;
}
/*
*show_info()
*displays contents of the utmp struct in human readable form
*note these sizes should not be hardwired
*/
show_info(struct utmp *utbufp){
printf("% -8.8s",utbufp->ut_name);
printf(" ");
printf("% -8.8s",utbufp->ut_line);
printf(" ");
printf("% 10ld",utbufp->ut_time);
printf(" ");
#ifdef SHOWHOST
printf("(%s)",utbufp->ut_host);
#endif
printf("\n");
}