天天看點

資訊安全系統設計基礎第九周學習總結

系統級I/O

前言:輸入/輸出是在主存和外部裝置(如磁盤驅動器、終端和網絡)之間拷貝資料的過程。輸入操作時從I/O裝置拷貝資料到主存,而輸出操作時從主存拷貝資料到I/O裝置。

10.1  Unix I/O

一個Unix檔案就是一個m個位元組的序列:B0,B1,B2,B3...Bk...Bm-1。

所有的I/O裝置,如網絡、磁盤盒終端,都被模型化為檔案,而所有的輸入和輸出都被當做對相應的檔案的讀和寫來執行。這是一種應用接口,成為Unix I/O。

①打開檔案:一個應用程式通過要求核心打開相應地檔案,來宣告它想要通路一個I/O裝置。核心傳回一個小的非負整數,叫做描述符。它在後續對此檔案的所有操作中辨別這個檔案。核心記錄有關這個打開檔案的所有資訊。應用程式隻需要記住這個辨別符。
Unix外殼穿件的每個程序開始時都有三個打開的檔案:标準輸入(描述符為0)、标準輸出(描述符為1)、标準錯誤(描述符為2)。頭檔案<unistd.h>定義了常量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,它們而已用來代替顯式的描述符值。
②改變目前的檔案位置。對于每個打開的檔案,核心保持着一個檔案位置k,初始為0。這個檔案位置是從檔案開頭起始的位元組偏移量。應用程式能夠通過執行seek操作,顯式地設定檔案的目前位置為k。
③讀寫檔案。一個讀操作就是從檔案拷貝n>0個位元組到存儲器,從目前檔案位置k開始,然後将k增加到k+n。給定一個大小為m位元組的檔案,當k>=m時執行讀操作會觸發一個稱為end-of -file(EOF)的條件,應用程式能檢測到這個條件。在檔案結尾處并沒有明确的“EOF”符号。
類似的,寫操作就是從存儲器拷貝n>0個位元組到一個檔案,從目前檔案位置k開始,然後更新k。
④關閉檔案。當應用完成了對檔案的通路之後,它就通知核心關閉這個檔案。作為響應,核心釋放檔案打開時建立的資料結構,并将這個描述符恢複到可用的描述符池中。無論一個程序因為何種原因終止時,核心都會關閉所有打開的檔案并釋放他們的存儲器資源。      

10.2  打開和關閉檔案

open函數将filename轉換為一個檔案描述符,并且傳回描述符數字。傳回的描述符總是在程序中目前沒有打開的最小描述符。flags參數指明了程序打算如何通路這個檔案。

O_RDONLY:隻讀。

O_WRONLY:隻寫。

O_RDWR:可讀可寫。

flags參數也可以是一個或者更多位掩碼的或,為寫提供給一些額外的訓示:

O_CREAT:如果檔案不存在,就建立它的一個截斷的(空的)檔案。

O_TRUNC:如果檔案已經存在,就截斷它。

O_APPEND:在每次寫操作前,設定檔案位置到檔案的結尾處。

mode參數指定了新檔案的通路權限位。這些位的符号名字所示。作為上下文的一部分,每個程序都是一個umask,它是通過調用umask函數來設定的。當程序通過帶某個mode參數的open函數調用來建立一個新檔案時,檔案的通路權限位被設定我mode&~umask。

程序是通過調用open函數來打開一個已存在的檔案或者建立一個新檔案的。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
//給定mode和umask的預設值
#define DEF_MODE   S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define DEF_UMASK  S_IWGRP|S_IWOTH
int open(char *filename,int fliags,mod_it mode);//傳回值成功為新檔案描述符,出錯為-1
fd=Open("foo.txt",O_RDONLY,0);//如何以讀的方式打開一個已存在的檔案
fd=Open("foo.txt",O_WRONLY|O_APPEND,0);//如何打開一個已存在檔案,并在後面添加一些資料
//建立一個新檔案,檔案的擁有者有讀寫權限,而所有其他的使用者都有讀權限
umask(DEF_UMASK);
fg=Open("foo.txt",O_CREAT|O_TRUNC|O_WEONLY,DEF_MODE);
//通過調用close函數關閉一個打開的檔案
int close(int fd);//傳回值成功為0,出錯為-1
      

以下為通路權限位在sys/stat.h中的定義:

資訊安全系統設計基礎第九周學習總結

10.3  讀和寫檔案

1、應用程式是通過分别調用read和write函數來執行輸入和輸出的。

#include <unistd.h>
ssize_t read(int fd,void *buf,size_t n);//傳回值:成功為讀的位元組數,若EOF為0,出錯為-1
ssize_t write(int fd,const void *buf,size_t n);//傳回值成功為寫的位元組數,出錯為-1      

2、read函數從描述符為fd的目前檔案位置拷貝最多n個位元組到存儲器位置buf,傳回值-1表示一個錯誤。而傳回值0表示EOF。否則,傳回值表示的是實際傳送的位元組數量。

3、write函數從存儲器位置buf拷貝至多n個位元組到描述符fd的目前檔案位置。

以下是一個例子,展示了一個程式使用read和write調用一次一個位元組地從标準輸入拷貝到标準輸出。

#include  "csapp.h"

int main(void)

{

    char c;

    while(Read(STDIN_FILENO,&c,1)!=0)

        Write(STDOUT_FILENO,&c,1);

    exit(0);

}    
      

通過調用lseek函數,應用程式能夠顯示地修改目前檔案的位置。

4、在某些情況下,read和write傳送的位元組比應用程式要求的要少,這些不足值不表示有錯誤。原因如下:

①讀時遇到EOF。假設我們豬呢比讀一個檔案,該檔案從目前檔案位置開始隻含有20多個位元組,而我們以50個位元組的片進行讀取。這樣一來,下一個read傳回的不足值為20,此後的read将通過傳回不足值0來發出EOF信号。
②從終端讀文本行。如果打開檔案是與終端相關聯的(如鍵盤和顯示器),那麼每個read函數将以此傳送一個文本行,傳回的不足值等于文本行的大小。
③讀和寫網絡套接字。如果打開的檔案對應于網絡套接字,那麼内部緩沖限制和較長的網絡延遲會引起read和write傳回不足值。對Unix管道調用read和write時,也有可能出現不足值,這種程序間的通信機制不在我們讨論的範圍之内。
實際上,除了EOF,在讀磁盤檔案時,将不會遇到不足值,而且在寫磁盤檔案時,也不會遇到不足值。如果想建立簡裝的諸如web伺服器這樣的網絡應用,就必須通過反複調用read和write處理不足值,直到所有需要的位元組都傳送完畢。      

10.4  用RIO包健壯地讀寫

1、RIO包會自動處理不足值。RIO提供了兩類不同的函數:

①無緩沖的輸入輸出函數。這些函數直接在存儲器和檔案之間傳送資料,沒有應用級緩沖,他們對将二進制資料讀寫到網絡和從網絡讀寫二進制資料尤其有用。
②帶緩沖的輸入函數。這些函數允許你高效地從檔案中讀取文本行和二進制資料,這些檔案的内容緩存在應用級緩沖區内,類似于像printf這樣的标準I/O函數提供的緩沖區。是線程安全的,它在同一個描述符上可以被交錯地調用。例如,可以從一個描述符中讀一些文本行,然後讀取一些二進制資料,接着再多讀取一些文本行。      

2、RIO的無緩沖的輸入輸出函數

通過調用rio_readn和rio_writen函數,應用程式可以在存儲器和檔案之間直接傳送資料。

#include "csapp.h"
//傳回值:若成功為傳送的位元組數,若EOF則為0,出錯為-1
ssize_t rio_readn(int fd,void *usrbuf,size_t n);
ssize_t rio_writen(int fd,void *usrbuf,size_t n);
      

rio_readn函數從描述符fd的目前檔案位置最多傳送n和位元組到存儲器位置usrbuf。類似地,rio_writen函數從位置usrbuf傳送n個位元組到描述符fd。rio_readn函數唉遇到EOF時隻能傳回一個不足值。rio_writen函數絕不會傳回不足值。對于同一個描述符,可以任意交錯地調用rio_readn和rio_writen。

如果rio_readn和rio_writen函數被一個從應用信号處理程式的發放你會中斷,那麼每個函數都會手動地重新開機read或write。為了盡可能有較好地可移植性,允許被中斷的系統調用,并在必要時重新開機他們。

3、RIO的帶緩沖的輸入函數

一個文本行就是一個由換行符結尾的ASCII碼字元序列。在Unix系統中,換行符(‘\n')與ASCII碼換行符(LF)相同,數字值為0x0a。

用一個程式來計算文本檔案中文本行的數量:用read函數來一次一個位元組地從檔案傳送到使用者存儲器,檢查每個位元組來查找換行符。這個方法的缺點是效率低,每讀取檔案中的一個位元組都要求陷入核心。

另一種方法是調用一個包裝函數(rio_readlineb),它從一個内部讀緩沖區拷貝一個文本行,當緩沖區變空時,會自動地調用read重新填滿緩沖區。對于既包含文本行也包含二進制資料的檔案,我們也提供了一個rio_readn帶緩沖區的版本,叫做rio_readnb,它從和rio_readlineb一樣的讀緩沖區中傳送原始位元組。

#include "csapp.h"
void rio_readinitb(rio_t *rp,int fd);//無傳回
ssize_t rio_readlineb(rio_t *rp,void *usrbuf,size_t maxlen);
ssize_t rio_readnb(rio_t *rp,void *usrbuf,size_t n);//傳回值:若成功為讀得位元組數,若EOF則為0,若出錯為-1      
ssize_t rio_readn(int fd,void *usrbuf,size_t n)
{
    size_t nleft=n;
    ssize_t nread;
    char *bufp=usrbuf;
    while(nleft>0){
        if((nread=read(fd,bufp,nleft))<0){
            if(errno==EINTR)
                nread=0;
            else
                return -1;
        }
        else if (nread==0)
            break;
        nleft-=nread;
        bufp+=nread;
    }
    return(n-nleft);
}        
      
ssize_t rio_writen(int fd,void *usrbuf,size_t n)
{
    size_t nleft=n;
    ssize_t nwritten;
    char *bufp=usrbuf;
    while(nleft>0){
        if((nwritten=write(fd,bufp,nleft))<=0){
            if(errno==EINTR)
                nwritten=0;
            else
                return -1;
        }
        nleft -=nwritten;
        bufp+=nwritten;
    }
    return n;
}
      

每打開一個描述符都會調用一次rio_readinitb函數。它将描述符fd和位址rp的一個類型為rio_t的讀緩沖區聯系起來。

4、RIO讀程式核心:rio-read函數

static ssize_t rio_read(rio_t *rp,char *usrbuf,size_t n)
{
    int cnt;
    while(rp->rio_cnt<=0)//如果緩沖區為空,先調用函數填滿緩沖區再讀資料
    {
        rp->rio_cnt=read(rp->rio_fd,rp->rio_buf,sizeof(rp->rio_buf));//調用read函數填滿緩沖區
        if(rp->rio_cnt<0)//排除檔案讀不出資料的情況
        {
            if(error != EINTR)
            {
                return -1;
            }
        }
        else if(rp->rio_cnt=0)
            return 0;
        else 
            rp->rio_bufptr = rp->rio_buf;//更新現在讀到的位置
    }
    cnt=n;
    if(rp->rio_cnt<n)
        cnt=rp->rio_cnt;//以上三步,将n與rp->rio_cnt中較小的值賦給cnt
    memcpy(usrbuf,rp->rio_bufptr,cnt);把讀緩沖區的内容拷貝到使用者緩沖區
    rp->rio_bufptr+=cnt;
    rp->rio_cnt-=cnt;
    return cnt;
}
      

當調用rio_read要求讀n個位元組時,讀緩沖區内有rp->rio_cnt個未讀位元組。如果緩沖區為孔,那麼會通過調用read再填滿它。這個read調用收到一個不足值并不是錯誤,隻不過讀緩沖區是填充了一部分。一旦緩沖區非空,rio_read就從讀緩沖區拷貝n和rp->rio_cnt中較小值個位元組到使用者緩沖區,并傳回拷貝的位元組數。

10.5 讀取檔案中繼資料

1、應用程式能夠通過調用stat和fstat函數,檢索到關于檔案的資訊(中繼資料)。

#include <unistd.h>
#include <sys/stat.h>
int stat(cost char *filename,struc sta *buf);
int fstat(int fd,struct stat *buf);
      
stat函數以檔案名作為輸入
fstat函數以檔案描述符作為輸入
stat資料結構中的重要成員:st_mode,st_size
st_size成員包含了檔案的位元組數大小
st_mode成員編碼了檔案通路許可位和檔案類型      

2、檔案類型:

  • 普通檔案:二進制或文本資料,宏指令:S_ISREG()
  • 目錄檔案:包含其他檔案的資訊,宏指令:S_ISDIR()
  • 套接字:通過網絡和其他程序通信的檔案,宏指令:S_ISSOCK()

3、Unix提供的宏指令根據st_mode成員來确定檔案的類型

10.6  共享檔案

1、核心用三個相關的資料結構來表示打開的檔案:

描述符表:每個打開的描述符表項指向檔案表中的一個表項
檔案表:所有程序共享這張表,每個表項包括檔案位置,引用計數,以及一個指向v-node表對應表項的指針
v-node表:所有程序共享這張表,包含stat結構中的大多數資訊      

2、三種打開檔案的類型:

  • 典型:描述符各自引用不同的檔案,沒有共享
  • 共享:多個描述符通過不同的檔案表表項引用同一個檔案。(關鍵思想:每個描述符都有自己的檔案位置,對不同描述符的讀操作可以從檔案的不同位置擷取資料)
  • 繼承:子程序繼承父程序打開檔案。調用fork後,子程序有一個父程序描述符表的副本,父子程序共享相同的打開檔案表集合,是以共享相同的檔案位置
資訊安全系統設計基礎第九周學習總結
資訊安全系統設計基礎第九周學習總結
資訊安全系統設計基礎第九周學習總結

10.7 I/0重定向

1、Unix外殼提供了I/O重定向操作符,允許使用者将磁盤檔案和标準輸入輸出聯系起來

2、重定向使用dup2函數

int dup2(int oldfd,int newfd);      

3、dup2函數拷貝描述符表表項oldfd到描述符表表項newfd,覆寫描述表表項newfd以前的内容。

4、如果newfd已經打開,dup2會在拷貝oldfd之前關閉newfd

10.8 标準I/O

1、ANSI C定義了一組進階輸入輸出函數,稱為标準I/O庫。提供了打開和關閉檔案的函數(fopen和fclose),讀和寫位元組的函數(fread和fwrite),讀和寫字元串的函數(fgets和fputs),格式化I/O函數(scanf和printf)

2、标準I/O庫将一個打開的檔案模型化為一個流。一個流就是一個指向FILE類型的結構的指針

3、每個ANSI C程式開始時都有三個打開的流stdin、stdout、stderr,分别對應标準輸入、标準輸出、标準錯誤

4、類型為FILE的流是對檔案描述符和流緩存區的抽象

======================================================

遇到的問題和解決方法

本章的學習内容看似少,對思路要求也挺高。代碼也很多。我在學習時遇到了不少記憶上的問題,很多參數、掩碼長得很相似,英文大寫有時也會讓我不知道它是哪個單詞的縮寫,盡管是生活中很常見的單詞。還有就是代碼很長,變量名字也很長,敲起來工作量很大也很容易出錯。我試着運作代碼。一開始提示頭檔案找不到。我上網百度才知道是因為“csapp.h”這個是這本教材編寫的一系列頭檔案,不是計算機自帶的。但可以從網上下載下傳下來。我嘗試了,但還沒有成功,我還在繼續努力解決中。

這個問題不解決就無法測試一些問題。如習題一“下面程式的輸出是什麼?”

#include "csapp.h"
int main()
{
    int fd1,fd2;
    fd1=Open("foo.txt",O_RDONLY,0);
    Close(fd1);
    fd2=Open("baz.txt",O_RDONLY,0);
    printf("fd2=%d\n",fd2);
    exit(0);
}
      

我想運作代碼驗證:将:

Close(fd1);
      

這個語句删除的話,此處輸出是多少?因為檔案沒有關閉,那麼此時輸出會是3還是4?

是以我還在嘗試解決代碼運作的問題。待續...

11.9解決問題

根據問題小組中韓玉琪同學的解答,我又嘗試着去做,結果發現問題解決了。此處附上解決方案連結:

http://group.cnblogs.com/topic/73278.html

實踐代碼

<<cp

功能:複制一個檔案

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);
}
      

<<ls

功能:列印出該目錄下的檔案清單

#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;
}      

<<who

功能:檢視使用者

#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, &current_record, reclen) == reclen )
		show_info(&current_record);
	close(utmpfd);
	return 0;			
}
      

<<fileinfo

功能:這個功能用來實作顯示檔案資訊,建立了一個stat資料結構。先判斷指令是否有操作數,有的話才能繼續進行下去,如果沒有報錯就列印出來相關檔案資訊,報錯就用perror将報錯資訊列印出來。

#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 );               
}      

<<setecho

功能:改變echo的狀态

#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 )
			oops("tcgettattr", 1);

        if ( argv[1][0] == 'y' )
                info.c_lflag |= ECHO ;
        else
                info.c_lflag &= ~ECHO ;

        if ( tcsetattr(0,TCSANOW,&info) == -1 )
               oops("tcsetattr",2);
	
		return 0;
}      

<<filesize

功能:用st_size計算檔案的位元組數大小

#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 );
}
      

<<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");
        else
                printf(" echo is OFF, since its bit is 0\n");

		return 0;
}
      

<<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;
}
      

<<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 *);
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;
}      

==================================================================================

參考文獻:

《深入了解計算機系統》