Linux에는 파일 열기에 대한 프로그램 요청을 처리하는 레이어/스크립트가 있습니까?
Bash에서 파일 설명자를 열 때처럼: exec 3 <>/documents/foo.txt
또는 텍스트 편집기가 열릴 때와 같습니다./documents/foo.txt
나는 편집자가 스스로 읽기/쓰기 액세스를 위해 "파일을 열 수 있다"는 것을 믿을 수 없습니다.
나는 오히려 이것이 "레이어"에 대한 요청이라고 생각합니다(init.d 스크립트?)는 특정 양의 파일만 여는 것으로 시작할 수 있으며, 열린 파일에 대한 액세스 종류, 열린 프로세스 등에 대한 탭을 유지합니다.
답변1
이 계층은 Linux 및 역사적인 Unix 설계에서 크게 벗어나지 않는 기타 시스템(그리고 대부분의 Unix가 아닌 운영 체제에서도 마찬가지)의 커널 내부에 있습니다.
커널의 이 부분을 커널이라고 합니다.VFS(가상 파일 시스템) 계층. VFS의 역할은 열린 파일에 대한 정보를 관리하는 것입니다.파일 설명자,열린 파일 설명및 디렉토리 항목), 파일 경로 구문 분석( 및 해석 /
) .
, ..
디렉토리 항목에 대한 작업을 올바른 파일 시스템 드라이버로 전달합니다.
대부분의 파일 시스템 드라이버도 커널에 있지만퓨즈파일 시스템 드라이버를 사용하면 이 기능을 커널 외부에 위임할 수 있습니다. 예를 들어 디스크 파일 시스템이루프 장치.
답변2
리눅스에서 파일 열기는 커널에 의해 직접 처리됩니다.하지만 프로세스에 영향을 주고 연구하기 위해 할 수 있는 일이 몇 가지 있습니다.
시스템 호출
위에서부터 파일과 상호 작용하는 데 사용하는 인터페이스 응용 프로그램이 다음과 같은 것을 볼 수 있습니다.시스템 호출.
열려 있는,읽다그리고쓰다당신이 기대하는 대로 하세요.통계파일을 열지 않고 파일에 대한 정보를 반환합니다.
strace를 사용하여 프로그램의 파일 관련 syscall 사용을 연구할 수 있습니다.
$ strace -e trace=%file /bin/ls /etc
[...]
stat("/etc", {st_mode=S_IFDIR|0755, ...}) = 0
openat(AT_FDCWD, "/etc", O_RDONLY...) = 3
이는 에 의해 발생한 syscall을 분석하여 해당 디렉토리에서 및 가 호출되었음을 ls /etc
보여줍니다 .stat
openat
/etc
디렉토리에서 파일 작업을 호출하는 이유가 궁금할 것입니다. UNIX에서는 디렉토리도 파일입니다. 사실은모든 것이 파일이다!
파일 설명자
openat() = 3
위의 출력에서 에 대해 궁금할 수도 있습니다 .
UNIX에서 열린 파일은 다음과 같이 표시됩니다.파일 설명자, 이는 특정 프로세스에 의해 열린 파일을 고유하게 표현한 것입니다. 파일 설명자 0, 1, 2는 일반적으로 다음을 위해 예약되어 있습니다.표준 스트림(사용자 입력/출력)이므로 처음으로 열린 파일은 3이 됩니다.
다음을 사용하여 특정 프로세스에 대해 열린 파일 설명자 목록을 얻을 수 있습니다.lsof
(엘나에스티영형펜에프파일):
$ cat /dev/urandom > /dev/null &
[1] 3242
$ lsof -p 3242
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
...
cat 3242 user 0u CHR 136,0 0t0 3 /dev/pts/0
cat 3242 user 1w CHR 1,3 0t0 1028 /dev/null
cat 3242 user 2u CHR 136,0 0t0 3 /dev/pts/0
cat 3242 user 3r CHR 1,9 0t0 1033 /dev/urandom
열에 FD
는 액세스와 함께 파일 설명자 번호가 표시됩니다.
당신은 또한 사용할 수 있습니다fuser
특정 파일을 보유하는 프로세스를 검색하려면 다음을 수행하십시오.
$ fuser /dev/urandom
/dev/urandom: ... 3242 ...
프로세스 정보 의사 파일 시스템 - /proc
지금쯤이면 다음과 같은 사항이 궁금할 것입니다.하지만 lsof
처음에 어떤 파일이 열려 있는지 어떻게 알 수 있나요??
글쎄, 살펴 보자!
$ strace -e trace=%file lsof -p 3242
...
stat("/proc/3242/", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/3242/stat", O_RDONLY) = 4
...
openat(AT_FDCWD, "/proc/3242/fd", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
readlink("/proc/3242/fd/0", "/dev/pts/0", 4096) = 10
lstat("/proc/3242/fd/0", {st_mode=S_IFLNK|0700, st_size=64, ...}) = 0
stat("/proc/3242/fd/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
openat(AT_FDCWD, "/proc/3242/fdinfo/0", O_RDONLY) = 7
...
따라서 lsof
더 많은 파일을 읽으면 어떤 파일이 열려 있는지 알 수 있습니다! 구체적으로는 디렉토리 /proc/3242/fd
. 아래의 모든 것은 /proc
커널이 보관하는 "가짜" 파일 시스템입니다. ls -l
구조를 보면 알 수 있습니다 .
파일 열기에 영향을 미침
파일 열기에 영향을 주는 데 사용할 수 있는 여러 가지 방법이 있지만 일부 스크립트를 바꾸는 것만큼 쉽지는 않습니다.
암호화 제공, 캐싱, 여러 디스크에 파일 분산 등 파일이 저장되거나 액세스되는 방식을 변경하려는 경우 이미 기존 방식이 있을 가능성이 높습니다.장치 매퍼귀하의 필요에 맞는 것입니다.
특정 디렉토리/마운트에서 파일 열기를 세밀하게 제어하려면 간단한 다음을 작성할 수 있습니다.퓨즈파일 시스템을 마운트하고 마운트하십시오.
프로그램/프로세스 수준에서 다음을 사용할 수 있습니다.LD_PRELOADC 라이브러리 호출을 변경하고 정상적인 syscall을 수행하지 못하도록 방지합니다.
가장 어렵지만 가장 유연한 방법은 자신만의 파일 시스템 드라이버를 작성하는 것입니다.
답변3
파일에 대한 액세스 관리는 운영 체제의 첫 번째이자 가장 중요한 기능에 관한 것입니다. 개인용 컴퓨터에서 가장 오래된 운영체제 중 하나인 DOS는 디스크 운영체제(Disk Operating System)를 의미한다. 이는 대부분의 경우 프로그램이 하드웨어에 직접 액세스할 수 있도록 허용했지만 파일 액세스에는 허용되지 않았습니다. 프로그램은 DOS 호출을 사용해야 했고 DOS는 프로그램의 파일 안팎으로 데이터를 넣는 작업을 관리했습니다. 디스크 유틸리티만 DOS에서 직접 하드 드라이브와 파일에 액세스할 수 있습니다.
Linux와 같은 최신 보호 모드 운영 체제는 DOS처럼 파일 액세스를 처리하지만 커널을 통과하려면 프로그램 자체(또는 메모리를 공유하도록 구성된 다른 프로그램) 외부의 모든 항목에 대한 모든 액세스가 필요합니다(Linux는 커널).
Linux의 프로그램은 C 라이브러리의 함수를 호출하여 파일에 데이터를 읽거나 쓸 수 있습니다. 그런 다음 C 라이브러리는 프로그램과 동일한 컨텍스트에서 계속 실행되는 동안 파일의 데이터에 대한 액세스를 구성하는 역할을 수행합니다. 그런 다음 C 라이브러리는 파일에 액세스하기 위해 올바른 함수를 사용하여 커널(Linux)을 호출하여 CPU를 링 0 또는 권한 모드로 전환합니다. 이제 CPU는 파일에 액세스하기 위해 하드웨어에 직접 액세스하는 권한 모드에서 Linux 파일 시스템 드라이버와 하드 드라이브 드라이버 소프트웨어를 실행하고 있습니다. 데이터는 C 라이브러리가 Linux에게 데이터를 넣으라고 지시한 메모리 영역에 복사되고, CPU는 프로그램의 보안 컨텍스트를 사용하여 사용자 모드로 다시 전환되고 C 라이브러리는 다시 시작되어 수행해야 하는 모든 처리를 수행합니다. 해당 데이터를 저장한 다음 프로그램 실행으로 돌아갑니다.
답변4
간단히 말해서, 프로그램이 파일에 쓸 때 이런 일이 발생합니다.
open
프로그램은 쓰기를 위해 경로로 지정된 파일을 커널에 요청합니다 .- 커널은 일부 내부 구조를 설정하고 파일을 여는 작업 중 일부를 파일 시스템 유형에 맞는 드라이버에 위임합니다. 그런 다음 커널은 정수(예: 3)인 파일 설명자를 프로그램에 반환합니다.
write
프로그램은 파일 설명자가 참조하는 파일에 대한 일련의 바이트(예: 문자열)를 커널에 요청합니다 .- 커널은 다시 드라이버에 작업을 위임합니다.
- 3단계와 4단계는 아마도 여러 번 반복될 것입니다.
close
프로그램은 파일 설명자가 참조하는 파일을 커널에 요청합니다 .- 커널은 다시 작업을 드라이버에 위임한 다음 내부 구조를 파괴합니다.
다음은 "Hello World!"를 작성하는 아주 최소한의 어셈블리 프로그램입니다. Greeting.txt 파일에:
.text
.globl _start
_start:
# Open and possible create file
mov $2, %rax # syscall 'open'
mov $path_start, %rdi # path
mov $0101, %rsi # create + write
mov $400, %edx # only user gets read permissions
syscall
mov %rax, %r10 # file descriptor
# Write string to file
mov $1, %rax # syscall 'write'
mov %r10, %rdi # file descriptor
mov $msg_start, %rsi # start of data
mov $msg_length, %edx # length of data
syscall # perform syscall
# Close file
mov $3, %rax # syscall 'close'
mov %r10, %rdi # file descriptor
syscall
# Exit program
mov $60, %rax # syscall 'exit'
syscall # perform syscall
.section .rodata
path_start:
.string "greeting.txt\0"
path_end:
path_length = path_end - path_start
msg_start:
.string "Hello World!\n"
msg_end:
msg_length = msg_end - msg_start
코드를 write.s에 저장하고 다음을 사용하여 빌드합니다.
as -o write.o write.s
ld -o write write.o
그런 다음
./write
모든 것이 잘 작동되길 바랍니다.
(참고: 저는 어떤 오류 처리도 하지 않습니다. 이것은 단지 장난감 코드일 뿐입니다.)