프로세스 종료 후 자동으로 삭제 된 임시 폴더


답변:


12

임시 파일의 경우 문제의 예제는 파일을 만든 다음 디렉토리에서 링크를 해제하고 ( "사라짐") 스크립트가 파일 설명자를 닫을 때 (아마도 종료시) 파일에서 차지하는 공간 시스템에서 회수 할 수 있습니다. 이것은 C와 같은 언어로 임시 파일을 처리하는 일반적인 방법입니다.

내가 아는 한 최소한 디렉토리를 사용할 수있는 방법으로 같은 방식으로 디렉토리를 열 수는 없습니다.

스크립트 종료시 임시 파일 및 디렉토리를 삭제하는 일반적인 방법은 정리 EXIT트랩 을 설치하는 것 입니다. 아래의 코드 예제는 파일 설명자를 완전히 저글링하지 않아도됩니다.

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT

# The rest of the script goes here.

또는 정리 함수를 호출 할 수 있습니다.

cleanup () {
    rm -f "$tmpfile"
    rm -rf "$tmpdir"
}

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap cleanup EXIT

# The rest of the script goes here.

EXIT트랩은 수신시에 실행되지 KILL더 정리 한 후 수행되지있을 것이라는 것을 의미 (포집 될 수 없다) 신호. 그러나 그것은 인해를 종료 할 때 실행됩니다 INT또는 TERM신호 (있는 경우 실행 bash또는 ksh다른 쉘에 당신이 후 이러한 신호를 추가 할 수 있습니다 EXIT에서 trap명령 행), 또는 경우로 인해 스크립트의 끝에 도착하거나 실행을 정상적으로 종료 exit요구.


5
이미 링크되지 않은 임시 디렉토리를 사용할 수없는 C뿐만 아니라 C 프로그램도 쉘이 아닙니다. 문제는 연결되지 않은 디렉토리에 파일이있을 수 없다는 것입니다. 링크되지 않은 빈 디렉토리를 작업 디렉토리로 사용할 수 있지만 파일을 작성하려고하면 오류가 발생합니다.
derobert

1
@derobert 그리고 링크되지 않은 디렉토리에는 .and ..항목 도 없습니다 . (리눅스에서 테스트 한 결과 플랫폼간에 일관성이 있는지 모르겠습니다.)
kasperd


1
스크립트가 exec another-command명백하게 호출되는 경우에도 EXIT 트랩이 실행되지 않습니다 .
Stéphane Chazelas


6

스크립트가 끝나면 스크립트가 실행될 쉘 함수를 작성하십시오. 아래 예제에서 나는 그것을 'cleanup'이라고 부르고 다음과 같이 출구 레벨에서 실행될 트랩을 설정합니다. 0 1 2 3 6

trap cleanup 0 1 2 3 6

cleanup()
{
  [ -d $TMP ] && rm -rf $TMP
}

자세한 내용은 게시물을 참조하십시오.


사람들은 없다 "출구 수준"하지만 신호 번호, 당신이에 연결하고 질문에 대한 대답 만한다고 설명한다. 트랩은 cleanup클린 종료 (0) 전과 SIGHUP (1), SIGINT (2), SIGQUIT (3) 및 SIGABRT (6) 수신시 실행됩니다. 그것은 것입니다 하지 실행할 cleanup때문에 등 SIGTERM, SIGSEGV, SIGKILL, SIGPIPE의 스크립트 종료 이것은 분명 부족한 경우.
mosvy

6

나중에 그 안에 경로를 사용하지 않으면 chdir을 넣은 다음 제거 할 수 있습니다.

#! /bin/sh
dir=`mktemp -d`
cd "$dir"
exec 4>file 3<file
rm -fr "$dir"

echo yes >&4    # OK
cat <&3         # OK

cat file        # FAIL
echo yes > file # FAIL

확인하지는 않았지만 C에서 openat (2)를 더 이상 파일 시스템에 존재하지 않는 디렉토리와 함께 사용할 때 가장 비슷한 문제 일 것입니다.

루트 사용자이고 Linux 인 경우 별도의 네임 스페이스와 그 mount -t tmpfs tmpfs /dir내부에서 재생할 수 있습니다 .

스크립트가 부정한 종료 (예 : SIGKILL)로 강제 종료되면 정식 답변 (EXIT에 트랩 설정)이 작동하지 않습니다. 민감한 데이터가 걸려있을 수 있습니다.

최신 정보:

다음은 네임 스페이스 접근 방식을 구현하는 작은 유틸리티입니다. 함께 컴파일해야합니다

cc -Wall -Os -s chtmp.c -o chtmp

주어진 CAP_SYS_ADMIN파일 기능 (루트로)

setcap CAP_SYS_ADMIN+ep chtmp

다음과 같이 (일반적으로) 사용자를 실행할 때

./chtmp command args ...

파일 시스템 네임 스페이스를 공유 해제하고 tmpfs 파일 시스템을 마운트하고 /proc/sysvipcchdir을 command지정한 후 주어진 인수로 실행 합니다. command없는 상속 CAP_SYS_ADMIN기능을.

해당 파일 시스템은에서 시작되지 않은 다른 프로세스에서 액세스 할 수 없으며 , 그 방법에 관계없이 자식과 자식이 죽을 command때 파일 내부에서 생성 된 모든 파일과 함께 마술처럼 사라집니다 command. 이것은 마운트 네임 스페이스를 공유하지 않는 것입니다 command. 동일한 사용자가 실행하는 프로세스와 다른 프로세스 간에는 하드 장벽이 없습니다 . 그들은 여전히 통해 하나의 네임 스페이스 내부에 몰래 수 ptrace(2), /proc/PID/cwd또는 다른 수단에 의해.

"무용지물"의 하이재킹은 /proc/sysvipc물론 어리석은 일이지만, 대안은 /tmp비어있는 디렉토리를 가진 스팸 으로,이 작은 프로그램을 제거하고 포크와 기다림으로 크게 복잡하게 만드는 것일 수 있습니다. 대안 적으로, dir예를 들어로 변경 될 수있다. /mnt/chtmp설치시 루트로 작성하십시오. 사용자가 구성 할 수 없도록하고 사용자 소유 경로로 설정하지 마십시오. 시간이 걸리지 않는 symlink 트랩 및 기타 털이 많은 물건에 노출 될 수 있습니다.

chtmp.c

#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mount.h>
int main(int argc, char **argv){
        char *dir = "/proc/sysvipc";    /* LOL */
        if(argc < 2 || !argv[1]) errx(1, "usage: %s prog args ...", *argv);
        argv++;
        if(unshare(CLONE_NEWNS)) err(1, "unshare(CLONE_NEWNS)");
        /* "modern" systemd remounts all mount points MS_SHARED
           see the NOTES in mount_namespaces(7); YUCK */
        if(mount("none", "/", 0, MS_REC|MS_PRIVATE, 0))
                err(1, "mount(/, MS_REC|MS_PRIVATE)");
        if(mount("tmpfs", dir, "tmpfs", 0, 0)) err(1, "mount(tmpfs, %s)", dir);
        if(chdir(dir)) err(1, "chdir %s", dir);
        execvp(*argv, argv);
        err(1, "execvp %s", *argv);
}

1
루트가 아닌 경우에도 새로운 사용자 네임 스페이스를 작성하고 내부에서 tmpfs 마운트를 수행하여 네임 스페이스로이를 수행 할 수 있습니다. 외부 세계로의 새로운 디렉토리 접근을 막는 것은 약간 까다 롭지 만 가능해야합니다.
R .. GitHub 중지 지원 얼음

여전히 CAP_SYS_ADMIN이 필요합니다. 나는 그것을 할 작은 setcap 지원 유틸리티에 대한 아이디어를 가지고 있으며, 그것으로 대답을 업데이트 할 것입니다.
qubert

1
커널이이를 막기 위해 잠기지 않는 한, 사용자 네임 스페이스 생성은 특권 작업이 아닙니다. 기본 디자인은 일반 사용자가 특별한 기능없이 안전하게 할 수 있도록 설계되었습니다. 그러나 많은 배포판이이를 불가능하게하는 충분한 공격 표면 / 위험이 있다고 생각합니다.
R .. GitHub 중지 지원 얼음

터미널에서 시도했습니다. 일부 임시 디렉토리, rm $PWD작업에서 쉘은 여전히 ​​해당 디렉토리에 있습니다. 그러나이 "폴더"에는 새로운 파일을 넣을 수 없습니다. & 3, & 4 파일로 읽기 / 쓰기 만 할 수 있습니다. 따라서 이것은 "임시 폴더"가 아닌 "임시 파일"입니다.
밥 존슨

@BobJohnson 그것은 내 대답에서 이미 말한 것과 다르지 않습니다 ;-)
qubert

0

특정 쉘이 필요합니까?

zsh가 옵션이면 다음을 읽으십시오 zshexpn(1).

<(...) 대신 = (...)를 사용하면 인수로 전달 된 파일은 목록 프로세스의 출력을 포함하는 임시 파일의 이름이됩니다. 이 상하는 해당 프로그램에 대한 <form 대신 사용될 수있다 lseek(참조 : lseek(2)입력 파일에).

[...]

또 다른 문제는 언제든지 임시 파일을 필요로하는 대체와 작업이 경우를 포함, 쉘에 의해 부인되는 발생 &!또는 &|대체를 포함하는 명령의 끝에 나타납니다. 이 경우 쉘에 더 이상 작업 메모리가 없기 때문에 임시 파일이 정리되지 않습니다. 해결 방법은 서브 쉘을 사용하는 것입니다 (예 :

(mycmd =(myoutput)) &!

분기 된 서브 쉘은 명령이 완료 될 때까지 기다린 다음 임시 파일을 제거합니다.

프로세스 대체가 적절한 시간 동안 지속되도록하는 일반적인 해결 방법은이를 익명 쉘 함수 (함수 범위와 함께 즉시 실행되는 쉘 코드)에 매개 변수로 전달하는 것입니다. 예를 들어이 코드는 다음과 같습니다.

() {
   print File $1:
   cat $1
} =(print This be the verse)

다음과 유사한 것을 출력합니다.

File /tmp/zsh6nU0kS:
This be the verse

예를 들어 파일을 해독하고 임시 파일에서 소총을 실행하기 위해 소총 (레인저 파일 관리자의 일부)에서 이것을 사용합니다. 하위 파일이 종료되면 삭제됩니다. (설정하는 것을 잊지 마십시오 $TERMCMD)

# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.