लिनक्स /proc/<pid>/environ
अपडेट नहीं करता है (जैसा कि मैं इसे समझता हूं, फ़ाइल में प्रक्रिया का प्रारंभिक वातावरण होता है)।
मैं एक प्रक्रिया के वर्तमान वातावरण को कैसे पढ़ सकता हूं ?
लिनक्स /proc/<pid>/environ
अपडेट नहीं करता है (जैसा कि मैं इसे समझता हूं, फ़ाइल में प्रक्रिया का प्रारंभिक वातावरण होता है)।
मैं एक प्रक्रिया के वर्तमान वातावरण को कैसे पढ़ सकता हूं ?
जवाबों:
/proc/$pid/environ
यदि प्रक्रिया अपने स्वयं के वातावरण को बदलती है तो अद्यतन करता है। लेकिन कई कार्यक्रमों है, क्योंकि यह एक सा व्यर्थ है अपने स्वयं के माहौल बदल रहा परेशान नहीं है: एक कार्यक्रम के माहौल न केवल के माध्यम से, सामान्य चैनलों के माध्यम से दिखाई दे रहा है /proc
और ps
, और यहां तक कि नहीं हर यूनिक्स संस्करण सुविधा के इस प्रकार है, तो अनुप्रयोगों भरोसा नहीं करते इस पर।
जहां तक कर्नेल का संबंध है, पर्यावरण केवल execve
प्रोग्राम को शुरू करने वाले सिस्टम कॉल के तर्क के रूप में प्रकट होता है। लिनक्स मेमोरी के माध्यम से एक क्षेत्र को उजागर करता है /proc
, और कुछ प्रोग्राम इस क्षेत्र को अपडेट करते हैं जबकि अन्य नहीं करते हैं। विशेष रूप से, मुझे नहीं लगता कि कोई भी शेल इस क्षेत्र को अपडेट करता है। जैसा कि क्षेत्र का एक निश्चित आकार है, नए चर जोड़ना या मूल्य की लंबाई बदलना असंभव होगा।
PATH=foo
एक शेल में लिखते हैं इसका मतलब यह नहीं है कि शेल संशोधित करने जा रहा है *envp
। कुछ गोले में, जो केवल एक आंतरिक डेटा संरचना को अद्यतन करता है, और यह बाहरी प्रोग्राम निष्पादन कोड है जो अपडेट करता है *envp
। को देखो assign_in_env
में variables.c
बैश स्रोत में, उदाहरण के लिए।
fork
तो libc sys_fork
बाल प्रक्रिया के लिए ढेर आवंटित वातावरण का उपयोग करके कॉल करता है।
argv
से अधिक सामान्य हैं, लेकिन दोनों मौजूद हैं)।
आप किसी प्रक्रिया के प्रारंभिक वातावरण को पढ़ सकते हैं /proc/<pid>/environ
।
यदि कोई प्रक्रिया अपना वातावरण बदलती है, तो पर्यावरण को पढ़ने के लिए आपके पास प्रक्रिया के लिए प्रतीक तालिका होनी चाहिए और वैश्विक चर से पर्यावरण को पढ़ने के ptrace
लिए सिस्टम कॉल (उदाहरण के लिए उपयोग करके gdb
) का उपयोग करें char **__environ
। चल रहे लिनक्स प्रक्रिया से किसी भी चर का मूल्य प्राप्त करने का कोई अन्य तरीका नहीं है।
यही जवाब है। अब कुछ नोटों के लिए।
उपरोक्त मानता है कि प्रक्रिया POSIX अनुपालन है, जिसका अर्थ है कि प्रक्रिया वैश्विक वातावरण का उपयोग करते char **__environ
हुए Ref Spec में निर्दिष्ट के रूप में अपने वातावरण का प्रबंधन करती है ।
एक प्रक्रिया के लिए प्रारंभिक वातावरण प्रक्रिया के ढेर पर एक निश्चित लंबाई के बफर में प्रक्रिया को पारित किया जाता है। (सामान्य तंत्र जो ऐसा करता है linux//fs/exec.c:do_execve_common(...)
।) चूंकि बफर के आकार की गणना प्रारंभिक वातावरण के लिए आवश्यक आकार से अधिक नहीं है, आप मौजूदा चर को मिटाए बिना या स्टैक को नष्ट किए बिना नए चर नहीं जोड़ सकते। इसलिए, किसी प्रक्रिया के वातावरण में बदलाव की अनुमति देने के लिए कोई भी उचित योजना ढेर का उपयोग करेगी, जहां मनमाने आकार में मेमोरी आवंटित की जा सकती है और उसे मुक्त किया जा सकता है, जो कि GNU libc
( glibc
) आपके लिए करता है।
यदि प्रक्रिया का उपयोग करता है glibc
, तो यह POSIX आज्ञाकारी है, Glibc __environ
में घोषित होने के साथ एक पॉइंटर को मेमोरी के साथ glibc//posix/environ.c
आरंभ __environ
करता है कि यह malloc
प्रक्रिया के ढेर से है, फिर स्टैक से प्रारंभिक वातावरण को इस ढेर क्षेत्र में कॉपी करता है। हर बार जब प्रक्रिया setenv
फ़ंक्शन का उपयोग करती है, तो glibc
वह realloc
उस क्षेत्र के आकार को समायोजित करने के लिए करता है __environ
जो नए मूल्य या चर को समायोजित करने के लिए इंगित करता है। (आप glibc स्रोत कोड के साथ डाउनलोड कर सकते हैं git clone git://sourceware.org/git/glibc.git glibc
)। वास्तव में तंत्र को समझने के लिए आपको हर्ड कोड को भी पढ़ना होगा hurd//init/init.c:frob_kernel_process()
(git क्लोन क्लोन git: //git.sv.gnu.org/hurd/hurd.git हर्ड)।
अब यदि नई प्रक्रिया केवल fork
एड है, इसके बाद exec
स्टैक को ओवरराइट किए बिना , तो तर्क और पर्यावरण की नकल जादू में किया जाता है linux//kernel/fork.c:do_fork(...)
, जहां copy_process
रूटीन कॉल dup_task_struct
जो कॉल करके नई प्रक्रिया के स्टैक को आवंटित करता है alloc_thread_info_node
, जो नई प्रक्रिया का उपयोग करके कॉल setup_thread_stack
( linux//include/linux/sched.h
) करता है alloc_thread_info_node
।
अंत में, POSIX __environ
सम्मेलन एक उपयोगकर्ता-स्थान सम्मेलन है। लिनक्स कर्नेल में इसका किसी भी चीज़ से कोई संबंध नहीं है। आप उपयोग glibc
किए बिना और __environ
वैश्विक के बिना एक यूजरस्पेस प्रोग्राम लिख सकते हैं और फिर आपके द्वारा पसंद किए जाने वाले पर्यावरण चर का प्रबंधन कर सकते हैं। ऐसा करने के लिए कोई आपको गिरफ्तार नहीं करेगा, लेकिन आपको अपने स्वयं के पर्यावरण प्रबंधन कार्यों ( setenv
/ getenv
) और अपने स्वयं के रैपर के लिए लिखना होगा sys_exec
और यह संभावना है कि कोई भी यह अनुमान लगाने में सक्षम नहीं होगा कि आप अपने वातावरण में बदलाव कहां डालते हैं।
/proc/[pid]/
दिखाई देने वाली फ़ाइलों में से कई में एक अजीब एन्कोडिंग है (किसी और को क्या और क्यों पता हो सकता है)। मेरे लिए, बस cat environ
वास्तव में पढ़ने के लिए प्रारूप में पर्यावरण चर प्रिंट आउट होगा। cat environ | strings
मेरे लिए यह हल किया।
इसे अपडेट किया जाता है और जब प्रक्रिया अपने पर्यावरण चर को प्राप्त / हटा देती है। क्या आपके पास एक संदर्भ है जो बताता है कि environ
फ़ाइल प्रक्रिया में प्रक्रिया के लिए अद्यतन नहीं की गई है।
xargs --null --max-args=1 echo < /proc/self/environ
या
xargs --null --max-args=1 echo < /proc/<pid>/environ
या
ps e -p <pid>
ऊपर ps
आउटपुट प्रारूप में प्रक्रिया के पर्यावरण चर को प्रिंट करेगा , पर्यावरण चर को सूची के रूप में देखने के लिए पाठ-प्रसंस्करण (पार्सिंग / फ़िल्टरिंग) आवश्यक है।
सोलारिस (पूछा नहीं गया, लेकिन संदर्भ के लिए मैं यहां पोस्ट करूंगा):
/usr/ucb/ps -wwwe <pid>
या
pargs -e <pid>
संपादित करें: / proc / pid / environ अपडेट नहीं है! मुझे सही साबित होना है। सत्यापन की प्रक्रिया नीचे है। हालाँकि, जिन बच्चों से प्रक्रिया कांटेक्ट होती है, वे प्रक्रिया पर्यावरण चर का वारिस कर देते हैं और यह उनके संबंधित / प्रोक / से / फ़िनिश फ़ाइल में दिखाई देता है। (स्ट्रिंग्स का उपयोग करें)
शेल में: यहाँ xargs एक चाइल्ड प्रोसेस है और इसलिए पर्यावरण वेरिएबल को इनहेरिट करता है और इसकी /proc/self/environ
फाइल में भी दिखाई देता है ।
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ export MASK=NIKHIL
[centos@centos t]$ printenv | grep MASK
MASK=NIKHIL
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
MASK=NIKHIL
[centos@centos t]$ unset MASK
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
[centos@centos t]$
अन्य सत्र से इसकी जाँच करना, जहाँ टर्मिनल / सत्र शेल की बाल प्रक्रिया नहीं है जहाँ पर्यावरण चर सेट किया गया है।
एक ही मेजबान पर एक और टर्मिनल / सत्र से सत्यापन:
टर्मिनल 1 :: ध्यान दें कि प्रिंटेन फोर्कलिफ्ट है और बैश की एक बच्चे की प्रक्रिया है और इसलिए यह अपनी स्वयं की फाइल को पढ़ता है।
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
टर्मिनल 2: एक ही मेजबान पर - इसे उसी शेल में लॉन्च न करें जहां उपरोक्त चर सेट किया गया था, टर्मिनल को अलग से लॉन्च करें।
[centos@centos ~]$ echo $$
4436
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey
[centos@centos ~]$ strings -f /proc/2610/environ | grep -i spidey
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey
[centos@centos ~]$
export foo=bar
एक बैश सत्र (pid xxxx) cat /proc/xxxx/environ | tr \\0 \\n
में करता हूं, फिर दूसरे बैश सत्र में करता हूं और मुझे दिखाई नहीं देता foo
।
gdb
पीआईडी से जुड़े पर्यावरण की जाँच करने की कोशिश की , लेकिन अभी भी वहाँ कोई संदर्भ नहीं है। जब भी कोई परिवर्तन होता है, तो मेमोरी में पर्यावरण वैरिएबल ब्लॉक वास्तविक हो जाता है और खरीद फाइलसिस्टम में अपनी प्रक्रिया 'environ फ़ाइल में प्रतिबिंबित नहीं होता है, लेकिन फिर भी बच्चे की प्रक्रिया को विरासत में प्राप्त करने की अनुमति देता है। इसका मतलब है कि यह आसान हो सकता है कि आंतरिक विवरण जानने के लिए जब कांटा होता है, तो बच्चे की प्रक्रिया को पर्यावरण चर की नकल कैसे मिलती है।
वैसे लेखक के वास्तविक इरादों के साथ निम्नलिखित का संबंध नहीं है, लेकिन यदि आप वास्तव में "READ" करना चाहते हैं /proc/<pid>/environ
, तो आप कोशिश कर सकते हैं
strings /proc/<pid>/environ
जो इससे बेहतर है cat
।
strings
। इसे सरल रखें।
xargs --null
।
tr '\0' '\n' < /proc/$$/environ | ...