프로세스가 동일한 파일 이름으로 다른 파일을 읽도록 만들기


9

파일을 읽는 응용 프로그램이 있습니다. 프로세스 이름~ / .configuration 파일 이라고합시다 . 때 processname은 실행 항상 읽고 ~ / .configuration을 다르게 구성 할 수 없습니다. 프로세스 이름 이 실행 중이 아닌 전과 후에 "~ / .configuration"을 사용하는 다른 응용 프로그램도 있습니다 .

포장 processname 의 내용을 대체하는 스크립트에 ~ / .configuration은 옵션이지만, (내용이 스왑 아웃하는 동안)이 바람직하지 그래서 내가 말했다 파일의 이전 내용을 잃은 어디 최근에 정전이 있었다.

(아마도 먼 관련된 것을 사용하는 방법이있다 LD_DEBUG=files processname가 특정 파일을 읽으려고 할 때 서로 다른 내용을 읽어 들이기로 프로세스를 속여위한은?)? 실행 파일에서 파일 이름을 검색하고 바꾸는 것은 너무 침습적이지만 잘 작동합니다.

open()전화 를받는 커널 모듈 ( https://news.ycombinator.com/item?id=2972958 ) 을 작성할 수는 있지만 더 간단하거나 깔끔한 방법이 있습니까?

편집 : processname 실행 파일 에서 ~ / .configuration 을 검색 할 때 ~ / .configuration 을 읽기 전에 다른 파일 이름을 읽으려고한다는 것을 알았습니다 . 문제 해결됨.


2
이것은 다소 비슷한 문제LD_PRELOAD 와 같이 또는 FUSE 를 통해 수행 될 수 있지만 기존 구현을 모르겠습니다.
Gilles 'SO- 악마 그만'

답변:


6

리눅스의 최신 버전, 당신은 할 수 공유 해제 (가) 네임 스페이스를 장착 . 즉, 파일 시스템이 다르게 마운트 된 상태에서 가상 파일 시스템을 다르게 보는 프로세스를 시작할 수 있습니다.

이것으로도 가능 chroot하지만 unshare귀하의 경우에 더 적합합니다.

마찬가지로 mount 네임 스페이스에 chroot권한이 unshare있는 수퍼 유저가 필요 합니다.

따라서 파일 ~/.configuration~/.configuration-for-that-cmd파일 이 있다고 가정 하십시오.

~/.configuration실제로 바인드 마운트 프로세스를 시작 ~/.configuration-for-that-cmd하고 실행할 수 that-cmd있습니다.

처럼:

sudo unshare -m sh -c "
   mount --bind '$HOME/.configuration-for-that-cmd' \
                '$HOME/.configuration' &&
     exec that-cmd"

that-cmd그리고 모든 후손 프로세스는 다르게 보일 것 ~/.configuration입니다.

that-cmd위는로 실행되며 다른 사용자 로 실행해야하는 경우 root사용 sudo -u another-user that-cmd합니다 .


귀하의 솔루션이 지금까지 제공된 두 가지 중 더 낫다고 생각합니다 (그리고 OP가 후의 것을 고려할 때 시간이나 리디렉션 프로세스의 결과에 따라 리디렉션되는 것이 나에게 적합하다고 생각됩니다). 그러나 나는 그들이 단일 파일을 원한다고 생각합니다 다르게 표시됩니다. 따라서 다른 곳으로 마운트하고 심볼릭 링크를 사용하여 실제 마운트 지점으로 다른 마운트 지점을 계산해야합니다.
Bratchley

1
@JoelDavis, 디렉토리 파일뿐만 아니라 모든 파일을 바인드 마운트 할 수 있습니다.
Stéphane Chazelas

틸. 그래도 보안 관리 기능이 있습니까? 내가있는 하위 디렉토리 (/ etc / fstab에서 바인딩)를 사용하여 시도했지만 "디렉토리가 아님"을 반환했지만 거의 동일한 /test작업을 수행했으며 문제없이 작동했습니다.
Bratchley

실제로 nm, 차이점을 알 수 있습니다. 처음에는 디렉토리에, 다음에는 파일에했습니다. VFS를 적절하게 리디렉션 / 수정한다고 가정했습니다. 누구든지, 새 장난감 주셔서 감사합니다.
Bratchley

3

소프트 링크.

두 개의 구성 파일을 작성하고 대부분 소프트 링크를 사용하여 그 중 하나를 가리 키지 만 특수 앱이 실행될 때 다른 링크를 가리 키도록 소프트 링크를 변경하십시오.

(이것은 끔찍한 해킹이지만 파일 내용을 변경하는 것보다 약간 더 안정적입니다.)

또는 $ HOME을 조작하십시오.

성가신 프로세스를 시작하는 스크립트에서 $ HOME을 일반 $ HOME 디렉토리 아래에 놓으십시오. 그러면 응용 프로그램은 거기에있는 구성 파일을 사용해야합니다 (테스트되고 기본 쉘 명령에서 작동합니다.

프로세스가 수행하는 작업에 따라 $ HOME을 변경하면 의도하지 않은 결과가 발생할 수 있습니다 (예 : 출력 파일이 잘못된 위치에있을 수 있음).


1

LD_PRELOAD 트릭을 사용하여이 작업을 수행 할 수 있습니다 . 다음은 특정 접두사로 시작하는 경로를 다른 위치에 매핑하는 구현입니다. 코드는 github에도 있습니다 .

예를 들어, /etc/루트 가 아닌 파일의 존재를 가짜로 만들 수 있습니다. 파일 /etc/ownCloud/sync-exclude.list이 존재하지 않을 때 작동을 거부하는 owncloud 클라이언트에 필요했습니다 .

하나의 디렉토리를 다른 디렉토리에 매핑하기 위해 open()and open64()함수를 재정 의하여 작동 합니다 (예 : 모든 open()호출을 /etc/ownCloud/...로 리디렉션 할 수 있음) /home/user1/.etc/ownCloud/....

그냥 조정하고 path_maplib를 미리로드하여 프로그램을 컴파일하고 실행하십시오.

gcc -std=c99 -Wall -shared -fPIC path-mapping.c -o path-mapping.so -ldl

LD_PRELOAD=/path/to/my/path-mapping.so someprogram

소스 코드 path-mapping.c:

#define _GNU_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdarg.h>
#include <malloc.h>

// List of path pairs. Paths beginning with the first item will be
// translated by replacing the matching part with the second item.
static const char *path_map[][2] = {
    { "/etc/ownCloud/", "/home/user1/.etc/ownCloud/" },
};

__thread char *buffer = NULL;
__thread int buffer_size = -1;

typedef FILE* (*orig_fopen_func_type)(const char *path, const char *mode);
typedef int (*orig_open_func_type)(const char *pathname, int flags, ...);

static int starts_with(const char *str, const char *prefix) {
    return (strncmp(prefix, str, strlen(prefix)) == 0);
}

static char *get_buffer(int min_size) {
    int step = 63;
    if (min_size < 1) {
        min_size = 1;
    }
    if (min_size > buffer_size) {
        if (buffer != NULL) {
            free(buffer);
            buffer = NULL;
            buffer_size = -1;
        }
        buffer = malloc(min_size + step);
        if (buffer != NULL) {
            buffer_size = min_size + step;
        }
    }
    return buffer;
}

static const char *fix_path(const char *path)
{
    int count = (sizeof path_map) / (sizeof *path_map); // Array length
    for (int i = 0; i < count; i++) {
        const char *prefix = path_map[i][0];
        const char *replace = path_map[i][1];
        if (starts_with(path, prefix)) {
            const char *rest = path + strlen(prefix);
            char *new_path = get_buffer(strlen(path) + strlen(replace) - strlen(prefix));
            strcpy(new_path, replace);
            strcat(new_path, rest);
            printf("Mapped Path: %s  ==>  %s\n", path, new_path);
            return new_path;
        }
    }
    return path;
}


int open(const char *pathname, int flags, ...)
{
    const char *new_path = fix_path(pathname);

    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open");

    // If O_CREAT is used to create a file, the file access mode must be given.
    if (flags & O_CREAT) {
        va_list args;
        va_start(args, flags);
        int mode = va_arg(args, int);
        va_end(args);
        return orig_func(new_path, flags, mode);
    } else {
        return orig_func(new_path, flags);
    }
}

int open64(const char *pathname, int flags, ...)
{
    const char *new_path = fix_path(pathname);

    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open64");

    // If O_CREAT is used to create a file, the file access mode must be given.
    if (flags & O_CREAT) {
        va_list args;
        va_start(args, flags);
        int mode = va_arg(args, int);
        va_end(args);
        return orig_func(new_path, flags, mode);
    } else {
        return orig_func(new_path, flags);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.