Presentation is loading. Please wait.

Presentation is loading. Please wait.

Linux System Programming

Similar presentations


Presentation on theme: "Linux System Programming"— Presentation transcript:

1 Linux System Programming
Lecture #2 – 입출력 시스템 호출

2 파일 시스템의 내부 구조 (1) 파일 시스템 배치: 1 2 n+2 부트스트랩 블록 슈퍼 블록 inode 블록들(n 개)
데이터 블록들 inode 블록들(n 개) 슈퍼 블록 부트스트랩 블록 LINUX 로드를 이한 하드웨어 지정부트 프로그램 포함 1 파일 시스템에 대한 중요한 정보들을 저장하고 있다 파일시스템의 총 크기, inode 블록의 크기, 갱신날짜 가용 자료 블록 번호들에 대한 체인을 저장한 목록 가용 inode 블록 번호들에 대한 체인을 저장한 목록 2 n+2

3 파일 시스템의 내부 구조 (2) 슈퍼 블록의 필드 구성: 커널은 수퍼블록 내용 변경을 주기적으로 디스크에 저장
파일 시스템의 전체 크기 파일 시스템 내의 사용 가능한 자유 블록의 수 파일 시스템 내에서 사용 가능한 자유 블록의 리스트 inode 리스트의 크기 파일 시스템 내의 사용 가능한 자유 inode의 수 파일 시스템 내의 사용 가능한 자유 inode의 리스트 자유 inode 리스트의 다음 자유 inode의 인덱스 자유 블록 리스트와 자유 inode 리스트를 위한 잠금 필드들 커널은 수퍼블록 내용 변경을 주기적으로 디스크에 저장

4 파일 시스템의 내부 구조 (3) inode 블록 Inode 테이블을 저장하는 공간 디스크 inode의 필드 구성 :
파일 소유자 식별자 파일의 유형 파일 접근 허가 파일 접근 시간 파일에 대한 링크 수 파일 데이터의 디스크 주소 목록 파일 크기

5 파일 시스템의 내부 구조 (4) 데이터 블록 사용자 파일을 저장하는 공간 파일을 블록 단위로 저장
블록의 크기 – 보통 1024 바이트 1500 바이트의 파일을 저장할 때에 2개의 디스크 블록을 할당 하나의 파일을 저장하는 디스크 블록 목록은 해당 파일의 inode에 저장

6 파일의 내부 표현 (1) 파일의 내부 표현 : inode 파일의 내부적 표현은 inode(index node)에 의해 표현
파일 소유자 식별자 파일의 유형 파일 접근 허가 파일 접근 시간 파일에 대한 링크 수 파일 데이터의 디스크 주소 목록 파일 크기 하나의 파일은 여러 개의 이름을 가질 수 있고, 그 모든 이름들은 하나의 inode에 매핑되며 이를 link라고 함

7 파일의 내부 표현 (2) 파일의 내부 표현 : inode
파일 접근과 관련된 커널 데이터 구조: inode 테이블 – 파일에 대한 빠른 접근을 위해 파일시스테을 마운트할 때에 inode table을 커널 공간으로 로딩 파일 테이블 – 참조되고 있는 모든 파일을 관리하기 위해 전역적으로 정의한 테이블 사용자 파일티스크립터 테이블 – 하나의 프로세스가 참조하는 파일을 관린하기 위해 프로세스마다 할당하는 테이블

8 파일의 내부 표현 (3) 파일 참조 관련 테이블 : 사용자 파일 디스크립터 테이블 파일 테이블 inode 테이블
파일 테이블 인덱스 indoe 번호 inode 사용자 파일 디스크립터 테이블 파일 테이블 inode 테이블

9 파일 열기 (1) 파일 열기 : open

10 파일 열기 (2)

11 파일 열기 (3) 파일 열기 후의 자료 구조 변화 fd1=open("/etc/passwd",O_RDONLY);
fd2=open("local",O_WRONLY); fd3=open("/etc/passwd",O_RDWR); 파일 열기 시스템 호출(open)이 실행되면 현재 파일 디스크립터 테이블에서 비어있는 인덱스 중에서 가장 작은 인덱스를 할당한다 파일 열기 후의 자료 구조 변화

12 파일 열기 (4) 표준 입출력 파일 하나의 프로세스가 생성되면 다음 세 개의 파일에 대해 자동적으로 열기를 수행한 후에 참조가 가능 표준 입력 파일 – keyboard 장치를 의미 표준 출력 파일 – console 장치를 의미 표준 에러 파일 – console 장치를 의미 파일 디스크립터 테이블의 첫번째 항목에서 세번째 항목까지는 표준 입출력 파일에 대한 파일 디스크립터를 저장 file descriptor 0 – 표준 입력 파일 file descriptor 1 – 표준 출력 파일 file descriptor 2 – 표준 에러 파일

13 파일 열기 (4) 파일 열기 예 : open 읽기(read)를 위한 파일 열기:  acctfd = open(account, O_RDONLY); 쓰기(write) 위한 파일 열기:  file = TMPFILE; fd   = open(file, O_WRONLY | O_CREAT| O_TRUNC, 0600); 추가(append)를 위한 파일 열기: logfd = open("/sys/log", O_WRONLY | O_APPEND | O_CREAT, 0600);

14 파일 열기 (5) 파일 열기 예 : open 읽기 및 쓰기를 위한 파일 열기 fdin = open(argv[1], O_RDWR); 쓰기 위한 새로운 파일 열기: 파일이 없으면 생성하고, 존재하면 비정상 종료한다. if((fdout = open(TMPFILE, O_WRONLY | O_CREAT | O_EXCL, 0666)) == -1) perror(TMPFILE);

15 파일 닫기 (1) 파일 닫기 : close

16 파일 닫기 (2) 파일 닫기 : close 커널은 파일 디스크립터와 해당되는 파일 테이블과 inode 테이블을 조작함으로써 close 작업을 한다. 파일 테이블 항의 참조 계수가 dup나 fork에 의해 1 이상이면 다른 사용자 파일 디스크립터가 그 파일 테이블 항을 참조하고 있는 것이다. 이때 커널은 참조 계수를 하나 감소시키고 close를 끝낸다. 파일 테이블 참조 계수가 1이면 커널은 그 항을 자유화하고 원래의 open 시스템 호출에서 할당된 inode를 방출한다.

17 파일 닫기 (3) 파일 닫기 : close 만약 다른 프로세스가 그 inode를 아직도 참조하고 있으면 커널은 그 inode 참조 계수를 하나 감소시키기만 한다. 그렇지 않으면 참조계수가 0이 되기 때문에 inode를 자유화한다. close 시스템 호출이 완료되면 사용자 파일 디스크립터 테이블은 비게 된다. 그 파일 디스크립터를 사용하려는 시도는 그 파일 디스크립터가 다른 시스템 호출로 다시 할당되기까지는 에러를 유발할 것이다. 프로세스가 exit할 때 커널은 활성 사용자 파일 디스크립터를 검사하여 내부적으로 모두 close한다. 그러므로 한 프로세스가 종료한 후에는 파일을 연(open) 채로 둘 수 없다.

18 파일 읽기 파일 읽기 : read

19 파일 쓰기 파일 쓰기 : write

20 예제 프로그램 (1) 예제 2-1: 표준 입력 파일(키보드)에서 데이터를 읽어 표준 출력 파일(화면)로 출력하는 것이다.
파일 디스크립터 0은 표준 입력, 1은 표준 출력을 의미한다. 일반적으로 표준 입출력 파일은 프로그램 수행 전에 열려(open) 있고, 터미널의 입출력 장치인 키보드와 화면(display)과 연관되어 있다. 프로그램 수행 시에 방향 키(< 혹은 >)를 이용하여 표준 입출력을 재지정(redirection)할 수 있다.

21 예제 프로그램 (2) #include <stdio.h> 2 main() {
 2  main()  { char buf[BUFSIZ]; //표준 입력 파일에서 읽은 문자를 저장할 // 버퍼를 선언하며, BUFSIZ은 버퍼의크기를 // 나타내며 시스템의 헤더 파일 stdio.h에 // 이미 정의되어 있다. /* n은 read 함수 반환값인 입력 문자수를 저장할 변수 */  6       int n;      /*표준 입력 파일에서 읽은 문자의 수가 0보다 클 동안 읽어 표준 출력에 출력한다. */  8       while((n= read(0, buf,BUFSIZ)) > 0)  9           write(1, buf, n); 10       exit(0); }

22 예제 프로그램 (3) 예제 2-2 : cp #include <stdio.h>
#include <fcntl.h> #define PMODE 0644 main(argc,argv) int argc; char *argv[]; { int fdin, fdout, n; char buf[BUFSIZ]; if(argc !=3) { fprintf(stderr, "Usage: %s filein fileout\n",argv[0]); exit(1); }

23 예제 프로그램 (4) if((fdin = open(argv[1],O_RDONLY)) == -1) {
perror(argv[1]); exit(2); } if((fdout = open(argv[2],O_WRONLY | O_CREAT | O_TRUNC, PMODE)) == -1) { perror(argv[2]); exit(3); while((n = read(fdin, buf, BUFSIZ)) > 0) write(fdout,buf, n); exit(0);

24 파일의 임의 접근 (1) 파일의 임의 접근 : lseek

25 파일의 임의 접근 (2) 파일의 임의 접근 : lseek

26 파일의 임의 접근 (3) 파일의 임의 접근 : lseek
rewind - 파일의 처음으로 read/write position을 설정한다. lseek (fd, 0L, 0); append - 파일의 끝으로 read/write position을 설정한다. lseek (fd, 0L, 2); update - 현재 위치의 데이터를 수정한다. read (fd, (char *) &record, sizeof (record)); /* update */ lseek (fd, (long) -sizeof (record), 1); write (fd, (char *) &record, sizeof (record));

27 파일의 임의 접근 (4) 파일의 임의 접근 : lseek
record position - 현재 read/write할 파일의 위치를 얻는다. loc = lseek (fd, 0L, 1); increase file - 기록할 레코드의 크기만큼 파일의 크기가 증가한다. lseek (fd, (long) MAX * sizeof(record), 2); write (fd, (char *) &record, sizeof (record));

28 예제 프로그램 (1) 예제 2-3 : 사원 관리를 위한 파일을 생성하는 프로그램을 작성하라. 사원 개인의 레코드 구조는 아래와 같다.   #define  NAMESIZE 24   struct employee {                 /* 레코드의 type을 employee로 한다    */          char name [NAMESIZE];   /* 레코드의 첫번째 필드에 이름을 저장  */          int salary ;               /* 레코드의 두번째 필드에 급여를 저장  */          int pid ;                  /* 레코드에 프로세스 ID(6장 참조) 저장  */   };

29 예제 프로그램 (2) /* Header file: ex2-3.h */ #define NAMESIZE 24
struct employee { char name[NAMESIZE]; int salary; int pid; };

30 예제 프로그램 (3) #include <fcntl.h> #include <stdio.h>
#include "ex2-3.h" main(argc,argv) int argc; char *argv[]; { int fd, open(), getpid(); struct employee record; if(argc < 2) { fprintf(stderr,"Usage: %s file\n",argv[0]); exit(1); }

31 예제 프로그램 (4) if((fd= open(argv[1],O_WRONLY | O_CREAT | O_EXCL, 0640))== -1) { perror(argv[1]); exit(2); } for(;;) { printf("Enter employee name <SPACE> salary: "); scanf("%s",record.name); if(record.name[0] == '.') break; scanf("%d",&record.salary); record.pid= getpid(); write(fd,(char *)&record, sizeof(record)); close(fd); exit(0);

32 예제 프로그램 (5) 예제 2-4 : 생성한 employeefile에서 lseek 함수를 이용하여 레코드 번호를 입력받아 해당 레코드를 출력하는 프로그램을 작성하라. 레코드 번호가 음수이면 프로그램을 종료한다.

33 예제 프로그램 (6) #include <fcntl.h> #include "ex2-3.h"
main(argc,argv) int argc; char *argv[]; { int fd, recnum; struct employee record; if(argc < 2) { printf("Usage: %s file\n",argv[0]); exit(1); } if((fd= open(argv[1],O_RDONLY))== -1) { perror(argv[1]); exit(2);

34 예제 프로그램 (7) for(;;) { printf("Enter record number: ");
scanf("%d", &recnum); if(recnum < 0) break; lseek(fd, (long) recnum*sizeof(record),0); if(read(fd,(char *) &record, sizeof(record))>0) printf("Employee: %s\tSalary: %d\n", record.name, record.salary); else printf("Record %d not found\n",recnum); } close(fd); exit(0);

35 예제 프로그램 (8) 예제 2-5 : 텍스트 파일을 읽어들여 lookup 테이블을 만들고 라인 번호를 입력으로 받아 해당 라인을 출력시키는 프로그램을 lseek 함수를 이용하여 작성하라. 라인 번호가 0보다 작으면 종료하며, lookup 테이블의 구조는 다음과 같다. static struct {        long offset;  /* 파일 내의 라인 offset을 저장한다 */        int  len;     /* 라인의 길이를 저장한다          */     } table [TABSIZE];

36 예제 프로그램 (9) #include <fcntl.h> #define TABSIZE 100
#define BUFSIZE 512 main(int argc, char *argv[]) { int n, i, entry, len; int fd, open(); long offset; static struct { int len; } table[TABSIZE]; char buf[BUFSIZE];

37 예제 프로그램 (10) if((fd = open(argv[1], O_RDONLY)) == -1) {
perror(argv[1]); exit(1); } /* build look up table */ entry = 0; offset = 0; while((n = read(fd, buf, BUFSIZE)) > 0) { for(i=0; i < n; i++) { /* line length include '\n' */ table[entry].len++; offset++; if(buf[i] == '\n') table[++entry].offset = offset;

38 예제 프로그램 (11) #ifdef DEBUG for(i=0; i < entry; i++)
printf("%d: %ld, %d\n", i+1, table[i].offset, table[i].len); #endif for(;;) { printf("Enter line number: "); scanf("%d",&n); if(--n < 0) break; lseek(fd, table[n].offset, 0); if(read(fd, buf, table[n].len) <= 0) continue; buf[table[n].len] = '\0'; printf("%s", buf); } close(fd); exit(0);

39 파일 디스크립터 복사 (1) 파일 디스크립터 복사 : dup

40 파일 디스크립터 복사 (2) 파일 디스크립터 복사 : dup
그림 2-4는 프로세스가 다음과 같은 순서로 시스템 호출을 수행한 결과를 보여준다. “/etc/passwd”를 열고(파일 디스크립터 3), 다시 “/etc/passwd”를 열고(파일 디스크립터 4), 그리고 “local”을 열고(파일 디스크립터 5), 마지막으로 파일 디스크립터 3을 dup하면 파일 디스크립터 6이 반환된다.

41 파일 디스크립터 복사 (3) 파일 디스크립터 복사 : dup

42 예제 프로그램 (1) 예제 2-6 : 표준 출력 파일 디스크립터(파일 디스크립터 1)를 닫고 dup로 화일 디스크립터를 복사한 후에 그것을 표준 출력 파일로 사용하여 표준 출력의 방향을 바꾸는 프로그램을 작성하라.

43 예제 프로그램 (2) #include <fcntl.h> #include <stdio.h>
main(int argc,char *argv[]) { close(1); if(open(argv[1],O_WRONLY | O_CREAT | O_TRUNC, 0644) == -1) { perror(argv[1]); exit(1); } close(2); if(dup(1) == -1) { perror(argv[0]); exit(2); printf("first line to stdout (uses fd 1)\n"); fprintf(stderr,"first line to stderr (uses fd 2)\n"); printf("second line to stdout\n"); fprintf(stderr,"second line to stderr\n");

44 파일의 제어 (1) 파일의 제어 : fcntl

45 파일의 제어 (2) fcntl 함수 명령어(cmd)의 기능 :

46 파일의 제어 (3) fcntl 함수의 반환 값 :

47 예제 프로그램 (1) 예제 2-7 : 프로그램 2-3에서 이미 작성된 employee 파일의 끝에 새로운 레코드를 입력받아 추가하는 프로그램을 fcntl 함수를 이용하여 작성하라. 입력이 “.”이면 프로그램을 종료하도록 한다.

48 예제 프로그램 (2) #include <fcntl.h> #include "ex2-3.h"
#define DUMMY 0 main(argc,argv) int argc; char *argv[]; { int fd, open(), getpid(), flags, fcntl(),pid; struct employee record; if(argc < 2) { printf("Usage: %s file\n",argv[0]); exit(1); } if((fd= open(argv[1],O_RDWR))== -1) { perror(argv[1]); exit(2); if((flags=fcntl(fd,F_GETFL, DUMMY)) == -1) { exit(3);

49 예제 프로그램 (3) flags |= O_APPEND; fcntl(fd, F_SETFL, flags);
pid = getpid(); for(;;) { printf("Enter employee name : "); scanf("%s",&record.name); if(record.name[0] == '.') break; printf("Enter employee salary: "); scanf("%d",&record.salary); record.pid= pid; write(fd,(char *) &record, sizeof(record)); } close(fd);

50 예제 프로그램 (4) 예제 2-8 : 터미널 장치 파일로부터 5초 이내에 응답이 들어오면 프로그램을 계속 수행하고 그렇지 않으면 종료하는 프로그램을 fcntl 함수와 O_NDELAY 플래그(표 2-1 참조)를 이용하여 프로그램을 작성하라. 단, 5초간 입력을 기다릴 때는 sleep(5) 함수를 이용한다.

51 예제 프로그램 (5) #include <stdio.h> #include <string.h>
#include <fcntl.h> main() { int fd, flags, open(), fcntl(); int i, n; char line[BUFSIZ]; if((fd = open("/dev/tty",O_RDONLY | O_NDELAY))== -1) { perror("/dev/tty"); exit(2); } printf("Enter your PIN within five seconds:\n"); sleep(5);

52 예제 프로그램 (6) if(read(fd,line,BUFSIZ) == 0) {
printf("\n ====> Sorry.\n"); exit(1); } flags = fcntl(fd,F_GETFL,0); flags &= ~O_NDELAY; /* turn off delay flags */ fcntl(fd,F_SETFL,flags); printf("Enter your bank account number:\n"); read(fd,line, BUFSIZ); i = strlen(line); line[i++] = '\0'; printf("%s\n",line);


Download ppt "Linux System Programming"

Similar presentations


Ads by Google