Các tập tin Linux được phát triển như thế nào?


112

Có những tệp đặc biệt trong Linux không phải là tệp thực sự.

Các ví dụ đáng chú ý và rõ ràng nhất trong số này là trong devthư mục, "tệp" như:

  • /dev/null - Bỏ qua bất cứ điều gì bạn viết vào tập tin
  • /dev/random - Xuất dữ liệu ngẫu nhiên thay vì nội dung của tệp
  • /dev/tcp - Gửi bất kỳ dữ liệu bạn ghi vào tập tin này qua mạng

Trước hết, tên của các loại "tệp" này thực sự là một loại tập lệnh hoặc nhị phân được ngụy trang là gì?

Thứ hai, chúng được tạo ra như thế nào? Các tệp này được tích hợp vào hệ thống ở cấp hạt nhân hay có cách nào để tự tạo "tệp ma thuật" (làm thế nào về a /dev/rickroll)?


1
Tôi không biết làm thế nào để gắn thẻ câu hỏi này, đặc biệt là vì tôi không biết tên của những gì tôi đang tìm kiếm. Hãy chỉnh sửa trong bất kỳ thẻ có liên quan.
IQAndreas

15
BTW, đây là một phần cơ bản của thiết kế các hệ điều hành unix và unix: (hầu như) mọi thứ đều là một tệp hoặc có thể được tạo ra trông giống như một tệp.
cas

5
Xem thêm: mknod (2) man 2 mknod
RobertL 6/11/2015

4
Đây là "các nút thiết bị". Tuy nhiên, những cái bạn đã đề cập - không giống như những thiết bị liên quan đến đĩa, bàn phím, chuột, thẻ âm thanh và các thiết bị khác - được gọi là "thiết bị giả", vì chúng không phải là thiết bị "thực" và chỉ tồn tại trong kernel. Có thể tạo một cái mới, bằng cách viết trình điều khiển thiết bị phù hợp và thêm nó vào kernel (ví dụ: thiết bị giả để theo dõi một số hoạt động trên máy tính). Trước khi thư mục / dev tồn tại trên đĩa - ngày nay, nó là một hệ thống tệp ảo (loại devfs) được tạo bởi kernel.
Baard Kopperud 6/11/2015

10
Tất cả các tệp, ngay cả các tệp "thực", là các tạo phẩm phần mềm. Các phần mềm đằng sau mỗi thiết bị, tập tin, ổ cắm, tập tin đặc biệt, hoặc một cái gì đó chưa được phát minh cung cấp một bảng các chức năng để xử lý open(), read(), close(), vv Sau đó, nó tùy thuộc vào phần mềm
waltinator

Câu trả lời:


101

/dev/zerolà một ví dụ về "tệp đặc biệt" - đặc biệt là "nút thiết bị". Thông thường chúng được tạo bởi quá trình cài đặt distro, nhưng bạn hoàn toàn có thể tự tạo chúng nếu bạn muốn.

Nếu bạn hỏi lsvề /dev/zero:

# ls -l /dev/zero
crw-rw-rw- 1 root root 1, 5  Nov 5 09:34 /dev/zero

"C" khi bắt đầu cho bạn biết rằng đây là "thiết bị ký tự"; loại khác là "thiết bị khối" (được in bởi ls"b"). Rất đại khái, các thiết bị truy cập ngẫu nhiên như ổ cứng có xu hướng là thiết bị chặn, trong khi những thứ liên tiếp như ổ đĩa băng hoặc card âm thanh của bạn có xu hướng là thiết bị ký tự.

Phần "1, 5" là "số thiết bị chính" và "số thiết bị phụ".

Với thông tin này, chúng ta có thể sử dụng mknodlệnh để tạo nút thiết bị của riêng mình:

# mknod foobar c 1 5

Điều này tạo ra một tệp mới có tên foobar, trong thư mục hiện tại, chính xác là giống như /dev/zero. (Tất nhiên bạn có thể đặt các quyền khác nhau trên nó nếu bạn muốn.) Tất cả "tệp" này thực sự chứa ba mục ở trên - loại thiết bị, số chính, số phụ. Bạn có thể sử dụng lsđể tra cứu mã cho các thiết bị khác và cũng tạo lại các mã đó. Khi bạn chán, chỉ cần sử dụng rmđể loại bỏ các nút thiết bị bạn vừa tạo.

Về cơ bản, số chính cho hạt nhân Linux nói chuyện với trình điều khiển thiết bị nào và số phụ nói với trình điều khiển thiết bị mà bạn đang nói về thiết bị nào. (Ví dụ: bạn có thể có một bộ điều khiển SATA, nhưng có thể nhiều ổ cứng được cắm vào nó.)

Nếu bạn muốn phát minh ra các thiết bị mới làm điều gì đó mới ... tốt, bạn sẽ cần chỉnh sửa mã nguồn cho nhân Linux và biên dịch kernel tùy chỉnh của riêng bạn. Vì vậy, đừng làm điều đó! :-) Nhưng bạn có thể thêm các tệp thiết bị trùng lặp với các tệp bạn đã có. Một hệ thống tự động như udev về cơ bản chỉ là xem các sự kiện của thiết bị và tự động gọi mknod/ rmcho bạn. Không có gì kỳ diệu hơn thế.

Vẫn còn các loại tệp đặc biệt khác:

  • Linux coi một thư mục là một loại tệp đặc biệt. (Thông thường bạn không thể trực tiếp mở một thư mục, nhưng nếu có thể, bạn sẽ thấy đó là một tệp bình thường chứa dữ liệu ở định dạng đặc biệt và cho hạt nhân biết nơi tìm tất cả các tệp trong thư mục đó.)

  • Một symlink là một tập tin đặc biệt. (Nhưng một liên kết cứng thì không.) Bạn có thể tạo liên kết tượng trưng bằng ln -slệnh. (Tra cứu trang này cho nó.)

  • Ngoài ra còn có một thứ gọi là "ống có tên" hoặc "FIFO" (hàng đợi vào trước, ra trước). Bạn có thể tạo một với mkfifo. Một FIFO là một tập tin ma thuật có thể được mở bằng hai chương trình cùng một lúc - một lần đọc, một lần viết. Khi điều này xảy ra, nó hoạt động như một ống vỏ bình thường. Nhưng bạn có thể bắt đầu mỗi chương trình một cách riêng biệt ...

Một tệp không "đặc biệt" theo bất kỳ cách nào được gọi là "tệp thông thường". Thỉnh thoảng bạn sẽ thấy đề cập đến điều này trong tài liệu Unix. Đó là ý nghĩa của nó; một tệp không phải là nút thiết bị hoặc liên kết tượng trưng hay bất cứ thứ gì. Chỉ là một tập tin bình thường, mỗi ngày không có thuộc tính phép thuật.


4
Ngoài ra còn có một loại tệp đặc biệt, ổ cắm miền Unix được liên kết với hệ thống tệp.
Brian Bi

8
Nếu bạn muốn chơi với mknod, hãy chạy cat /proc/devicesđể xem các số chính cho tất cả các trình điều khiển. Điều này đưa chúng ta đến một loại tệp đặc biệt khác /prochệ thống tệp ( câu trả lời này nói về nó).
ugoren 6/11/2015

8
Các Unice khác đã phát minh ra các tập tin đặc biệt của riêng họ, ví dụ Solaris có cửa .
Kevin

6
Tiểu nitlog: bạn không cần phải biên dịch lại kernel để viết một ký tự / thiết bị chặn mới :) crashcference.ca/int sinhtion -linux-kernel-program / / Nếu không thì đây là một câu trả lời thực sự tốt, +1!
Chỉ huy Coriander Salamander

1
@MathologistsOrchid: Một bước trả lời của bạn bị thiếu (hoặc ít nhất là chỉ nói ngầm) là thực tế rằng các tệp đặc biệt đó hoàn toàn không phải là các tập lệnh shell hoặc nhị phân (như câu hỏi ngụ ý), mà là một giao diện để truy cập chức năng hiện có trong nhân hệ điều hành.
mơ mộng

34

Hầu hết các /devmục là inodes thiết bị khối hoặc inodes thiết bị nhân vật. Wikipedia có nhiều chi tiết về điều đó, mà tôi sẽ không lặp lại.

Nhưng /dev/tcpnhững gì được đề cập trong câu hỏi của bạn không được giải thích bởi bất kỳ câu trả lời hiện có. /dev/tcp/dev/udpkhác với hầu hết các /devmục khác . Các thiết bị khối và nhân vật được thực hiện bởi các hạt nhân, nhưng /dev/tcp/dev/udpđược thực hiện trong chế độ người dùng.

Shell bash là một chương trình có triển khai /dev/tcp/dev/udp(được sao chép từ ksh93). Khi bạn cố gắng mở một đường dẫn bên dưới những người có toán tử chuyển hướng bash, nó sẽ không thực hiện một opencuộc gọi hệ thống thông thường . Thay vào đó, bash sẽ tạo ra một ổ cắm TCP và kết nối nó với cổng được chỉ định.

Điều đó được thực hiện trong chế độ người dùng và chỉ trong một số chương trình như có thể thấy trong ví dụ sau đây thể hiện sự khác biệt giữa cho phép bashcatthử mở/dev/tcp/::1/22

$ cat /dev/tcp/::1/22
cat: /dev/tcp/::1/22: No such file or directory
$ cat < /dev/tcp/::1/22
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.3

Một điểm khác biệt ksh93bashsẽ chỉ thực hiện các kết nối TCP đó với các toán tử chuyển hướng, chứ không phải ở những nơi khác mà nó có thể mở các tệp như sourcehoặc .dựng sẵn.


Ngoài ra, GNU gawkcũng có các trường hợp đặc biệt tương tự /inet{,4,6}/{tcp,udp}/$port/$remote/$rport, kể từ đâu đó khoảng năm 2010 (tôi không nhớ chính xác và không thể tìm thấy ghi chú phát hành).
dave_thndry_085

6
IMO, một cách tốt hơn để nêu quan điểm /dev/tcplà KHÔNG phải là tệp. Không bao giờ có một tập tin gọi là này. Cú pháp của Bash để mở socket sử dụng chuỗi /dev/tcp/addressnhư tên tệp, nhưng gọi nó là "tệp được triển khai trong không gian người dùng" nghe có vẻ lạ. Thật thú vị khi kshmóc những tên tập tin đó cho mọi thứ, mặc dù không chỉ là chuyển hướng. Điều đó gần hơn với "thực hiện một tập tin".
Peter Cordes

@PeterCordes tôi tin rằng UWIN thiết lập chúng như những tập tin thực tế. và tôi nghĩ 3dfs cũng làm như vậy. Hãy nhớ rằng, bashchỉ sao chép hành vi này, nhưng nó bắt nguồn từ nơi khác.
mikeerv 7/11/2015

19

Ngoài các nút thiết bị được giải thích trong các câu trả lời khác (được tạo bằng mknod (2) hoặc được cung cấp bởi một số devfs ), Linux còn có các tệp "ma thuật" khác được cung cấp bởi các hệ thống tệp ảo đặc biệt , đặc biệt là trong /proc/(xem Proc (5) , đọc về Procfs ) và trong /sys/(đọc về sysfs ).

Các tệp giả này (xuất hiện từ -eg đến stat (2) - như các tệp thông thường, không phải là thiết bị) là chế độ xem ảo được cung cấp bởi kernel; đặc biệt, việc đọc từ /proc/(ví dụ với cat /proc/$$/maps, hoặc bằng cách mở (2) -ing /proc/self/statustrong chương trình của bạn) thường không liên quan đến bất kỳ I / O vật lý nào từ đĩa hoặc mạng, do đó khá nhanh.

Để tạo một số tệp giả bổ sung trong /proc/bạn thường nên viết mô-đun hạt nhân của riêng bạn và tải nó (xem ví dụ này ).


3
AFAIK thông tin về việc mở rộng / Proc đã lỗi thời. Mặc dù về mặt kỹ thuật vẫn có thể, / Proc (hay đúng hơn là Procfs) chỉ nên giữ thông tin về các quy trình đang chạy. Tất cả các tệp giả khác bao gồm các tệp có chứa thông tin thời gian chạy hoặc tùy chọn cấu hình cho kernel sẽ đi vào / sys (sysfs). Vẫn còn một số tệp giả không liên quan đến quá trình trong / Proc (ví dụ: meminfo, cpuinfo) vì lý do tương thích, nhưng các tệp giả mới sẽ đi vào sysfs.
mơ mộng

13

Chúng được gọi là các nút thiết bị và được tạo bằng tay mknodhoặc tự động bằng udev. Chúng thường là các giao diện giống như tệp cho các thiết bị ký tự hoặc khối với trình điều khiển trong kernel - ví dụ: đĩa là thiết bị khối, ttys và cổng nối tiếp, v.v. là thiết bị ký tự.

Ngoài ra còn có các loại tệp "đặc biệt" khác, bao gồm các ống được đặt tên và fifos và ổ cắm.


9

Vì những người dùng khác đã giải thích rất chi tiết, các tệp đặc biệt yêu cầu mã để sao lưu chúng. Tuy nhiên, dường như không ai đề cập rằng Linux cung cấp một số cách để viết mã đó trong không gian người dùng:

A. FUSE (Hệ thống tập tin trong USErspace) cho phép bạn viết một cái gì đó giống như /prockhông có nguy cơ làm hỏng kernel và thực hiện bằng ngôn ngữ / thời gian chạy mà bạn chọn, chẳng hạn như Go , Node.js , Perl , PHP , Python , Ruby , Rust , vv .

Nó cũng có lợi thế là các hệ thống tập tin FUSE có thể được gắn mà không cần sudochạy khi người dùng thực hiện việc gắn kết.

Dưới đây là một số ví dụ về những điều mọi người đã viết bằng FUSE:

  • mp3fs (Xem các tệp FLAC của bạn dưới dạng các tệp MP3 được tạo nhanh chóng khi bạn sao chép / nhấp-kéo chúng vào trình phát MP3 của bạn)
  • PyTagsFS (Xem phương tiện của bạn trong một cây các thư mục ảo được xây dựng từ các thẻ siêu dữ liệu)
  • fuse-zip (tập tin Mount Zip dưới dạng thư mục)
  • FuseISO (Mount ISO không có quyền root)
  • iFUSE (Mount iDevices)
  • FuseDAV (chia sẻ Mount WebDAV)
  • fuse-exfat (Mount các hệ thống tập tin định dạng exFAT)
  • ntfs-3g ( Trình điều khiển NTFS của Linux)

B. Nếu bạn muốn tạo một thiết bị đầu vào ảo như bàn phím, chuột, cần điều khiển, v.v. (ví dụ: để viết trình điều khiển không gian người dùng cho thiết bị USB mà bạn đang sử dụng libusb), có uinput .

Ràng buộc cho nó khó tìm hơn, nhưng tôi biết chúng tồn tại cho Go (chỉ dành cho Bàn phím), PythonRuby (2) .

Ví dụ về sử dụng uinput trong thế giới thực bao gồm:

  • G15Daemon (Trình điều khiển Linux cho LCD và các phím chơi trò chơi trên bàn phím chơi game Logitech G15)
  • ds4drv (Trình điều khiển cho bộ điều khiển Sony DualShock 4)
  • xboxdrv (trình điều khiển bộ điều khiển thay thế Xbox 360 và Linux tương đương với x360ce rất nặng thiết kế các trò chơi như Runner2: Future Legend of Nhịp điệu Alien có thể nghĩ rằng họ đang nói chuyện với một bộ điều khiển Xbox thực khi họ không)
  • Các trình điều khiển Wiimote cũ như cwiid được yêu cầu trước khi ai đó cuối cùng đã viết trình điều khiển Wiimote kernel để hỗ trợ sẽ có sẵn theo mặc định.

C. Đối với các thiết bị ký tự chung, có CUSE (Thiết bị ký tự trong USErspace). Nó ít phổ biến hơn mặc dù.

Người sử dụng chỉ số API CUSE mà tôi biết cá nhân của là cùng một chương trình mà nhắc tạo của nó: osspd , mà thực hiện /dev/dsp, /dev/adsp/dev/mixer(API âm thanh OSS) trong userspace để họ có thể được chuyển qua PulseAudio hoặc DMIX.

Ràng buộc CUSE duy nhất tôi có thể tìm thấy là cusepy , chưa được cập nhật từ năm 2010.

D. Bạn có thể không cần một tập tin đặc biệt mới.

Ví dụ: bạn có thể mở giao tiếp thô với bất kỳ thiết bị USB nào bằng libusb (Danh sách các ràng buộc trên trang) và sau đó liên lạc với các chương trình khác thông qua một số cơ chế khác (ổ cắm TCP / UDP, đọc / ghi stdin / stdout hoặc các tệp thông thường trên đĩa , Vân vân.).


1
cusepy có thể đã không được cập nhật trong một thời gian (thực tế, nó chưa bao giờ được cập nhật; nó chỉ có một cam kết!), nhưng chỉ cần viết một thiết bị nhân vật bằng cusepy vài tuần trước, tôi có thể xác nhận rằng nó vẫn hoạt động tốt. Nó đã thiếu một vài chức năng liên quan đến việc triển khai poll, nhưng vì cusepy sử dụng ctypes và các ràng buộc được tự động dựa trên các tệp tiêu đề C, việc sửa bất kỳ chức năng bị thiếu nào chỉ là vấn đề thêm tên hàm mong muốn vào danh sách các hàm được xuất trong setup.py.
Aleksi Torhamo

1
Một ví dụ thú vị khác về việc sử dụng FUSE là sshfs . Nó cho phép bạn duyệt hệ thống tệp từ xa như thể nó là cục bộ bằng kết nối SSH bên dưới.
Ông Deathless

@ Mr.Deathless Yeah. Tôi thực sự sử dụng nó và có nghĩa là để đề cập đến nó nhưng tôi quên.
ssokolow

6

Cuốn sách Trình điều khiển thiết bị Linux (rất khuyến khích) giải thích chi tiết điều này và thậm chí bạn đã tạo một mô-đun hạt nhân làm ví dụ này, nhưng tóm lại, mỗi trình điều khiển thiết bị có các chức năng cụ thể được gọi khi mở tệp, đóng , đọc, viết, v.v ... Các tệp "đặc biệt" chỉ làm một cái gì đó đặc biệt bên trong các chức năng đó, thay vì truy cập vào phần cứng lưu trữ trên đĩa.

Ví dụ, hàm write /dev/nullkhông làm gì cả, bỏ qua các byte. Hàm đọc /dev/randomtrả về một số ngẫu nhiên.


1

mount -t devtmpfs

Cũng rất thú vị khi thấy rằng trong các hệ thống hiện đại, /devthường là loại hệ thống tập tin có thể được gắn bất cứ nơi nào bạn muốn. Ubuntu 16.04:

mkdir d
sudo mount -t devtmpfs none d
head -c 10 d/random
sudo umount d

Điều này được kích hoạt bởi CONFIG_DEVTMPFS=yvà cho phép chính kernel tạo và hủy các tập tin thiết bị khi cần thiết.

CONFIG_DEVTMPFS_MOUNT=y

Tùy chọn này làm cho kernel devtmpfs tự động gắn trên /dev.

drivers/base/Kconfig các tài liệu:

config DEVTMPFS_MOUNT
    bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs"
    depends on DEVTMPFS
    help
      This will instruct the kernel to automatically mount the
      devtmpfs filesystem at /dev, directly after the kernel has
      mounted the root filesystem. The behavior can be overridden
      with the commandline parameter: devtmpfs.mount=0|1.
      This option does not affect initramfs based booting, here
      the devtmpfs filesystem always needs to be mounted manually
      after the rootfs is mounted.
      With this option enabled, it allows to bring up a system in
      rescue mode with init=/bin/sh, even when the /dev directory
      on the rootfs is completely empty.

file_operations

Cuối cùng, bạn nên tạo mô-đun hạt nhân thiết bị nhân vật của riêng bạn để xem chính xác những gì đang xảy ra.

Dưới đây là một ví dụ có thể chạy tối thiểu: Hiểu các tệp thiết bị ký tự (hoặc ký tự đặc biệt)

Bước quan trọng nhất, là thiết lập file_operationscấu trúc, ví dụ:

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = read,
    .open = open,
};

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

có chứa các con trỏ hàm được gọi cho mỗi lệnh gọi hệ thống liên quan đến tệp.

Sau đó, rõ ràng là bạn ghi đè các cuộc gọi hệ thống liên quan đến tệp đó để làm bất cứ điều gì bạn muốn, và vì vậy đây là cách kernel thực hiện các thiết bị như thế nào /dev/zero.

Tạo /devcác mục tự động mà không cầnmknod

Bí ẩn cuối cùng là làm thế nào kernel tự động tạo /devcác mục.

Cơ chế có thể được quan sát bằng cách tạo một mô-đun hạt nhân tự thực hiện như sau: https://stackoverflow.com/questions/5970595/how-to-create-a-device-node-from-the-init-module- code-of-a-linux-kernel-module / 45531867 # 45531867 và thực hiện device_createcuộc gọi.


Trong OpenBSD có một kịch bản MAKEDEV đơn giản hóa điều này một chút, xem man.openbsd.org/MAKEDEV.8 Không chắc tại sao Linux không có nó ngoại trừ việc nó phức tạp hơn. Có lẽ các bộ phận có thể được thích nghi. Bạn có thể nói MKNOD tty chẳng hạn và nó xử lý các chi tiết.
Alan Corey
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.