티스토리 뷰

728x90

 안녕하세요! 오늘은 리눅스에서 중요한 개념인 시스템콜(system call) 관련된 예제를 실습해보겠습니다.

 시스템 콜에 대해 아주 간단하게 개념을 한번 보고 예제 시작하겠습니다~!

시스템콜이란 ?

어플리케이션이 커널에 있는 기능들을 사용할 때 system call이 일어납니다.

  • 커널
    •  리눅스 운영체제에서 프로세스 및 애플리케이션 간의 CPU, RAM 공유할 수 있도록 관리해주는 시스템
    • 주변 기기 관리
    • 어플리케이션으로 부터 시스템콜 처리
    • 컴퓨터가 켜졌을 경우 disk로부터 바로 로딩

 리눅스는 User Space, Kernel Space 이렇게 두개로 나뉘어져있습니다. 이때 User Space에서 Kernel Space까지 가서 함수를 불러오는 것이 시스템콜입니다!

 우리 보통 C언어에서 #include <stdio.h>하잖아요? 이때는 User Space에 있는 Libraries로부터 함수를 불러오는 것이랍니다. 따라서 C언어의 (ex printf)와 같은 함수는 Function Call이라 부릅니다. function call은 User Space 안에서도 충분히 처리 가능하지만 system call은 user space뿐만 아니라 kernel space까지 내려가야한다는 점을 기억해주세요!!


자 그럼 바로 System Call 에 대해서 자세히 봅시다. 모든 리눅스 명령어는 man 명령어를 통해 매뉴얼을 볼 수 있습니다. 

man syscalls

 밑으로 내려가면 시스템 콜 함수에 대해서도 확인할 수 있습니다. q를 눌러서 빠져나와봅시다!!

 unistd.h 파일도 한번 둘러봅시다. unistd.h파일은 POSIX 운영체제 API에 대한 액세스 관련 정보를 제공하는 헤더파일입니다. 이곳에서 system call을 어떻게 사용하는지 확인할 수 있습니다.

 system call에서 에러 처리도 한번 다뤄볼게요! 시스템 콜은 시스템 콜이 성공했는지 실패했는지 알려주기 위해 status value를 리턴합니다. 만약 system call이 -1을 리턴한다면 에러가 발생했다는 뜻입니다. errno.h 파일에 가면 에러코드에 대한 설명이 나와있으니 한번 확인해보세요!

sudo vi /usr/include/asm-generic/errno-base.h

1. getpid()를 통해 자신의 프로세스 번호를 출력하는 프로그램

 첫번째 예제는 system call의 한 종류인 getpid()를 이용해서 자신의 프로세스 번호를 출력하는 프로그램을 C언어로 작성해보겠습니다! 

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(){
	pid_t my_pid;
    pid_t my_ppid;
    
    my_pid=getpid();
    my_ppid=getppid();
    
    printf("pid: %d, ppid: %d",my_pid,my_ppid);
    return 0;
}

2. open 프로그램 작성 [open, perror 활용]

열고자 하는 파일을 인자로 받아 시스템 콜을 활용해 여는 프로그램을 만들어봅시다.

 open(2)함수를 O_RDONLY 플래그로 지정하여 파일 디스크립터를 얻습니다. open(2)에 에러가 발생하면 perror(3)을 이용해 standard error로 메시지를 출력합니다! 만약 open(2)가 성공했을 경우에도 standard output으로 메시지를 출력합니다.

* open(2)->system call 2번을 의미합니다.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc,char *argv[]){
	//parameter가 2개(open,filename)이 아닌경우 에러처리
	if(argc != 2){
		printf("usage: opentest filename\n");
		exit(0);
	}
    
    //입력받은 parameter 출력
	printf("first parameter: %s",argv[0]);
	printf("second parameter: %s",argv[1]);
    
    //open() 함수
	int fd; //file descriptor
	fd=open(argv[1],O_RDONLY); //open(filename,flags,mode)
    
	if(fd==-1){ //open error
		perror("first open: ");
		exit(0);
	}else {
		printf("file %s open success\\n",argv[1]);
	}
    
	close(fd);
	return 0;
}
  • argc → 파라미터 개수 
  • argv → 파라미터들, 문자열이 들어있는 포인터들에 대한 배열

 위의 코드에서 사용된 시스템 콜은 총 두개입니다. open(),close()와() perror입니다! perror는 오류 메세지를 출력하는 시스템콜이고 open은 파일을 읽거나 쓰기 위해 여는 시스템 콜입니다. open() 함수는 성공적으로 실행된다면 file descriptor 를 반환하고 실패했을 경우 -1을 반환합니다. 따라서 -1을 반환했을 경우 오류가 발생했다고 인지해서 if 조건문을 통해 오류 처리를 합니다. 만약 open()함수가 제대로 실행 됐을 경우에는 file [filename] open success가 출력됩니다. 

 

 - open 함수 flags

  • O_RDONLY : 읽기만을 허용
  • O_WRONLY : 쓰기만을 허용
  • O_RDWR: 읽고 쓰는 것을 허용
  • O_APPEND: 파일의 기존 내용을 이어서 확장
  • O_CREAT : 파일이 존재하지 않을 때, 파일을 생성
  • O_EXCL : 기존에 파일이 없을 경우 파일을 생성, 파일이 있을 경우 오류 메시지 출력
  • O_TRUNC : 파일을 생성할 때 이미 있는 파일이고, 쓰기 옵션으로 열었으면 내용을 모두 지우고 파일의 길이를 0으로 변경
  • O_SYNC : 파일에 쓸 경우 보통 버퍼에 먼저 쓰고 디스크에 옮기지만 O_SYNC의 경우 디스크에 먼저 쓰고 리턴

- open 함수 mode

좌측 그림은 open 함수 mode에 관련된 내용입니다.

ex) open(~,~,S_IRUSR|S_IWUSR)일 경우 -> 유저가 쓰고 읽을 수 있다.

ex) open (~,~,0644) = open(~,~,S _IRUSR | S _IWUSR | S IRGRP | S _IROTH

-> 사용자에게 읽기와 쓰기  권한을 모두 주기 위해 S_IRUSR 과 S_IWUSR 을 설정할 경우 0400+0200이므로 0600으로 쓰면 됩니다! (나머지 그룹과 다른 사용자 모드도 유사한 방식으로 계산)

728x90
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함