who命令
獲取正在登錄系統的用戶
使用Linux的who命令
第一個參數book代表用戶名,第二個參數tty7代表終端名,第三個參數代表時間,第四個參數代表用戶的登錄地址。
閱讀手冊
使用命令讀手冊
$ man who
可以知道who這個命令從 /var/run/utmp 和 /var/log/wtmp 兩個文件中獲取數據,
再通過命令,查找關於 “utmp” 的信息
$ man -k utmp
-k的意思是根據關鍵字查找
$man 5 utmp
我們查詢到一些關於utmp結構體中的元素,比如ut_user用戶名字、ut_line用戶設備、ut_time登錄時間等。
who命令的工作流程
打開utmp
+----> 讀取記錄 ------ +
| |
+-------顯示記錄 |
關閉utmp <------ +
who命令的編寫---版本1
1 #include <stdio.h> 2 #include <utmp.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <time.h> 6 7 void show_info(struct utmp *utbufp); 8 int main() 9 { 10 struct utmp current_record; 11 int utmp_fd; 12 int reclen = sizeof(current_record); 13 14 utmp_fd = open(UTMP_FILE,O_RDONLY); 15 if(utmp_fd == -1) 16 return -1; 17 18 while( read(utmp_fd, ¤t_record,reclen) == reclen ) 19 show_info(¤t_record); 20 21 close(utmp_fd); 22 return 0; 23 } 24 25 void show_info(struct utmp *utbufp) 26 { 27 28 printf("%-8.8s",utbufp->ut_name); 29 printf(" "); 30 printf("%-8.8s",utbufp->ut_line); 31 printf(" "); 32 printf("%101d",utbufp->ut_time); 33 printf(" "); 34 printf("(%s)",utbufp->ut_host); 35 printf(" "); 36 printf("\n"); 37 }
輸出結果:
問題:
1. 有部分數據不是真實用戶的。
2. 時間顯示不對。
解決方法:
1.第一個問題
繼續使用命令
$ man 5 utmp
看到 ut_type中 USER_PROCESS表示的是已經登錄的用戶 ,那么第一個問題就解決了。
2.第二個問題
使用命令
$ man -k time | grep transform
看到ctime,使用命令查看ctime的使用方法
$ man 3 ctime
使用這個函數將 timeval轉換成一個字符串並返回一個指針,那么第二個問題也解決了。
who命令的編寫---版本2
1 #include <stdio.h> 2 #include <utmp.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <time.h> 6 7 void show_info(struct utmp *utbufp); 8 void show_time(long timeval); 9 int main() 10 { 11 struct utmp current_record; 12 int utmp_fd; 13 int reclen = sizeof(current_record); 14 15 utmp_fd = open(UTMP_FILE,O_RDONLY); 16 if(utmp_fd == -1) 17 return -1; 18 19 while( read(utmp_fd, ¤t_record,reclen) == reclen ) 20 show_info(¤t_record); 21 22 close(utmp_fd); 23 return 0; 24 } 25 26 void show_info(struct utmp *utbufp) 27 { 28 if(utbufp->ut_type != USER_PROCESS) 29 return; 30 31 printf("%-8.8s",utbufp->ut_name); 32 printf(" "); 33 printf("%-8.8s",utbufp->ut_line); 34 printf(" "); 35 show_time(utbufp->ut_time); 36 printf(" "); 37 printf("(%s)",utbufp->ut_host); 38 printf("\n"); 39 } 40 41 void show_time(long timeval) 42 { 43 char *cp; 44 45 cp = ctime(&timeval); 46 47 printf("%12.12s",cp+4); 48 49 }
輸出結果:
這樣一個簡單的who命令就完成了。
------------------------------於2019/5/5更新---------------------
改良who命令
在Linux---cp命令中,介紹了有關緩沖區和系統開銷的知識,因此,我們可以改良自己編寫的who命令。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <utmp.h> #define NRECS 16 #define NULLUT ((struct utmp*)NULL) #define UTSIZE (sizeof(struct utmp)) static char utmpbuf[NRECS * UTSIZE]; static int num_recs; static int cur_rec; static int fd_utmp = -1; struct utmp* utmp_next(); int utmp_reload(); int utmp_open(char *filename); void utmp_close(); int utmp_open(char *filename) { fd_utmp = open(filename , O_RDONLY); cur_rec = 0; num_recs = 0; return fd_utmp; } struct utmp* utmp_next() { struct utmp* recp; if(fd_utmp == -1) { return NULLUT; } if(cur_rec == num_recs && utmp_reload() == 0) { return NULLUT; } recp = (struct utmp*) &utmpbuf[cur_rec * UTSIZE]; cur_rec++; return recp; } int utmp_reload() { int aimt_read; aimt_read = read(fd_utmp, utmpbuf, NRECS * UTSIZE); num_recs = aimt_read / UTSIZE; cur_rec = 0; return num_recs; } void utmp_close() { if(fd_utmp != -1) close(fd_utmp); }
編寫一個增大緩沖區的庫,調用的次數減少到原來的1/16。這樣程序能夠在更短的時間內完成。
1 #include <stdio.h> 2 #include <utmp.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <time.h> 6 #include <sys/types.h> 7 #include <stdlib.h> 8 9 void show_info(struct utmp *utbufp); 10 void show_time(long timeval); 11 12 #define SHOWHOST 13 14 int main() 15 { 16 struct utmp* utbufp , *utmp_next(); 17 if( utmp_open(UTMP_FILE) == -1) 18 { 19 perror(UTMP_FILE); 20 exit(1); 21 } 22 23 while( (utbufp = utmp_next()) != ((struct utmp *)NULL)) 24 show_info(utbufp); 25 26 utmp_close(); 27 return 0; 28 } 29 30 void show_info(struct utmp *utbufp) 31 { 32 if(utbufp->ut_type != USER_PROCESS) 33 return; 34 35 printf("%-8.8s",utbufp->ut_name); 36 printf(" "); 37 printf("%-8.8s",utbufp->ut_line); 38 printf(" "); 39 show_time(utbufp->ut_time); 40 printf(" "); 41 printf("(%s)",utbufp->ut_host); 42 printf("\n"); 43 } 44 45 void show_time(long timeval) 46 { 47 char *cp; 48 49 cp = ctime(&timeval); 50 51 printf("%12.12s",cp+4); 52 53 }
本篇筆記自拜讀《 Unix/Linux編程實踐教程》
我也推薦和我一樣的初學者去拜讀這本書,讓你對linux有可下手的地方。