who命令的編寫
阿新 • • 發佈:2019-01-06
一.who的功能:
檢視當前哪些使用者正在使用系統
二.who的工作流程:
從 /var/run/utmp 檔案中讀取已登入使用者的資訊,然後輸出
(注意:我的操作環境是ubuntu11.10 ,有些地方與其他系統不同)
如在我的ubuntu11.10中utmp.h在 /usr/include 和 /usr/include/i386-linux-gnu/bits 中
三.內容詳解
/usr/include中的/utmp.h有:
#include <bits/utmp.h> /* Compatibility names for the strings of the canonical file names. */ #define UTMP_FILE _PATH_UTMP
在path.h中有:
#define _PATH_UTMP "/var/run/utmp"
則 UTMP_FILE 就是檔案路徑/var/run/utmp
/usr/include/i386-linux-gnu/bits/utmp.h中包含資訊:
#ifndef _UTMP_H # error "Never include <bits/utmp.h> directly; use <utmp.h> instead." #endif #include <paths.h> #include <sys/time.h> #include <sys/types.h> #include <bits/wordsize.h> #define UT_LINESIZE 32 #define UT_NAMESIZE 32 #define UT_HOSTSIZE 256 /* The structure describing an entry in the database of previous logins. */ struct lastlog { #if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32 int32_t ll_time; #else __time_t ll_time; #endif char ll_line[UT_LINESIZE]; char ll_host[UT_HOSTSIZE]; }; /* 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. */ }; /* Backwards compatibility hacks. */ #define ut_name ut_user #ifndef _NO_UT_TIME /* We have a problem here: `ut_time' is also used otherwise. Define _NO_UT_TIME if the compiler complains. */ # define ut_time ut_tv.tv_sec #endif #define ut_xtime ut_tv.tv_sec #define ut_addr ut_addr_v6[0] /* 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 /* Old Linux name for the EMPTY type. */ #define UT_UNKNOWN EMPTY /* Tell the user that we have a modern system with UT_HOST, UT_PID, UT_TYPE, UT_ID and UT_TV fields. */ #define _HAVE_UT_TYPE 1 #define _HAVE_UT_PID 1 #define _HAVE_UT_ID 1 #define _HAVE_UT_TV 1 #define _HAVE_UT_HOST 1
struct utmp結構儲存登入資訊
四.自己寫的who命令的程式碼(版本一):
#include<stdio.h> #include<utmp.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<time.h> #define SHOWHOST void showtime(long); void show_info(struct utmp *utbufp); int main() { struct utmp utbuf; // read info into here int utmpfd; // read from this descriptor if( (utmpfd = open(UTMP_FILE,O_RDONLY)) == -1) { perror(UTMP_FILE); //UTMP_FILE is in utmp.h exit(1); } while( read( utmpfd,&utbuf,sizeof(utbuf)) ==sizeof(utbuf)) show_info(&utbuf); close(utmpfd); return 0; } void show_info(struct utmp *utbufp) { if(utbufp->ut_type != USER_PROCESS) //ut_type==USER_PROCESS時,表示已經登入的使用者 return ; printf("%-8.8s",utbufp->ut_user); printf(" "); printf("%-8.8s",utbufp->ut_line); printf(" "); showtime( utbufp->ut_time); // printf("%12.12s",ctime(&(utbufp->ut_tv).tv_sec)+4); printf(" "); #ifdef SHOWHOST if(utbufp->ut_host[0] != '\0') printf("(%s)",utbufp->ut_host); #endif printf("\n"); } void showtime(long timeval) { char *cp; cp = ctime(&timeval); printf("%12.12s",cp + 4); }
五.運用緩衝技術的who命令程式碼(版本二):
在版本一中,每次只能讀取一個數據,因此需要不停的讀取,所以導致效率低下。可以加入緩衝機制提高程式的執行效率。緩衝技術的主要思想是一次讀入大量的資料放入緩衝區,需要的時候從緩衝區取得資料。
程式使用一個 utmplib.c檔案實現緩衝演算法,在main函式中只要呼叫 utmplib.c中相應函式即可。在 utmplib.c中用一個能容納16個utmp結構的陣列作為緩衝區。utmp_next 函式來從緩衝區取得下一個utmp結構的資料。
修改原來的main 函式,通過呼叫utmp_next 來取得資料,當緩衝區的資料都被取出後,utmp_next會呼叫read,通過核心再次獲得16條記錄充滿緩衝區,用這種方法可以是read的呼叫次數減少到原來的 1/16 。
utmplib.c 程式碼如下:
#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<sys/types.h>
#define NRECS 16
#define NULLUT ((struct utmp *) NULL )
#define UTSIZE (sizeof(struct utmp))
static char utmpbuf[NRECS * UTSIZE]; //一次可以儲存16個utmp結構的陣列
static int num_recs; //緩衝區中的資料個數
static int cur_rec ; //緩衝區中已使用的資料個數
static int fd_utmp = -1;
int utmp_open(char * filename)
{
fd_utmp = open(filename,O_RDONLY);
cur_rec = num_recs = 0;
return fd_utmp;
}
/*
* utmp_reload返回值是緩衝區的資料個數
*/
int utmp_reload()
{
int amt_read;
amt_read = read(fd_utmp,utmpbuf,NRECS * UTSIZE);
num_recs = amt_read/UTSIZE ;
cur_rec = 0;
return num_recs ;
}
/*
* utmp_next 返回指向結構的指標
*/
struct utmp *utmp_next()
{
struct utmp *recp;
if( fd_utmp == -1)
return NULLUT;
if( cur_rec == num_recs && utmp_reload() == 0)
return NULLUT;
// recp指向下一個資料
recp = (struct utmp *)&utmpbuf[cur_rec * UTSIZE];
cur_rec++;
return recp;
}
void utmp_close()
{
if(fd_utmp != -1)
close(fd_utmp);
}
who.c中只更改main函式,其餘不變,main函式程式碼如下:
int main()
{
struct utmp *utbufp,
*utmp_next();
if( (utmp_open(UTMP_FILE)) == -1)
{
perror(UTMP_FILE); //UTMP_FILE is in utmp.h
exit(1);
}
while(( utbufp = utmp_next()) != ((struct utmp *) NULL))
show_info(utbufp);
utmp_close();
return 0;
}