[Linux] SysCall

정재훈·2022년 4월 6일
0

Linux

목록 보기
10/19
post-thumbnail

시스템

시스템 개념

시스템 : 구성 요소들이 상호작용하는 집합체
컴퓨팅 시스템 : CPU, 기억장치, 입출력장치 등이 상호작용을 하는 집합체
임베디드 시스템 : 컴퓨팅 시스템 중, 전용기능(특정목적)을 수행하도록 만들어진 시스템

컴퓨팅 시스템 구성

  1. HW : CPU/메모리 + 페리퍼럴(주변장치) , 페리퍼럴 : CPU/메모리 외 모든 입출력장치 , SSD 저장장치도 페리퍼럴이다.
  2. SW :
    1) Application Level : App, Shell
    2) Middleware Level : API, Library
    3) Low Level : 리눅스 커널

API : APP Level에서 사용하는 함수, Library : API 모음집
시스템 콜 : 리눅스에서 APP이 커널의 기능을 쓸 수 있도록 만든 API , POSIX와 Therad Programming으로 개발

시스템 프로그래밍 : OS가 제공하는 API를 이용한 프로그래밍
시스템콜(syscall) : 리눅스에서의 시스템 프로그래밍
win32 API : 윈도우에서의 시스템 프로그래밍
펌웨어(F/W) : OS 없음

POSIX(포식스)

POSIX : Application 개발자들을 위해 OS마다 제공되는 API들이 하나로 통일된 API
여러 임베디드 OS에서도 편리하게 APP 개발 가능하다.

과거 VS 현재 임베디드 시스템

과거 : APP/OS/HW 모두 매번 새로 개발하여 제작하였습니다.
현재 : 기존에 만들어진 틀을 이용하여 Firmware와 HW만 새로 개발합니다.

System Call(Syscall :시스콜)

리눅스 APP이 리눅스 커널에게 어떤 부탁을 하기 위해 만들어진 API
High Level API(= Wrapper 함수) : printf, scanf, fopen() 등
Low Level API : open(), 시스콜

파일처리 API (시스콜,Low Level API)

리눅스에서는 모든 장치들을 파일로 관리합니다. 따라서, 파일을 어떻게 관리하는지 알면 장치들을 손쉽게 제어할 수 있습니다.

  1. open() : fopen이 사용하는 syscall , 파일 열기
  2. read() : fscanf가 사용하는 syscall , 파일 읽기 : 널 문자(\0)을 고려한다.
  3. write() : fprintf가 사용하는 syscall
  4. close() : fclose가 사용하는 syscall , 파일 닫기

vi에서 시스콜 메뉴얼 확인하기

사용할 syscall API에 커서를 두고 Shift + K를 입력합니다. 그러면 해당 API의 메뉴얼을 확인할 수 있습니다.

예를 들어, open()이라는 시스콜 API의 메뉴얼을 확인하면 다음과 같고, 더 많은 정보를 하단에서 찾아볼수 있습니다.

해당 메뉴얼에서 파라미터 값이나 특정 값들을 더 찾아보고 싶을 때에는 /[찾고자 하는 값]을 통해 검색을 하고 n(다음) N(이전)을 통해 추가로 검색합니다.

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

int main()
{
	// use syscall : open, read, close
	
    // fd : File Desciptor(정수형) => 하나의 프로그램이 파일에 접근하려고 할때, 부여되는 정수(번호)
    int fd = open("./test.txt", O_RDONLY, 0);  // 만약 fd가 음수면 error이다.
    
    // ERROR 처리에 대한 로그메세지를 꼭 남기자
    if(fd < 0)
    {
		printf("FILE OPEN ERROR\n");
        exit(1);  // 오류에 인한 종료
	}

    char buf[1000] = {0};
    read(fd,buf,1000-1); // consider a null char

    printf("%s",buf); // high level API

    close(fd);

    return 0;
}

open()의 메뉴얼

양식 : int open(path, flag, mode)
flag
필수옵션

  1. O_RDONLY - 읽기만 가능
  2. O_WRONLY - 쓰기만 가능
  3. O_RDWR - 읽기/쓰기 둘 다 가능, 읽기만 해도 되고 쓰기만 해도 됨

추가옵션 : 필수옵션 | 추가옵션 이렇게 사용한다. ex) O_RDONLY|O_CREAT

  1. O_CREAT : 없으면 새로 생성
  2. O_APPEND : 덧붙이기
  3. O_TRUNC : 파일 내용 제거 후 사용

mode
0777 : rwxrwxrwx
0644 : rw-r--r-- (보통 이거 씀)

#include <stdio.h>
// 메뉴얼 확인 : open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 메뉴얼 확인 : write(), close()
#include <unistd.h>
// 메뉴얼 확인 : exit()
#include <stdlib.h>
// 메뉴얼 확인 : strlen()
#include <string.h>

int main()
{
    int fd = open("./test.txt",O_WRONLY|O_TRUNC, 0664);
    if(fd <0) // 에러 로그 메세지
    {
        printf("OPEN FILE ERROR\n");
        exit(1);
    }


    char *buf = "HI SYSTEM CALL"; 

    write(fd, buf, strlen(buf)); // 해당 문자열을 파일에 적기

    printf("%s\n",buf);

    close(fd);



    return 0;
}

READ & WRITE

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

int main()
{
    int fd = open("./cal.txt", O_RDONLY, 0644); // 읽기전용

    char buf[1000] = { 0 }; 
    read(fd, buf, 1000); // 1값 읽기
    close(fd);

    int num = atoi(buf); // 불러온 문자 숫자로 바꾸기
    num *= 2;  // 2씩 곱하기
    printf("\n===[%d]===\n", num);
    sprintf(buf, "%d", num);

    fd = open("./cal.txt", O_WRONLY | O_TRUNC, 0644); // 기존에 적힌 문자 지우고 새로 쓰기
    write(fd, buf, strlen(buf));
    close(fd);

    return 0;
}

구조체 저장하기

파일에 구조체 저장하기

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

typedef struct Node // 구조체 정의
{
    int x,y,z;
}go;

int main()

{
    int fd = open("./test.txt", O_WRONLY|O_TRUNC,0644); // 쓰기 전용으로 열기
    if(fd < 0)
    {
        printf("ERROR OPEN FILE\n");
        exit(1);
    }

    go temp = {3,5,99}; // 구조체 초기화

    write(fd, &temp, sizeof(temp)); // 시작 주소와 길이 입력

    close(fd);

    return 0;
}

test.txt : binary 값으로 들어간다.

저장된 구조체 값 읽기

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

typedef struct Node  // 구조체 정의
{
    int x,y,z;
}go;


int main()
{

    int fd = open("./test.txt", O_RDONLY, 0664);
    if(fd < 0)
    {
        printf("ERROR OPEN FILE");
        exit(1);
    }

    go temp; // 구조체 선언

    read(fd,&temp,sizeof(temp)); // 구조체 읽기

    printf("%d %d %d\n", temp.x, temp.y, temp.z); // 구조체 나누어 출력 : 3 5 99

    close(fd);
    return 0;
}

lseek & offset

offset : 저장장치가 어디까지 읽었는지 내부적으로 동작한다. raed를 수행하면 offset값이 그 다음으로 이동한다.

lseek : 기준점에서 offset만큼 떨어져 있는 곳으로 offset을 옮기는 시스템 콜
lseek(fd, 기준으로 이동할 값, 기준) : 값은 음수도 가능하다.
기준 :

1. SEEK_CUR : 현재위치에서 부터
2. SEEK_SET : 시작점에서 부터
3. SEEK_END : 끝 지점에서 부터

다음 코드를 통해 완벽히 lseek와 offset을 이해해보자.

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


int main()
{
    int fd = open("./test.txt", O_RDONLY, 0); // 37byte의 값이 test.txt에 들어있다.
    if(fd < 0)
    {
        printf("ERROR FILE OPEN\n");
        exit(1);
    }

    char buf[11] = {0};
    int n;

    n = lseek(fd, 0, SEEK_CUR); // 현재 위치는 아무것도 읽지 않았으므로 0인 상태
    printf("%d\n",n); // 0

    read(fd,buf,10); // 10만큼 읽고 offset도 +10 이 된다. => 현재 offset : 10

    n = lseek(fd, 0, SEEK_CUR); // 현재 위치 OFFSET을 변수에 넣기
    printf("%d\n",n);   // 10

    n = lseek(fd, 5, SEEK_CUR); // 현재 위치에서 +5한 OFFSET 넣기
    printf("%d\n",n); // 15

    n = lseek(fd, -6, SEEK_CUR); // 현재 위치에서 -6한 OFFSET 넣기
    printf("%d\n",n); // 9

    n = lseek(fd, 0, SEEK_SET); // 맨 처음 위치 OFFSET 넣기
    printf("%d\n",n); // 0

    n = lseek(fd, 0, SEEK_END); // 맨 끝 위치 OFFSET 넣기
    printf("%d\n",n); // 37

    n = lseek(fd, 10, SEEK_SET); // 맨 앞 위치에서 +10한 OFFSET 넣기
    printf("%d\n",n); // 10

    close(fd);


    return 0;
}
profile
여러 방향으로 접근하는 개발자

0개의 댓글