Jak tworzone są pliki systemu Linux „/ dev”?

112

W Linuksie są specjalne pliki, które tak naprawdę nie są plikami.

Najbardziej godne uwagi i wyraźne przykłady znajdują się w devfolderze „pliki”, takie jak:

  • /dev/null - Ignoruje wszystko, co piszesz do pliku
  • /dev/random - Wyprowadza losowe dane zamiast zawartości pliku
  • /dev/tcp - Wysyła dane zapisywane do tego pliku przez sieć

Przede wszystkim, jak nazywają się te typy „plików”, które są w rzeczywistości jakimś skryptu lub pliku binarnego w przebraniu?

Po drugie, w jaki sposób są tworzone? Czy te pliki są wbudowane w system na poziomie jądra, czy też istnieje sposób, aby samodzielnie stworzyć „magiczny plik” (a może a /dev/rickroll)?

IQAndreas
źródło
1
Nie miałem pojęcia, jak oznaczyć to pytanie, zwłaszcza, że ​​nie znam nazwy tego, czego szukam. Edytuj dowolne odpowiednie tagi.
IQAndreas,
15
BTW, jest to podstawowa część projektowania systemów operacyjnych uniksowych i podobnych do unixa: (prawie) wszystko jest plikiem lub może wyglądać jak plik.
cas
5
Zobacz także: mknod (2) man 2 mknod
RobertL,
4
Są to „węzły urządzeń”. Jednak te, o których wspomniałeś - w przeciwieństwie do dysków, klawiatury, myszy, kart dźwiękowych i innych urządzeń - są tak zwanymi „pseudo-urządzeniami”, ponieważ nie są one „prawdziwymi” urządzeniami i istnieją tylko w jądrze. Można utworzyć nowe, pisząc odpowiedni sterownik urządzenia i dodając go do jądra (np. Pseudo-urządzenie do monitorowania aktywności na komputerze). Zanim katalog / dev istniał na dysku - obecnie jest to wirtualny system plików (typu devfs) tworzony przez jądro.
Baard Kopperud
10
Wszystkie pliki, nawet „prawdziwe”, są artefaktami oprogramowania. Oprogramowanie za każdym urządzeniu, pliku gniazda, specjalnym pliku, lub coś jeszcze wynalezione zamieszczono tabelę funkcji do obsługi open(), read(), close(), itd. Po tym, to zależy od oprogramowania
waltinator

Odpowiedzi:

101

/dev/zerojest przykładem „specjalnego pliku” - w szczególności „węzła urządzenia”. Zwykle są one tworzone przez proces instalacji dystrybucji, ale możesz je całkowicie stworzyć samodzielnie, jeśli chcesz.

Jeśli zapytasz lso /dev/zero:

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

Litera „c” na początku informuje, że jest to „urządzenie znakowe”; drugim typem jest „urządzenie blokowe” (wydrukowane lsjako „b”). Z grubsza urządzenia o swobodnym dostępie, takie jak dyski twarde, są zwykle urządzeniami blokowymi, podczas gdy sekwencyjne rzeczy, takie jak napędy taśm lub karta dźwiękowa, są zwykle urządzeniami znakowymi.

Część „1, 5” to „główny numer urządzenia” i „mniejszy numer urządzenia”.

Dzięki tym informacjom możemy użyć mknodpolecenia, aby utworzyć własny węzeł urządzenia:

# mknod foobar c 1 5

Spowoduje to utworzenie nowego pliku o nazwie foobarw bieżącym folderze, który działa dokładnie tak samo jak /dev/zero. (Jeśli chcesz, możesz oczywiście ustawić różne uprawnienia). Cały ten „plik” naprawdę zawiera trzy powyższe elementy - typ urządzenia, numer główny, mniejszy numer. Możesz użyć lsdo wyszukania kodów dla innych urządzeń i ich odtworzenia. Kiedy się nudzisz, po prostu użyj, rmaby usunąć właśnie utworzone węzły urządzenia.

Zasadniczo liczba główna informuje jądro Linuksa, z którym sterownikiem urządzenia ma rozmawiać, a liczba mniejsza informuje sterownik urządzenia, o którym urządzeniu mówisz. (Na przykład prawdopodobnie masz jeden kontroler SATA, ale może podłączono do niego wiele dysków twardych.)

Jeśli chcesz wymyślić nowe urządzenia, które zrobią coś nowego ... musisz edytować kod źródłowy jądra Linux i skompilować własne niestandardowe jądro. Więc nie róbmy tego! :-) Ale możesz dodać pliki urządzeń, które powielają te, które już masz dobrze. Zautomatyzowany system, taki jak udev, po prostu obserwuje zdarzenia urządzenia i automatycznie dzwoni mknod/ rmdo ciebie. Nic więcej magii niż to.

Istnieją jeszcze inne rodzaje plików specjalnych:

  • Linux uważa katalog za specjalny rodzaj pliku. (Zwykle nie możesz bezpośrednio otworzyć katalogu, ale gdybyś mógł, znajdziesz normalny plik, który zawiera dane w specjalnym formacie i informuje jądro, gdzie znaleźć wszystkie pliki w tym katalogu).

  • Dowiązanie symboliczne to specjalny plik. (Ale twardy link nie jest.) Możesz tworzyć dowiązania symboliczne za pomocą ln -spolecenia. (Poszukaj w nim strony podręcznika.)

  • Jest też coś o nazwie „nazwany potok” lub „FIFO” (kolejka pierwsze wejście, pierwsze wyjście). Możesz go utworzyć za pomocą mkfifo. FIFO to magiczny plik, który można otworzyć jednocześnie przez dwa programy - jeden odczyt, jeden zapis. Kiedy tak się dzieje, działa jak normalna rura osłonowa. Ale możesz uruchomić każdy program osobno ...

Plik, który w żaden sposób nie jest „specjalny”, nazywany jest „zwykłym plikiem”. Od czasu do czasu zobaczysz wzmiankę o tym w dokumentacji Uniksa. To właśnie oznacza; plik, który nie jest węzłem urządzenia, dowiązaniem symbolicznym ani niczym innym. Po prostu zwykły, codzienny plik bez magicznych właściwości.

MathematicalOrchid
źródło
4
Jest jeszcze jeden rodzaj specjalnego pliku, gniazdo domeny Unix powiązane z systemem plików.
Brian Bi,
8
Jeśli chcesz się bawić mknod, biegnij, cat /proc/devicesaby zobaczyć główne liczby dla wszystkich sterowników. Co prowadzi nas do jeszcze innego rodzaju specjalnego /procsystemu plików ( ta odpowiedź mówi o tym).
ugoren,
8
Inne Unices wymyśliły własne pliki specjalne, np. Solaris miał drzwi .
Kevin,
6
Drobny nitpick: nie musisz rekompilować jądra, aby napisać nowy znak / urządzenie blokowe :) crashcourse.ca/introduction-linux-kernel-programming/... W przeciwnym razie jest to naprawdę dobra odpowiedź, +1!
Dowódca kolendry Salamander
1
@MathematicalOrchid: Krokiem, na który brakuje odpowiedzi (lub przynajmniej stwierdzeniem niejawnym), jest fakt, że te specjalne pliki nie są wcale ukrytymi skryptami powłoki lub plikami binarnymi (jak sugeruje pytanie), ale raczej interfejsem dostępu do funkcji, która jest obecna w jądrze systemu operacyjnego.
Marzyciel
34

Większość /devwpisów to i-węzły urządzeń blokowych lub i-węzły urządzeń znakowych. Wikipedia ma wiele szczegółów na ten temat, których nie zamierzam powtarzać.

Ale /dev/tcpktóre jest wymienione w twoim pytaniu, nie jest wyjaśnione żadną z istniejących odpowiedzi. /dev/tcpi /dev/udpróżnią się od większości innych /devpozycji. Urządzenia blokowe i znakowe są realizowane przez jądro, ale /dev/tcpi /dev/udpsą realizowane w trybie użytkownika.

Powłoka bash to jeden program, który ma implementację /dev/tcpi /dev/udp(skopiowany z ksh93). Gdy spróbujesz otworzyć ścieżkę poniżej operatorów przekierowujących bash, nie wykona ona zwykłego openwywołania systemowego. Zamiast tego bash utworzy gniazdo TCP i podłączy je do określonego portu.

Jest to zaimplementowane w trybie użytkownika i tylko w niektórych programach, co widać w poniższym przykładzie, który pokazuje różnicę między wynajmowaniem basha catpróbą otwarcia/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

Różnica ksh93polega na tym bash, że będzie wykonywać tylko połączenia TCP z operatorami przekierowania, a nie w innych miejscach, w których może otwierać pliki takie jak sourcelub .wbudowane.

kasperd
źródło
Także GNU awk ma gawkpodobne przypadki specjalne /inet{,4,6}/{tcp,udp}/$port/$remote/$rport, ponieważ gdzieś około 2010 roku (nie pamiętam dokładnie i nie mogę znaleźć informacji o wydaniu).
dave_thompson_085,
6
IMO, lepszy sposób na stwierdzenie /dev/tcp, że NIE jest to plik. Nigdy nie ma pliku o nazwie to. Składnia Basha do otwierania gniazd używa łańcucha /dev/tcp/addressjak nazwy pliku, ale nazywanie go „plikiem zaimplementowanym w przestrzeni użytkownika” po prostu brzmi dziwnie. Interesujące jest to, że kshprzechwytuje te nazwy plików do wszystkiego, nie tylko przekierowań. Jest to bliższe „implementacji pliku”.
Peter Cordes,
@PeterCordes Wierzę, że UWIN ustawia je jako rzeczywiste pliki. i myślę, że 3dfs robi to samo. pamiętaj, bashskopiowałem tylko to zachowanie, ale pochodzi ono z innego miejsca.
mikeserv
19

Oprócz węzłów urządzeń wyjaśnionych w innych odpowiedziach (utworzonych za pomocą mknod (2) lub dostarczonych przez niektóre devfs ), Linux ma inne „magiczne” pliki dostarczane przez specjalne wirtualne systemy plików , w szczególności w /proc/(patrz proc (5) , przeczytaj o procfs ) i we /sys/(czytaj o sysfs ).

Te pseudopliki (które pojawiają się jako -eg do stat (2) - jako zwykłe pliki, a nie jako urządzenia) są wirtualnym widokiem udostępnianym przez jądro; w szczególności czytanie z /proc/(np. przy pomocy cat /proc/$$/mapslub przez otwarte (2) -wpisywanie /proc/self/statusw twoim programie) zasadniczo nie wymaga fizycznego wejścia / wyjścia z dysku lub sieci, więc jest dość szybkie.

Aby utworzyć dodatkowy pseudoplik /proc/należy na ogół napisać własny moduł jądra i załadować go (patrz np. To ).

Basile Starynkevitch
źródło
3
AFAIK informacja o przedłużeniu / proc jest nieaktualna. Chociaż nadal jest to technicznie możliwe, / proc (a raczej procfs) powinien przechowywać tylko informacje o uruchomionych procesach. Wszystkie inne pseudopliki, w tym te, które zawierają informacje o środowisku wykonawczym lub opcje konfiguracji jądra, powinny przejść do katalogu / sys (sysfs). Nadal istnieją pewne niepowiązane z procesem pseudopliki w / proc (np. Meminfo, cpuinfo) ze względów kompatybilności, ale nowe pseudopliki powinny przejść do sysfs.
Marzyciel
13

Są nazywane węzłami urządzeń i są tworzone ręcznie mknodlub automatycznie udev. Zazwyczaj są to interfejsy przypominające pliki do urządzeń znakowych lub blokowych ze sterownikami w jądrze - np. Dyski to urządzenia blokowe, tty i porty szeregowe itp. To urządzenia znakowe.

Istnieją również inne „specjalne” typy plików, w tym nazwane potoki oraz fifos i gniazda.

cas
źródło
9

Jak już szczegółowo wyjaśnili inni użytkownicy, specjalne pliki wymagają kodu, aby wykonać ich kopię zapasową. Jednak wydaje się, że nikt nie wspomniał, że Linux zapewnia kilka sposobów pisania tego kodu w przestrzeni użytkownika:

A. FUSE (system plików w USErspace) pozwala napisać coś takiego /procbez ryzyka awarii jądra i zrobić to w wybranym przez siebie języku / środowisku wykonawczym, takim jak Go , Node.js , Perl , PHP , Python , Ruby , Rust , itp .

Ma również tę zaletę, że systemy plików FUSE mogą być montowane bez, sudoponieważ działają jako użytkownik wykonujący montaż.

Oto kilka przykładów rzeczy, które ludzie napisali za pomocą FUSE:

  • mp3fs (Przeglądaj swoje pliki FLAC jako pliki MP3, które są tworzone w locie podczas kopiowania / przeciągania ich do odtwarzacza MP3)
  • PyTagsFS (Wyświetl swoje multimedia w drzewie wirtualnych folderów zbudowanych z tagów metadanych)
  • fuse-zip (Zamontuj pliki Zip jako foldery)
  • FuseISO ( mocowanie ISO bez uprawnień roota)
  • iFUSE (Mount iDevices)
  • FuseDAV ( mocowanie udziałów WebDAV)
  • fuse-exfat (Podłącz systemy plików w formacie exFAT)
  • ntfs-3g ( kierowca Linux NTFS)

B. Jeśli chcesz utworzyć wirtualne urządzenie wejściowe, takie jak klawiatura, mysz, joystick itp. (Np. Aby napisać sterownik przestrzeni użytkownika dla urządzenia USB, z którym rozmawiasz libusb), nie ma danych wejściowych .

Wiązania są trudniejsze do znalezienia, ale wiem, że istnieją dla Go (tylko klawiatura), Python i Ruby (2) .

Przykłady użycia wejścia rzeczywistego obejmują:

  • G15Daemon (sterownik Linux dla wyświetlacza LCD i klawiszy do gier na klawiaturach Logitech G15)
  • ds4drv (Driver do kontrolerów Sony DualShock 4)
  • xboxdrv (Alternatywny sterownik kontrolera XBox 360 i system Linux odpowiadający x360ce, więc źle zaprojektowane gry, takie jak Runner2: Future Legend of Rhythm Alien, mogą myśleć, że rozmawiają z prawdziwym kontrolerem XBox, gdy nie są)
  • Stare sterowniki Wiimote, takie jak cwiid , były wymagane, zanim ktoś w końcu napisał sterownik Wiimote do jądra, aby obsługa była domyślnie dostępna.

C. W przypadku ogólnych urządzeń postaci istnieje CUSE (urządzenia postaci w USErspace). Jest jednak znacznie mniej popularny.

Jedynym użytkownikiem API Cuse że jestem osobiście świadomy jest ten sam program co skłoniło jej utworzenia: osspd , który realizuje /dev/dsp, /dev/adsporaz /dev/mixer(API dźwięku OSS) w przestrzeni użytkownika, więc mogą być kierowane przez PulseAudio lub dmix.

Jedyne wiązanie CUSE , które udało mi się znaleźć, to cusepy , które nie było aktualizowane od 2010 roku.

D. W ogóle może nie być potrzebny nowy plik specjalny.

Na przykład możesz otworzyć surową komunikację z dowolnym urządzeniem USB za pomocą libusb (Lista powiązań na stronie), a następnie komunikować się z innymi programami za pomocą innego mechanizmu (gniazda TCP / UDP, odczyt / zapis stdin / stdout lub zwykłe pliki na dysku itp.).

ssokolow
źródło
1
cusepy może nie być od jakiegoś czasu aktualizowany (w rzeczywistości nigdy nie był aktualizowany; ma tylko jedno zatwierdzenie!), ale po napisaniu urządzenia znakowego za pomocą cusepy kilka tygodni temu, mogę potwierdzić, że nadal działa dobrze. Brakowało kilku funkcji związanych z implementacją poll, ale ponieważ cusepy używa ctypów, a powiązania są generowane automatycznie na podstawie plików nagłówkowych C, naprawienie wszelkich brakujących funkcji jest tylko kwestią dodania pożądanej nazwy funkcji do listy eksportowanych funkcji w setup.py.
Aleksi Torhamo
1
Innym ciekawym przykładem użycia FUSE jest sshfs . Pozwala przeglądać zdalny system plików tak, jakby był lokalny przy użyciu połączenia SSH pod spodem.
Mr. Deathless,
@ Mr.Deathless Tak. Właściwie to używam i chciałem o tym wspomnieć, ale zapomniałem.
ssokolow
6

Książka Sterowniki urządzeń Linux (wysoce zalecane) szczegółowo to wyjaśnia, a nawet stworzyłeś moduł jądra, który robi to jako przykład, ale w skrócie, każdy sterownik urządzenia ma określone funkcje, które są wywoływane, gdy plik jest otwierany, zamykany , czytanie, pisanie itp. Pliki „specjalne” po prostu robią coś specjalnego w obrębie tych funkcji, zamiast uzyskiwać dostęp do pamięci na dysku.

Na przykład funkcja zapisu po /dev/nullprostu nic nie robi, ignorując bajty. Funkcja odczytu dla /dev/randomzwraca liczbę losową.

Karl Bielefeldt
źródło
1

mount -t devtmpfs

Interesujące jest również to, że we współczesnych systemach /devzwykle jest to typ systemu plików, który można zamontować w dowolnym miejscu. Ubuntu 16.04:

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

Jest to włączone przez CONFIG_DEVTMPFS=yi pozwala samemu jądru tworzyć i niszczyć pliki urządzeń w razie potrzeby.

CONFIG_DEVTMPFS_MOUNT=y

Ta opcja powoduje automatyczne podłączanie devtmpfs do jądra /dev.

drivers/base/Kconfig dokumenty:

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

Na koniec powinieneś stworzyć własny moduł jądra urządzenia postaci, aby zobaczyć dokładnie, co się dzieje.

Oto minimalny możliwy do uruchomienia przykład: Zrozumienie plików urządzeń znakowych (lub znaków specjalnych)

Najważniejszym krokiem jest skonfigurowanie file_operationsstruktury, np .:

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;
}

który zawiera wskaźniki funkcji wywoływane dla każdego wywołania systemowego związanego z plikiem.

Wtedy staje się oczywiste, że przesłonisz wywołania systemowe związane z plikami, aby zrobić, co chcesz, i tak jądro implementuje takie urządzenia /dev/zero.

Twórz /devwpisy automatycznie bezmknod

Ostatnia tajemnica polega na tym, jak jądro automatycznie tworzy /devwpisy.

Mechanizm można zaobserwować, tworząc moduł jądra, który robi to sam, jak pokazano na stronie : https://stackoverflow.com/questions/5970595/how-to-create-a-device-node-from-the-init-module- code-of-a-linux-kernel-module / 45531867 # 45531867 i sprowadza się do device_createwywołania.

Ciro Santilli
źródło
W OpenBSD jest skrypt MAKEDEV, który trochę to upraszcza, patrz man.openbsd.org/MAKEDEV.8 Nie jestem pewien, dlaczego Linux go nie ma, z wyjątkiem tego, że jest o wiele bardziej skomplikowany. Może części mogą zostać dostosowane. Możesz powiedzieć na przykład MKNOD tty, który obsługuje szczegóły.
Alan Corey