किसी फ़ाइल के अस्तित्व में नहीं होने पर मैं किसी प्रक्रिया को कैसे रौंद सकता हूँ?


31

मेरे पास एक प्रोग्राम है जो अपनी सेटिंग्स को स्टोर करता है ~/.config/myprogramमैं अंतःक्रियात्मक रूप से और बैच पंक्तिबद्ध प्रणाली के साथ दोनों का उपयोग करता हूं। अंतःक्रियात्मक रूप से चलने पर, मैं चाहता हूं कि यह प्रोग्राम मेरी कॉन्फ़िगरेशन फ़ाइलों का उपयोग करे (और यह करता है)। लेकिन जब बैच मोड में चल रहा है, तो विन्यास फाइल आवश्यक नहीं है क्योंकि मैं कमांड लाइन विकल्प निर्दिष्ट करता हूं जो सभी प्रासंगिक सेटिंग्स को अधिलेखित करता है। इसके अलावा, नेटवर्क पर कॉन्फ़िगरेशन फ़ाइलों तक पहुँचने से प्रोग्राम का स्टार्टअप समय कई सेकंड बढ़ जाता है; यदि फ़ाइलें मौजूद नहीं हैं, तो प्रोग्राम बहुत तेज़ी से लॉन्च होता है (जैसा कि प्रत्येक कार्य में केवल एक मिनट लगता है, यह बैच जॉब विवादास्पद पर महत्वपूर्ण प्रभाव डालता है)। लेकिन क्योंकि मैं भी कार्यक्रम का उपयोग अंतःक्रियात्मक रूप से करता हूं, मैं हर समय अपनी कॉन्फ़िगरेशन फ़ाइलों को स्थानांतरित / हटाना नहीं चाहता। इस बात पर निर्भर करता है कि कब मेरे बैच की नौकरियां क्लस्टर पर आधारित होंगी (अन्य उपयोगकर्ताओं के उपयोग के आधार पर),

(इसके अलावा: नेटवर्क फ़ाइल का प्रदर्शन इतना धीमा है कि शायद एक बग है, लेकिन मैं सिर्फ क्लस्टर का एक उपयोगकर्ता हूं, इसलिए मैं केवल इसके चारों ओर काम कर सकता हूं, इसे ठीक नहीं कर सकता।)

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

मैं इस कार्यक्रम के विशेष उदाहरणों को कैसे अपनी कॉन्फ़िगरेशन फ़ाइलों के बहाने में बदल सकता हूं (कार्यक्रम को संशोधित किए बिना) मौजूद नहीं है? मैं फॉर्म के रैपर के लिए उम्मीद कर रहा हूं pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options..., लेकिन मैं अन्य समाधानों के लिए तैयार हूं।


2
आप इसे एक ऐसे उपयोगकर्ता के रूप में चला सकते हैं जिसके पास फ़ाइल पढ़ने की अनुमति नहीं है।
Psimon

1
@psimon क्लस्टर के "बस एक उपयोगकर्ता" के रूप में, मैं अपने बैच की नौकरी को चलाने के लिए एक नया उपयोगकर्ता नहीं बना सकता। हालांकि यह एक चतुर विचार है, और अगर कोई बेहतर सुझाव नहीं है, तो मैं क्लस्टर व्यवस्थापक को मेरे लिए यह करने के लिए तैयार करूंगा।
जेफरी बोसबोम

या एक स्क्रिप्ट सेट करें जो पहले कॉन्फ़िगरेशन फ़ाइल का नाम बदल देता है, प्रोग्राम चलाता है और फिर दोबारा कॉन्फ़िगरेशन फ़ाइल का नाम बदलता है।
Psimon

@psimon मुझे लगता है कि मैं और अधिक स्पष्ट हो सकता था: मैं एक ही समय में और बैच मोड में अंतःक्रियात्मक रूप से कार्यक्रम का उपयोग कर सकता हूं, यह इस बात पर निर्भर करता है कि मेरे बैच की नौकरियां कब क्लस्टर पर निर्धारित होती हैं।
जेफरी बोसबोम

1
हां, यदि इसके गतिशील रूप से जुड़ा हुआ है, तो आप LD_PRELOADहुक का उपयोग कर सकते हैं । यह आसान है (आप इसे लागू कर सकते हैं एक या दो घंटे में, यदि आप सी जानते हैं) विकल्प की तुलना में, जो है ptrace। आप शायद ऐसा करने के लिए नकलीचोट का उपयोग कर सकते हैं (जो LD_PRELOAD है, मेरा मानना ​​है)।
व्युत्पन्न

जवाबों:


33

वह प्रोग्राम संभवतः उस फ़ाइल के पथ को हल करता है $HOME/.config/myprogram। तो आप इसे बता सकते हैं कि आपके घर की निर्देशिका कहीं और है, जैसे:

HOME=/nowhere your-program

अब, हो सकता है कि आपके प्रोग्राम को आपके होम डायरेक्टरी में कुछ और संसाधन की आवश्यकता हो। यदि आप जानते हैं कि वे कौन से हैं, तो आप अपने प्रोग्राम के लिए एक नकली घर तैयार कर सकते हैं, जिसमें उस संसाधन की जरूरत हो।

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram

5
यह उत्तर मेरी समस्या को हल करता है, इसलिए मैंने इसे स्वीकार कर लिया है, हालांकि यह इस प्रश्न के शीर्षक में प्रश्न का पूरी तरह से सामान्य उत्तर नहीं है। एक प्रीलोड हुक, जैसा कि एक अन्य उत्तर में वर्णित है, एक अधिक सामान्य (लेकिन यह भी उच्च-प्रयास) समाधान है।
जेफरी बोसबोम

28

यदि अन्य सभी विफल हो जाते हैं, तो एक रैपर लाइब्रेरी लिखें, जिसे आप उपयोग करके इंजेक्ट करेंगे LD_PRELOADताकि कॉल को open("/home/you/my-program/config.interactive")इंटरसेप्ट किया जा सके लेकिन कोई भी अन्य गुजर जाएगा। यह किसी भी प्रकार के कार्यक्रम, यहां तक ​​कि शेल स्क्रिप्ट के लिए काम करता है, क्योंकि यह सिस्टम कॉल को फ़िल्टर करेगा।

extern int errno;

int open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    return get_real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1;
  }
}

नोट: मैंने इस कोड का परीक्षण नहीं किया है, और मुझे यकीन नहीं है कि यह errnoहिस्सा 100% काम करता है।

देखो कैसे और fakerootजैसे कॉल के लिए यह करता है ।getuid(2)stat(2)

असल में, लिंकर उस एप्लिकेशन को आपकी लाइब्रेरी से लिंक करेगा, जो openप्रतीक को ओवरराइड करता है। चूंकि आप openअपने स्वयं के पुस्तकालय में नामित दो अलग-अलग फ़ंक्शन का उपयोग नहीं कर सकते हैं , इसलिए आपको इसे दूसरे भाग (जैसे get_real_open) में अलग करना होगा जो मूल openकॉल के लिए लिंक करेगा ।

मूल: ./Application

Application -----> libc.so
            open()

पकड़ा: LD_PRELOAD=yourlib_wrap.so ./Application

Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
            open()                 get_real_open()                 open()

संपादित करें: जाहिरा तौर पर एक ldध्वज है जिसे आप सक्षम कर सकते हैं ( --wrap <symbol>) जो आपको डबल लिंकिंग का सहारा लिए बिना रैपर लिखने की अनुमति देता है:

/* yourlib.c */
#include <stdio.h>

int __real_open(const char *pathname, int flags)

int __wrap_open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    /* the undefined reference here will resolve to "open" at linking time */
    return __real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1; 
  }
}

2

अपनी कॉन्फ़िगरेशन फ़ाइल को रास्ते से हटाएं, और इंटरेक्टिव उपयोग-केस के लिए एक शेल स्क्रिप्ट आवरण लिखें जो फ़ाइल को उसके सामान्य गंतव्य में कॉपी करता है, प्रोग्राम चलाता है, और बाहर निकलने पर इसे हटा देता है।


मेरा हालिया संपादन देखें: मैं बैच शेड्यूलिंग को नियंत्रित नहीं करता हूं, इसलिए हो सकता है कि मैं एक ही समय में कार्यक्रम का उपयोग कर रहा हूं और एक बैच की नौकरी के हिस्से के रूप में।
जेफरी बोसबोम

1

यह यूनियनफुट / एफ़्यू के साथ संभव होना चाहिए। आप chrootप्रक्रिया के लिए एक वातावरण बनाते हैं। आप वास्तविक निर्देशिका का उपयोग केवल पढ़ने के लिए परत के रूप में करते हैं और उसके ऊपर एक खाली डालते हैं। फिर आप chrootवातावरण में संबंधित निर्देशिका में Unionfs वॉल्यूम को माउंट करते हैं और वहां फ़ाइल हटाते हैं। प्रक्रिया इसे नहीं देखेगी लेकिन अन्य सभी करते हैं।


0

कॉन्फ़िगरेशन फ़ाइल का नाम बदलें उदा config.interactive। उदाहरण के लिए एक और खाली फ़ाइल बनाएँ config.script

अब, एक नरम लिंक बनाएं config(या जो भी एप्लिकेशन को कॉन्फ़िगरेशन फ़ाइल के रूप में अपेक्षा करता है) जो भी आपको आवश्यक है, वास्तविक कॉन्फिगरेशन और अपना एप्लिकेशन चलाएं।

ln -s config.interactive config

अपने लिंक को बाद में साफ करना याद रखें।


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

1
रवींद्र! मुझे सोचने और जल्दी टाइप करने की आवश्यकता है। क्या यह एक बड़ा अनुप्रयोग है? क्या इसे चेरोट में स्थानांतरित किया जा सकता है और अंतःक्रियात्मक रूप से वहां से भाग सकता है? यह सब इस बात पर निर्भर करता है कि कार्यक्रम किसके साथ इंटरैक्ट करता है, मुझे लगता है। यह भी एक बहुत ही कठिन काम हो सकता है कि यह सब कुछ एक chroot में भी आवश्यक हो। (मुझे लगता है कि मैंने खुद को उस विकल्प से बाहर कर दिया है!)
garethTheRed

0

यदि आपने ठीक से बताया है कि आपका प्रोग्राम कॉन्फ़िगरेशन फ़ाइल का उपयोग कैसे करता है, तो मैंने इसे अनदेखा कर दिया है। कई कार्यक्रमों (जैसे bashऔर vi) तुरंत प्रारंभ पर एक विन्यास फाइल चैक करेंगे; यदि फ़ाइल मौजूद है, तो उसे पढ़ें और बंद करें। ये प्रोग्राम इन आरंभीकरण फ़ाइलों को फिर से एक्सेस नहीं करते हैं। यदि आपका कार्यक्रम ऐसा है, तो पढ़ें।

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

DELAY_TIME=1
REALPATH="~/.config/myprogram"
HOLDPATH="${REALPATH}.hold"

mv "$REALPATH" "$HOLDPATH"
(sleep "$DELAY_TIME"; mv "$HOLDPATH" "$REALPATH")&
myprogram

यह कॉन्फ़िगरेशन फ़ाइल को रास्ते से हटाता है, लेकिन फिर इसे एक सेकंड बाद में वापस ले जाता है, भले ही myprogramवह अभी भी चल रहा हो। यह उस समय की एक बहुत ही संक्षिप्त विंडो बनाता है जिसके दौरान फ़ाइल अनुपलब्ध है - क्या संभावना है कि आप इस विंडो के दौरान प्रोग्राम को अंतःक्रियात्मक रूप से चलाएंगे? (यहां तक ​​कि अगर आप करते हैं, तो आप बस बाहर निकल सकते हैं और पुनरारंभ कर सकते हैं, और कॉन्फ़िगरेशन फ़ाइल संभवतः वापस आ जाएगी।)

यह एक दौड़ की स्थिति पैदा करता है; यदि प्रोग्राम को फ़ाइल खोलने के लिए पाने में बहुत लंबा समय लगता है, तो उसे वास्तविक फ़ाइल मिल सकती है। यदि ऐसा अक्सर होता है कि यह एक समस्या है, तो बस DELAY_TIME का मान बढ़ाएं।


1
सबसे बुरी चीज क्या है जो गलत हो सकती है? मैंने सचमुच ऐसा होता देखा है। उत्पादन में।
हेंक लैंगवेल्ड

-1

मैं स्टीफ़न के जवाब की तरह है, लेकिन यह होगा चाल किसी भी फाइल को विश्वास में किसी भी कार्यक्रम है खाली - (क्योंकि इसके dentry अस्थायी रूप से एक फ़ाइल है कि वास्तव में रिक्त है के लिए अंक) :

cat <./test.txt
###OUTPUT###
notempty

mount --bind /dev/null ./test.txt
cat <./test.txt
###NO OUTPUT###

umount ./test.txt
cat <./test.txt
###OUTPUT###
notempty

आप यह भी कर सकते हैं:

mount --bind ./someotherconfig.conf ./unwanted.conf

अगर तुम चाहते हो।


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

@Scott - मैं असहमत हूं - इससे पहले कि हर दूसरे mvने फ़ाइल में आईएनजी पर कुछ भिन्नता की सिफारिश की - जिसके इसके डेंट्री को प्रभावित करने के अलावा अन्य परिणाम हो सकते हैं जैसे कि वास्तव में फ़ाइल या अन्य को काट देना और आदि - जबकि यह कुछ भी नहीं पर काम करता है। फिर भी, मुझे यह अनुमान लगाना चाहिए unshareकि mount...
माइक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.