Unix System Programming 4 - :namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />김성호(moohou) :namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
_________________________________________________________________________
제4장 디레토리, 화일시스템, 특수 화일
4.1. 개요
디렉토리 : 디렉토리는 화일 이름들의 창고와 같다.
화일 시스템 : 화일시스템은 디렉토리와 화일들의 집합으로서, UNIX 화일구조를 구성하는 디렉토리와 화일들의 계층적인 트리구조의 일부를 나타낸다.
특수 화일 : UNIX 는 화일의 개념을 시스템에 연결되어 있는 주변장치에까지 확장시킨다.
4.2. 디렉토리와 AT&T 시스템 V 인트페이스 정의
AT&T 의 시스템 V 인터페이스 정의(SVID)는 실제로 UNIX 디렉토리의 형식을 정의하지 않지만, 디렉토리를 다루는 것을 일반화하기 위해 ftw와 getcwd 라 불리는 두 서브루틴을 도입한다. 그러나 UNIX 의 다른 버전에서는 이식이 불가능하다.
4.3. 디렉토리 : 사용자 관점
각 사용자는 보통 자신의 홈 디렉토리(home directory)를 갖는다. 홈 디렉토리는 사용자가 로그인할 때 들어가는 장소이고, 거기서 화일을 생성하거나 다룰 수 있다. 부디렉토리는 다시 자신의 부디렉토리를 가질 수 있고, 이러한 과정은 무한히 반복될 수 있다.
현재 디렉토리
로그인한 사용자는 자신이 작업하기 위한 현재 작업디렉토리(current working directory) 또는 현재 디렉토리라고 불리는 화일구조의 한 특정한 장소를 갖게 된다.
$cd /usr/keith
$pwd
/usr/keith
시스템에 있어서 현재 디렉토리는 화일의 상대적인 경로이름(relative path name)을 찾을 때 시작하는 디렉토리이다.
$cat book/chap1 은
$car /usr/keith/book/chap1 과 동일하고,
명령어 $cat file1 은
$cat /usr/keith/file1 과 동일하다.
4.4. 디렉토리의 구현
사실, UNIX 디렉토리는 단지 화일에 불과하다. 그러나 디렉토리와 보통의 화일 사이에는 몇 개의 중요한 차이점이 있다. 디렉토리는 creat 프리미티브를 사용해서는 생성되지 않는다. 구조적으로 대부분의 UNIX 시스템에서의 디렉토리는 16 바이트로 된 항목의 열로서 구성된다.
각 항목은 디렉토리에 포함된 각 화일이나 부 디렉토리에 대응한다. 각 항목은 디렉토리에 포함된 각 화일이나 부 디렉토리에 대응한다. 각 16 바이트는 화일의 inode 번호라고 불리는 양의 정수값을 위한 2 바이트와 화일이름을 저장하는 14 바이트로 구성된다.
inode 번호는 화일을 유일하게 식별한다. (실제로 inode 번호는 화일시스템 내에서 유일하다.) inode 번호는 inode 구조라 불리는 디스크 기초 자료구조(disk-based data structure)를 마련하기 위해 운영체제에 의해 사용된다.
이 구조는 화일에 대한 모든 관리 정보 즉, 크기, 소유자의 사용자 식별번호, 그룹식별번호, 허가, 생성일, 마지막 변경된 날, 화일 자료를 갖고 있는 디스크의 블럭 주소등을 포함한다. 위의 디렉토리 표현은 편의상 나타낸 것이고, 실제로는 2 바이트의 inode 번호가 이진수 형태로 저장된다.
이 두 바이트는 종종 인쇄 불가능한 값(ASC II 값이 아님)을 가진다. cat 명령을 사용하여 디렉토리의 내용을 프린트 해보면 화면에 이상한 문자들이 나타난다. 디렉토리를 조사하는 좋은 방법은 -c 옵션을 갖는 8 진수 덤프(octal dump) od 를 사용하는 것이다.
현재 디렉토리의 내용을 보기 위해서는
$od -c . 를 수행해야 한다.
이 명령에서 '.' 는 현재 디렉토리를 나타내는 표준기호이다.
4.4.1. link 와 unlink 의 재고찰
각 link 는 단지 새로운 화일 이름에 원래의 화일 이름과 같은 inode 번호를 가지는 새로운 디렉토리 슬롯(slot)을 만들게 된다. 만일 화일 abc 가 새이름 xyz 를 가지도록 하는 다음의 명령문
link("abc", "xyz"); 를 수행한다.
화일이 디렉토리로 부터 제거될때 16 바이트의 디렉토리 슬롯은 실제로 제거되지 않는다. 단지 inode 번호에 화일이 제거 되었다는 것을 알려주기 위해 0 을 저장한다. 반대로 디렉토리에서 새로운 화일이 생성되면, 시스템은 inode 번호와 이름을 거기에다 겹쳐 쓴다. 만일 빈 슬롯이 없으면 화일의 이름은 디렉토리의 끝에 더해진다. 즉 디렉토리 자체가 확장된다.
4.4.2. 점과 이중점
'.' 과 '..' 은 모든 디렉토리에 항상 존재하는 화일이다. 점은 현재 디렉토리를 가리키는 표준 UNIX 표기법으로서,
$cat ./fred
or
$ls . 등으로 사용한다.
이 중점은 현재 디렉토리의 부모 디렉토리 즉, 현재 디렉토리를 포함하는 디렉토리를 가리키는 표준 표기법이다. 사실 '.' 과 '..' 은 단지 현재 디렉토리와 부모 디렉토리에 대한 링크이다.
4.4.3. 디렉토리의 허가
보통의 화일과 같이, 디렉토리도 다른 사용자의 접근 가능성을 제어하는 접근 허가를 가진다. 디렉토리 허가도 보통의 화일 허가처럼 소유자, 그룹, 그외 사용자에 대해 각각 접근 특권을 명시한 'rwx' 의 세비트씩으로 구성된다.
- 디렉토리에 대한 읽기 허가는 디렉토리에 내에 있는 화일이나 부디렉토리의 이름에 대한 리스트를 볼 수 있다는 것을 의미한다.
- 디렉토리에 대한 쓰기 허가는 사용자가 디렉토리 내의 화일을 제거하거나 새로운 화일을 만들 수 있다는 것을 의미한다.
- 디렉토리에 대한 수행허가(또는 탐색허가)는 cd 명령 또는 프로그램안의 chdir 시스템 호출을 사용하여 사용자가 디렉토리 내부로 들어가는 것을 허용한다.
4.5. 디렉토리와 프로그래밍
표준 운영체제 헤더 화일 /usr/include/sys/dir.h 는 디렉토리 항목의 완전한 형식(format)을 정의한 자료구조를 갖고 있다.
#define dirsiz 14
struct direct{
ino_t d_ino;
char d_name[DIRSIZ];
};
자료형 ino_t 는 헤더화일 /usr/include/sys/types.h 에 정의되어 있다. (따라서, 이 화일은 direct 구조를 사용하는 모든 프로그램에 포함되어야 한다.) ino_t 는 unsigned short 와 동일하기 때문에, direct 구조의 총 크기는 16 바이트 즉, 디스크의 디렉토리 슬롯의 크기와 일치한다.
d_ino 필드는 화일 inode 번호를 가지고, d_name 필드는 화일 이름을 가진다. 화일이름이 14 자까지 가능하고 14 자가 되지 않는 화일 이름은 null 로 끝난다. 화일 이름이 14 자인 경우는 null 로 끝나지 않기 때문에 d_name 필드에 대해서는 C 라이브러리의 문자열 함수를 사용할 수 없다.
4.5.1. 현재 디렉토리
프로세스의 초기의 현재 디렉토리는 프로세스가 시작한 디렉토리로 지정된다. 그러나 chdir 이라 불리는 시스템 호출을 통해서 프로세스가 디렉토리를 변경하는 것이 가능하다.
4.5.2. chdir 에 의한 디렉토리 변경
char *path;
int retval;
retval = chdir(path);
chdir 시스템 호출은 path 가 호출 프로세스의 새로운 현재 작업 디렉토리가 되게 한다. 이 변경은 단지 chdir 호출을 부른 프로세스에만 적용된다. chdir 은 실행하고 -1 을 돌려준다.
4.5.3. 디렉토리 생성
디렉토리들을 creat 시스템 호출로는 생성할 수 없다. 대신에 특별한 시스템 호출 mknod 를 사용하면 된다. mknod 는 많은 다른 기능을 갖고 있다. 특수 화일을 만드는데 사용될 수 있다. 프로세스간의 통신 채널인 FIFO 를 만드는데도 mknod 를 이용할 수 있다.
mknod 에 대한 접근은 제한되어 있어, 슈퍼사용자만이 디렉토리를 생성하는데 이 호출을 사용할 수 있다.
int retval, mode;
char *path;
retval = mknod(path, mode);
디렉토리를 생성하고 접근허가를 설정하기 위해서는 팔진수 040000 에 원하는 접근 허가 값을 mode 에 지정하면 된다. 헤더화일 stat.h 에 이 값을 나타내는 상수 S_IFDIR 이 정의되어 있다.
- 040777 모든 사용자에게 읽기, 쓰기, 탐색허가를 허용하는 디렉토리를 생성한다.
- 040755 소유자에게는 읽기, 쓰기, 탐색 허가를 그외의 사용자에게는 읽기와 탐색허가 만을 허용하는 디렉토리를 생성한다. 즉, 소유자만이 이 디렉토리에 화일을 생성할 수 있다.
mknod 는 성공하면 0 을 실패하면 -1 을 돌려준다. 사용자가 디렉토리를 생성할 수 있는 방법은 mkdir 명령을 사용하는 것이다.
$mkdir dname 은 디렉토리 dname 을 생성한다.
4.5.4. 루트 디렉토리 변경
UNIX 화일 시스템의 맨 꼭대기는 루트 디렉토리라 불리며 '/' 로 표기된다. UNIX 는 프로세스가 화일 시스템 계층의 출발점을 변경할 수 있도록 하는 시스템 호출을 제공한다. 이 시스템 호출이 chroot 이다. 그러나 이것은 거의 사용되지 않는다.
int retval;
char *path;
retval = chroot(path);
chroot 가 성공하면, path 는 '/' 로 시작하는 화일을 탐색하는 출발점이 된다. (호출 프로세스에 대해서만 적용되고, 전 시스템에는 영향을 끼치지 않는다). chroot 는 실패하면 -1 을 돌려주고, 루트 디렉토리는 변경되지 않는다. 이 호출은 슈퍼사용자만 이용할 수 있다.
4.5.5. 현재 디렉토리의 이름 탐색
UNIX 시스템 V 는 현재 작업 디렉토리의 이름을 알려주는 getcwd 라 불리는 서브루틴(시스템 호출이 아님)을 정의한다. 실제로는 pwd 프로그램을 수행시킴으로써 결과를 얻는다.
int size;
char *buf, *ret, *getcwd();
ret = getcwd(buf, size);
getcwd 는 현재 디렉토리 경로이름에 대한 포인터를 돌려준다. 이상한 이유에서 인수 size 는 복귀되는 경로이름의 길이보다 적어도 2 가 더 커야 한다. buf 가 null 포인터이면 getcwd 는 동적 메모리에서 size개 의 바이트를 할당한다. getcwd 는 실패하고 null 값을 돌려준다.
4.5.6. 디렉토리 트리 탐색
때때로 디렉토리 계층 트리상의 주어진 디렉토리로부터 출발하여 그 디렉토리의 아래에 있는 모든 화일과 부 디렉토리를 탐색하는 연산이 필요한 경우가 있다.
#include <ftw.h>
char *path;
int func();
int depth, ret;
ret = ftw(path, func, depth);
func 는 사용자가 정의한 함수로서 path 에서 출발하여 방문하는 모든 화일이나 디렉토리에 대해 호출된다. 사용법에서 볼 수 있듯이 func 는 함수 포인터로서 ftw 루틴에 전달된다. 그래서 ftw 를 호출하기에 앞서 이 함수를 선언할 필요가 있다.
depth 인수는 ftw 에 의해 사용되는 서로 다른 화일 기술어의 수를 조절하는 기능을 한다. 일반적인 경우에는 1 이 가장 안전하다. func 는 3개의 인수 즉, 객체(object) 이름이 저장된 null 로 끝나는 문자열, 객체에 대한 자료가 저장된 stat 에 대한 포인터, 정수코드를 가지고 호출된다.
int func(name, statptr, type)
char *name;
struct stat *statptr;
int type;
{
}
헤더 화일 ftw.h 에 정의 되어 있는 값은
FTW_F 객체가 화일이다.
FTW_D 객체가 디렉토리이다.
FTW_DNR 객체가 읽을 수 없는 디렉토리이다.
FTW_NS 객체가 stat 루틴이 성공적으로 수행할 수 없는 것이다.
4.6. UNIX 화일 시스템
지금까지, 화일들은 디렉토리라 불리는 그룹들로 편성되고, 디렉토리들은 계층적 트리구조의 일부분을 형성한다는 것을 살펴보았다. 디렉토리들은 그룹이 되어 화일 시스템이라는 객체 (object)를 이룬다. 화일 시스템들은 보통 UNIX 시스템의 관리자(administator)에게만 연관이 있다.
모든 화일 시스템들은 부트스트랩구역(bootstrap area), 화일 시스템 수퍼블럭(file system super block), 화일 시스템 inode 구조를 위해 준비된 블럭, 특정 화일 시스템에서 화일을 구성하는 자료 블럭등을 위한 4개의 구역으로 구성된다.
이 블력의 첫 부분(화일 시스템에서의 논리적 블럭 0, 그러나 물리적으로는 디스크 분할이 시작하는 장소)은 부트 스트랩블럭으로 사용된다. 즉, 이 블럭은 시스템 시작 시간에 UNIX를 로드하기 위해 사용하는 하드웨어 지정(hardware-specific) 부트 프로그램을 포함한다.
4.6.1. 화일 시스템 조작을 위한 시스템 호출
UNIX 에는 화일 시스템을 다루기 위한 2개의 기본적인 시스템 호출이 있다. mount 는 사용자가 화일 시스템을 이용할 수 있도록 해주고 unmount 는 화일 시스템을 내려 사용자에게 보이지 않도록 한다.
4.6.2. 화일 시스템 탑재 : mount
char *partition, *dir;
int rwflag;
mount(partition, dir, rwflag);
mount 는 화일이 partition 으로 식별되는 디스크 분할에 있는 화일 시스템 볼륨을 디렉토리 dir 로 탑재한다. 보통 partition은 /dev/name 형태의 이름을 갖는다(name 은 다소 바뀔수 있다).
/dev 는 특수화일이 저장된 디렉토리 이름이다. 특수화일은 주변장치를 위해 사용된다. 탑재된 후 partition 에 대한 디렉토리 계층은 디렉토리 dir 을 통해 도달할 수 있다. 인수 rwflag 의 하위비트가 1 로 지정되면 (즉, rwflag 가 1과 같으면), 화일시스템은 읽기 허가만 가지고 탑재된다.
mount 는 슈퍼사용자에 의해서만 호출될 수 있고, 실패한 경우는 -1 을 성공한 경우는 0 을 돌려준다.
4.6.3. 화일 시스템 내리기 : umount
char *partition;
umount(partition);
umount 는 디스크분할 partition 에 위치한 앞서 탑재되었던 화일시스템을 디렉토리 계층으로부터 제거한다. 그러면 이 화일시스템에 있는 화일이나 디렉토리는 이제 접근이 불가능하게 된다.
사용자가 화일시스템에 있는 화일을 사용하고 있을 때 또는 사용자의 현재 디렉토리가 화일 시스템에 있는 디렉토리일때는 umount 가 실패를 하게된다.
캐슁과 sync 호출
효율성을 위해서, 탑재된 화일 시스템의 수퍼 블럭의 복사가 UNIX 기계장치의 주기억장치에 저장된다. UNIX 는 모든 주기억장치의 버퍼의 내용을 디스크로 보내주는 시스템 호출 sync 를 제공한다.
sync();
sync 는 화일시스템의 특수화일 이름을 통해 저수준(low level)에서 화일 시스템을 조사할 필요가 있거나 기계파손에 대비하여 자료보존을 해주는 프로그램에 의해 사용된다. 화일시스템이 너무 오랫동안 과거내용을 가지고 있게 하지않기 위해서 UNIX 는 시스템은 다중 사용자 모드에 있는 동안 반복하여 sync 를 호출하는 유틸리티 프로그램 update 를 수행시킨다. 보통 이 기간은 30 초로 UNIX 시스템 V 에서는 시스템 관리자에 의해 조절가능하다.
4.6.4. 화일 시스템과 미래
커널이 동시에 여러 다른 배치를 갖는 화일시스템들을 제공해주도록 하는 화일시스템 스위치(file system switch)를 도입하였다. 분산화일시스템(distributed file system)은 여러 다른 기계장치에 있는 사용자들이 동시에 같은 화일에 접근할 수 있도록 해준다. RFS(Remote File Sharing)는 원격기계장치(remote machine)의 디렉토리 계층을 국부 시스템(local system)의 디렉토리에 올릴 수 있게 해 준다.
4.7. UNIX 특수 화일
UNIX 시스템에 부착된 주변장치(즉 디스크, 터미널, 프리터, 테이프 등)는 화일 시스템 내에서 화일이름으로 표현된다. 이 화일들을 특수 화일이라 한다.
화일 시스템에 대응되는 디스크 분할도 특수화일로 표현된다. 이 특수화일들은 보통 디렉토리 /dev 에 저장된다.
/dev/tty00
/dev/tty01
/dev/tty02
는 3개의 시스템 단말기 출입구(port)의 이름이다.
/dev/lp
/dev/rmt0
는 라인프린터와 자기테이프에 대한 이름이다. 디스크 분할에 대한 이름은 다음과 같다.
/dev/dk0
/dev/dk1
open, close, read, write 는 모두 프로그램내에서 특수 화일에 사용될 수 있다.
#include <fcntl.h>
main()
{
int i, fd;
fd = open("/dev/tty00", O_WRONLY);
for(i = 0; i < 100; i++)
write(fd, "x", 1);
close(fd);
}
는 100 개의 문자 x 를 단말기 출입구 tty00 에 출력시킨다.
4.7.1. 블럭과 문자 특수화일
UNIX 특수화일들은 블럭장치(block device)와 문자장치(charater device)로 나눌 수 있다.
1. 블럭 특수화일들은 디스크나 자기테이프 같은 장치를 포함한다. 이 장치들과 커널사이의 자료전송은 표준크기블럭(보통1024바이트) 단위로 일어난다. 모든 블럭장치는 임의접근을 제공한다.
2. 문자 특수화일들은 이러한 구조화된 전송기법을 공유하지 않는 단말기 라인, 모뎀라인,프린터등과 같은 장치들을 포함한다. 임의접근은 허용될 수도 않을 수도 있다.
화일 시스템들은 단지 블럭 장치에서만 존재할 수 있다는 것에 유의하라. UNIX 는 특정 주변장치를 구동시키기 위하여 블럭장치표와 문자장치표를 갖고 있다. 주변장치와 자료를 교환하는 순서는 다음과 같다.
1. 시스템 호출 read 또는 write 는 정상적인 방법으로 특수 화일의 inode 에 접근한다.
2. 시스템은 장치가 블럭장치인지 문자장치인지를 알기위해 inode 구조의 플래그를 검사하여 주번호 (major number)를 추출한다.
3. 장치 사황표의 해당항목을 찾기 위해 주번호를 사용하고, 자료 전송을 위해 장치 특성구동기 루틴을 호출한다.
주변장치에 대한 접근은 보통의 디스크 화일에 대한 접근과 동일하다.
4.7.2. stat 구조의 재고찰
3장에서 언급했던 stat 구조는 특수화일 정보를 저장하기 위한 두 필드를 갖는다.
st_mode : 특수화일의 경우 st_mode 는 화일의 허가에 블럭장치에 해당하는 8진수 060000 이나 문자장치에 해당하는 020000 을 더한 값을 갖는다. 이 값대신에 stat.h 에서 정의된 기호상수 S_IFBLK 와
S_IFCHR 을 사용하기도 한다.
st_rdev : st_rdev 는 주장치번호돠 보조 장치번호를 갖는다.
이 정보를 알기 위해서는 ls 명령에 -l 옵션을 주면 된다. 예를 들어,
$ls -l /dev/tty3
crw--w--w- 1 ben other 8, 3 Sep 13 10:19 /dev/tty3
결과의 첫번째 열의 문자 'c' 는 /dev/tty3 가 특수 화일이라는 것을 알려준다. 정수값 8과 3은 장치번호와 보조장치번호이다. 프로그램내에서도 st_mode 를 조사해 볼 수 있다.
if((buf.st_mode & S_IFMT) == S_IFCHR)
printf("It's a character device\n
");
else
printf("It's not\n");
S_IFNT 는 stat.h 에서 정의된 특수 비트 매스크(special bit mask)이다.
ustat 는 가용디스크 블럭의 총 갯수와 가용 inode 의 갯수와 같은 기본 화일시스템 정보를 얻을 수 있다.
#include <sys/types.h>
#include <ustat.h>
int dev, ret;
struct ustat buf;
ret = ustat(dev, & buf);
여기서 dev 는 stat 구조의 st_rdev 로부터 알아낸 주장치번호와 보조장치번호를 갖는다. 인수 buf 는 헤더화일 ustat.h 에서 정의된 ustat 구조이다.
ustat 구조는 다음과 같다.
struct ustat{
daddr_t f_tfree;
ino_t f_tinode;
char f_fname[6];
char f_fpack[6];
}
f_tfree 는 dev 에 의해 지정된 화일시스템에서의 가용디스크 블럭의 총갯수를 저장하고 f_tinode 는 이 화일시스템에 대한 가용 inode 의 갯수를 저장한다. f_name 과 f_fpack 은 시스템 관리자가 정의한 화일시스템과 팩(pack)이름을 갖는다.
'Academy I > Tech Academy' 카테고리의 다른 글
Unix System Programming 8 (0) | 2014.12.16 |
---|---|
Unix System Programming 7 (0) | 2014.12.16 |
Unix System Programming 6 (0) | 2014.12.16 |
Unix System Programming 5 (0) | 2014.12.16 |
Unix System Programming 3 (0) | 2014.12.16 |
Unix System Programming 2 (0) | 2014.12.16 |
Unix System Programming 1 (0) | 2014.12.16 |
Domain Driven Design - Modeling (0) | 2014.12.15 |