システム・プログラム 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro-2000/2000-04-24
/file-syscall.html
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.is.tsukuba.ac.jp/~yas/index-j.html
<<< ---------------------------------------------------------------------- 1: 2: /* 3: file-copy.c -- ファイルをコピーする簡単なプログラム 4: ~yas/syspro1/file/file-copy.c 5: $Header: /home/lab2/OS/yas/syspro1/file/RCS/file-copy.c,v 1.3 1998/04/27 14:35:36 yas Exp $ 6: Start: 1995/03/04 16:40:24 7: */ 8: 9: #include <stdio.h> /* stderr */ 10: #include <fcntl.h> /* open(2) */ 11: 12: extern void file_copy( char *from_name, char *to_name ); 13: 14: main( int argc, char *argv[] ) 15: { 16: if( argc != 3 ) 17: { 18: fprintf( stderr,"Usage: %s from to\n", argv[0] ); 19: exit( 1 ); 20: } 21: file_copy( argv[1],argv[2] ); 22: } 23: 24: #define BUFFSIZE 1024 25: 26: void file_copy( char *from_name, char *to_name ) 27: { 28: int from_fd,to_fd ; 29: char buff[BUFFSIZE] ; 30: int rcount ; 31: int wcount ; 32: 33: from_fd = open( from_name,O_RDONLY ); 34: if( from_fd == -1 ) 35: { 36: perror( from_name ); 37: exit( 1 ); 38: } 39: to_fd = open( to_name,O_WRONLY|O_CREAT|O_TRUNC,0666 ); 40: if( to_fd == -1 ) 41: { 42: perror( to_name ); 43: exit( 1 ); 44: } 45: while( (rcount=read(from_fd,buff,BUFFSIZE)) > 0 ) 46: { 47: if( (wcount=write(to_fd,buff,rcount))!= rcount ) 48: { 49: perror( to_name ); 50: exit( 1 ); 51: } 52: } 53: close( from_fd ); 54: close( to_fd ); 55: } ---------------------------------------------------------------------- >>>
open()は、ファイルを開くシステム・コールである。O_RDONLYとは、 読み込み専用でファイルを開くことを意味している。open() システム・コー ルは、結果としてファイル記述子を返す。ファイル記述子は、負でない小さな 整数(だいたい0〜128の範囲)である。ファイル記述子は、read()システ ム・コールやwrite()システム・コールで実際にファイルを読み書きする時に 使われる。
エラーが起きた時には、open() システム・コールは、-1 を返す。この時、エ ラーの番号が errno という変数に格納される。perror() は、errno変数を解 析して、より詳しいエラー・メッセージを表示する関数である。perror() の 引数は、エラー・メッセージとともに表示される文字列である。
ここでは、出力用のファイルを開いている。O_WRONLYは、書き込み専用でファ イルを開くことを意味している。O_CREATは、ファイルが存在しなければ作る ように指示するものである。ファイルが存在する場合、上書きされる。 O_TRUNCは、ファイルが存在している時には、その大きさを0にすることを指 示するものである。0666 (C言語で0から始まる数は、8進数)は、ファイルを 作る時のモードである。この数値に従って、ファイルのモード(ls -l で rwxrwxrwx と表示される部分)が決定される。作成されるファイルのモードは、 ここで指定されたモードから現在の umask が落とされた(引かれた)値とな る。
read() システム・コールは、第1引数で指定されたファイル記述子のファイ ルを読み込み、それを第2引数の番地へ保存する。読み込むバイト数は、第3 引数で与えられる。結果として読み込んだバイト数を返す。通常は、BUFFSIZE が返される。read() システム・コールの結果、ファイル上の読み書きする位 置が、実際に読み込んだバイト数だけずれる。ファイルの末尾近くや、ファイ ルが端末の時、BUFFSIZE 以下の値が返される。ファイルの末尾に行き着くと 0 が返される。エラーが起きると、-1 が返される。
write() システム・コールは、第1引数で指定されたファイル記述子のファイ ルへデータを書き込む。書き込まれるデータは、第2引数で与えられた番地か ら、第3引数で与えらた大きさである。write() システム・コールは、結果と して書き込んだバイト数を返す。ファイル上の読み書きする位置が、実際に読 み込んだバイト数だけずれる。通常は、BUFFSIZE が返される。空き容量不足 などで書き込みが失敗した時には、-1 を返す。エラーが起きると、-1 が返さ れる。
close() は、ファイルを閉じるシステム・コールである。このシステム・コールを実行してしまうと、そのファイル記述子は無効になる。すなわち、read() や write() を行うと、エラーになる。
---------------------------------------------------------------------- % mkdir file% cd file
% cp ~yas/syspro1/file/file-copy.c .
% make file-copy
cc file-copy.c -o file-copy % ls
file-copy file-copy.c % ./file-copy file-copy.c aaa
% ls
aaa file-copy file-copy.c % diff aaa file-copy.c
% ls -l aaa file-copy.c
-rw-r--r-- 1 yas lab 1086 4月 27日 23時50分 aaa -rw-r--r-- 1 yas lab 1086 4月 27日 23時50分 file-copy.c %
----------------------------------------------------------------------
---------------------------------------------------------------------- % man open open(2) open(2) NAME open - open for reading or writing C SYNOPSIS #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *path, int oflag, ... /* mode_t mode */); DESCRIPTION path points to a path name naming a file. open opens a file descriptor for the named file and sets the file status flags according to the value of oflag. oflag values are constructed by OR-ing Flags from the following list (only one of the first three flags below may be used): O_RDONLY Open for reading only. O_WRONLY Open for writing only. O_RDWR Open for reading and writing. ... O_CREAT If the file exists, this flag has no effect, except as noted under O_EXCL below. Otherwise, the file is created and the owner ID of the file is set to the effective user IDs of the process, the group ID of the file is set to the effective group IDs of the process or to the group ID of the directory in which the file is being created. This is determined as follows: ... O_TRUNC If the file exists, its length is truncated to 0 and the mode and owner are unchanged. O_TRUNC has no effect on special files or directories. ... The named file is opened unless one or more of the following are true: EACCES The file does not exist and write permission is denied by the parent directory of the file to be created. EACCES O_CREAT or O_TRUNC is specified and write permission is denied. ... SEE ALSO chmod(2), close(2), creat(2), dup(2), exec(2), fcntl(2), getdtablesize(2), getmsg(2), getrlimit(2), intro(2), lseek(2), putmsg(2), read(2), stat(2), stat(5), umask(2), write(2) DIAGNOSTICS Upon successful completion, the file descriptor is returned. Otherwise, a value of -1 is returned and errno is set to indicate the error. ----------------------------------------------------------------------マニュアルの読み方参照。
---------------------------------------------------------------------- 1: /* 2: fd-print.c -- ファイル記述子を表示するプログラム 3: ~yas/syspro1/file/fd-print.c 4: $Header: /home/lab2/OS/yas/syspro1/file/RCS/fd-print.c,v 1.2 1998/04/27 16:25:12 yas Exp $ 5: Start: 1997/04/21 18:23:13 6: */ 7: 8: #include <fcntl.h> 9: 10: void main( int argc, char *argv[] ) 11: { 12: int i ; 13: int fd ; 14: for( i=1 ; i<argc ; i++ ) 15: { 16: fd = open( argv[i],O_RDONLY ); 17: printf("%s: %d\n",argv[i],fd ); 18: } 19: } ----------------------------------------------------------------------
---------------------------------------------------------------------- % ./fd-print fd-print.cfd-print.c: 3 % ./fd-print fd-print.c /etc/passwd fd-print.c
fd-print.c: 3 /etc/passwd: 4 fd-print.c: 5 %
----------------------------------------------------------------------
プログラムが実行される時、open() システム・コールを使わなくても、次の 3つのファイル記述子は使える状態になっている。
stdio-thru.cは、標準入力で指定されたファイルの内容を標準出力で指定され たファイルへコピーするプログラムである。
---------------------------------------------------------------------- 1: 2: /* 3: stdio-thru.c -- 標準入力から標準出力へのコピー 4: ~yas/syspro1/file/stdio-thru.c 5: $Header: stdio-thru.c,v 1.2 97/04/21 23:33:05 yas Exp $ 6: Start: 1995/03/04 16:40:24 7: */ 8: 9: #include <stdio.h> /* stderr */ 10: 11: extern void stdio_thru(void); 12: 13: main( int argc, char *argv[] ) 14: { 15: if( argc != 1 ) 16: { 17: fprintf( stderr,"Usage: %s\n", argv[0] ); 18: exit( 1 ); 19: } 20: stdio_thru(); 21: } 22: 23: #define BUFFSIZE 1024 24: 25: void stdio_thru() 26: { 27: char buff[BUFFSIZE] ; 28: int rcount ; 29: int wcount ; 30: 31: while( (rcount=read(0,buff,BUFFSIZE)) > 0 ) 32: { 33: if( (wcount=write(1,buff,rcount))!= rcount ) 34: { 35: perror("stdout"); 36: exit( 1 ); 37: } 38: } 39: close( 0 ); 40: close( 1 ); 41: } ----------------------------------------------------------------------このプログラムは、引数をとらない。"<" や ">" は、シェルにより解釈され、 このプログラムには渡されない。
file_copy() とは異なり、stdio_thru() では、ファイルを開く操作(open()) を行うことなく、入出力(read(),write)を行っている。このような事が可能 な理由は、UNIXでは、ファイル記述子 0, 1, 2 は、シェルにより既に開 かれているからである。
---------------------------------------------------------------------- % ./stdio-thruljd
ljd sk
sk ^D % ls bbb
bbb not found % ./stdio-thru < file-copy.c > bbb
% ls -l file-copy.c bbb
-rw-r--r-- 1 yas lab 1086 4月 28日 01時29分 bbb -rw-r--r-- 1 yas lab 1086 4月 27日 23時35分 file-copy.c % diff file-copy.c bbb
%
----------------------------------------------------------------------
file-copy.c, stdio-thru.c の2つのプログラムを参考にして、UNIX の tee プログラムと同じような機能をもつプログラムを作りなさい。プログラムの名 前は、tee ではなく、別の名前(mytee) としなさい。tee の場合、標準の tee が動いているのか、自分で作った tee が動いているのか区別がつかない。 ただし、出力するファイルは、一つでもよい。 -i オプションや -a オプションには対応しなくてもよい。
mytee は、次のようにして、標準入力を標準出力にコピーしながら、同時にファ イルにも保存するものである。
この結果として、画面には、次のように grep コマンドを実行した時と同じ結果が表示される。% grep pattern file1 | ./mytee result![]()
% grep pattern file1![]()
同時に、ファイル reult には、画面に出力された結果とまったく同じものが 保存される。
tee コマンドの名前は、アルファベットの「T」に由来する。図形的に考えれ ば、動きを理解することができる。tee コマンドは、左(パイプラインで標準 入力)から入ったデータを下(引数で与えられたファイル)に保存しながら、 右(標準出力)にも出力する。tee コマンドは、時間のかかる処理の結果や、 後で参照したい中間結果をファイルに保存するために利用される。次の例は、 makeコマンドの実行結果を make.out へ保存すると同時に、それを user にメー ルで送るものである。
% make |& tee make.out | mailx -s make result user''
これにより、user は、メールが届いたことで、make コマンドの実行終了を知 ることができる。同時に、作業していたディレクトリでその結果を参照するこ とができる。
この課題では、入出力には、システムコールを使いなさい。
UNIXの cat コマンドと同様の動きをするプログラムを作りなさい。このプロ グラムの名前を mycat とする。引数として、なにも与えられなかった時には、 標準入力を標準出力にコピーしなさい。また、引数として "-" が指定された 時には、その位置で標準入力を標準出力にコピーしなさい。たとえば、次のよ うな場合、file1 とfile2 の内容の間に、標準入力の内容をコピーしなさい。
% mycat file1 - file2![]()
この課題では、入出力には、システムコールを使いなさい。