Làm thế nào để đọc các biến môi trường của một quá trình


43

Linux /proc/<pid>/environkhông cập nhật (theo tôi hiểu, tệp chứa môi trường ban đầu của quy trình).

Làm thế nào tôi có thể đọc môi trường hiện tại của một quá trình ?

Câu trả lời:


20

/proc/$pid/environkhông cập nhật nếu quá trình thay đổi môi trường của chính nó. Nhưng nhiều chương trình không bận tâm đến việc thay đổi môi trường của chính họ, bởi vì điều đó hơi vô nghĩa: môi trường của chương trình không hiển thị qua các kênh thông thường, chỉ thông qua /procps, và thậm chí không phải mọi biến thể unix đều có loại tính năng này, vì vậy các ứng dụng không dựa vào trên đó

Theo như kernel, môi trường chỉ xuất hiện dưới dạng đối số của lệnh execvegọi hệ thống khởi động chương trình. Linux hiển thị một vùng trong bộ nhớ thông qua /procvà một số chương trình cập nhật vùng này trong khi các chương trình khác thì không. Đặc biệt, tôi không nghĩ bất kỳ shell nào cập nhật khu vực này. Vì khu vực có kích thước cố định, sẽ không thể thêm các biến mới hoặc thay đổi độ dài của giá trị.


vì vậy, hiệu quả là không có cách nào để truy cập vào quá trình '* envp (mảng con trỏ tới cài đặt môi trường). @Gilles, bạn có thể vui lòng hiển thị nếu có thể đính kèm trình gỡ lỗi và đọc mảng con trỏ vào cài đặt môi trường.
Nikhil Mulley

2
@Nikhil Chắc chắn rồi. Nhưng chỉ vì bạn viết PATH=footrong một cái vỏ không có nghĩa là cái vỏ sẽ sửa đổi *envp. Trong một số shell, chỉ cập nhật cấu trúc dữ liệu bên trong và đó là mã thực thi chương trình bên ngoài cập nhật *envp. Nhìn vào assign_in_envtrong variables.cnguồn bash, ví dụ.
Gilles 'SO- ngừng trở nên xấu xa'

9
@Gilles: Câu trả lời này là sai nhất (-1). Môi trường trong / Proc / $$ / môi trường được đọc từ ngăn xếp của quy trình. Xem fs / Proc / base.c. Đây là môi trường ban đầu. Nó không bao giờ được cập nhật và trên thực tế không thể. Môi trường mà libc setenv sử dụng được phân bổ trên heap và được khởi tạo với nội dung của môi trường trong ngăn xếp. Nếu tiến trình gọi libc's forkthì libc thực hiện sys_forkcuộc gọi bằng môi trường phân bổ heap cho tiến trình con.
Jonathan Ben-Avraham

7
@ JonathanBen-Avraham Bạn nói đúng rằng môi trường ban đầu không được cập nhật trong bất kỳ shell nào. Tuy nhiên, khu vực đó không chỉ được đọc trong Linux, tôi đã gặp các chương trình sử dụng nó để báo cáo trạng thái của họ (báo cáo trạng thái thông qua argvphổ biến hơn nhưng cả hai đều tồn tại).
Gilles 'SO- ngừng trở thành ác quỷ'

39

Bạn có thể đọc môi trường ban đầu của một quá trình từ /proc/<pid>/environ.

Nếu một quá trình thay đổi môi trường của nó, thì để đọc môi trường, bạn phải có bảng ký hiệu cho quy trình và sử dụng lệnh ptracegọi hệ thống (ví dụ bằng cách sử dụng gdb) để đọc môi trường từ char **__environbiến toàn cục. Không có cách nào khác để lấy giá trị của bất kỳ biến nào từ quy trình Linux đang chạy.

Đó là câu trả lời. Bây giờ cho một số ghi chú.

Các giả định ở trên giả định rằng quy trình tuân thủ POSIX, nghĩa là quy trình quản lý môi trường của nó bằng cách sử dụng biến toàn cục char **__environnhư được chỉ định trong Ref Spec .

Môi trường ban đầu cho một quy trình được chuyển đến quy trình trong bộ đệm có độ dài cố định trên ngăn xếp của quy trình. (Cơ chế thông thường thực hiện điều này là linux//fs/exec.c:do_execve_common(...).) Vì kích thước của bộ đệm được tính không lớn hơn kích thước cần thiết cho môi trường ban đầu, bạn không thể thêm các biến mới mà không xóa các biến hiện có hoặc phá vỡ ngăn xếp. Vì vậy, bất kỳ lược đồ hợp lý nào để cho phép thay đổi trong môi trường của quy trình sẽ sử dụng heap, trong đó bộ nhớ ở các kích thước tùy ý có thể được phân bổ và giải phóng, đó chính xác là những gì GNU libc( glibc) làm cho bạn.

Nếu quy trình sử dụng glibc, thì nó tuân thủ POSIX, với __environkhai báo trong glibc//posix/environ.cGlibc sẽ khởi tạo __environmột con trỏ tới bộ nhớ mà nó malloclà từ heap của tiến trình, sau đó sao chép môi trường ban đầu từ ngăn xếp vào vùng heap này. Mỗi khi quá trình sử dụng setenvhàm, glibcsẽ thực hiện reallocđể điều chỉnh kích thước của khu vực __environtrỏ đến để chứa giá trị hoặc biến mới. (Bạn có thể tải xuống mã nguồn glibc với git clone git://sourceware.org/git/glibc.git glibc). Để thực sự hiểu cơ chế, bạn cũng sẽ phải đọc mã Hurd trong hurd//init/init.c:frob_kernel_process()(git clone git: //git.sv.gnu.org/hurd/hurd.git Hurd).

Bây giờ nếu quy trình mới chỉ là forked, mà không execghi đè lên ngăn xếp tiếp theo , thì phép thuật sao chép đối số và môi trường được thực hiện linux//kernel/fork.c:do_fork(...), trong đó các copy_processlệnh gọi thường quy dup_task_structphân bổ ngăn xếp của quy trình mới bằng cách gọi ( ) alloc_thread_info_nodegọi cho quy trình mới bằng cách sử dụng .setup_thread_stacklinux//include/linux/sched.halloc_thread_info_node

Cuối cùng, __environquy ước POSIX là quy ước không gian người dùng . Nó không có kết nối với bất cứ thứ gì trong nhân Linux. Bạn có thể viết chương trình không gian người dùng mà không cần sử dụng glibcvà không có __environtoàn cục và sau đó quản lý các biến môi trường theo cách bạn muốn. Không ai sẽ bắt bạn làm điều này nhưng bạn sẽ phải viết các chức năng quản lý môi trường ( setenv/ getenv) của riêng bạn và các trình bao bọc của riêng bạn sys_execvà có khả năng là không ai có thể đoán được bạn đặt các thay đổi vào môi trường của bạn ở đâu.


Nhiều tệp trong đó /proc/[pid]/dường như có một mã hóa kỳ lạ (người khác có thể biết cái gì và tại sao). Đối với tôi, chỉ đơn giản là cat environin ra các biến môi trường ở định dạng thực sự khó đọc. cat environ | stringsđã giải quyết điều này cho tôi
retrohacker

@retrohacker này đưa ra một giải pháp mạnh mẽ hơn: askubuntu.com/questions/978711/...
Frank Kusters

20

Nó được cập nhật khi và quá trình thu nhận / xóa các biến môi trường của nó. Bạn có tham chiếu trong đó tuyên bố rằng environtệp không được cập nhật cho quy trình trong thư mục quy trình của nó trong hệ thống tập tin / Proc không?

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

hoặc là

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

hoặc là

ps e -p <pid>

Ở trên sẽ in các biến môi trường của quá trình ở psđịnh dạng đầu ra, xử lý văn bản (phân tích / lọc) được yêu cầu để xem các biến môi trường dưới dạng danh sách.

Solaris (không hỏi, nhưng để tham khảo tôi sẽ đăng ở đây):

/usr/ucb/ps -wwwe <pid>

hoặc là

pargs -e <pid> 

EDIT: / Proc / pid / môi trường không được cập nhật! Tôi đứng sửa. Quá trình xác minh dưới đây. Tuy nhiên, những đứa trẻ mà quá trình được chia đôi sẽ thừa hưởng biến môi trường quy trình và nó có thể nhìn thấy trong tệp / Proc / self / môi trường tương ứng của chúng. (Sử dụng chuỗi)

Với trong shell: ở đây xargs là một tiến trình con và do đó thừa hưởng biến môi trường và cũng phản ánh trong /proc/self/environtệp của nó .

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

Kiểm tra nó từ phiên khác, trong đó thiết bị đầu cuối / phiên không phải là tiến trình con của trình bao nơi đặt biến môi trường.

Xác minh từ một thiết bị đầu cuối / phiên khác trên cùng một máy chủ:

terminal1 :: Lưu ý rằng printenv là fork và là một quá trình con của bash và do đó nó đọc tệp môi trường của chính nó.

[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$ 

terminal2: trên cùng một máy chủ - không khởi chạy nó trong cùng một vỏ nơi đặt biến trên, khởi chạy thiết bị đầu cuối riêng biệt.

[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
Tôi làm export foo=bartrong phiên của một bash (pid xxxx), sau đó làm cat /proc/xxxx/environ | tr \\0 \\ntrong phiên của bash khác và tôi không thấy foo.

Tôi đã cập nhật câu trả lời ở trên với một ví dụ kiểm tra quá trình tương tự trong shell.
Nikhil Mulley

Bạn nói đúng. Tôi đứng sửa. Cảm ơn. Bây giờ tôi phải đi và đọc hướng dẫn của mình để kiểm tra các biến môi trường của một quy trình khác với trong nhóm quy trình người dùng.
Nikhil Mulley

1
Một điều nữa: Tôi đã thử kiểm tra môi trường gắn gdb vào pid, nhưng vẫn không có tài liệu tham khảo nào ở đó. Khối biến môi trường trong bộ nhớ được phân bổ lại bất cứ khi nào có thay đổi và không phản ánh trong tệp môi trường của quy trình riêng trong hệ thống tệp Proc, nhưng cho phép được thừa kế bởi quy trình con. Điều đó có nghĩa là điều này có thể trở nên dễ dàng hơn để biết các chi tiết nội tại khi ngã ba xảy ra, quá trình con có được các biến môi trường được sao chép như thế nào.
Nikhil Mulley

Tôi hy vọng @Gilles sẽ ném một chút ánh sáng ngọn đuốc của mình vào điều này .. :-)
Nikhil Mulley

7

Vâng, những điều sau đây không liên quan đến ý định thực sự của tác giả, nhưng nếu bạn thực sự muốn "ĐỌC" /proc/<pid>/environ, bạn có thể thử

strings /proc/<pid>/environ

cái nào tốt hơn cat


1
+1 cho strings. Giữ cho nó đơn giản.
Ed Randall

Đồng ý @EdRandall, điều này cảm thấy như cách tiếp cận dễ dàng hơn so với xargs --null.
Per Lundberg

"Tệp" bị hủy kết thúc, thay thế null bằng dòng mới và các công cụ bình thường hoạt động trở lại (với các cảnh báo thông thường), ví dụ:tr '\0' '\n' < /proc/$$/environ | ...
Thor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.