1、who命令的作用
通过在terminal调用who命令,我们可以看到现在登录在linux系统的用户。用户登录信息的数据结构定义在/usr/include/utmp.h。
wall pts/4 2019-03-07 09:09 (10.165.33.169)
shen pts/16 2019-03-05 10:04 (10.165.39.163)
li pts/25 2019-03-07 10:26 (10.165.21.93)
要完成who命令的功能实现,我们需要用到以下几个系统调用。
open:打开一个文件
read:读取文件中一定长度的数据
close:关闭文件
2、需要使用的系统调用
2.1 打开一个文件 open:
open系统调用在进程和文件之间建立一个连接,这个连接被称为文件描述符,它就像一个由进程通向内核的管道。
open | |
目标 | 打开一个文件 |
头文件 | #include<fcntl.h> |
函数原型 | int fd = open(char * name, int how) |
参数 | name 文件名 how 打开方式(O_RDONLY,O_WRONLY,O_RDWR) |
返回值 | -1 打开失败 int 成功返回 |
如果文件成功打开,内核会返回一个正整数的值,这个数值就是文件描述符。如果打开多个文件,它们对应的描述符是不同的。如果将一个文件打开多次,它们的文件描述符也是不同的。
2.2 从文件中读取数据 read:
read系统调用请求内核从fd所指定的文件中读取qty个字节的数据,并存放到buf所指向的内存空间中。如果读取成功返回所读取的字节数目,否则返回-1.
read | |
目标 | 将数据读取到缓冲区 |
头文件 | #include<unistd.h> |
函数原型 | ssize_t numread = read(int fd, void* buf, size_t qty) |
参数 | fd 文件描述符 buf 用来存放数据的缓冲区 qty 要读取的字节数 |
返回值 | -1 遇到错误 int 成功返回 |
2.3 关闭文件 close:
close系统调用会关闭进程和文件fd之间的连接,如果关闭的过程中发生错误,会返回-1。成功返回0.
close | |
目标 | 关闭一个文件 |
头文件 | #include<unistd.h> |
函数原型 | int result = close(int fd) |
参数 | fd 文件描述符 |
返回值 | -1 遇到错误 int 成功返回 |
3、程序编写
#include <stdio.h>
#include <unistd.h>
#include <utmp.h>
#include <fcntl.h>
#include <time.h>
void showtime(long);
void show_info(struct utmp*);
void who(){
struct utmp utbuf;
int utmpfd;
if((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1){ // UTMP_FILE记录了文件位置
perror(UTMP_FILE);
_exit(1);
}
while(read(utmpfd, &utbuf, sizeof(struct utmp)) == sizeof(struct utmp)){
show_info(&utbuf);
}
close(utmpfd);
}
void show_info(struct utmp* utbuf){
if(utbuf->ut_type != USER_PROCESS) // USER_PROCESS用来标示活跃用户
return;
printf("% -8.8s", utbuf->ut_name);
printf(" ");
printf("% -8.8s", utbuf->ut_line);
printf(" ");
showtime(utbuf->ut_time);
#ifdef SHOWHOST
if(utbuf->ut_host[0] != '\0')
printf("(%s)", ufbuf->ut_host);
#endif
printf("\n");
}
void showtime(long timeval){
char* cp;
cp = ctime(&timeval); // 对时间进行输出格式转换
printf("%12.12s", cp+4);
}
运行结果为:
wall pts/4 Mar 7 09:09
shen pts/16 Mar 5 10:04
li pts/25 Mar 7 10:26
UTMP_FILE是包含登录用户的信息的文件。但是UTMP_FILE中还包含许多非活跃的用户登录信息,utmp使用USER_PROCESS用于指明那些活跃的用户登录信息。t_time是1970年1月1日0时距离现在时刻的时间差,并不是我们想要的标准时间格式。使用time下的ctime函数,可以将其转化为标准时间。ctime的输出格式为Wed Jun 30 21:49:08 1992 \n 将指针加4跳过星期。
整个程序十分简单。我们打开UTMP_FILE文件,然后按照大小utmp结构体的大小依次读取每条登录用户的信息,直到读到文件末尾,将文件关闭。