Linux /proc/<pid>/environ
nie aktualizuje się (jak rozumiem, plik zawiera początkowe środowisko procesu).
Jak mogę odczytać aktualne środowisko procesu ?
Linux /proc/<pid>/environ
nie aktualizuje się (jak rozumiem, plik zawiera początkowe środowisko procesu).
Jak mogę odczytać aktualne środowisko procesu ?
Odpowiedzi:
/proc/$pid/environ
aktualizuje się, jeśli proces zmieni własne środowisko. Ale wiele programów nie zawraca sobie głowy zmianą własnego środowiska, ponieważ jest to trochę bezcelowe: środowisko programu nie jest widoczne przez normalne kanały, tylko przez /proc
i ps
, i nawet nie każdy wariant unixa ma taką funkcję, więc aplikacje nie polegają na tym.
Jeśli chodzi o jądro, środowisko pojawia się tylko jako argument execve
wywołania systemowego uruchamiającego program. Linux udostępnia obszar pamięci /proc
, a niektóre programy aktualizują ten obszar, a inne nie. W szczególności nie sądzę, aby jakakolwiek powłoka aktualizowała ten obszar. Ponieważ obszar ma stały rozmiar, dodanie nowych zmiennych lub zmiana długości wartości byłaby niemożliwa.
PATH=foo
w powłoce, nie oznacza, że powłoka się zmieni *envp
. W niektórych powłokach aktualizuje to tylko wewnętrzną strukturę danych i aktualizuje się zewnętrzny kod wykonania programu *envp
. Spójrz na przykład assign_in_env
w variables.c
źródle bash.
fork
to libc wykonuje sys_fork
połączenie, używając środowiska przydzielonego do sterty dla procesu potomnego.
argv
są częstsze, ale oba istnieją).
Możesz odczytać początkowe środowisko procesu z /proc/<pid>/environ
.
Jeśli proces zmienia swoje środowisko, to aby odczytać środowisko, musisz mieć tabelę symboli dla procesu i użyć ptrace
wywołania systemowego (na przykład za pomocą gdb
), aby odczytać środowisko ze char **__environ
zmiennej globalnej . Nie ma innego sposobu uzyskania wartości dowolnej zmiennej z uruchomionego procesu Linux.
To jest odpowiedź. Teraz kilka notatek.
Powyższe zakłada, że proces jest zgodny z POSIX, co oznacza, że proces zarządza swoim środowiskiem przy użyciu zmiennej globalnej char **__environ
określonej w Spec Spec .
Początkowe środowisko dla procesu jest przekazywane do procesu w buforze o stałej długości na stosie procesu. (Zwykłym mechanizmem, który to robi linux//fs/exec.c:do_execve_common(...)
.) Ponieważ rozmiar bufora jest obliczany jako nie większy niż rozmiar wymagany dla środowiska początkowego, nie można dodawać nowych zmiennych bez usuwania istniejących zmiennych lub niszczenia stosu. Tak więc każdy rozsądny schemat pozwalający na zmiany w środowisku procesu wykorzystywałby stertę, w której pamięć o dowolnych rozmiarach może być przydzielana i zwalniana, co dokładnie robi dla ciebie GNU libc
( glibc
).
Jeśli proces używa glibc
, to jest zgodny z POSIX, a __environ
deklaracja w glibc//posix/environ.c
Glibc inicjuje __environ
wskaźnikiem do pamięci, że malloc
pochodzi ze sterty procesu, a następnie kopiuje środowisko początkowe ze stosu do tego obszaru sterty. Za każdym razem proces wykorzystuje setenv
funkcję, glibc
wymaga się realloc
, aby dostosować rozmiar obszaru, który __environ
wskazuje, aby pomieścić nową wartość lub zmienną. (Możesz pobrać kod źródłowy glibc za pomocą git clone git://sourceware.org/git/glibc.git glibc
). Aby naprawdę zrozumieć mechanizm, musisz także przeczytać kod Hurd w hurd//init/init.c:frob_kernel_process()
(git clone git: //git.sv.gnu.org/hurd/hurd.git hurd).
Teraz, jeśli nowy proces jest tylko fork
edytowany, bez późniejszego exec
nadpisywania stosu, to magia kopiowania argumentów i środowiska jest wykonywana linux//kernel/fork.c:do_fork(...)
, gdzie copy_process
rutynowe wywołania, dup_task_struct
które przydzielają stos nowego procesu przez wywołanie alloc_thread_info_node
, które wywołuje setup_thread_stack
( linux//include/linux/sched.h
) dla nowego procesu za pomocą alloc_thread_info_node
.
Wreszcie __environ
konwencja POSIX to konwencja przestrzeni użytkownika . Nie ma połączenia z niczym w jądrze Linuksa. Możesz napisać program przestrzeni użytkownika bez użycia globalnego i glibc
bez niego, __environ
a następnie zarządzać zmiennymi środowiskowymi w dowolny sposób. Nikt cię nie aresztuje za to, ale będziesz musiał napisać własne funkcje zarządzania środowiskiem ( setenv
/ getenv
) i własne opakowania sys_exec
i jest prawdopodobne, że nikt nie będzie w stanie zgadnąć, gdzie wprowadzasz zmiany w swoim środowisku.
/proc/[pid]/
wydaje się mieć dziwne kodowanie (ktoś inny może wiedzieć, co i dlaczego). Dla mnie po prostu cat environ
wydrukowałbym zmienne środowiskowe w naprawdę trudnym do odczytania formacie. cat environ | strings
rozwiązałem to dla mnie.
Jest aktualizowany w miarę, jak proces nabywa / usuwa swoje zmienne środowiskowe. Czy masz odniesienie, które stwierdza, że environ
plik nie jest aktualizowany dla procesu w katalogu procesu w systemie plików / proc?
xargs --null --max-args=1 echo < /proc/self/environ
lub
xargs --null --max-args=1 echo < /proc/<pid>/environ
lub
ps e -p <pid>
Powyżej wydrukuje zmienne środowiskowe procesu w ps
formacie wyjściowym, przetwarzanie tekstu (parsowanie / filtrowanie) jest wymagane, aby zobaczyć zmienne środowiskowe jako listę.
Solaris (nie pytany, ale w celach informacyjnych opublikuję tutaj):
/usr/ucb/ps -wwwe <pid>
lub
pargs -e <pid>
EDYCJA: / proc / pid / Environment nie jest aktualizowany! Poprawiono mnie. Proces weryfikacji jest poniżej. Jednak elementy potomne, z których rozwidla się proces, dziedziczą zmienną środowiskową procesu i jest ona widoczna w odpowiednim pliku / proc / self / environment. (Użyj ciągów)
With in the shell: tutaj xargs jest procesem potomnym i dlatego dziedziczy zmienną środowiskową, a także odzwierciedla w swoim /proc/self/environ
pliku.
[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]$
Sprawdzanie go z innej sesji, w której terminal / sesja nie jest procesem potomnym powłoki, w której ustawiona jest zmienna środowiskowa.
Weryfikacja z innego terminala / sesji na tym samym hoście:
terminal1: Zauważ, że printenv jest rozwidlony i jest potomnym procesem bash, a zatem czyta własny plik środowiska.
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
terminal2: na tym samym hoście - nie uruchamiaj go w tej samej powłoce, w której ustawiono powyższą zmienną, uruchom terminal osobno.
[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
w sesji jednego basha (pid xxxx), potem robię cat /proc/xxxx/environ | tr \\0 \\n
w sesji innego basha i nie widzę foo
.
gdb
do pid, ale wciąż nie ma tam odniesienia. Blok zmiennych środowiskowych w pamięci zostaje ponownie przydzielony za każdym razem, gdy zachodzi zmiana i nie odzwierciedla pliku środowiska własnego procesu w systemie plików proc, ale pozwala na dziedziczenie przez proces potomny. Oznacza to, że łatwiej będzie poznać wewnętrzne szczegóły, kiedy nastąpi rozwidlenie, w jaki sposób proces potomny pobiera zmienne środowiskowe w takiej postaci, w jakiej są.
Cóż, poniższe informacje nie są powiązane z prawdziwymi intencjami autora, ale jeśli naprawdę chcesz „CZYTAĆ” /proc/<pid>/environ
, możesz spróbować
strings /proc/<pid>/environ
co jest lepsze niż cat
to.
strings
. Nie komplikuj.
xargs --null
.
tr '\0' '\n' < /proc/$$/environ | ...