Linux實踐——編寫who命令
Q1: who命令能做些什麽?
$ who xxx :0 yyyy-mm-dd hh:mm (:0) xxx pts/0 yyyy-mm-dd hh:mm (:0)
這是在CentOS7上的輸出結果,who的版本為8.22。每一行代表一個已經登陸的用戶,第一列是用戶名,第二列是終端名,第三列是登錄時間。
可以通過閱讀手冊詳細查看who命令。
$ man who
Q2: who命令是如何工作的?
首先我們先閱讀聯機幫助:
DESCRIPTION Print information about users who are currently logged in. If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is common. If ARG1 ARG2 given, -m presumed: ‘am i‘ or ‘mom likes‘ are usual.
通過描述得知已登錄用戶的信息一般會在/var/run/utmp或/var/log/wtmp中。
utmp文件中保存的是當前正在本系統中的用戶的信息。wtmp文件中保存的是登錄過本系統的用戶的信息。
現在關註utmp文件,who通過讀取該文件獲得信息。使用帶有-k命令可以根據關鍵字搜索聯機幫助:
$ man -k utmp
註意觀察描述,有一行包含可能有用的信息:
utmpx (5) - login records
接著使用man查看聯機幫助:
$ man 5 utmp
瀏覽手冊,發現該文件結構定義在頭文件<utmp.h>中,首先去/usr/include/目錄下尋找:
$ find /usr/include/utmp.h /usr/include/utmp.h
然後用more或者cat命令查看該文件:
$ more /usr/include/utmp.h
瀏覽發現該文件並不是聲明原始數據結構的頭文件:
/* Get system dependent values and data structures. */ #include <bits/utmp.h>
接著再到下一層目錄bits當中查看,這裏註意在C源文件中不能include<bits/utmp.h>,仍然是include<utmp.h>。
$ more /usr/include/bits/utmp.h
通過瀏覽代碼,獲取到結構體:
/* 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. */ #ifdef __WORDSIZE_TIME64_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. */ };
觀察當中的變量,可以獲取到who所使用的成員變量ut_type(who用來過濾空白而留下當前用戶)、ut_line(顯示設備名,即用戶的終端)、ut_user(用戶名)、ut_host(遠程登錄用戶名,(:0)顯示)、ut_time(時間)。
所以who命令其實是打開utmp文件,讀取記錄,顯示記錄,然後關閉utmp文件。
Q3: 如何編寫who?
根據以上分析得知who命令按照打開文件,讀取記錄,顯示記錄,關閉文件的流程工作。打開文件用open,讀取用read,顯示printf,關閉close。其中printf就不用介紹了。另外三個具體如下:
open 目標 打開一個文件 頭文件 #include <fcntl.h> 函數原型 int fd = open(char *name, int how) 參數 name 文件名 how O_RDONLY, O_WRONLY, O_RDWR 返回值 -1 遇到錯誤 int 成功返回
Linux實踐——編寫who命令