Có cách nào để thay đổi các biến môi trường của một quy trình khác trong Unix không?


105

Trên Unix, có cách nào để một quy trình có thể thay đổi các biến môi trường của quy trình khác (giả sử tất cả chúng đều được điều hành bởi cùng một người dùng) không? Một giải pháp chung sẽ là tốt nhất, nhưng nếu không, trong trường hợp cụ thể khi một người là con của người kia thì sao?

Chỉnh sửa: Làm thế nào về thông qua gdb?


Điều này khiến tôi cảm thấy tồi tệ hơn cả. Vấn đề thực tế bạn muốn giải quyết là gì?
Jens

1
Ví dụ: Tôi muốn xác định một biến môi trường để mọi ứng dụng mới - được khởi chạy bởi giao diện người dùng - sẽ nhận được nó. Tôi không biết bất kỳ phương pháp nào ngoại trừ việc xác định các biến trong một trong các tập lệnh khởi động và ĐĂNG NHẬP LẠI. Tuy nhiên, tôi không muốn đăng nhập lại, mà chỉ xác định các biến trong phiên hiện tại để các ứng dụng mới có thể nhận được nó - mà không cần đăng xuất khỏi giao diện người dùng.
AlikElzin-kilaka

Câu trả lời:


142

Qua gdb:

(gdb) attach process_id

(gdb) call putenv ("env_var_name=env_var_value")

(gdb) detach

Đây là một vụ hack khá khó chịu và tất nhiên chỉ nên được thực hiện trong bối cảnh của một kịch bản gỡ lỗi.


8
Vì vậy, điều này dường như ngụ ý rằng bạn thực sự có thể thay đổi môi trường của một quy trình nếu bạn gắn vào quy trình như GDB, và sau đó tách ra. Có vẻ như có thể viết một chương trình chỉ làm điều này.
đau buồn

3
"Có vẻ như có thể viết một chương trình chỉ làm việc này" Thật vậy .. đúng như vậy.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

2
Nó thậm chí hoạt động trên Windows bằng cygwin, cho các quy trình không được biên dịch bằng cygwin!
Juan Carlos Muñoz

11
Lưu ý rằng điều này chỉ hoạt động nếu quá trình không lưu trữ vĩnh viễn giá trị sau getenv trước đó.
Đã rút vào

1
ptrace: Operation not permitted
gerrit

22

Về mặt kỹ thuật, bạn có thể làm được (xem các câu trả lời khác), nhưng nó có thể không giúp được gì cho bạn.

Hầu hết các chương trình sẽ mong đợi rằng env vars không thể thay đổi từ bên ngoài sau khi khởi động, do đó hầu hết có thể sẽ chỉ đọc các vars mà họ quan tâm khi khởi động và khởi tạo dựa trên đó. Vì vậy, thay đổi chúng sau đó sẽ không tạo ra sự khác biệt, vì chương trình sẽ không bao giờ đọc lại chúng.

Nếu bạn đăng bài này là một vấn đề cụ thể, có lẽ bạn nên thực hiện một cách tiếp cận khác. Nếu nó chỉ vì tò mò: Câu hỏi hay đấy :-).


1
Trường hợp sử dụng phổ biến nhất sẽ hữu ích là làm cho các quy trình con kế thừa các biến môi trường mới, ví dụ, trong môi trường máy tính để bàn nơi bạn muốn các thiết bị đầu cuối mới sử dụng các biến mới.
Hjulle

13

Về cơ bản, không. Nếu bạn có đủ đặc quyền (gốc, hoặc ở đó) và xem xét / dev / kmem (bộ nhớ hạt nhân), và bạn đã thực hiện các thay đổi đối với môi trường của quy trình và nếu quy trình thực sự tham chiếu lại biến môi trường sau đó (tức là quy trình chưa chụp một bản sao của env var và không chỉ sử dụng bản sao đó), thì có lẽ, nếu bạn may mắn và thông minh, và gió thổi đúng hướng, và pha của mặt trăng là chính xác, có lẽ, bạn có thể đạt được điều gì đó.


2
Tôi không nhận được câu trả lời.
AlikElzin-kilaka

@kilaka: Từ khóa là từ thứ hai - Không . Phần còn lại của câu trả lời nói rằng nếu bạn có quyền root hoặc đang chạy trình gỡ lỗi, thì có thể bạn có thể làm điều đó, nhưng đối với tất cả các mục đích thực tế, câu trả lời là Không .
Jonathan Leffler

Bạn có một tập lệnh shell đang chạy; bạn muốn thay đổi môi trường trong quy trình cha của shell script của mình ... vì vậy, shell script khởi chạy gdbtrên quy trình mẹ và được tập lệnh thực hiện thay đổi và nó hoạt động mà không làm hỏng quy trình mẹ. Được - bạn có thể làm được, nhưng đó không phải là việc bạn sẽ làm thường xuyên. Vì vậy, vì mục đích thực tế, câu trả lời vẫn là Không . Phần còn lại của câu trả lời bao gồm các lựa chọn thay thế có thể thực hiện được về mặt lý thuyết, hơi không thực tế.
Jonathan Leffler

7

Trích dẫn Jerry Peek:

Bạn không thể dạy một con chó cũ những thủ thuật mới.

Điều duy nhất bạn có thể làm là thay đổi biến môi trường của tiến trình con trước đó bắt đầu nó: nó sẽ nhận được bản sao của môi trường mẹ, xin lỗi.

Xem http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm để biết thêm chi tiết.

Chỉ cần một bình luận về câu trả lời về việc sử dụng / proc. Trong linux / proc được hỗ trợ nhưng, nó không hoạt động, bạn không thể thay đổi /proc/${pid}/environtệp, ngay cả khi bạn là root: nó hoàn toàn ở chế độ chỉ đọc.


Điều vẫn đặt ra câu hỏi: các giá trị env var thực sự được lưu trữ ở đâu? Điều đó được thực hiện bởi hạt nhân? Hay shell lưu trữ các giá trị và / proc / <pid> / environ sẽ lấy chúng từ đó?
oliver 16/10/08

Đây là một chi tiết triển khai và nó có thể là một câu hỏi hay (riêng biệt). Tôi nghĩ rằng mọi UNIX đều sử dụng cách riêng của nó để lưu trữ, nhưng tất cả chúng đều có chung hành vi được mô tả ở trên, là một phần của thông số kỹ thuật.
Davide

7

Tôi có thể nghĩ ra cách khá giả tạo để làm điều đó và nó sẽ không hoạt động đối với các quy trình tùy ý.

Giả sử rằng bạn viết thư viện chia sẻ của riêng mình, thực hiện 'char * getenv'. Sau đó, bạn thiết lập 'LD_PRELOAD' hoặc 'LD_LIBRARY_PATH' env. vars để cả hai quy trình của bạn được chạy với thư viện được chia sẻ của bạn được tải trước.

Bằng cách này, về cơ bản bạn sẽ có quyền kiểm soát mã của hàm 'getenv'. Sau đó, bạn có thể làm đủ mọi trò lố. 'Getenv' của bạn có thể tham khảo tệp cấu hình bên ngoài hoặc phân đoạn SHM cho các giá trị thay thế của vars env. Hoặc bạn có thể thực hiện tìm kiếm / thay thế regexp trên các giá trị được yêu cầu. Hoặc là ...

Tôi không thể nghĩ ra cách dễ dàng để làm điều đó đối với các quy trình đang chạy tùy ý (ngay cả khi bạn là root), thiếu viết lại trình liên kết động (ld-linux.so).


Điều này nên làm được. Bạn có thể có một cơ sở dữ liệu gdbm nhỏ cho các cặp var = value. Tôi có một cái gì đó tương tự cho malloc tại stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg

Tôi nghĩ rằng phương pháp này yêu cầu phải suy nghĩ trước. Bạn cũng phải cẩn thận để không vô tình áp dụng nó cho quá nhiều quy trình.
dstromberg

3

Hoặc yêu cầu quy trình của bạn cập nhật tệp cấu hình cho quy trình mới và sau đó:

  • thực hiện kill -HUP trên quy trình mới để đọc lại tệp cấu hình đã cập nhật, hoặc
  • yêu cầu quá trình kiểm tra tệp cấu hình cho các bản cập nhật mọi lúc mọi nơi. Nếu thay đổi được tìm thấy, hãy đọc lại tệp cấu hình.

2

Không xa như tôi biết. Thực sự là bạn đang cố gắng giao tiếp từ quá trình này sang quá trình khác gọi một trong các phương thức IPC (bộ nhớ được chia sẻ, semaphores, sockets, v.v.). Sau khi nhận dữ liệu bằng một trong các phương pháp này, bạn có thể đặt các biến môi trường hoặc thực hiện các hành động khác trực tiếp hơn.


1

Nếu unix của bạn hỗ trợ hệ thống tệp / proc, thì việc ĐỌC env là điều không cần thiết - bạn có thể đọc môi trường, dòng lệnh và nhiều thuộc tính khác của bất kỳ quy trình nào mà bạn sở hữu theo cách đó. Thay đổi nó ... Chà, tôi có thể nghĩ ra một cách, nhưng đó là một ý tưởng XẤU.

Trường hợp tổng quát hơn ... Tôi không biết, nhưng tôi nghi ngờ có một câu trả lời di động.

(Đã chỉnh sửa: câu trả lời ban đầu của tôi giả định OP muốn ĐỌC env, không thay đổi nó)


Rất tiếc, tôi đã chỉnh sửa câu trả lời của mình - Tôi cho rằng anh ấy muốn đọc env, chứ không phải thay đổi nó.
Mike G.

1
Đừng để tôi bị treo cổ. Ý tưởng tồi của bạn là gì?
raldi 15/10/08

Trên Linux, tôi tin rằng bạn CÓ THỂ mở / proc / <pid> / mem read-write cho quá trình khác mà bạn sở hữu ... Tuy nhiên, tôi không chắc. Cố gắng, và thực sự gây rối với môi trường, sẽ là một ý tưởng tồi. Vì vậy, tôi không đề nghị bạn thử nó ...
Mike G.

1

UNIX có đầy đủ giao tiếp giữa các quá trình. Kiểm tra xem bản sao mục tiêu của bạn có một số. Dbus đang trở thành một tiêu chuẩn trong IPC "máy tính để bàn".

Tôi thay đổi các biến môi trường bên trong trình quản lý cửa sổ Awesome bằng cách sử dụng awesome-client với là "người gửi" Dbus của mã lua.


1

Không phải là một câu trả lời trực tiếp nhưng ... Raymond Chen đã có một cơ sở lý luận [dựa trên Windows] chỉ về điều này vào ngày hôm trước : -

... Mặc dù chắc chắn có những cách thực hiện không được hỗ trợ hoặc những cách hoạt động với sự hỗ trợ của trình gỡ lỗi, nhưng không có gì được hỗ trợ để truy cập có lập trình vào dòng lệnh của quy trình khác, ít nhất là không có gì được cung cấp bởi hạt nhân. ...

Đó không phải là hệ quả của nguyên tắc không theo dõi thông tin mà bạn không cần. Kernel không cần lấy dòng lệnh của tiến trình khác. Nó đưa dòng lệnh được chuyển tới CreateProcesshàm và sao chép nó vào không gian địa chỉ của quá trình đang được khởi chạy, ở vị trí nơiGetCommandLine hàm có thể truy xuất nó. Khi tiến trình có thể truy cập dòng lệnh của chính nó, các trách nhiệm của hạt nhân sẽ được thực hiện.

Vì dòng lệnh được sao chép vào không gian địa chỉ của quá trình, nên quá trình này thậm chí có thể ghi vào bộ nhớ chứa dòng lệnh và sửa đổi nó. Nếu điều đó xảy ra, thì dòng lệnh gốc sẽ bị mất vĩnh viễn; bản sao duy nhất được biết đã bị ghi đè.

Nói cách khác, bất kỳ cơ sở hạt nhân nào như vậy sẽ

  • khó thực hiện
  • có khả năng là một mối quan tâm bảo mật

Tuy nhiên, lý do rất có thể chỉ đơn giản là có những trường hợp sử dụng hạn chế cho một cơ sở như vậy.


1

Có vẻ như putenv không hoạt động bây giờ, nhưng setenv thì có. Tôi đang kiểm tra câu trả lời được chấp nhận trong khi cố gắng đặt biến trong trình bao hiện tại nhưng không thành công

$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=

và biến thể hoạt động như thế nào:

$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
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.