信息安全系统设计基础第九周学习总结
第十章 系統(tǒng)級(jí)I/O的實(shí)踐
學(xué)習(xí)目標(biāo):
代碼閱讀理解:
1.編譯運(yùn)行代碼
2.使用man學(xué)習(xí)理解相關(guān)系統(tǒng)調(diào)用, 理解參數(shù)、返回值的含義
3.會(huì)用grep -nr xxx /usr/include 查宏定義
who1.c
who2.c
cp1.c
echostate.c
fileinfo.c
filesize.c
ls1.c
ls2.c
setecho.c
spwd.c
testioctl.c
一、自己編寫(xiě)的who
1.正版who應(yīng)該是:
- 我們可以看到,who命令是查詢(xún)當(dāng)前登錄的每個(gè)用戶,輸出包括用戶名、終端類(lèi)型、登錄日期及遠(yuǎn)程主機(jī)。
- man一下who,可以看到,who命令是讀取/var/run/utmp文件來(lái)得到以上信息的。
- man一下utmp,知道utmp這個(gè)文件,是二進(jìn)制文件,里面保存的是結(jié)構(gòu)體數(shù)組,這些數(shù)組是struct utmp結(jié)構(gòu)體的。
2.自己嘗試編寫(xiě)
(1)偽代碼
- 打開(kāi)記錄所在文件:utmp - 將文件中的記錄逐條讀取 - 每一條讀取的記錄都要在屏幕上打印 - 關(guān)閉文件(2)問(wèn)題1:
- 剛開(kāi)始的時(shí)候覺(jué)得是警告就沒(méi)有在意,因?yàn)橹斑\(yùn)行代碼的時(shí)候也有警告,但是最后可以運(yùn)行出來(lái)。
- 但是:
問(wèn)題1解決:
- 在record.ut_time輸出時(shí)我使用的類(lèi)型是字符數(shù)組%s,但是實(shí)際上:
- 它在utmp中定義的是ut_tv.tv_sec,而ut_sec是int32_t型的。所以我換用了%ld輸出。
成功版1
(3)問(wèn)題2:
- 這個(gè)與正版的who運(yùn)行看起來(lái)差別還是挺大的
- 第一,沒(méi)有對(duì)齊
- 第二,時(shí)間顯示看不懂
- 第三,記錄比正版who多
問(wèn)題2解決
解決對(duì)齊問(wèn)題:
- 對(duì)齊的問(wèn)題很好解決。我使用的是\t制表符來(lái)排的,但是由于user的長(zhǎng)度不一,導(dǎo)致錯(cuò)位,可以換成固定長(zhǎng)度,不足補(bǔ)0的方法顯示。
解決時(shí)間顯示問(wèn)題:
- 使用man查找與time格式化相關(guān)(這一部分改了好久,最后還是去網(wǎng)上搜索的編寫(xiě)who的相關(guān)內(nèi)容、time的相關(guān)內(nèi)容才得以解決)
- 判斷應(yīng)該是strftime,進(jìn)入查看用法,繼續(xù)修改try_who代碼
- 這個(gè)警告應(yīng)該是64位機(jī)的問(wèn)題,運(yùn)行之后和第一次的問(wèn)題一樣顯示核心已轉(zhuǎn)儲(chǔ),但是我到現(xiàn)在都不知道怎么在原句上解決。
- 百度了一下想仔細(xì)看一下這個(gè)localtime的問(wèn)題,找到一篇特別詳細(xì)的文章:c++ 時(shí)間類(lèi)型詳解(time_t和tm),我決定分開(kāi)每一步的變量試一試,直接在定義的時(shí)候就限制住每一個(gè)變量,至少能知道到底是哪一個(gè)錯(cuò)了,結(jié)果沒(méi)有警告,編譯運(yùn)行成功:
解決顯示記錄多的問(wèn)題:
- 問(wèn)題原因:utmp中保存的用戶,不僅僅是已經(jīng)登陸的用戶,還有系統(tǒng)的其他服務(wù)所需要的,所以在顯出所有登陸用戶的時(shí)候,應(yīng)該過(guò)濾掉其他用戶,只保留登陸用戶。在utmp結(jié)構(gòu)中的ut_type可以區(qū)別,登陸用戶的ut_type是USER_PROCESS,加一個(gè)判斷就可以了:
- 終于和正版who至少看起來(lái)一樣了!!!
(4)改進(jìn)
- 在打開(kāi)和關(guān)閉文件的時(shí)候加上失敗情況處理。
3.我的代碼
#include <stdio.h> #include <stdlib.h> #include <unistd.h> //read #include <sys/types.h> //open #include <sys/stat.h> #include <fcntl.h> #include <utmp.h> //utmp #include <time.h> //strftimeint main() {struct utmp record;int fd;int len = sizeof(record);struct tm *p;time_t t;char fortime[40];if ( (fd = open(UTMP_FILE, O_RDONLY)) == -1 ){perror( UTMP_FILE ); exit(1);}while(read(fd,&record,len)){if(record.ut_type == USER_PROCESS)//只顯示類(lèi)型為USER_PROCESS的一般進(jìn)程{printf("%-10.10s",record.ut_user);printf("%-10.10s",record.ut_line);//以下為對(duì)時(shí)間的轉(zhuǎn)換操作t = record.ut_time; p = localtime(&t);strftime(fortime,40,"%F %R",p);printf("%12s",fortime);if(record.ut_host[0]!='\0');printf("\t(%s)",record.ut_host);printf("\n");}}if (close(fd) == -1){perror( UTMP_FILE ); exit(1);}return 0; }4.who——老師的代碼
*其實(shí)看別人寫(xiě)的代碼比自己寫(xiě)更糾結(jié)...
#include <stdio.h> #include <stdlib.h> #include <utmp.h> #include <fcntl.h> #include <unistd.h>#define SHOWHOST int show_info( struct utmp *utbufp ) {printf("%-8.8s", utbufp->ut_name); printf(" "); printf("%-8.8s", utbufp->ut_line); printf(" "); printf("%10ld", utbufp->ut_time); printf(" "); #ifdef SHOWHOST //?這個(gè)是為了測(cè)試代碼時(shí)用的嗎?printf("(%s)", utbufp->ut_host); #endifprintf("\n"); return 0; } int main() {struct utmp current_record; int utmpfd; int reclen = sizeof(current_record);/*打開(kāi)UTMP_FILE讀取信息,如果打開(kāi)失敗則輸出失敗信息。*/if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){perror( UTMP_FILE ); exit(1);}/*讀取信息到存儲(chǔ)器中,reclen就是是讀的字節(jié)數(shù),然后再調(diào)用函數(shù)打印出來(lái)。*/while ( read(utmpfd, ¤t_record, reclen) == reclen )show_info(¤t_record);close(utmpfd);return 0; }- 這個(gè)代碼沒(méi)有做記錄的判斷,也沒(méi)有做時(shí)間的轉(zhuǎn)換
- 老師兩個(gè)who代碼是一樣的?
2.ls
3.filesize
(1)代碼
#include <stdio.h> #include <sys/stat.h>int main() {struct stat infobuf; if ( stat( "/etc/passwd", &infobuf) == -1 )perror("/etc/passwd");elseprintf(" The size of /etc/passwd is %d\n", infobuf.st_size ); }(2)功能
- 用st_size計(jì)算文件的字節(jié)數(shù)大小。
4.fileinfo
(1)代碼
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h>void show_stat_info(char *, struct stat *);int main(int argc, char *argv[]) {struct stat info; if (argc>1){if( stat(argv[1], &info) != -1 ){show_stat_info( argv[1], &info );return 0;}elseperror(argv[1]); }return 1; } void show_stat_info(char *fname, struct stat *buf) {printf(" mode: %o\n", buf->st_mode); printf(" links: %d\n", buf->st_nlink); printf(" user: %d\n", buf->st_uid); printf(" group: %d\n", buf->st_gid); printf(" size: %d\n", (int)buf->st_size); printf("modtime: %d\n", (int)buf->st_mtime); printf(" name: %s\n", fname ); }(2)功能
#include <stdio.h> #include <sys/types.h> #include <dirent.h>void do_ls(char []);int main(int argc, char *argv[]) {/*如果操作數(shù)只有1個(gè),表明ls后面沒(méi)有帶參數(shù),默認(rèn)為當(dāng)前目錄,.表示當(dāng)前目錄。*/if ( argc == 1 )do_ls( "." );/*如果ls后面有參數(shù),就把參數(shù)讀入argv中。*/elsewhile ( --argc ){printf("%s:\n", *++argv );do_ls( *argv );}return 0; }/*因?yàn)閘s和dir功能相近,用dir來(lái)實(shí)現(xiàn)ls*/ void do_ls( char dirname[] ) {DIR *dir_ptr;struct dirent *direntp;/*如果沒(méi)有指向的那個(gè)地址,報(bào)錯(cuò)*/if ( ( dir_ptr = opendir( dirname ) ) == NULL )fprintf(stderr,"ls1: cannot open %s\n", dirname);else{/*遞歸的方式來(lái)讀取*/while ( ( direntp = readdir( dir_ptr ) ) != NULL )printf("%s\n", direntp->d_name );closedir(dir_ptr);} }- 這個(gè)功能用來(lái)實(shí)現(xiàn)顯示文件信息
5.setecho與echostate
(1)代碼
setecho:
#include <stdio.h> #include <stdlib.h> #include <termios.h>#define oops(s,x) { perror(s); exit(x); }int main(int argc, char *argv[]) {struct termios info;if (argc == 1) //后面沒(méi)有帶參數(shù)的話就不做任何操作,退出exit(0);if (tcgetattr(0,&info)==-1)//tcgetattr函數(shù)用于獲取與終端相關(guān)的參數(shù)。參數(shù)fd為終端的文件描述符,返回的結(jié)果保存在termios 結(jié)構(gòu)體中,這里fd為0,是標(biāo)準(zhǔn)輸入。這句用于讀取設(shè)備屬性oops("tcgettattr", 1);if ( argv[1][0] == 'y' )//如果運(yùn)行命令后面的參數(shù)第一個(gè)字母是“y”,執(zhí)行“設(shè)置打開(kāi)提示符”的命令info.c_lflag |= ECHO ;/*打開(kāi)提示符*/else//對(duì)其它所有的參數(shù)都執(zhí)行“設(shè)置隱藏提示符”的命令info.c_lflag &= ~ECHO ;/*隱藏提示符*/if ( tcsetattr(0,TCSANOW,&info) == -1 )//將修改后的參數(shù)寫(xiě)回設(shè)備oops("tcsetattr",2);return 0; }echostate:
#include <stdio.h> #include <stdlib.h> #include <termios.h>int main() {struct termios info;int rv;rv = tcgetattr( 0, &info ); /* read values from driver */if ( rv == -1 ){perror( "tcgetattr");exit(1);}if ( info.c_lflag & ECHO )printf(" echo is on , since its bit is 1\n");elseprintf(" echo is OFF, since its bit is 0\n");return 0; }(2)功能
setecho用來(lái)改變輸入指令是否可見(jiàn)。
輸入y(或是以y開(kāi)頭的一串字符),命令可見(jiàn)否則(即輸入不以y開(kāi)頭的字符),命令不可見(jiàn)echostate顯示輸入命令是否可見(jiàn)。
echo is on:命令可見(jiàn)echo is off:命令不可見(jiàn)
6.spwd
(1)代碼
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h>ino_t get_inode(char *); void printpathto(ino_t); void inum_to_name(ino_t , char *, int );int main() {printpathto( get_inode( "." ) ); putchar('\n'); return 0; }void printpathto( ino_t this_inode ) {ino_t my_inode ;char its_name[BUFSIZ];if ( get_inode("..") != this_inode ){chdir( ".." ); inum_to_name(this_inode,its_name,BUFSIZ);my_inode = get_inode( "." ); printpathto( my_inode ); printf("/%s", its_name ); } }void inum_to_name(ino_t inode_to_find , char *namebuf, int buflen) {DIR *dir_ptr; struct dirent *direntp; dir_ptr = opendir( "." );if ( dir_ptr == NULL ){perror( "." );exit(1);}while ( ( direntp = readdir( dir_ptr ) ) != NULL )if ( direntp->d_ino == inode_to_find ){strncpy( namebuf, direntp->d_name, buflen);namebuf[buflen-1] = '\0'; closedir( dir_ptr );return;}fprintf(stderr, "error looking for inum %d\n", (int) inode_to_find);exit(1); }ino_t get_inode( char *fname ) {struct stat info;if ( stat( fname , &info ) == -1 ){fprintf(stderr, "Cannot stat ");perror(fname);exit(1);}return info.st_ino; }(2)功能
- 列出當(dāng)前目錄
7.testioctl
(1)代碼
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h>int main() {struct winsize size;if( isatty(STDOUT_FILENO) == 0)exit(1);if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) {perror("ioctl TIOCGWINSZ error");exit(1);}printf("%d rows %d columns\n", size.ws_row, size.ws_col);return 0; }(2)功能
- 獲得終端設(shè)備的窗口大小
- 下圖一個(gè)是我的終端全屏的,一個(gè)是還原之后的。
8.cp
(1)代碼
#include <stdio.h>//標(biāo)準(zhǔn)輸入輸出 #include <stdlib.h>//C標(biāo)準(zhǔn)函數(shù)庫(kù) #include <unistd.h>//Unix類(lèi)系統(tǒng)定義符號(hào)常量 #include <fcntl.h>//定義了很多宏和open,fcntl函數(shù)原型#define BUFFERSIZE 4096//定義存儲(chǔ)器容量 #define COPYMODE 0644//定義復(fù)制的長(zhǎng)度void oops(char *, char *);int main(int argc, char *argv[]) {int in_fd, out_fd, n_chars;//三個(gè)描述符值char buf[BUFFERSIZE];//存儲(chǔ)器位置if (argc != 3) {//檢查argc的值是否為三,如果不是,返回標(biāo)準(zhǔn)錯(cuò)誤fprintf(stderr, "usage: %s source destination\n", *argv);exit(1);}/*檢查cp的第一個(gè)參數(shù),要復(fù)制的文件,用open打開(kāi),in_fd為open返回的描述符如果返回-1,代表打開(kāi)失敗,提示錯(cuò)誤*/if ((in_fd = open(argv[1], O_RDONLY)) == -1)oops("Cannot open ", argv[1]);/*檢查cp的第二個(gè)參數(shù),復(fù)制的目的地址,用create在目的地址創(chuàng)建新文件,out_fd為open返回的描述符如果返回-1,代表創(chuàng)建失敗,提示錯(cuò)誤*/if ((out_fd = creat(argv[2], COPYMODE)) == -1)oops("Cannot creat", argv[2]);/*cp指令的動(dòng)作就是讀取一個(gè)文件的內(nèi)容到存儲(chǔ)器,在新的地址創(chuàng)建空白文件,再?gòu)拇鎯?chǔ)器將內(nèi)容寫(xiě)入新文件。這里判斷復(fù)制是否成功:如果能讀取順利,而讀取的位數(shù)和寫(xiě)的位數(shù)不同,是寫(xiě)錯(cuò)誤;如果讀取失敗,是讀錯(cuò)誤。*/while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0)if (write(out_fd, buf, n_chars) != n_chars)oops("Write error to ", argv[2]);if (n_chars == -1)oops("Read error from ", argv[1]);/*這里執(zhí)行的是關(guān)閉文件的動(dòng)作,in_fd和out_fd兩個(gè)文件描述符所指向的文件只要有一個(gè)關(guān)閉錯(cuò)誤,就提示關(guān)閉錯(cuò)誤。*/if (close(in_fd) == -1 || close(out_fd) == -1)oops("Error closing files", ""); }/*這個(gè)是用來(lái)輸出錯(cuò)誤信息的函數(shù)*/ void oops(char *s1, char *s2) {fprintf(stderr, "Error: %s ", s1);perror(s2);//用來(lái)將上一個(gè)函數(shù)發(fā)生錯(cuò)誤的原因輸出到標(biāo)準(zhǔn)設(shè)備(stderr)exit(1); }參考資料
參考資料1:深入理解計(jì)算機(jī)系統(tǒng)(第二版)
參考資料2:編寫(xiě)who命令--從Linux中學(xué)習(xí)Linux
參考資料3:c++ 時(shí)間類(lèi)型詳解(time_t和tm)
參考資料4:20135202閆佳歆——信息安全系統(tǒng)設(shè)計(jì)基礎(chǔ)第八周學(xué)習(xí)總結(jié)
轉(zhuǎn)載于:https://www.cnblogs.com/hyq20135317/p/4965333.html
總結(jié)
以上是生活随笔為你收集整理的信息安全系统设计基础第九周学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 概率算法1
- 下一篇: 【ObjectC—浅copy和深copy