[유닉스프로그래밍] 시스템 프로그래밍
01. 시스템 프로그래밍이란
- 시스템 호출과 라이브러리 함수
- 시스템 호출과 라이브러리 함수의 비교
02. 시스템 도구
- 기본 명령
- 컴파일 환경
- 오류 처리 함수
- 동적 메모리 할당
- 명령행 인자
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. 파일 입출력
- 개요
02. 저수준 파일 입출력
- 파일 기술자
- 파일 생성과 열고 닫기
- 파일 읽기와 쓰기
- 파일 오프셋 지정
- 파일 기술자 복사
- 파일 기술자 제어
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. 파일과 디렉토리
- 유닉스 파일의 특징
02. 파일 정보 검색
- 파일 정보 검색
- 파일 종류 검색
03. 파일 접근 권한 제어
- 파일 접근 권한 검색
- 파일 접근 권한 변경
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.