[SW]/IT 총 정리 (2021) (완)

[유닉스프로그래밍] 시스템 프로그래밍

시원00 2023. 5. 27. 18:53
728x90

01. 시스템 프로그래밍이란

  1. 시스템 호출과 라이브러리 함수
  2. 시스템 호출과 라이브러리 함수의 비교

02. 시스템 도구

  1. 기본 명령
  2. 컴파일 환경
  3. 오류 처리 함수
  4. 동적 메모리 할당
  5. 명령행 인자

 

 

01. 시스템 프로그래밍이란?

 

시스템 프로그래밍의 정의

- 일반적인 응용 프로그래밍과 달리 유닉스/리눅스에서 제공하는 시스템 호출을 사용하여 프로그램을 작성하는 것을 의미

  

시스템 호출

- 시스템이 제공하는 서비스를 이용해 프로그램을 작성할 수 있도록 제공되는 프로그래밍 인터페이스

- 기본적인 형태는 C언어의 함수 형태로 제공

 

라이브러리 함수

- 미리 컴파일된 함수들을 묶어서 제공하는 특수한 형태의 파일

- 자주 사용하는 기능을 독립적으로 분리하여 구현해둠으로써 프로그램의 개발과 디버깅을 쉽게 하고 컴파일을 좀 더 빠르게 할 수 있음

- /lib, /usr/lib에 위치하며 lib*.a 또는 lib*.so 형태로 제공

 

시스템 호출과 라이브러리 함수의 비교

- 시스템 호출: 커널의 해당 서비스 모듈을 직접 호출하여 작업하고 결과를 리턴

- 라이브러리 함수: 일반적으로 커널 모듈을 직접 호출하지 않음

 

 

02. 시스템 도구

 

컴파일이란

- 텍스트로 작성한 프로그램을 시스템이 이해할 수 있는 기계어로 변환하는 과정

- 보통 컴파일 과정과 라이브러리 링크 과정을 묶어서 수행하는 것을 의미

 

gcc 컴파일러

- GNU C 컴파일러: gcc

     대부분 GNU C 컴파일러 사용

     우분투를 설치하면 보통 gcc 컴파일러가 설치되어 있고 gcc 명령을 이용해 알 수 있음

- 아래와 같은 error 메시지가 나오면 gcc가 설치되어 있는 상태

gcc: fatal error: no input files
compilation terminated.

- 만약 설치되어 있지 않다면 아래와 같은 오류 메시지가 나옴

     apt-get install gcc 명령을 이용해 설치 가능

Command 'gcc' not found, but can be installed with: 
sudo apt install gcc

- apt-get install gcc 명령 입력 후 오류가 난다면 소프트웨어 업데이터를 실행하여 모든 업데이트 완료 후 다시 설치 진행

 

- GNU C 컴파일러 사용

     1. 코드 작성 (C언어, 주로 gedit 이용)

     2. 컴파일: gcc 컴파일 할 소스 파일명

          | 기본 실행 파일명은 a.out

          | 실행파일명 지정은 -o 옵션 (ex. gcc -o test test.c)

     3. 실행: ./실행파일명 (ex. ./test)

 

Makefile과 make

- 소스 파일 여러 개를 묶어서 실행파일을 생성하는 도구

     1. 코드 작성: main.c, addnum.c

// main.c
#include <stdio.h>
extern int addnum(int a, int b);

int main(void) {
	int sum;
    
    sum = addnum(1,5);	// addnum.c
    printf("Sum 1-5 = %d\n", sum);
    
    return 0;
}
// addnum.c
int addnum(int a, int b) {
	int sum = 0;
    
    for (; a <= b; a++)
    	sum += a;
    return sum;
}

     2. Makefile 작성: main.c와 addnum.c를 묶어서 add라는 실행파일 생성

# Makefile

CC=gcc
CFLAGS=
OBJS=main.o addnum.o
LIBS=
all:	add

add:	$(OBJS)
	$(CC) $(GFLAGS) -o add $(OBJS) $(LIBS)
        
main.o: main.c
	$(CC) $(CFLAGS) -c main.c
addnum.o:	addnum.c
	$(CC) $(CFLAGS)	-c addnum.c
        
clean:
	rm -f $(OBJS) add core

     3. make 실행 

     4. 실행파일 실행 (./add)

 

오류 처리

- 리눅스에서 시스템콜 및 라이브러리 함수를 수행하다가 오류가 발생되면 사용자의 프로그램으로 오류 결과를 넘겨줌

- 시스템 호출은 오류 발생 시 -1을 리턴하며 라이브러리 함수는 NULL을 리턴함

- 또한, 오류 발생 시 전역 변수 errno에 오류의 종류를 알려주는 코드값이 저장됨

- 그러나 errno에 저장되는 값은 상수이므로 이것만으로는 오류의 의미를 파악하기 어려움

- 오류 코드를 메시지로 변환해 출력해주는 오류 처리 함수를 사용할 수 있음

     perror(3)

     strerror(3)

 

오류 처리 함수: perror()

- 오류 메시지 출력: perror()

     errno에 저장된 값을 읽어 이에 해당하는 메시지를 표준 오류로 출력

     함수의 인자로 지정한 문자열과 콜론을 출력한 후 오류 메시지를 출력

     인자가 NULL일 경우 콜론을 출력하지 않고 오류 메시지만 출력

     일반적으로 함수의 인자로는 프로그램(파일)의 이름을 지정하는 것이 좋음

- 필요한 헤더파일과 함수 원형

#include <stdio.h>
void perror(const char *s);

 

예제 1-1. 오류 처리 함수: perror()

- 존재하지 않는 파일(server.txt)에 access 함수를 이용해 접근하여 오류 메시지를 출력하도록 함

 

오류 처리 함수: strerror()

- 오류 메시지 출력: strerror()

     ANSI C에서 추가로 정의한 함수

     함수의 인자로 errno에 저장된 값을 받아 오류 메시지를 리턴함

     리턴된 오류 메시지를 사용자가 적절하게 가공할 수 있다는 장점이 있음

- 필요한 헤더피일과 함수 원형

#include <string.h>
char *strerror(int errnum);

 

예제 1-2. 오류 처리 함수: strerror()

- 존재하지 않는 파일(server.txt)에 access 함수를 이용해 접근해서 일부러 오류 메시지를 출력하도록 함

 

메모리 할당

- 배열은 프로그램이 시작할 때 필요한 메모리를 미리 확보함

- 이와 달리 프로그램이 실행 도중에 필요한 메모리 공간을 할당하고 더 이상 사용하지 않을 때 해당 공간을 해제하는 것이 동적 메모리 할당임

- 동적 메모리 할당을 활용하면 필요한 데이터양에 따라 메모리 공간을 효율적으로 사용할 수 있음

- 메모리를 동적으로 할당하는 함수로는 malloc, calloc, realloc 등이 있고, 사용을 마친 메모리를 해제하는 함수로는 free가 있음

 

동적 메모리 할당 1: malloc()

- 메모리 할당: malloc()

- 필요한 헤더파일과 함수원형

#include <stdlib.h>
void *malloc(size_t size);

- 인자로 지정한 크기의 메모리 할당

- 함수 사용 예시

char *ptr
ptr = malloc(sizeof(char) * 100);

- 인자로 지정한 크기의 메모리를 할당하는데 성공하면 메모리의 시작 주소를 리턴

- 만약 메모리 할당에 실패하면 NULL 포인트를 리턴

- 인자로 지정하는 메모리 크기는 바이트 단위

- 할당된 메모리에는 어떤 형태의 데이터도 저장할 수 있음

- 주의할 점: 할당된 메모리를 초기화하지 않음

 

예제 1-3. 동적 메모리 할당 1: malloc()

 

동적 메모리 할당 2: calloc()

- 메모리 할당과 초기화: calloc()

- 필요한 헤더파일과 함수 원형

#include <stdlib.h>
void *calloc(size_t nelem, size_t elsize);

- nelem * elsize 만큼의 메모리를 할당하고, 0으로 초기화

     nelem = number of element

     elsize = size of element

- 함수 사용 예시

char *ptr
ptr = calloc(10, 20);

 

예제 1-4. 동적 메모리 할당 2: calloc()

 

동적 메모리 할당 3: realloc()

- 메모리 추가 할당: realloc()

- 필요한 헤더파일과 함수원형

#include <stdlib.h>
void *realloc(void *ptr, size_t size);

- 이미 할당받은 메모리(ptr)에 size 크기의 메모리를 추가로 할당

- 함수 사용 예시

char *ptr, *new;
ptr = malloc(sizeof(char) * 100);
new = realloc(ptr, 100);

- 이미 할당받은 메모리에 추가로 메로리를 할당할 때 사용

- 이전에 할당받은 메모리와 추가할 메모리를 합한 크기의 메모리를 새롭게 할당하고 주소를 리턴

- 이전 메모리의 내용은 새로 할당된 메모리로 복사되며 이전 메모리의 주소는 필요 없음

 

예제 1-5. 동적 메모리 할당 3: realloc()

 

동적 메모리 할당 4: free()

- 메모리 해제: free()

- 사용을 마친 메모리를 해제하고 반납

- 필요한 헤더파일과 함수원형

#include <stdlib.h>
void free(void *ptr)

- 함수가 성공하면 ptr이 가리키던 메모리는 더 이상 의미가 없음

 

명령행 인자

- 명령행: 사용자가 명령을 입력하는 행

- 명령행 인자: 명령을 입력할 때 함께 지정한 인자(옵션, 옵션인자, 명령인자 등)

- 명령행 인자의 전달: main 함수로 자동 전달

int main(int argc, char *argv[])

- argc: 명령과 인자를 포함한 개수로, argv 배열의 크기

- argv: 명령과 각 인자를 담고 있는 배열

 

예제 1-6. 명령행 인자

 

 


 

01. 파일 입출력

  1. 개요

02. 저수준 파일 입출력

  1. 파일 기술자
  2. 파일 생성과 열고 닫기
  3. 파일 읽기와 쓰기
  4. 파일 오프셋 지정
  5. 파일 기술자 복사
  6. 파일 기술자 제어

 

 

01. 파일 입출력

 

파일

- 파일은 관련 있는 데이터들의 집합으로 하드디스크 같은 저장장치에 일정한 형태로 저장됨

- 데이터를 저장하기 위해서 뿐만 아니라 데이터를 전송하거나 장치에 접근하기 위해서도 사용

 

저수준 파일 입출력과 고수준 파일 입출력

- 저수준 파일 입출력: 커널의 시스템 호출을 사용하여 파일 입출력을 실행하며, 특수 파일도 읽고 쓸 수 있음

- 고수준 파일 입출력: 표준 입출력 라이브러리로 다양한 형태의 파일 입출력 함수를 제공함

  저수준 파일 입출력 고수준 파일 입출력
파일 지시자 int fd(파일 기술자) FILE *fp; (파일 포인터)
특징 더 빠르다.
바이트 단위로 읽고 쓴다.
특수 파일에 대한 접근이 가능하다.
사용하기 쉽다.
버퍼 단위로 읽고 쓴다.
데이터의 입출력 동기화가 쉽다.
여러 가지 형식을 지원한다.

 

 

02. 저수준 파일 입출력

 

파일 기술자

- 현재 열려있는 파일을 구분하는 정수값

- 저수준 파일 입출력에서 열린 파일을 참조하는데 사용

- 0번: 표준 입력, 1번: 표준 출력, 2번: 표준 오류

파일 기술자 할당

 

파일 생성과 열고 닫기

- 파일 열기: open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag, [mode_t mode]);

- path에 지정한 파일을 oflag에 지정한 플래그 값에 따라 열고 파일기술자를 리턴

- oflag 값

종류 기능
O_RDONLY 파일을 읽기 전용으로 연다.
O_WRONLY 파일을 쓰기 전용으로 연다.
O_RDWR 파일을 읽기와 쓰기가 가능하게 연다.
O_CREAT 파일이 없으면 파일을 생성한다.
O_EXCL O_CREAT 옵션과 함께 사용할 경우 기존에 없는 파일이면 파일을 생성하지만, 파일이 이미 있으면 파일을 생성하지 않고 오류 메시지를 출력한다.
O_APPEND 파일의 맨 끝에 내용을 추가한다.
O_TRUNC 파일을 생성할 때 이미 있는 파일이고 쓰기 옵션으로 열었으면 내용을 모두 지우고 파일의 길이를 0으로 변경한다.

- mode: 0644 같이 숫자로 파일 접근 권한 지정 (플래그 값으로 지정 가능)

플래그 모드 설명
S_IRWXU 0700 소유자 읽기/쓰기/실행 권한
S_IRUSR 0400 소유자 읽기 권한
S_IWUSR 0200 소유자 쓰기 권한
S_IXUSR 0100 소유자 실행 권한
S_IRWXG 0070 그룹 읽기/쓰기/실행 권한
S_IRGRP 0040 그룹 읽기 권한
S_IWGRP 0020 그룹 쓰기 권한
S_IXGRP 0010 그룹 실행 권한
S_IRWXO 0007 기타 사용자 읽기/쓰기/실행 권한
S_IROTH 0004 기타 사용자 읽기 권한
S_IWOTH 0002 기타 사용자 쓰기 권한
S_IXOTH 0001 기타 사용자 실행 권한

 

- 파일 생성: creat

#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *path, mode_t mode);

- 파일 생성 함수, open 함수에 파일 생성 기능이 없던 구버전 유닉스에서 사용

- open 함수와 달리 옵션을 지정하는 부분이 없음

- creat 함수로 파일을 생성하면 파일 기술자를 리턴하므로 별도로 open할 필요 없음

 

- 파일 닫기: close

#include <unistd.h>
int close(int fildes);

- 프로세스에서 열 수 있는 파일 개수가 제한되어 있으므로 파일의 사용이 끝나면 닫아야 함

 

예제 2-1. 새 파일 열고 닫기

- ubuntu.txt 파일 열기: 파일이 없으면 파일을 생성, 접근권한은 0644로 설정

 

예제 2-2. O_EXCL 플래그 사용하기

- ubuntu.txt 파일 열기: 기존에 없는 파일이면 파일을 생성하지만, 파일이 이미 있으면 파일을 생성하지 않고 오류 메시지를 출력, 접근권한은 0644로 설정

 

예제 2-3. 파일 기술자 할당

- 0번 파일기술자를 닫음

- 11행에서 0번을 닫았으므로 새로 생성한 파일은 가장 작은 번호인 0번이 할당된다.

 

파일 읽기와 쓰기

- 파일 읽기: read

#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t nbytes);

- 파일에서 nbytes로 지정한 크기만큼 바이트를 읽어서 buf에 저장

- 실제로 읽어온 바이트 개수를 리턴

- 리턴값이 0이면 파일의 끝에 도달했음을 의미

- 파일의 종류에 상관없이 무조건 바이트 단위로 읽어온다.

 

- 파일 쓰기: write

#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t nbytes);

- buf가 가리키는 메모리에서 nbytes로 지정한 크기만큼 파일에 기록

- 실제로 쓰기를 수행한 바이트 수를 리턴

 

예제 2-4. 파일 읽고 쓰기

- ubuntu.txt 파일로부터 buf에 6bytes씩 읽어오기

- buf에서 읽어온만큼 ubuntu.bak 파일에 쓰기

 

파일 오프셋 지정

- 파일 오프셋 위치 지정: lseek

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fildes, off_t offset, int whence);

- offset으로 지정한 크기만큼 오프셋을 이동시킨다.

- offset의 값은 whence 값을 기준으로 해석한다.

설명
SEEK_SET 파일의 시작 기준
SEEK_CUR 현재 위치 기준
SEEK_END 파일의 끝 기준
lseek(fd, 5, SEEK_SET); //파일의 시작에서 5번재 위치로 이동
lseek(fd, 0, SEEK_END); //파일의 끝에서 0번째, 즉 끝으로 이동
lseek(fd, 0, SEEK_CUR); //파일 오프셋의 현재 위치

 

예제 2-5. 파일 오프셋 사용하기

- 파일 오프셋의 현재 위치 찾기

- 파일의 시작에서 4번째 위치로 이동

 

파일 기술자 복사

- 파일 기술자 복사: dup

#include <unistd.h>
int dup(int fildes);

- 기존 파일 기술자를 인자로 받아 새로운 파일 기술자를 리턴

- 새로운 파일 기술자는 현재 할당할 수 있는 파일 기술자 중 가장 작은 값으로 자동 할당

 

- 파일 기술자 복사: dup2

#include <unistd.h>
int dup2(int fildes, int fildes2);

- 새로운 파일 기술자를 지정할 수 있다.

 

예재 2-6. 파일 기술자 복사하기

- 표준출력(1)을 닫음

- fd를 복사하면 가장 작은 값인 1로 복사

- 표준출력한 내용이 파일로 저장

 

예제 2-7. dup2 함수 사용하기

- 표준출력(1)으로 지정하여 복사

- 표준출력한 내용이 파일로 저장

 

파일 기술자 제어

- 파일 기술자 제어: fcntl

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fildes, int cmd, /* arg */ ...);

- 파일 기술자가 가리키는 파일에 cmd로 지정한 명령을 수행

- cmd의 종류에 따라 인자(arg)를 지정할 수 있음

- 자주 사용하는 cmd

F_GETFL 상태 플래그 정보를 읽어온다.
F_SETFL 상태 플래그 정보를 설정한다. 설정할 수 있는 플래그는 대부분 open 함수에서 지정하는 플래그다.

 

예제 2-8. fcntl 함수로 파일 기술자 제어하기

- 상태 flag 정보를 읽어옴

- 파일을 추가 모드로 수정

- 상태 flag 정보를 업데이트함

- 파일에 내용 추가

 

 


 

01. 파일과 디렉토리

  1. 유닉스 파일의 특징

02. 파일 정보 검색

  1. 파일 정보 검색
  2. 파일 종류 검색

03. 파일 접근 권한 제어

  1. 파일 접근 권한 검색
  2. 파일 접근 권한 변경

04. 디렉토리 관련 함수

 

 

01. 파일과 디렉토리

 

유닉스 파일의 특징

- 파일: 유닉스에서 파일은 데이터 저장, 장치구동, 프로세스 간 통신 등에 사용

- 파일의 종류: 일반파일, 특수파일, 디렉토리

- 일반파일

     텍스트 파일, 실행파일, 라이브러리, 이미지 등 유닉스에서 사용하는 대부분의 파일

     편집기나 다른 응용 프로그램을 통해 생성

- 장치파일

     장치를 사용하기 위한 특수 파일

     블록장치파일: 블록단위(8KB)로 읽고 쓴다.

     문자장치파일: 섹터단위(512바이트)로 읽고 쓴다. -> 로우디바이스(Raw Device)

     예: /devices

- 디렉토리

     디렉토리도 파일로 취급

     디렉토리와 관련된 데이터 블록은 해당 디렉토리에 속한 파일의 목록과 inode 저장

 

- 파일의 종류 구분

     ls -l 명령으로 파일의 종류 확인 가능: 결과의 맨 앞글자로 구분

     파일 종류 식별 문자

문자 파일의 종류
- 일반 파일
d 디렉토리
b 블록 장치 특수 파일
c 문자 장치 특수 파일
l 심볼릭 링크

     예제

# ls -l /
lrwxrwxrwx   1 root root	9 7월 16일 15:22 bin -> ./usr/bin
drwxr-xr-x  42 root sys	1024 8월 5일 03:26 usr
......
# ls -lL /dev/dsk/c0d0s0
brw-r----- 1 root sys 102, 0 8월 3일 10:59 /dev/dsk/c0d0s0
# ls -lL /dev/rdsk/c0d0s0
crw-r----- 1 root sys 102, 0 8월 3일 12:12 /dev/rdsk/c0d0s0

 

- 파일의 구성 요소: 파일명, inode, 데이터블록

- 파일명

     사용자가 파일에 접근할 때 사용

     파일명과 관련된 inode가 반드시 있어야 함

     파일명은 최대 255자까지 가능

     파일명은 대소문자를 구분하며, '.'으로 시작하면 숨김 파일

- inode

     외부적으로는 번호로 표시하며, 내부적으로는 두 부분으로 나누어 정보 저장

          파일 정보를 저장하는 부분, 데이터 블록의 주소 저장하는 부분

     파일의 inode 번호는 ls -i 명령으로 확인 가능

- 데이터 블록

     실제로 데이터가 저장되는 부분

 

 

02. 파일 정보 검색

 

파일 정보 검색 1

- 파일명으로 파일 정보 검색: stat

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *restrict path, struct stat *buf);

- inode에 저장된 파일 정보 검색

- path에 검색할 파일의 경로를 지정하고, 검색한 정보를 buf에 저장

- stat 구조체

struct stat {
    dev_t	st_dev; // inode가 저장되어 있는 장치의 장치 번호
    ino_t	st_ino; // inode 번호
	mode_t	st_mode; // 파일의 형식과 접근 권한
    nlink_t	st_nlink; // 하드링크의 개수
    uid_t	st_uid;
    gid_t	st_gid;
    dev_t 	st_rdev; // 장치 파일이면 주장치 번호와 부장치 번호를 저장
    off_t	st_size;
    time_t	st_atime; // 접근시간 (파일을 open할 때마다 갱신됨)
    time_t	st_mtime; // 수정시간 (파일의 내용이 수정되면 갱신됨)
    time_t	st_ctime; // 변경시간 (파일의 속성, 권한, 크기 등이 변경되면 갱신됨) 
    blksize_t	st_blksize; // 파일의 내용을 입출력할 때 사용하는 버퍼의 크기 
    blkcnt_t	st_blocks; // 파일을 512바이트씩 블록으로 나눈 갯수 
    char	st_fstype[_ST_FSTYPSZ]; // 파일시스템 종류 정보
};

 

예제 3-1. 파일명으로 inode 정보 검색하기

- ubuntu.txt 파일의 정보를 buf에 저장

 

파일 정보 검색 2

- 파일 기술자로 파일 정보 검색: fstat

#include <sys/types.h>
#include <sys/stat.h>
int fstat(int fd, struct stat *buf);

- fd로 지정한 파일의 정보를 검색하여 buf에 저장

 

예제 3-2. fstat으로 파일 정보 검색하기

- 파일기술자를 이용해 ubuntu.txt 파일의 정보를 buf에 저장

 

파일 종류 검색 1

- 상수를 이용한 파일 종류 검색

- 파일의 종류 검색 관련 상수

상수명 상수값(16진수) 기능
S_IFMT 0xF000 st_mode 값에서 파일의 종류를 정의한 부분을 가져옴
S_IFIFO 0x1000 FIFO 파일
S_IFCHR 0x2000 문자 장치 특수 파일
S_IFDIR 0x4000 디렉토리
S_IFBLK 0x6000 블록 장치 특수 파일
S_IFREG 0x8000 일반 파일
S_IFLNK 0xA000 심볼릭 링크 파일
S_IFSOCK 0xC000 소켓 파일

- S_IFMT를 st_mode 값과 AND(&) 연산하면 파일의 종류 부분만 남게 된다.

 

예제 3-3. 상수를 이용해 파일 종류 검색하기

- S_IFMT를 st_mode 값과 AND(&) 연산해 파일의 종류 부분만 남김

 

파일 종류 검색 2

- 매크로를 이용한 파일 종류 검색

매크로명 매크로 정의 기능
S_ISFIFO(mode) (((mode)&0xF000) == 0x1000) 참이면 FIFO 파일
S_ISCHR(mode) (((mode)&0xF000) == 0x2000) 참이면 문자 장치 특수 파일
S_ISDIR(mode) (((mode)&0xF000) == 0x4000) 참이면 디렉토리
S_ISBLK(mode) (((mode)&0xF000) == 0x6000) 참이면 블록 장치 특수 파일
S_ISREG(mode) (((mode)&0xF000) == 0x8000) 참이면 일반 파일
S_ISLINK(mode) (((mode)&0xF000) == 0xa000) 참이면 심볼릭 링크 파일
S_ISSOCK(mode) (((mode)&0xF000) == 0xc000) 참이면 소켓 파일

- 각 매크로는 인자로 받은 mode 값을 0xF000과 AND 연산 수행

- AND 연산의 결과를 파일의 종류별로 정해진 값과 비교하여 파일의 종류 판단

- 이 매크로는 POSIX 표준

 

예제 3-4. 매크로를 이용해 파일 종류 검색하기

 

 

03. 파일 접근 권한 제어

 

파일 접근 권한 검색

- 상수를 이용한 파일 접근 권한 검색

상수명 상수값 기능
S_ISUID 0x800 st_mode 값과 AND 연산이 0이 아니면 setuid가 설정됨
S_ISGID 0x400 st_mode 값과 AND 연산이 0이 아니면 setgid가 설정됨
S_ISVTX 0x200 st_mode 값과 AND 연산이 0이 아니면 스티키 비트가 설정됨
S_IREAD 00400 st_mode 값과 AND 연산으로 소유자의 읽기 권한 확인
S_IWRITE 00200 st_mode 값과 AND 연산으로 소유자의 쓰기 권한 확인
S_IEXEC 00100 st_mode 값과 AND 연산으로 소유자의 실행 권한 확인

- sticky 비트: 특정 디렉토리를 누구나 자유롭게 사용할 수 있게 하기 위함. 공용 디렉토리에 사용. 공유모드라고도 함.

- 소유자의 접근권한 추출과 관련된 상수만 정의

- 소유자 외 그룹과 기타사용자의 접근권한은?

     st_mode의 값을 왼쪽으로 3비트 이동시키거나 상수값을 오른쪽으로 3비트 이동시켜 AND 수행

     st_mode & (S_IREAD >> 3)

 

- POSIX에서 정의한 접근권한 관련 상수

     시프트 연산 없이 직접 AND 연산이 가능한 상수 정의

상수명 상수값 기능
S_IRWXU 00700 소유자 읽기/쓰기/실행 권한
S_IRUSR 00400 소유자 읽기 권한
S_IWUSR 00200 소유자 쓰기 권한
S_IXUSR 00100 소유자 실행 권한
S_IRWXG 00070 그룹 읽기/쓰기/실행 권한
S_IRGRP 00040 그룹 읽기 권한
S_IWGRP 00020 그룹 쓰기 권한
S_IXGRP 00010 그룹 실행 권한
S_IRWXO 00007 기타 사용자 읽기/쓰기/실행 권한
S_IROTH 00004 기타 사용자 읽기 권한
S_IWOTH 00002 기타 사용자 쓰기 권한
S_IXOTH 00001 기타 사용자 실행 권한

 

예제 3-5. 상수를 이용해 파일 접근 권한 검색하기

- 상수를 이용해 소유자의 읽기 권한 확인

- 상수를 이용해 그룹의 읽기 권한 확인

- POSIX에서 정의한 접근 권한 검색 관련 상수 이용해 시프트 연산 없이 기타 사용자의 읽기 권한 확인

 

파일 접근 권한 검색

- 함수를 사용한 파일 접근 권한 검색: access

#include <unistd.h>
int access(const char *path, int amode);

- path에 지정된 파일이 amode로 지정한 권한을 가졌는지 확인하고 리턴

- 접근권한이 있으면 0을, 오류가 있으면 -1을 리턴

- 오류메시지

     ENOENT: 파일이 없음

     EACCES: 접근권한이 없음

- amode 값

     R_OK: 읽기 권한 확인

     W_OK: 쓰기 권한 확인

     X_OK: 실행 권한 확인

     F_OK: 파일이 존재하는지 확인

 

예제 3-6. access 함수를 이용해 접근 권한 검색하기

- ubuntu.bak 파일이 존재하는지 확인

- ubuntu.txt 파일에 접근 가능하며 읽기 권한 있는지 확인

 

파일 접근권한 변경

- 파일명으로 접근권한 변경: chmod

#include <sys/types.h>
#include <sys/stat.h>
intn chmod(const char *path, mode_t mode);

- path에 지정한 파일의 접근권한을 mode값에 따라 변경

- 접근권한을 더할 때는 OR 연산자를, 뺄 때는 NOT 연산 후 AND 연산자 사용

     chmod(path, S_ORWXU);

     chmod(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);

     mode |= S_IWGRP;

     mode &= ~(S_IROTH);

- 반드시 mode 값 설정 후 chmod(path, mode)

 

- 파일 기술자로 접근 권한 변경: fchmod

#include <sys/types.h>
#include <sys/stat.h>
int fchmod(int fd, mode_t mode);

 

예제 3-7. chmod 함수 사용하기

- 접근 권한 변경

- 앞에서 설정한 모드값으로 접근 권한 변경

 

 

04. 디렉토리 관련 함수

 

디렉토리 관련 함수

- 디렉토리 생성: mkdir

#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode);

- path에 지정한 디렉토리를 mode 권한에 따라 생성한다.

 

- 디렉토리 삭제: rmdir

#include <unistd.h>
int rmdir(const char *path);

 

- 디렉토리명 변경: rename

#include <stdio.h>
int rename(const char *old, const char *new);

 

예제 3-8. 디렉토리 생성/삭제/이름 변경하기

- 0755 모드로 ubuntu 디렉토리 생성

- 0755 모드로 linux 디렉토리 생성

- ubuntu 디렉토리를 ubuntu20.04로 이름 변경

- linux 디렉토리 삭제

 

 

FIN.

728x90