วิธีอ่านตัวแปรสภาวะแวดล้อมของกระบวนการ


43

ลินุกซ์/proc/<pid>/environไม่อัปเดต (ตามที่ฉันเข้าใจว่าไฟล์มีสภาพแวดล้อมเริ่มต้นของกระบวนการ)

ฉันจะอ่านสภาพแวดล้อมปัจจุบันของกระบวนการได้อย่างไร

คำตอบ:


20

/proc/$pid/environจะอัปเดตหากกระบวนการเปลี่ยนสภาพแวดล้อมของตนเอง แต่หลายโปรแกรมไม่รำคาญสภาพแวดล้อมที่เปลี่ยนแปลงตัวเองเพราะมันเป็นบิตไม่มีจุดหมาย: สภาพแวดล้อมของโปรแกรมไม่สามารถมองเห็นผ่านช่องทางปกติเพียงผ่าน/procและpsและแม้ไม่ทุกตัวแปรยูนิกซ์มีชนิดของคุณลักษณะนี้เพื่อให้การใช้งานที่ไม่ต้องพึ่งพา บนมัน

เท่าที่เคอร์เนลเกี่ยวข้องสิ่งแวดล้อมจะปรากฏขึ้นเป็นอาร์กิวเมนต์ของการexecveเรียกระบบที่เริ่มต้นโปรแกรมเท่านั้น Linux แสดงพื้นที่ในหน่วยความจำผ่าน/procและบางโปรแกรมอัพเดตพื้นที่นี้ในขณะที่บางโปรแกรมไม่ทำ โดยเฉพาะอย่างยิ่งฉันไม่คิดว่าเชลล์จะอัพเดทพื้นที่นี้ เนื่องจากพื้นที่มีขนาดคงที่จึงไม่สามารถเพิ่มตัวแปรใหม่หรือเปลี่ยนความยาวของค่าได้


ดังนั้นอย่างมีประสิทธิภาพไม่มีวิธีการเข้าถึงกระบวนการ '* envp (อาร์เรย์ของตัวชี้ไปยังการตั้งค่าสภาพแวดล้อม) @Gilles คุณสามารถแสดงได้หรือไม่ว่าสามารถแนบดีบักเกอร์และอ่านอาเรย์ของพอยน์เตอร์กับการตั้งค่าสภาพแวดล้อมได้
Nikhil Mulley

2
@Nikhil แน่นอนว่ามันเป็น แต่เพียงเพราะคุณเขียนในเปลือกไม่ได้หมายความว่าเปลือกจะไปปรับเปลี่ยนPATH=foo ในเปลือกหอยบางที่การปรับปรุงเพียงโครงสร้างข้อมูลภายในและก็เป็นโค้ดโปรแกรมภายนอกว่าการปรับปรุง*envp *envpดูassign_in_envในvariables.cแหล่งทุบตีเช่น
Gilles 'SO- หยุดความชั่วร้าย'

9
@Gilles: คำตอบนี้ทำให้เข้าใจผิดได้ดีที่สุด (-1) สภาวะแวดล้อมใน / proc / $$ / environ ถูกอ่านจากสแต็กของกระบวนการ ดู fs / proc / base.c นี่คือสภาพแวดล้อมเริ่มต้น มันไม่เคยอัปเดตและในความเป็นจริงไม่สามารถ สภาวะแวดล้อมที่ libc setenv ใช้ถูกจัดสรรบนฮีปและเริ่มต้นด้วยเนื้อหาของสภาพแวดล้อมในสแต็ก หากกระบวนการเรียกใช้ libc forkดังนั้น libc จะทำการsys_forkโทรโดยใช้สภาพแวดล้อมที่จัดสรรฮีปสำหรับกระบวนการย่อย
Jonathan Ben-Avraham

7
@ JonathanBen-Avraham คุณถูกต้องที่สภาพแวดล้อมเริ่มต้นไม่ได้รับการปรับปรุงในเชลล์ใด ๆ อย่างไรก็ตามพื้นที่นั้นไม่ได้อ่านอย่างเดียวภายใต้ Linux ฉันพบโปรแกรมที่ใช้รายงานสถานะของพวกเขา (รายงานสถานะผ่านargvเป็นเรื่องปกติมากขึ้น แต่มีอยู่ทั้งคู่)
Gilles 'หยุดความชั่วร้าย'

39

คุณสามารถอ่านสภาพแวดล้อมเริ่มต้นของกระบวนการ/proc/<pid>/environได้

หากกระบวนการเปลี่ยนแปลงสภาพแวดล้อมดังนั้นเพื่อที่จะอ่านสภาพแวดล้อมคุณต้องมีตารางสัญลักษณ์สำหรับกระบวนการและใช้การptraceเรียกของระบบ (ตัวอย่างเช่นโดยใช้gdb) เพื่ออ่านสภาพแวดล้อมจากchar **__environตัวแปรโกลบอล ไม่มีวิธีอื่นในการรับค่าของตัวแปรใด ๆ จากกระบวนการ Linux ที่ทำงานอยู่

นั่นคือคำตอบ ตอนนี้สำหรับบันทึกย่อบางส่วน

ดังกล่าวข้างต้นสันนิษฐานว่าเป็นกระบวนการตาม POSIX ซึ่งหมายความว่ากระบวนการจัดการสภาพแวดล้อมของการใช้ตัวแปรทั่วโลกchar **__environตามที่ระบุไว้ในRef Spec

สภาพแวดล้อมเริ่มต้นสำหรับกระบวนการถูกส่งผ่านไปยังกระบวนการในบัฟเฟอร์ความยาวคงที่บนสแต็กของกระบวนการ (กลไกปกติที่เป็นlinux//fs/exec.c:do_execve_common(...)เช่นนี้) เนื่องจากขนาดของบัฟเฟอร์ถูกคำนวณให้มีขนาดไม่เกินขนาดที่ต้องการสำหรับสภาพแวดล้อมเริ่มต้นคุณไม่สามารถเพิ่มตัวแปรใหม่โดยไม่ต้องลบตัวแปรที่มีอยู่หรือทำให้สแต็กแตก ดังนั้นรูปแบบที่สมเหตุสมผลใด ๆ ที่จะอนุญาตให้มีการเปลี่ยนแปลงในสภาพแวดล้อมของกระบวนการจะใช้ heap ซึ่งหน่วยความจำในขนาดที่กำหนดเองสามารถจัดสรรและปลดปล่อยได้ซึ่งเป็นสิ่งที่ GNU libc( glibc) ทำเพื่อคุณ

หากกระบวนการใช้glibcแล้วมันเป็นไปตาม POSIX โดยมี__environการประกาศในglibc//posix/environ.cGlibc เริ่มต้น__environด้วยตัวชี้ไปยังหน่วยความจำที่มันmallocมาจากกองของกระบวนการจากนั้นคัดลอกสภาพแวดล้อมเริ่มต้นจากสแต็กลงในพื้นที่กองนี้ ทุกครั้งที่กระบวนการใช้setenvฟังก์ชั่นglibcทำreallocเพื่อปรับขนาดของพื้นที่ที่__environชี้ไปเพื่อรองรับค่าหรือตัวแปรใหม่ (คุณสามารถดาวน์โหลดซอร์สโค้ด glibc ด้วยgit clone git://sourceware.org/git/glibc.git glibc) ในการทำความเข้าใจกลไกคุณจะต้องอ่านรหัส Hurd ในhurd//init/init.c:frob_kernel_process()(git clone git: //git.sv.gnu.org/hurd/hurd.git hurd)

ตอนนี้ถ้ากระบวนการใหม่เป็นเพียงforked โดยไม่ต้องต่อมา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ประชุมเป็นผู้ใช้พื้นที่การประชุม มันไม่มีส่วนเกี่ยวข้องใด ๆ กับเคอร์เนล Linux คุณสามารถเขียนโปรแกรม userspace โดยไม่ต้องใช้glibcและไม่มี__environโกลบอลจากนั้นจัดการตัวแปรสภาพแวดล้อมตามที่คุณต้องการ ไม่มีใครจะจับกุมคุณในการทำเช่นนี้ แต่คุณจะต้องเขียนฟังก์ชั่นการจัดการสภาพแวดล้อมของคุณ ( setenv/ getenv) และสิ่งห่อหุ้มของคุณเองsys_execและมีโอกาสที่จะไม่มีใครสามารถเดาได้ว่าคุณใส่อะไรไว้ในสภาพแวดล้อมของคุณ


ไฟล์หลายไฟล์/proc/[pid]/ดูเหมือนจะมีการเข้ารหัสแปลก ๆ (บางคนอาจรู้ว่าอะไรและเพราะอะไร) สำหรับฉันเพียงcat environพิมพ์ตัวแปรสภาพแวดล้อมในรูปแบบที่อ่านยาก cat environ | stringsแก้ไขปัญหานี้ให้ฉัน
retrohacker

@retrohacker สิ่งนี้ให้โซลูชันที่มีประสิทธิภาพยิ่งขึ้น: askubuntu.com/questions/978711/…
Frank Kusters

20

มันถูกอัพเดตเป็นและเมื่อกระบวนการได้มา / ลบตัวแปรสภาพแวดล้อม คุณมีการอ้างอิงซึ่งระบุว่าenvironไฟล์ไม่ได้รับการปรับปรุงสำหรับกระบวนการในไดเรกทอรีกระบวนการภายใต้ระบบไฟล์ / proc หรือไม่

xargs --null --max-args=1 echo < /proc/self/environ

หรือ

xargs --null --max-args=1 echo < /proc/<pid>/environ

หรือ

ps e -p <pid>

ด้านบนจะพิมพ์ตัวแปรสภาพแวดล้อมของกระบวนการในpsรูปแบบผลลัพธ์การประมวลผลข้อความ (การแยกวิเคราะห์ / การกรอง) จำเป็นต้องใช้เพื่อดูตัวแปรสภาพแวดล้อมเป็นรายการ

Solaris (ไม่ถาม แต่สำหรับการอ้างอิงฉันจะโพสต์ที่นี่):

/usr/ucb/ps -wwwe <pid>

หรือ

pargs -e <pid> 

แก้ไข: / proc / pid / environ ไม่ได้รับการอัพเดต! ฉันยืนแก้ไขแล้ว กระบวนการตรวจสอบอยู่ด้านล่าง อย่างไรก็ตามเด็ก ๆ ที่กระบวนการนั้นจะแยกสืบทอดตัวแปรสภาพแวดล้อมของกระบวนการและมันสามารถมองเห็นได้ในไฟล์ / proc / self / 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]$

ตรวจสอบจากเซสชันอื่นโดยที่เทอร์มินัล / เซสชันไม่ใช่กระบวนการย่อยของเชลล์ที่ตั้งค่าตัวแปรสภาพแวดล้อม

การตรวจสอบจากเทอร์มินัล / เซสชันอื่นบนโฮสต์เดียวกัน:

terminal1::โปรดทราบว่า printenv เป็น fork'd และเป็นกระบวนการลูกของ bash และด้วยเหตุนี้มันจึงอ่านไฟล์สภาพแวดล้อมของตัวเอง

[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 ~]$ 

1
ที่ฉันทำexport foo=barในช่วงหนึ่งของการทุบตี (xxxx PID) แล้วทำในเซสชั่นทุบตีอื่นและผมไม่เห็นcat /proc/xxxx/environ | tr \\0 \\n foo

ฉันปรับปรุงคำตอบข้างต้นด้วยตัวอย่างการตรวจสอบกระบวนการเดียวกันภายในเชลล์
Nikhil Mulley

คุณถูก. ฉันยืนแก้ไขแล้ว ขอบคุณ ตอนนี้ฉันต้องไปอ่านคู่มือเพื่อตรวจสอบตัวแปรสภาพแวดล้อมของกระบวนการที่แตกต่างกันในกลุ่มกระบวนการผู้ใช้
Nikhil Mulley

1
อีกอย่างหนึ่ง: ฉันลองตรวจสอบสภาพแวดล้อมที่แนบgdb กับ pid แต่ก็ยังไม่มีการอ้างอิง ตัวแปรสภาพแวดล้อมบล็อกในหน่วยความจำจะได้รับการจัดสรรใหม่เมื่อใดก็ตามที่มีการเปลี่ยนแปลงและไม่ได้สะท้อนให้เห็นในไฟล์ environ 'กระบวนการของตัวเองในระบบไฟล์ proc แต่ช่วยให้ได้รับการสืบทอดโดยกระบวนการเด็ก ซึ่งหมายความว่าสิ่งนี้จะง่ายต่อการรู้รายละเอียดที่แท้จริงเมื่อ fork เกิดขึ้นกระบวนการลูกได้รับการคัดลอกตัวแปรสภาพแวดล้อมอย่างไร
Nikhil Mulley

ฉันหวังว่า @Gilles จะขว้างคบเพลิงของเขาที่จุดนี้ .. :-)
Nikhil Mulley

7

ต่อไปนี้ไม่เกี่ยวข้องกับความตั้งใจที่แท้จริงของผู้เขียน แต่ถ้าคุณต้องการ "อ่าน" จริงๆ/proc/<pid>/environคุณอาจลอง

strings /proc/<pid>/environ

ซึ่งดีกว่าcatมัน


1
+1 stringsสำหรับ ง่าย ๆ เข้าไว้.
Ed Randall

เห็นด้วย @EdRandall นี้รู้สึกเหมือนวิธีง่าย xargs --nullVS
ต่อ Lundberg

"ไฟล์" ถูกยกเลิกเป็นโมฆะแทนที่โมฆะด้วยเครื่องมือบรรทัดใหม่และเครื่องมือปกติทำงานอีกครั้ง (ด้วยคำเตือนปกติ) เช่น:tr '\0' '\n' < /proc/$$/environ | ...
Thor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.