資訊安全系統設計基礎第十周學習總結
估算學習時間:共9小時
讀書:4
代碼:3
作業:0
部落格:2
實際學習時間:共7.5小時
讀書:2.5
代碼:3.5
部落格:1.5
耗時估計的公式:Y=X+X/N ,Y=X-X/N
課本第十章 系統級I/O
- 輸入輸出I/O是在主存和外部裝置(如磁盤,網絡和終端)之間拷貝資料的過程。
- 輸入就是從I/O裝置拷貝資料到主存,而輸出就是從主存拷貝資料到I/O裝置。
- 所有語言的運作時系統都提供執行I/O的較進階别的工具。例如,ANSI C提供标準I/O庫,包含像printf和scanf這樣執行帶緩沖區的I/O函數。C++語言用它的重載操作符<<(輸出)和>>(輸入)提供了類似的功能。在UNIX系統中,是通過使用由核心提供的系統級Unix I/O函數來實作這些比較進階的I/O函數的。
- 學習Unix I/O原因:了解Unix I/O将幫助你了解其他的系統概念;有時你除了使用Unix I/O外别無選擇。
10.1 unix i/o 596
所有的I/O裝置,如網絡、磁盤和終端,都被模型化為檔案,而所有的輸入和輸出都被當做對相應的檔案的讀和寫來執行。這種将裝置優雅地映射為檔案的方式,允許Unix核心引出一個簡單、低級的的應用接口,稱為Unⅸ I/O,這使得所有的輸入和輸出都能以一種統一且一緻的方式來執行:
- 打開檔案。一個應用程式通過要求核心打開相應的檔案,來宣告它想要通路一個I/O裝置。核心傳回一個小的非負整數,叫做描述符,它在後續對此檔案的所有操作中辨別這個檔案。核心記錄有關這個打開檔案的所有資訊。應用程式隻需記住這個描述符。Unⅸ外殼建立的每個程序開始時都有三個打開的檔案:标準輸入(描述符為0)、标準輸出(描述符為1)和标準錯誤(描述符為2)。頭檔案可用來代替顯式的描述符值。
- 改變目前的檔案位置。對于每個打開的檔案,核心保持着一個檔案位置k,初始為0。這個檔案位置是從檔案開頭起始的位元組偏移量。應用程式能夠通過執行seek操作,顯式地設定檔案的目前位置為k。
- 讀寫檔案。一個讀操作就是從檔案拷貝n>0個位元組到存儲器,從目前檔案位置k開始,然後将k增加到k+n。給定一個大小為m位元組的檔案,當k>=m時執行讀操作會觸發―個稱為end-of-file(EOF)的條件,應用程式能檢測到這個條件。在檔案結尾處處并沒有明确的“EOF”符号。
- 關閉檔案。當應用完成了對檔案的通路之後,它就通知核心關閉這個檔案。作為響應,核心釋放檔案打開時建立的資料結構,并将這個描述符恢複到可用的描述符池中。無論一個程序因為何種原因終止時,核心都會關閉所有打開的檔案并釋放它們的存儲器資源。
10.2 打開和關閉檔案 597
- 程序是通過調用open函數來打開一個已存在的檔案或者建立一個新檔案:
資訊安全系統設計基礎第十周學習總結 - flags參數表示程序打算如何通路這個檔案,它的值包括:
O_RDONLY
O_WRONLY
O_RDWR
- flags參數也可以是一個或者更多位掩碼的或,提供一些額外的訓示:
O_CREAT
O_TRUNC:如果檔案已經存在,就截斷它。
O_APPEND
- mode參數指定了新檔案的通路權限位。符号名字如下圖。作為上下文的一部分,每個程序都有一個umask它是通過調用umask函數來設定的。當程序通過帶某個mode參數的open函數調用來建立一個新檔案時,檔案的通路權限位被設定為mode&umask。
資訊安全系統設計基礎第十周學習總結
10.3 讀和寫檔案 598
應用程式是通過分别調用系統函數 read和write函數來執行輸入和輸出的。
旁注:size_t是作為usigned int,而ssize_t是作為int。
在某些情況下,read和write傳送的位元組比應用程式要求的要少。出現這種情況的可能的原因有:
讀時遇到EOF。假設該檔案從目前檔案位置開始隻含有20個位元組,而應用程式要求我們以50個位元組的片進行讀取,這樣一來,這個read的傳回的值是20,在此之後的read則傳回0。
從終端讀文本行。如果打開的檔案是與終端相關聯的,那麼每個read函數将一次傳送一個文本行,傳回的不足值等于文本行的大小。
讀和寫socket。如果打開的檔案對應于網絡套接字,那麼内部緩沖限制和較長的網絡延遲會導緻read和write傳回不足值。
10.4 用rio包健壯地讀寫 599
RIO提供了兩類不同的函數:
無緩沖的輸入輸出函數
帶緩沖的輸入函數
10.4.1 rio的無緩沖的輸入輸出函數 600
- rio_readn函數從描述符fd的目前檔案位置最多傳送n個位元組到存儲器位置usrbuf。類似的rio_writen函數從位置usrbuf傳送n個位元組到描述符fd。rio_readn函數在遇到EOF時隻能傳回一個不足值。rio_writen函數絕不會傳回不足值。
- 注意:如果rio_readn和rio_writen函數被一個從應用信号處理程式的傳回中斷,那麼每個函數都會手動地重新開機read或write。
10.4.2 rio的帶緩沖的輸入函數 600
- 一個文本行就是一個由 換行符 結尾的ASCII碼字元序列。在Unix系統中,換行符是‘\n’,與ASCII碼換行符LF相同,數值為0x0a。假設我們要編寫一個程式來計算文本檔案中文本行的數量應該如何來實作呢?
一種方法是用read函數來一次一個位元組地從檔案傳送到使用者存儲器,檢查每個位元組來查找換行符。這種方法的問題就是效率不高,每次取檔案中的一個位元組都要求陷入核心。
一種更好的方法是調用一個包裝函數(rio_readlineb),它從一個内部緩沖區拷貝一個文本行,當緩沖區變空時,會自動的調用read系統調用來重新填滿緩沖區。
- 在帶緩沖區的版本中,每打開一個描述符都會調用一次rio_readinitb函數,它将描述符fd和位址rp處的一個類型為rio_t的讀緩沖區聯系起來。
- rio_readinitb函數從檔案rp讀取一個文本行(包括結尾的換行符),将它拷貝到存儲器位置usrbuf,并且用空字元來結束這個文本行。
- RIO讀程式的核心是rio_read函數,rio_read函數可以看成是Unix read函數的帶緩沖區的版本。當調用rio_read要求讀取n個位元組的時候,讀緩沖區内有rp->rio_cnt個未讀的位元組。如果緩沖區為空的時候,就會調用read系統函數去填滿緩沖區。這個read調用收到一個不足值的話并不是一個錯誤,隻不過讀緩沖區的是填充了一部分。
- 一旦緩沖區非空,rio_read就從讀緩沖區拷貝n和rp->rio_cnt中較小值個位元組到使用者緩沖區,并傳回拷貝位元組的數目。
- 對于應用程式來說,rio_read和系統調用read有着相同的語義。出錯時傳回-1;在EOF時,傳回0;如果要求的位元組超過了讀緩沖區内未讀的位元組的數目,它會傳回一個不足值。rio_readlineb函數多次調用rio_read函數。每次調用都從讀緩沖區傳回一個位元組,然後檢查這個位元組是否是結尾的換行符。
- rio_readlineb函數最多讀取(maxlen-1)個位元組,餘下的一個位元組留給結尾的空字元。超過maxlen-1位元組的文本行被截斷,并用一個空字元結束。
10.5 讀取檔案中繼資料 604
- 應用程式能夠通過調用stat和fstat函數,檢索到關于檔案的資訊。
- stat函數結構
資訊安全系統設計基礎第十周學習總結 - st_size成員包含了檔案的位元組數大小。st_mode成員則編碼了檔案通路許可位和檔案類型。Unix識别大量不同的檔案類型。普通檔案包括某種類型的二進制或文本資料。對于核心而言,文本檔案和二進制檔案毫無差別。
- 目錄檔案包含關于其他檔案的資訊。套接字是一種用來通過網絡與其他程序通信的檔案。Unix提供的宏指令根據st_mode成員來确定檔案的類型。這些宏的一個子集如下:
資訊安全系統設計基礎第十周學習總結
10.6 共享檔案 606
核心用三個相關資料結構來表示打開的檔案
描述符表
檔案表
v-node表
10.7 i/o重定向 608
- Unix外殼提供了I/O重定向操作符,允許使用者将磁盤檔案和标準輸入輸出聯系起來。
- I/O重定向的工作方式: 一種是使用dup2函數。
資訊安全系統設計基礎第十周學習總結 - dup2函數拷貝描述符表表項oldfd到描述符表表項newfd,覆寫描述符表表項newfd以前的内容。如果newfd已經打開了,dup2會在拷貝oldfd之前關閉newfd。
10.8 标準i/o 609
- ANSI C定義了一組進階輸入輸出函數,成為标準I/O庫,為程式員提供了Unix I/O的較進階别的替代。這個庫(libc)提供了打開和關閉檔案的函數(fopen和fclose)、讀和寫位元組的函數(fread和fwrite)、讀和寫字元串的函數(fgets和fputs)、以及複雜的格式化I/O函數(printf和scanf)。
- 标準I/O庫将一個打開的檔案模型化為一個流。對于程式員而言,一個流就是一個指向FILE類型的結構的指針。每個ANSI C程式開始時都有三個打開的流stdin、stdout和stderr,分别對應于标準輸入、标準輸出和标準錯誤:
資訊安全系統設計基礎第十周學習總結
10.9 綜合:我該使用哪些i/o函數 610
- 這一章讨論過的各種I/O包
資訊安全系統設計基礎第十周學習總結 - 标準I/O流,從某種意義上來說是全雙工的,因為程式能夠在同一個流上執行輸入和輸出。
- 建議在網絡套接字上不要使用标準I/O函數來進行輸入和輸出。而要使用健壯的RIO函數。
10.10 小結 611
- Unix提供了少量的系統級函數,它們允許應用程式打開、關閉、讀和寫檔案,提取檔案的中繼資料,以及執行I/O重定向。Unix的讀和寫操作會出現不足值,應用程式必須能正确地預計和處理這種情況。應用程式不應直接調用unⅸ I/O函數,而應該使用RIO包,RIO包通過反複執行讀寫操作,直到傳送完所有的請求資料,自動處理不足值。
- Unix核心使用三個相關的資料結構來表示打開的檔案。描述符表中的表項指向打開檔案中的表項,而打開檔案表中的表項又指向v-node表中的表項,每個程序都有它自己單獨的描述符表,而所有的程序共享同一個打開檔案表和v-node表,了解這些結構的一般組成就能使我們清楚地了解檔案共享和I/O重定向。
- 标準I/O庫是基于Unix I/O實作的,并提供了一組強大的進階I/O例程,對于大多數應用程式而言,标準I/O更簡單,是優于Unix I/O的選擇。然而,因為對标準I/O和網絡檔案的一些互相不相容的限制,Unix I/O比标準I/O更适用于網絡應用程式。
附錄A錯誤處理
A.1 Unix系統中的錯誤處理
-
Unix風格的處理錯誤
遇到錯誤後傳回-1,并且将全局變量errno設定為指明錯誤原因的錯誤代碼;
如果成功完成,就傳回有用的結果。
-
Posix風格的處理錯誤
傳回0表示成功,傳回非0表示失敗;
有用的結果在傳進來的函數參數中。
-
DNS風格的處理錯誤
有兩個函數,gethostbyname和gethostbyaddr,失敗時傳回NULL指針,并設定全局變量h_errno。
-
錯誤報告函數小結
貫穿本書,使用下列錯誤報告函數來包容不同的錯誤處理風格:
``#include "csapp.h"
void unix_error(char *msg);
void posix_error(int code,char *msg);
void dns_error(char *msg);
void app_error(char *msg);
A.2 錯誤處理包裝函數
-
Unix風格
成功時傳回void,傳回錯誤時包裝函數列印一條資訊,然後退出。
void Kill(pid_t pid, int signum) { int rc; if ((rc = kill(pid, signum)) < 0) unix_error("Kill error"); }
-
Posix風格
成功時傳回void,錯誤傳回碼中不會包含有用的結果。
void Pthread_detach(pthread_t tid) { int rc; if ((rc = pthread_detach(tid)) != 0) posix_error(rc, "Pthread_detach error"); }
- DNS風格
struct hostent *Gethostbyname(const char *name) { struct hostent *p; if ((p = gethostbyname(name)) == NULL) dns_error("Gethostbyname error"); return p; }
編譯運作代碼
cp1.c
echostate.c
fileinfo.c
filesize.c
ls1.c
ls2.c
setecho.c
spwd.c
testioctl.c
who1.c
who2.c
cp1
複制檔案。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
define BUFFERSIZE 4096
#define COPYMODE 0644
void oops(char *, char *);
int main(int argc, char *argv[])
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
if (argc != 3) {
fprintf(stderr, "usage: %s source destination\n", *argv);
exit(1);
}
if ((in_fd = open(argv[1], O_RDONLY)) == -1)
oops("Cannot open ", argv[1]);
if ((out_fd = creat(argv[2], COPYMODE)) == -1)
oops("Cannot creat", argv[2]);
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]);
if (close(in_fd) == -1 || close(out_fd) == -1)
oops("Error closing files", "");
}
void oops(char *s1, char *s2)
{
fprintf(stderr, "Error: %s ", s1);
perror(s2);
exit(1);
}
運作結果如下:
echostate
檢驗在指令行中輸入指令時是否可見,如果可見,傳回echo is on , since its bit is 1
#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");
else
printf(" echo is OFF, since its bit is 0\n");
return 0;
}
fileinfo
檢視檔案資訊。
#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;
}
else
perror(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 );
}
filesize
計算檔案的位元組數大小。
#include <stdio.h>
#include <sys/stat.h>
int main()
{
struct stat infobuf;
if ( stat( "/etc/passwd", &infobuf) == -1 )
perror("/etc/passwd");
else
printf(" The size of /etc/passwd is %d\n", infobuf.st_size );
}
ls1
顯示目前目錄下的檔案。
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
void do_ls(char []);
int main(int argc, char *argv[])
{
if ( argc == 1 )
do_ls( "." );
else
while ( --argc ){
printf("%s:\n", *++argv );
do_ls( *argv );
}
return 0;
}
void do_ls( char dirname[] )
{
DIR *dir_ptr;
struct dirent *direntp;
if ( ( dir_ptr = opendir( dirname ) ) == NULL )
fprintf(stderr,"ls1: cannot open %s\n", dirname);
else
{
while ( ( direntp = readdir( dir_ptr ) ) != NULL )
printf("%s\n", direntp->d_name );
closedir(dir_ptr);
}
}
ls2
檢視檔案的詳細資訊,比如使用者名,群組名,大小,建立時間,讀寫權限等。
#include <stdio.h>
#include<string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
void do_ls(char[]);
void dostat(char *);
void show_file_info( char *, struct stat *);
void mode_to_letters( int , char [] );
char *uid_to_name( uid_t );
char *gid_to_name( gid_t );
int main(int argc, char *argv[])
{
if ( argc == 1 )
do_ls( "." );
else
while ( --argc ){
printf("%s:\n", *++argv );
do_ls( *argv );
}
return 0;
}
void do_ls( char dirname[] )
{
DIR *dir_ptr;
struct dirent *direntp;
if ( ( dir_ptr = opendir( dirname ) ) == NULL )
fprintf(stderr,"ls1: cannot open %s\n", dirname);
else
{
while ( ( direntp = readdir( dir_ptr ) ) != NULL )
dostat( direntp->d_name );
closedir(dir_ptr);
}
}
void dostat( char *filename )
{
struct stat info;
if ( stat(filename, &info) == -1 )
perror( filename );
else
show_file_info( filename, &info );
}
void show_file_info( char *filename, struct stat *info_p )
{
char *uid_to_name(), *ctime(), *gid_to_name(), *filemode();
void mode_to_letters();
charmodestr[11];
mode_to_letters( info_p->st_mode, modestr );
printf( "%s", modestr );
printf( "%4d " , (int) info_p->st_nlink);
printf( "%-8s " , uid_to_name(info_p->st_uid) );
printf( "%-8s " , gid_to_name(info_p->st_gid) );
printf( "%8ld " , (long)info_p->st_size);
printf( "%.12s ", 4+ctime(&info_p->st_mtime));
printf( "%s\n" , filename );
}
void mode_to_letters( int mode, char str[] )
{
strcpy( str, "----------" );
if ( S_ISDIR(mode) ) str[0] = 'd';
if ( S_ISCHR(mode) ) str[0] = 'c';
if ( S_ISBLK(mode) ) str[0] = 'b';
if ( mode & S_IRUSR ) str[1] = 'r';
if ( mode & S_IWUSR ) str[2] = 'w';
if ( mode & S_IXUSR ) str[3] = 'x';
if ( mode & S_IRGRP ) str[4] = 'r';
if ( mode & S_IWGRP ) str[5] = 'w';
if ( mode & S_IXGRP ) str[6] = 'x';
if ( mode & S_IROTH ) str[7] = 'r';
if ( mode & S_IWOTH ) str[8] = 'w';
if ( mode & S_IXOTH ) str[9] = 'x';
}
#include <pwd.h>
char *uid_to_name( uid_t uid )
{
struct passwd *getpwuid(), *pw_ptr;
static char numstr[10];
if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){
sprintf(numstr,"%d", uid);
return numstr;
}
else
return pw_ptr->pw_name ;
}
#include <grp.h>
char *gid_to_name( gid_t gid )
{
struct group *getgrgid(), *grp_ptr;
static char numstr[10];
if ( ( grp_ptr = getgrgid(gid) ) == NULL ){
sprintf(numstr,"%d", gid);
return numstr;
}
else
return grp_ptr->gr_name;
}
setecho
設定在指令行中輸入指令時是否可見,如果可見,輸入setecho yes;如果設定為不可見,輸入setecho no。
#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 )
exit(0);
if ( tcgetattr(0,&info) == -1 ) /* get attribs */
oops("tcgettattr", 1);
if ( argv[1][0] == 'y' )
info.c_lflag |= ECHO ; /* turn on bit*/
else
info.c_lflag &= ~ECHO ; /* turn off bit */
if ( tcsetattr(0,TCSANOW,&info) == -1 ) /* set attribs*/
oops("tcsetattr",2);
return 0;
}
運作結果如圖:
spwd
顯示目前所在目錄。
#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 *);
voidprintpathto(ino_t);
voidinum_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;
}
testioctl
#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;
}
who1
從UTMP_FILE檔案中讀取想要的資訊到存儲器中,然後再用标準輸出函數列印到螢幕上,最後關閉檔案。
#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
printf("(%s)", utbufp->ut_host);
#endif
printf("\n");
return 0;
}
int main()
{
struct utmp current_record;
int utmpfd;
int reclen = sizeof(current_record);
if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
perror( UTMP_FILE );
exit(1);
}
while ( read(utmpfd, ¤t_record, reclen) == reclen )
show_info(¤t_record);
close(utmpfd);
return 0;
}
who2
#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
printf("(%s)", utbufp->ut_host);
#endif
printf("\n");
return 0;
}
int main()
{
struct utmp current_record;
int utmpfd;
int reclen = sizeof(current_record);
if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
perror( UTMP_FILE );
exit(1);
}
while ( read(utmpfd, ¤t_record, reclen) == reclen )
show_info(¤t_record);
close(utmpfd);
return 0;
}
用man學習了解相關系統調用, 了解參數、傳回值的含義
1.Linux man中的man就是manual的縮寫,用來檢視系統中自帶的各種參考手冊,但是手冊頁分為好幾個部分,如下所示:
1 Executable programs or shell commands(使用者指令幫助)
# 2 System calls (系統調用幫助) #
3 Library calls (庫函數調用幫助)
4 Special files (usually found in /dev)
5 File formats and conventions eg /etc/passwd(配置檔案幫助)
6 Games
7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
8 System administration commands (usually only for root)
9 Kernel routines [Non standard]
1是普通的指令
2是系統調用,如open,write之類的(通過這個,至少可以很友善的查到調用這個函數,需要加什麼頭檔案)
3是庫函數,如printf,fread4是特殊檔案,也就是/dev下的各種裝置檔案
5是指檔案的格式,比如passwd, 就會說明這個檔案中各個字段的含義
6是給遊戲留的,由各個遊戲自己定義
7是附件還有一些變量,比如向environ這種全局變量在這裡就有說明
8是系統管理用的指令,這些指令隻能由root使用,如ifconfig
2.man page大緻分為一下部分:
NAME:簡單指令、資料名稱說明
SYNOPSIS:簡短的指令文法(sysntax)簡介
DESCRIPTION:較為完整的說明,需要認真閱讀
OPTION:針對SYNOPSIS中列舉的所有可用選項說明
COMMANDS:當這個軟體在執行的時候,可用在此軟體中使用指令
FILES:這個軟體或資料所使用或參考或連結到的檔案
SEE ALSE:可以參考的,與這個指令有關的其他說明
EXAMPLE:一些可以參考的範例,這個最好用
BUGS:是否有相關的bug
3.man中的相關操作
ctrl + F或者Page Down:向下翻頁
ctrl + B或者Page Up:向上翻頁
gg到第一行
GG到最後一行
/start:能在整手冊中搜尋start相關字元,使用n查找下一個,使用N查找上一個
j,k與vi中一樣使用,j向下一行,k向上一行
d下翻半頁
u上翻半頁
h擷取man使用幫助
q退出man
4.使用帶有-k選項的man指令可以根據關鍵字搜尋聯機幫助。
使用帶有-f選項的man指令可以根據關鍵字在聯機幫助中搜尋完全比對的條目。
5.常見的系統調用指令見:http://www.2cto.com/os/201307/224623.html
6.利用man學習這些指令,例:
資訊安全系統設計基礎第十周學習總結
用grep -nr xxx /usr/include 查宏定義
感悟
如果想進一步了解系統,熟悉一些系統底層的東西還是非常必要的,可以先了解一些指令是如何實作相關功能的。
參考資料
- 教材:第十章,詳細學習指導:http://group.cnblogs.com/topic/73069.html
- 課程資料:https://www.shiyanlou.com/courses/413 實驗十,課程邀請碼:W7FQKW4Y
- 教材中代碼運作、思考一下,讀代碼的學習方法:http://www.cnblogs.com/rocedu/p/4837092.html。
- CSAPP第10章系統級I/O問題:http://www.zhihu.com/question/31499851
- Linux系統調用學習:http://blog.chinaunix.net/uid-20758579-id-1876888.html