// 코드를 작성하는 도중에 필요한 API가 있으면 man 페이지를 참고하여 헤더 파일을 추가하면 된다. 그러나 필요한 헤더 파일을 include 하는 것을 잊어도, gcc에 -Wall 옵션을 붙여서 실행하면 적절하게 경고해준다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stst.h>
#include <fcntl.h>

static void do_cat(const char *path);
static void die(const char *s);

int
main(int argc,char *argv[])
{
    int i;
    if(argv<2){
        // fprintf()는 printf()와 비슷한 기능을 가진 함수다.
        fprintf(stderr,"%s: file name not given\n",argv[0]);
        exit(1);
    }
    for(i=1;i<argc;i++){
        do_cat(argv[i]);
    }
    exit(0);
}

#define BUFFER_SIZE 2048

static void do_cat(const char *path)
{
    int fd;
    unsigned char buf[BUFFER_SIZE];
    int n;
    
    // O_RDONLY, 읽기 전용으로 파일을 열었다.
    fd=open(path,O_RDONLY);
    if(fd<0) die(path);
    // 무한루프. while(1)과 같다.
    for(;;){
        // fd로 지정한 스트림에서 바이트 열을 읽어서 buf에 담는다. 읽어들이는 크기는 최대 sizeof buf, 즉 배열 buf의 크기만큼이다. 배열 buf의 크기는 BUFFER_SIZE로 2048이라고 코드의 윗부분에 정의했다. 따라서 sizeof buf 대신에 BUFFER_SIZE를 사용해도 무관하다.
        n=read(fd,buf,sizeof buf);
        // 파일 처리에 있어서 에러가 발생하면 종료한다.
        if(n<0) die(path);
        // 읽은 바이트 수가 0, 즉 파일의 끝에 도달하여 더 읽어 들일 바이트가 없는지 확인하고 없다면 break, 즉 파일의 끝까지 읽었을 때 종료된다.
        if(n==0) break;
        // STDOUT_FILENO 는 표준 출력이다. 여기서는 n바이트 즉, read()로 읽어들인 바이트 수만큼 쓰고 있다. read()가 언제나 버퍼 크기 가득 읽어들이는 것은 아니다. 예를 들어 길이가 2050인 파일이라면 먼저 2048바이트만 읽고 그다음에는 2바이트만 읽는다. 또한 스트림이 파이프에 연결된 경우에는 읽어들이는 크기가 매번 달라진다.
        if(write(STDOUT_FILENO,buf,n)<0) die(path);
    }
    // 파일을 닫는 동시에 파일이 정상적으로 닫혔는지 확인하기 위해 if문을 사용하고 있다.
    int status=close(fd);
    if(status<0) die(path);
}

static void
die(const char *s)
{
    // perror()은 라이브러리 함수다.
    perror(s);
    exit(1);
}

 

 

 

perror(3)

#include <stdion.h>

void perror(const char *s);

perror() 함수는 errno 값에 해당하는 에러 메시지를 표준 에러 출력에 출력한다. 또한, 문자열 s가 빈 문자열이 아닌 경우에는 s의 내용을 출력하고 이어서 에러 메시지를 출력한다. 위 예에서는 open() 함수로 열려고 했던 파일의 경로를 출력하도록 했다.

 

우리가 작성한 cat 명령어에 에러를 발생시키도록 하여 어떠한 메시지가 출력되는지 살펴보자.

첫 번째 명령어는 존재하지 않는 파일을 실행시켜보았을 때의 예이고, 두 번째 명령어는 내용을 읽기가 가능한 파일이 아니라 디렉토리를 인자로 넣었을 때의 예이고, 세 번째 명령어는 읽기 권한이 없는 파일을 인자로 실행시켜보았을 때의 예이다.

 

strerror()

에러 처리는 perror() 이외에 strerror()라는 라이브러리 함수도 사용할 수 있다.

#include <string.h>

char *strerror(int errnum);

이 함수는 errno 값인 errnum에 해당하는 에러 메시지를 반환한다. strerror()의 반환값은 다시 함수를 호출할 때 덮어써지므로 보통 즉시 출력한다.

+ Recent posts