1、序
可能是外面的炎熱姻僧,身上的汗臭规丽,逼仄的筆記本屏幕,這幾種糟糕的事物聚集在一起撇贺,導(dǎo)致現(xiàn)在一點寫作熱情都沒有赌莺。不過一會還要鍛煉,趁著剛寫完程序松嘶,我覺得還是稍微寫寫心得艘狭,也算是一個復(fù)習(xí)。希望對大家有所幫助。
本篇文章我想應(yīng)該是更加強調(diào)如何善用man——在線聯(lián)機文檔巢音,這個強大的工具遵倦。用好了這樣一個工具,我想對以后的工作官撼,肯定是有所裨益的梧躺。好了,閑話不多說傲绣,直接切入正題掠哥。
2、實現(xiàn)
這個程序我打算按照書上的安排秃诵,設(shè)計成兩個版本续搀,但是,如果兩個版本顷链,我覺得無論如何對大家學(xué)習(xí)知識都沒有任何好處——絕對增加了大家的負(fù)擔(dān)——本來一個簡單的問題還要分兩步走目代,事倍功半。
#include <stdio.h>
#include <unistd.h>
#include <utmp.h>
#include <fcntl.h>
#include <time.h>
void show_info(struct utmp * buffer);
void show_time(time_t *time);
int main(int argc, char **argv)
{
struct utmp buffer_utmp;
int buffer_len=sizeof(buffer_utmp);
int utmp_fd=open("/var/run/utmp", O_RDONLY);//打開用戶文件
while(read(utmp_fd,&buffer_utmp, buffer_len) == buffer_len)
{
show_info(&buffer_utmp);
}
return 0;
}
void show_info(struct utmp * buffer)
{
printf("%-10s ",buffer->ut_user);//打印用戶名
printf("%-10s ", buffer->ut_line);//打印登錄終端
//printf("%20d ",buffer->ut_tv.tv_sec);//打印時間
show_time(&(buffer->ut_tv.tv_sec));//按照字符串打印時間
int i;
for(i=0;i<3;i++)
printf("%d.",buffer->ut_addr_v6[i]);
printf("%d",buffer->ut_addr_v6[i]);
printf("\n");
}
void show_time(time_t *time)
{
printf("%-20s ",ctime(time));
}
3嗤练、分析
大家也看到了榛了,本身代碼并不復(fù)雜,還不到50行煞抬,但是霜大,從引用的頭文件中,也可以看出來革答,這個程序系統(tǒng)系統(tǒng)相關(guān)性很強战坤,涉及到很多的系統(tǒng)文件記憶數(shù)據(jù)結(jié)構(gòu)。所以残拐,這篇文章將用一部分篇幅來說說系統(tǒng)調(diào)用途茫。
1)我們首先用指令man who來看看who程序的具體說明,注意到在文檔中有提到/var/run/utmp溪食,這個文件其實就是存用戶登錄信息的文件囊卜。我們也能猜到,只有在開機的狀態(tài)下用戶才能夠登錄错沃,所以不可能把當(dāng)前登錄的用戶寫到磁盤中栅组,因此/var/run/utmp文件實際上是駐留在內(nèi)存中的一大坨數(shù)據(jù)。
說到數(shù)據(jù)枢析,這個文件就應(yīng)該有一定的結(jié)構(gòu)——我們輸入who命令的時候玉掸,也是逐條按順序顯示用戶登錄信息的。那么這個結(jié)構(gòu)的定義(存儲登錄用戶信息的數(shù)據(jù)結(jié)構(gòu))放在哪里呢醒叁?同樣司浪,還是在man who里面泊业,說到了utmp.h——這個文件中即存儲了一堆的struct結(jié)構(gòu)體,來定義存儲登錄用戶信息的類型断傲。
2)再man utmp一下脱吱,我們就進入了utmp.h的說明文檔(本人用的centos,我想這個和平臺沒太大相關(guān)性认罩。)如果英文還可以的同學(xué),我覺得看注釋就完全可以明白了续捂。當(dāng)然由于我用的事centos垦垂,所以“登錄時間”那一部分是一個內(nèi)嵌的結(jié)構(gòu)體。這點需要注意下牙瓢。
3)好劫拗,程序基本上就已經(jīng)成了。如我給大家的程序顯示那樣矾克。main函數(shù)中页慷,首先定義一個struct utmp類型的變量,然后從文件中胁附,一個一個地讀struct utmp類型的變量酒繁,并將變量中的內(nèi)容通過函數(shù)show_info顯示出來。
4)感覺差不多要完工了控妻。不過還有個事要注意州袒,就是打印時間的函數(shù)。由于utmp結(jié)構(gòu)體中存儲的時間是一個整數(shù)弓候,其表示相對于1970年1月1日0時的秒數(shù)郎哭,因此需要將其轉(zhuǎn)換成人類能讀懂的時間值,所以我們又用到了一個轉(zhuǎn)換函數(shù)——ctime菇存。繼續(xù)man ctime夸研。我們就能看到關(guān)于這個函數(shù)的具體說明。
但是還有一點需要注意依鸥,就是ctime()的參數(shù)類型亥至,由于系統(tǒng)相關(guān)性,所以Linux表示時間統(tǒng)一用到了time_t類型來表示時間毕籽,其實就是個int類型抬闯,但是為了讓生成可執(zhí)行文件的時候看著舒心點,不會彈出一大堆warning关筒,note來溶握,我覺得還是按照人家套路辦事會比較好些。
5)最后注意一點蒸播,對于utmp結(jié)構(gòu)體中有一個成員屬性ut_type睡榆,這個指的就是上面定義的一大堆#define萍肆,先看下常量名稱,我想大家就都明白了胀屿。此處需要說明的是塘揣,書中說/var/run/utmp文件中存了所有終端的信息,不管有沒有用戶用這些終端宿崭,都會顯示出來亲铡。不過目前我的這個utmp沒有產(chǎn)生這種狀況。只顯示了用戶登錄的終端信息葡兑。所以有的時候還是需要根據(jù)環(huán)境具體分析問題奖蔓。