Linux /proc/<pid>/environ
khô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 ?
Linux /proc/<pid>/environ
khô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:
/proc/$pid/environ
khô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 /proc
và ps
, 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 execve
gọ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 /proc
và 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ị.
PATH=foo
trong 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_env
trong variables.c
nguồn bash, ví dụ.
fork
thì libc thực hiện sys_fork
cuộc gọi bằng môi trường phân bổ heap cho tiến trình con.
argv
phổ biến hơn nhưng cả hai đều tồn tại).
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 ptrace
gọi hệ thống (ví dụ bằng cách sử dụng gdb
) để đọc môi trường từ char **__environ
biế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 **__environ
như đượ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 __environ
khai báo trong glibc//posix/environ.c
Glibc sẽ khởi tạo __environ
một con trỏ tới bộ nhớ mà nó malloc
là 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 setenv
hàm, glibc
sẽ thực hiện realloc
để điều chỉnh kích thước của khu vực __environ
trỏ đế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à fork
ed, mà không exec
ghi đè 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_process
lệnh gọi thường quy dup_task_struct
phân bổ ngăn xếp của quy trình mới bằng cách gọi ( ) alloc_thread_info_node
gọi cho quy trình mới bằng cách sử dụng .setup_thread_stack
linux//include/linux/sched.h
alloc_thread_info_node
Cuối cùng, __environ
quy ướ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 glibc
và không có __environ
toà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_exec
và 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.
/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 environ
in 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
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 environ
tệ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/environ
tệ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 ~]$
export foo=bar
trong phiên của một bash (pid xxxx), sau đó làm cat /proc/xxxx/environ | tr \\0 \\n
trong phiên của bash khác và tôi không thấy foo
.
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.
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
nó
strings
. Giữ cho nó đơn giản.
xargs --null
.
tr '\0' '\n' < /proc/$$/environ | ...