암호화용 파이프를 사용하는 tar 다중 볼륨 모드의 ENOSPC(테이프 끝 감지)

암호화용 파이프를 사용하는 tar 다중 볼륨 모드의 ENOSPC(테이프 끝 감지)

사용tar다중 볼륨 모드오류를 사용하여 ENOSPC첫 번째 테이프의 끝을 감지하고 사용자에게 다음 테이프를 묻는 메시지를 표시합니다. 이 동작을 시뮬레이션하려면 다음 예를 고려하십시오./dev/full

tar -cvf - --multi-volume . > /dev/full

예상한 결과

[...]
Prepare volume #2 for ‘-’ and hit return:

다음과 같은 암호화 프로그램을 통해 tar출력을 전송할 때 문제가 발생합니다 .aespipegpg

tar -cvf - --multi-volume . | gpg -c --batch -q --passphrase 123 > /dev/full

gpg그러면 코드 2로 종료 됩니다.

gpg: [stdout]: write error: No space left on device
gpg: [stdout]: write error: No space left on device
gpg: filter_flush failed on close: No space left on device

ENOSPC는 tar가 특정 errno를 모르기 때문에 분명히 tar로 전파되지 않습니다.gpgbash 스크립트를 사용하여 오류를 포착하고 ENOSPC 오류를 "재발생"시키는 방법이 있습니까 ?tar

예를 들어, 명명된 파이프와 함께 tar를 사용하면 gpg실패할 경우 파이프가 손상되고 tar는 SIGPIPE 141로 존재하게 됩니다. 그러나 ENOSPC여전히 손상된 파이프 오류가 아닌 다른 방법으로 tar에 신호를 보내야 합니다.

고정된 테이프 크기를 지정하는 해결 방법을 피하고 싶습니다. 또한 테이프 스패닝을 처리하는 데 을 사용한다는 것도 알고 있는데 mbuffer, 이는 테이프를 개별적으로 추출할 수 없기 때문에 권장되지 않습니다.

편집: ENOSPC가 발생할 때 tar를 남기고 버퍼에 있는 데이터가 손실될 가능성이 높기 때문에 이것이 더 복잡해진다는 것을 방금 깨달았습니다. 대부분의 테이프 드라이버 구현에서는 이후에 또 다른 쓰기 작업이 발생하도록 허용하지만 gpg 및 aespipe에는 데이터를 버퍼에 저장하기 위한 재시도 논리가 포함되어 있지 않습니다.

편집 2: 추가 연구에 따르면 FreeBSD에는 오류 발생 과 함께 암호화를 수행하는 star옵션이 있는 것으로 나타났습니다.-compress-program-multivolnew-volume-script=...

star: Operation not permitted. Cannot lock fifo memory.
star: Can only compress files

파일이 아닌 장치에 쓰는 경우. 그래서 이것은 또한 막 다른 골목입니다.

답변1

파이프를 통해 쓰기 오류를 전파할 수 없습니다.

어떤 종류의 해킹으로 달성할 수 있다고 하더라도 파이프라인은완충기파이프 판독기가 파이프 기록기에 "신호"를 보내려고 하면 후자는 이미 오류를 일으킨 데이터를 기록하고 이미 성공 상태(>0)를 얻었으며 이에 따라 상태를 업데이트했을 수 있습니다. 그것이 작동하려면 글쓰기 과정이 시간을 거슬러 올라가야 합니다. 게다가 파이프 판독기 자체가 자체 버퍼링 및 상태 유지를 수행할 수 있으며 이로 인해 비동기화가 발생할 수 있습니다.

유일한 방법은 tar일부 채널을 통해 데이터를 전달하는 대신 암호화 루틴을 직접 호출하는 것입니다. 소스 코드를 수정하고 다시 컴파일하는 대신 원숭이/라이브 패치를 사용하여 라이브러리 함수를 LD_PRELOAD대체 write()하고 데이터를 원본 write().

ENOSPC해킹을 사용하여 LD_PRELOAD시뮬레이션하는 방법

ENOSPC이로 인해 40960바이트를 초과하여 쓰려고 시도하면 fd 1(stdout)에 대한 쓰기가 실패하고 그 후에는 카운터를 재설정하고 다시 성공하게 됩니다.

tar -cf filename가 아닌 와 함께 작동하도록 하려면 tar -cf -테스트 fd == 1fd != 2.

$ cat <<'EOT' >enospc.c
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
#include <errno.h>

#define MAX     40960

ssize_t write(int fd, const void *b, size_t z){
        ssize_t w;
        static typeof (write) *o_write;
        static size_t count;
        if(!o_write) o_write = dlsym(RTLD_NEXT, "write");
        if(fd == 1 && count + z > MAX){
                count = 0;
                errno = ENOSPC;
                return -1;
        }
        w = o_write(fd, b, z);
        if(w > 0) count += w;
        return w;
}
EOT

$ cc -Wall -shared enospc.c -o enospc.so -ldl

$ seq -f 'n foo%04g.tar' 1 10000 |
  LD_PRELOAD=./enospc.so tar -M -cf- /etc/X11 > foo0000.tar
tar: Removing leading `/' from member names
Prepare volume #2 for ‘-’ and hit return: Prepare volume #3 for ‘/tmp/foo0001.tar’ and hit return: Prepare volume #4 for ‘/tmp/foo0002.tar’ and hit return: Prepare volume #5 for ‘/tmp/foo0003.tar’ and hit return: Prepare volume #6 for ‘/tmp/foo0004.tar’ and hit return: Prepare volume #7 for ‘/tmp/foo0005.tar’ and hit return: Prepare volume #8 for ‘/tmp/foo0006.tar’ and hit return: Prepare volume #9 for ‘/tmp/foo0007.tar’ and hit return: $

$ ls foo000*
foo0000.tar  foo0002.tar  foo0004.tar  foo0006.tar  foo0008.tar
foo0001.tar  foo0003.tar  foo0005.tar  foo0007.tar

답변2

귀하의 질문에는 몇 가지 문제가 있습니다.

  • 테이프 끝 조건을 감지하는 올바른 방법은 0을 반환하고 errno가 설정되지 않은 write(2)를 확인하는 것입니다. 따라서 다중 볼륨 테이프 아카이브를 지원하는 올바른 tar 구현은 write(2)가 0을 반환하는지 확인합니다.

  • errno ENOSPC는 파일 시스템의 일반 파일에 쓸 때만 생성되므로 이 errno는 다중 볼륨 테이프 아카이브의 기초로 적합하지 않습니다.

  • 파이프를 통해 쓰기 오류를 다시 전파하는 것은 불가능합니다.

  • UNIX tar 명령은 다중 볼륨 아카이브를 지원하지 않습니다.

  • gtar는 다중 볼륨 아카이브 작성을 지원하지만 약 100% 확률로 올바르게 다시 읽을 수 없습니다. 후속 아카이브가 순차적으로 올바른 볼륨 번호를 가지고 있는지 항상 식별할 수 있는 것은 아니기 때문에 5%입니다. 이는 호환되지 않는 새로운 다중 볼륨 형식을 도입하지 않고는 수정할 수 없는 gtar의 설계 결함으로 인해 발생합니다.

  • star는 루트가 호출될 때만 FIFO 메모리 잠금을 시도합니다. 인용한 메시지에 기록된 오류 코드는 sueruser(루트)가 아님을 의미합니다. "루트" 권한이 제한된 환경에서 이 스타 인스턴스를 실행하고 있습니까?

  • 출력이 일반 파일이 아닌 경우 압축기의 출력이 차단되지 않기 때문에 star는 압축기를 실행하지 않지만 tar 구현에서는 출력을 차단해야 합니다. 이 경우 압축하려면 다음과 같은 명령을 호출하십시오.star -c ... | compress ...

일반적으로 tar 프로그램의 출력을 암호화하려면 여러 테이프의 출력을 관리하는 프로그램을 통해 암호화 프로그램의 출력을 전송해야 합니다.

참고: 보다 심층적인 답변을 원하시면 언제든지 추가 정보를 보내주시기 바랍니다.

관련 정보