Tại sao tôi có thể mèo / dev?


41

Tôi có thể cat /dev, tôi có thể ls /dev, tôi không thể less /dev. Tại sao không catcho tôi catthư mục này nhưng không có thư mục khác?

Hình ảnh của hành vi này trong zsh.


@KamilMaciorowski, đây là đầu ra và neofetchthông tin của bạn :) i.imgur.com/3azpnDt.png
haboutnnah

Câu trả lời:


43

Trong lịch sử (lên đến V7 UNIX, hoặc khoảng năm 1979), readcuộc gọi hệ thống đã hoạt động trên cả tệp và thư mục. readtrên một thư mục sẽ trả về một cấu trúc dữ liệu đơn giản mà chương trình người dùng sẽ phân tích để có được các mục nhập thư mục. Thật vậy, lscông cụ V7 đã làm chính xác điều này - readtrên một thư mục, phân tích cấu trúc dữ liệu kết quả, đầu ra theo định dạng danh sách có cấu trúc.

Khi các hệ thống tập tin trở nên phức tạp hơn, cấu trúc dữ liệu "đơn giản" này trở nên phức tạp hơn, đến mức một readdirchức năng thư viện được thêm vào để giúp các chương trình phân tích đầu ra của read(directory). Các hệ thống và hệ thống tập tin khác nhau có thể có các định dạng trên đĩa khác nhau, điều này đang trở nên phức tạp.

Khi Sun giới thiệu Hệ thống tệp mạng (NFS), họ muốn trừu tượng hóa hoàn toàn cấu trúc thư mục trên đĩa. read(directory)Tuy nhiên, thay vì trả lại cho họ một đại diện độc lập với nền tảng của thư mục, họ đã thêm một cuộc gọi hệ thống mới - getdirents- và bị cấm readtrên các thư mục gắn trên mạng. Cuộc gọi hệ thống này đã nhanh chóng được điều chỉnh để hoạt động trên tất cả các thư mục theo các hương vị UNIX khác nhau, làm cho nó trở thành cách mặc định để lấy nội dung của các thư mục. (Lịch sử được tóm tắt từ https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )

Bởi vì readdirbây giờ là cách mặc định để đọc các thư mục, read(directory)thường không được triển khai (trả về -EISDIR) trên hầu hết các hệ điều hành hiện đại (ví dụ, QNX, là một ngoại lệ đáng chú ý thực hiện readdirnhư read(directory)). Tuy nhiên, với thiết kế "hệ thống tập tin ảo" trong hầu hết các nhân hiện đại, nó thực sự tùy thuộc vào hệ thống tập tin riêng lẻ cho dù việc đọc một thư mục có hoạt động hay không.

Và thực tế, trên macOS, devfshệ thống tập tin nằm dưới /devmountpoint thực sự hỗ trợ việc đọc ( https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/miscfs/devfs/devfs_vnops.c#L629 ) :

static int
devfs_read(struct vnop_read_args *ap)
{
        devnode_t * dn_p = VTODN(ap->a_vp);

    switch (ap->a_vp->v_type) {
      case VDIR: {
          dn_p->dn_access = 1;

          return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context);

Điều này gọi một cách rõ ràng READDIRnếu bạn cố đọc /dev(đọc các tệp bên dưới /devđược xử lý bởi một chức năng riêng biệt - devfsspec_read). Vì vậy, nếu một chương trình gọi readhệ thống gọi /dev, nó sẽ thành công và có được danh sách thư mục!

Đây thực sự là một tính năng được nắm giữ từ những ngày đầu của UNIX và đã không được sử dụng trong một thời gian rất dài. Một phần trong tôi nghi ngờ rằng điều này đang được giữ xung quanh vì một số lý do tương thích ngược, nhưng nó có thể dễ dàng là thực tế rằng không ai quan tâm đủ để loại bỏ tính năng này vì nó không thực sự gây tổn hại gì.


Có lẽ sau này, vì nó đã bị xóa khỏi hầu hết các thư mục.
dùng253751

36

Ít hơn là một trình xem tệp văn bản, cat là một công cụ để sao chép dữ liệu tùy ý. Vì vậy, ít thực hiện kiểm tra riêng của mình để đảm bảo rằng bạn không mở thứ gì đó sẽ có lượng dữ liệu khổng lồ hoặc hành xử rất kỳ lạ. Mặt khác, mèo hoàn toàn không kiểm tra như vậy - nếu hạt nhân cho phép bạn mở thứ gì đó (ngay cả khi đó là đường ống hoặc thiết bị hoặc thứ gì đó tệ hơn), mèo sẽ đọc nó.

Vậy tại sao HĐH cho phép mèo mở thư mục? Theo truyền thống trong các hệ thống kiểu BSD, tất cả các thư mục có thể được đọc dưới dạng tệp và đó là cách các chương trình sẽ liệt kê một thư mục ở vị trí đầu tiên: chỉ bằng cách diễn giải các cấu trúc dirent được lưu trữ trên đĩa.

Sau đó, các cấu trúc trên đĩa đó bắt đầu phân kỳ khỏi dirent được sử dụng bởi kernel: trong đó trước đó một thư mục là một danh sách tuyến tính, các hệ thống tập tin sau đó bắt đầu sử dụng hashtables, B-cây, v.v. Vì vậy, việc đọc các thư mục trực tiếp không còn đơn giản nữa - kernel đã phát triển các chức năng chuyên dụng cho việc này. (Tôi không chắc đó là lý do chính hay nếu chúng chủ yếu được thêm vào vì những lý do khác như bộ nhớ đệm.)

Một số hệ thống BSD tiếp tục cho phép bạn mở tất cả các thư mục để đọc; Tôi không biết liệu họ có cung cấp cho bạn dữ liệu thô từ đĩa hay không, liệu họ có trả lại danh sách dirent giả lập hay không, liệu họ có để trình điều khiển hệ thống tập tin quyết định hay không.

Vì vậy, có lẽ macOS là một trong những hệ điều hành mà kernel cho phép nó miễn là hệ thống tập tin cung cấp dữ liệu. Và sự khác biệt là /devtrên một devfshệ thống tệp được viết để cho phép điều này trong những ngày đầu, trong khi /trên hệ thống tệp APFS đã bỏ qua tính năng này là không cần thiết trong thời hiện đại.

Tuyên bố miễn trừ trách nhiệm: Tôi thực sự chưa thực hiện bất kỳ nghiên cứu nào về BSD hoặc macOS. Tôi chỉ đang bay nó.


Điều này dường như có ý nghĩa. Có phần lưu trữ nào khác với hệ thống tập tin hệ điều hành tiêu chuẩn không? Tôi giả sử /etcsẽ, vì vậy tôi sử dụng nó như là điểm chuẩn của tôi.
haboutnnah

2
Ngược lại, nói chung / etc chỉ là một thư mục thông thường chứa các tệp thông thường. Có thể có các hệ thống tập tin ảo khác - chạy mounthoặc /sbin/mountđể xem những gì hiện đang được gắn kết ở đâu.
grawity

Bạn đúng! Xem điều này: i.imgur.com/pcVpo1o.png
haboutnnah

Điều này thực sự gọn gàng
@grawity

6
@haboutnnah Ảnh chụp màn hình của bạn xác nhận rằng đó /devlà một hệ thống tệp ảo sử dụng devfstrình điều khiển trong khi đó /etclà một phần của /hệ thống tệp sử dụng apfstrình điều khiển. Vì vậy, lý do catsẽ đọc một và không phải là một sự khác biệt giữa các trình điều khiển apfsdevfs.
kasperd
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.