Mô tả tập tin trên exec


7

Theo mặc định, bộ mô tả tệp vẫn mở trên các hàm exec. Lợi ích có lẽ dễ hiểu đối với người mô tả 0-2. Nhưng có một trường hợp sử dụng thực tế để giữ cho các mô tả khác mở? Có ứng dụng thực sự nào dựa vào thực tế này không?


Hoàn toàn ngược lại, OpenSSH đặc biệt mất nhiều thời gian để đóng các mô tả> = 3 theo mặc định (thông qua closefrom(2)cuộc gọi).
thrig

1
@thrig Điều đó không có nghĩa là nó vô dụng để vượt qua một bộ mô tả tệp mở cho mục đích khác. Trong thực tế, những khó khăn lớn mà OpenSSH phải trải qua để đảm bảo tất cả các bộ mô tả tệp khác được đóng lại sẽ cho biết mức độ hữu ích của nó có thể vượt qua các bộ mô tả tệp mở theo cách này.
Andrew Henle

Thậm chí một số tập lệnh shell thiết lập các mô tả> 2 và chuyển chúng vào các ống lệnh để có hiệu quả hữu ích.
Kaz

rất thường là một đường ống có liên quan và quá trình con sẽ đọc hoặc ghi đường ống đó và mô tả tệp của đường ống sẽ không phải là 0 ... 2
user3629249

Câu trả lời:


11

Có một cờ bạn có thể đặt trên một bộ mô tả tệp (theo open(): O_CLOEXEC trở lên với fcntl(): FD_CLOEXEC) nếu bạn không muốn fd đó được chuyển đến các lệnh được thực thi.

Đó là những gì bạn nên làm cho các mô tả tệp nội bộ của bạn nếu bạn sẽ thực thi các lệnh.

Trong shell, đó là những gì ksh93khi bạn làm exec 3< some-filechẳng hạn. Đối với các shell hoặc fds khác được mở bằng { cmd1; cmd2; } 3< file, bạn cần phải đóng bằng tay nếu bạn không muốn cmd1hoặc cmd2truy cập vào fd đó : {cmd1 3<&-; cmd2; } 3< file. Đó là cách thực hành tốt nhưng không phải lúc nào cũng tuân theo vì nó thường không quan trọng nếu bạn không thực hiện .

Bây giờ, cho dù tính năng này là hữu ích. Vâng, một số lệnh dựa vào nó.

Một vài lệnh lấy một bộ mô tả tệp làm đối số có nghĩa là đã được mở bởi một người gọi. Một vài ví dụ xuất hiện trong tâm trí:

  • xtermvới -Stùy chọn của nó
  • qemu cho những thứ khác nhau
  • flock (để khóa một tập tin trên fd của người gọi)
  • các testlệnh aka [cho nó -tlựa chọn (OK các testtiện ích được xây dựng ở hầu hết các Bourne giống như vỏ hiện nay, nhưng vẫn còn là một testlệnh có thể được thực hiện).
  • dialog cần mô tả tập tin cho đầu vào từ người dùng, đầu ra và lỗi cho người dùng và đầu vào và đầu ra cho người gọi, vì vậy bạn có thể sử dụng thêm fds cho điều đó.
  • gpghoặc opensslmà bạn có thể chỉ định một bộ mô tả tệp để truyền đạt cụm mật khẩu hoặc thông tin khác.

Có một số tiện ích của trình trợ giúp (ví dụ, nhu cầu thực thi có thể là chạy một phần của lệnh với tư cách là một người dùng hoặc nhóm khác sử dụng tệp thực thi setuid / setgid) dựa vào đó.

Quá trình thay thế phụ thuộc vào nó:

Trong, diff <(cmd1) <(cmd2)2 mô tả tệp (cho các đường ống) được truyền tới diffvà diff truy cập chúng bằng cách mở chúng thông qua đặc biệt / dev / fd / n được truyền dưới dạng đối số.

Đối với các shell không có quá trình thay thế, bạn cũng thực hiện tương tự với các thao tác như:

cm1 | { cmd2 | diff /dev/fd/3 -; } 3<&0

Thật tuyệt khi biết có rất nhiều ứng dụng. Thành thật mà nói, tôi đã mong đợi chỉ một vài trường hợp sử dụng phức tạp.
rv

@rv thực sự còn nhiều hơn thế nữa. Tra cứu SystemD Socket Activation cho các dịch vụ hệ thống, ví dụ.
chim cánh cụt359

4

TinyMUSH và có lẽ nhiều bộ mã anh chị em và trẻ em của nó sử dụng chức năng này của exec để có hiệu quả tuyệt vời. Người ta có thể ra lệnh khởi động lại máy chủ, có thể nâng cấp lên nhị phân hoàn toàn mới, trong khi vẫn để người dùng kết nối.

Điều này được thực hiện bằng cách viết một db thông tin nhỏ về mỗi người dùng được kết nối, bao gồm cả mô tả tệp của họ. Bản sao TinyMUSH mới được thực thi đọc db khởi động lại để khôi phục kiến ​​thức về người dùng được kết nối và chọn nơi nó rời đi.

Kết quả cuối cùng: các tính năng mới được phát hành chỉ với một khoảng dừng ngắn hiển thị cho người dùng.

Nginx làm một cái gì đó tương tự như để nâng cấp nhị phân mà không mất kết nối.


1

Ổ cắm được kết nối có thể được chuyển cho một tiến trình con theo cách này, vì vậy, ví dụ một máy chủ mạng chấp nhận các kết nối đến có thể chuyển hoàn toàn việc xử lý chúng sang quy trình khác.

Xem mã nguồn cho inetd , ví dụ phổ biến.


Câu hỏi là về các lệnh được thực thi, không phải các tiến trình con. Lưu ý rằng đối với inetd, ổ cắm nằm trên fds 0,1,2.
Stéphane Chazelas

@ StéphaneChazelas Câu hỏi là về các lệnh được thực thi, không phải các tiến trình con. Lưu ý rằng đối với inetd, ổ cắm nằm trên fds 0,1,2 Không. Các câu hỏi là Nhưng có trường hợp sử dụng thực tế nào để giữ các mô tả khác mở không? có ứng dụng thực sự nào dựa vào thực tế này không? Câu trả lời của tôi là một ví dụ về "trường hợp sử dụng thực tế" với "ứng dụng thực" - chuyển một ổ cắm đã mở cho một quy trình con. Thực tế là inetdsử dụng file descriptor 0, 12với mục đích đi qua các ổ cắm mở là một quy ước rằng dòng lên với việc giữ những mở vì lý do khác.
Andrew Henle

Có, inetd là một trường hợp thực tế vượt qua 0,1,2. Chính nguồn mà bạn liên kết để đóng cẩn thận mọi thứ khác ngoài 0,1,2 trước khi thực hiện chương trình; thấy mainrun_service. Đây không phải là một ví dụ về việc chuyển fds ngoài 0,1,2, đó là câu hỏi.
dave_thndry_085

-1

Tôi không nghĩ có những chương trình thực tế, chung chung vượt qua mọi thứ ngoài mô tả 2. Nếu có, chương trình exec () ed sẽ phải giả sử số mô tả tệp được mã hóa cứng, vd

write(3, ...);

hoặc là

fp = fdopen(3, "r");

đó là thực hành mã hóa xấu. Chỉ trong trường hợp bạn kiểm soát chặt chẽ cả chương trình phụ huynh và trẻ em, và không ai khác có thể can thiệp, điều đó có thể có ý nghĩa.


1
Hoặc người gọi có thể chuyển FD đó làm đối số hoặc env var cho callee.
Stéphane Chazelas

1
Thực tế có rất nhiều chương trình "thực sự chung chung" thực hiện điều này. Có các công cụ Bernstein dự kiến ​​sẽ chuyển / nhận mô tả tệp 3, 6 và 7 như một phần của các giao thức được xác định rõ như xử lý UCSPI và Bernstein TTY. "kích hoạt ổ cắm" của systemd có một giao thức liên quan đến bộ mô tả tệp 3 trở lên. Và như thế.
JdeBP
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.