एक प्रक्रिया बनाना एक ही फ़ाइल नाम के लिए एक अलग फ़ाइल पढ़ें


9

मेरे पास एक एप्लिकेशन है जो एक फ़ाइल पढ़ता है। चलो इसे प्रक्रिया नाम और फ़ाइल ~ / .configuration कहते हैं । जब प्रक्रियानाम चलता है तो यह हमेशा पढ़ता है ~ / .configuration और अलग तरीके से कॉन्फ़िगर नहीं किया जा सकता है। अन्य अनुप्रयोग भी हैं जो "~ / .configuration" पर निर्भर करते हैं, पहले और बाद में, लेकिन नहीं जब तक प्रक्रियानाम चल रहा है।

एक स्क्रिप्ट में रैपिंग प्रक्रियानाम जो ~ / .configuration की सामग्री को प्रतिस्थापित करता है, एक विकल्प है, लेकिन मेरे पास हाल ही में एक पावर आउटेज था (जबकि सामग्री बाहर स्वैप की गई थी), जहां मैंने उक्त फ़ाइल की पिछली सामग्री खो दी है, इसलिए यह वांछनीय नहीं है।

क्या कोई तरीका है (शायद किसी चीज़ को संबंधित रूप से उपयोग करते हुए LD_DEBUG=files processname?) किसी प्रक्रिया को किसी विशिष्ट फ़ाइल को पढ़ने की कोशिश करने पर विभिन्न सामग्रियों को पढ़ने में मूर्ख बनाने के लिए? निष्पादन योग्य में फ़ाइल नाम को खोजना और बदलना थोड़ा बहुत आक्रामक है, लेकिन साथ ही साथ काम भी करना चाहिए।

मुझे पता है कि एक कर्नेल मॉड्यूल लिखना संभव है जो open()कॉल ( https://news.ycombinator.com/item?id=2972958 ) लेता है , लेकिन क्या कोई सरल या क्लीनर तरीका है?

संपादित करें: जब मैं इस प्रक्रिया के निष्पादन योग्य में ~ / .configuration की खोज कर रहा था तो मुझे लगा कि इसने ~ / .configuration पढ़ने से पहले एक और फ़ाइल नाम पढ़ने की कोशिश की है । समस्या सुलझ गयी।


2
यह कुछ इसी तरह की समस्या केLD_PRELOAD साथ या FUSE के माध्यम से किया जा सकता है , लेकिन मुझे कोई मौजूदा कार्यान्वयन नहीं पता है।
गिल्स एसओ- बुराई को रोकें '

जवाबों:


6

लिनक्स के हाल के संस्करणों में, आप कर सकते हैं साझाकरण हटाने के नाम स्थान माउंट । यही है, आप ऐसे प्रोसेस शुरू कर सकते हैं जो वर्चुअल फाइल सिस्टम को अलग तरह से देखते हैं (फाइल सिस्टम अलग-अलग माउंट किए गए हैं)।

यह भी किया जा सकता है chroot, लेकिन unshareआपके मामले के लिए अधिक अनुकूल है।

जैसे 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अगर यह एक और उपयोगकर्ता के रूप में चलाने की जरूरत है ।


मुझे लगता है कि आपका समाधान शायद अब तक दिए गए दो में से बेहतर है (और ओपी के बाद क्या है, यह समय के आधार पर पुनर्निर्देशित करना या एक खोज प्रक्रिया के परिणाम iffy मेरे लिए लगता है), लेकिन मुझे लगता है कि वे एक ही फाइल चाहते हैं अलग दिखाने के लिए। इसलिए उन्हें संभवतः इसे कहीं और माउंट करना होगा और एक सिम्लिंक का उपयोग करना होगा, जिसे अलग-अलग माउंट बिंदुओं पर गिनकर रीडायरेक्शन के वास्तविक बिंदु के रूप में कार्य करना होगा।
ब्राचली

1
@JoelDavis, आप किसी भी फ़ाइल को बांध सकते हैं, न केवल निर्देशिका वाले।
स्टीफन चेज़लस

टीआईएल। क्या इसके साथ सुरक्षा नियंत्रण हैं, हालांकि? मैंने इसे एक उपनिर्देशिका का उपयोग करने की कोशिश की, जहाँ मैं (/ / / fstab से बाइंडिंग) में था और यह "नॉट ए डाइरेक्टरी" था, लेकिन मैंने उसी के तहत बहुत अधिक /testकाम किया और यह बिना किसी समस्या के काम किया।
ब्राचली

दरअसल, nm मैं अंतर देख सकता हूं, मैंने इसे पहली बार एक डायरेक्टरी में किया और अगली फाइल। मैं यह मान रहा था कि यह VFS को उचित रूप में पुनर्निर्देशित / संशोधित करेगा। Anywho, नए खिलौने के लिए धन्यवाद।
ब्राचली

3

मुलायम लिंक।

अधिकांश समय एक सॉफ्ट लिंक के साथ दो कॉन्फिग फाइल बनाएं और उनमें से एक को इंगित करें, लेकिन विशेष ऐप के चलने पर सॉफ्ट लिंक को दूसरे को इंगित करने के लिए बदलें।

(मुझे पता है कि यह एक भयानक हैक है, लेकिन यह फ़ाइल सामग्री को बदलने की तुलना में थोड़ा अधिक विश्वसनीय है)।

या, $ HOME में हेरफेर करें।

उस स्क्रिप्ट में जो कष्टप्रद प्रक्रिया शुरू करती है, $ $ HOME को नियमित रूप से $ HOME निर्देशिका के तहत कुछ होने के लिए सेट करें, और आपके ऐप को तब वहाँ स्थित कॉन्फ़िग फ़ाइल का उपयोग करना चाहिए (परीक्षण किया गया है, और बेसिक शेल कमांड के लिए काम करता है, ~ एक्सपैंड टू $ होम)।

इस प्रक्रिया के आधार पर, $ HOME बदलने के अनपेक्षित परिणाम हो सकते हैं (अर्थात आउटपुट फ़ाइलें गलत जगह समाप्त हो सकती हैं)।


1

आप इसे LD_PRELOAD ट्रिक का उपयोग करके कर सकते हैं । यहाँ एक कार्यान्वयन है जो मानचित्रों को एक विशिष्ट उपसर्ग के साथ दूसरे स्थान पर शुरू करता है। कोड भी जीथब पर है

उदाहरण के लिए, आप /etc/रूट किए बिना किसी फ़ाइल के अस्तित्व को नकली बना सकते हैं । यह स्वयं उस क्लाक क्लाइंट के लिए आवश्यक था जो फ़ाइल के /etc/ownCloud/sync-exclude.listमौजूद न होने पर काम करने से मना कर देता है।

यह ओवरराइडिंग के द्वारा काम करता है open()और open64()एक डायरेक्टरी को दूसरे में मैप करने के लिए कार्य करता है , उदाहरण के लिए सभी open()कॉल्स को /etc/ownCloud/...रीडायरेक्ट किया जा सकता है /home/user1/.etc/ownCloud/...

बस समायोजित करें path_map, फिर संकलित करें और अपने कार्यक्रम को पहले से लोड किए गए परिवाद के साथ चलाएं:

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);
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.