«Все є файлом» — підхід до дизайну інтерфейсу в похідних Unix. Хоча це словосполучення не є принципом або філософією дизайну Unix, воно є поширеним способом аналізу дизайну і впливає на дизайн нових інтерфейсів, надаючи перевагу, в порядку важливості: представлення об'єктів як дескриптори файлів замість альтернатив, як-от абстрактні дескриптори або назви, робота над об'єктами зі стандартними операціями введення / виведення, повернення потоків байтів для інтерпретації програмами (а не явно структурованих даних) і дозвіл використання або створення об'єктів шляхом відкриття або створення файлів у просторі назв глобальної файлової системи Коли йдеться про Unix, межі між загальними інтерпретаціями «файлу» та «дескриптора файлу» часто розмиті, і назви файлів є найменш важливою частиною цього принципу; тому іноді його описують як «Все є дескриптором файлу»..

Цей підхід по-різному інтерпретується залежно від часу, філософії кожної системи та сфери, до якої він застосовується. Решта цієї статті демонструє яскраві приклади деяких із цих інтерпретацій та їхні наслідки.

Об'єкти як дескриптори файлів

У Unix каталог можна відкрити як звичайний файл, що містить записи фіксованого розміру (іноди, ім'я файлу), але каталоги не можуть бути записані безпосередньо, і вони змінюються ядром як побічний ефект створення та видалення файлі в каталозі.Thompson, Ken; Ritchie, Dennis (3 листопада 1971). .

Деякі інтерфейси дотримуються лише певної підмножини цих принципів. Наприклад, канали (pipes) не існують у межах файлової системи— системний виклик pipe() створює пару неіменованих дескрипторів файлів.Thompson, Ken; Ritchie, Dennis (лютий 1973). .. Опис системного виклику: ./man2/pipe.2. Цю прогалину було згодом усунуто з появою іменованих каналів (FIFO), запроваджених стандартом POSIX.

Це не означає, що читання та запис є єдиними операціями над об'єктом: ioctl() та подібні інтерфейси дозволяють виконувати специфічні для об'єкта операції (наприклад, керування характеристиками tty), дескриптори файлів каталогів можуть використовуватися для зміни механізму пошуку шляхів (із дедалі більшою кількістю варіантів системних викликів *at(), таких як openat()The IEEE and (2024). ) або для зміни робочого каталогу на той, що представлений дескриптором файлу,The IEEE and (2024). . що в обох випадках запобігає стану гонитви та працює швидше за альтернативний пошук за повним шляхом.The IEEE and (2024).

Дескриптори файлів сокетів потребують налаштування (встановлення віддаленої адреси та з'єднання) після створення, перш ніж їх можна буде використовувати для введення/виведення (I/O). Серверний сокет може взагалі не використовуватися для прямого введення/виведення — у протоколах зі встановленням з'єднання bind() призначає сокету локальну адресу, а listen() використовує цей сокет для очікування підключення віддаленого процесу, після чого повертає новий дескриптор файлу сокета, що представляє це пряме двонаправлене з'єднання.

Цей підхід дозволяє керувати об'єктами, що використовуються програмою, у стандартизований спосіб, як і будь-яким іншим файлом — після прив'язки до адреси привілеї можуть бути скинуті, а серверний сокет може бути розподілений між багатьма процесами за допомогою fork() (або, відповідно, закритий у підпроцесах, які не повинні мати доступу), або сокети окремих з'єднань можуть бути передані як стандартне введення/виведення спеціалізованим обробникам для цих з'єднань, як у парадигмах /CGI/.

Багато інтерфейсів, присутніх у ранніх версіях Unix, які не використовували дескриптори файлів, були дубльовані в пізніших розробках: системні виклики alarm() / setitimer() планують доставку сигналу після закінчення зазначеного часу; цей таймер успадковується дочірніми процесами та зберігається після . API POSIX timer_create() виконує подібну функцію, але знищує таймер у дочірніх процесах і під час exec(); ці таймери ідентифікуються непрозорими дескрипторами (handles). Обидва інтерфейси завжди доставляють свої завершення асинхронно і не можуть бути оброблені через / , що ускладнює їх інтеграцію в складний цикл подій.

Реалізація timerfd (уперше з'явилася в Linux) перетворює кожен об'єкт таймера на дескриптор файлу, за яким можна спостерігати окремо за допомогою poll() тощо, і чиє успадкування дочірніми процесами можна контролювати за допомогою стандартних засобів close(), CLOEXEC та CLOFORK.

Хоча API POSIX має функцію timer_getoverrun(), яка повертає кількість спрацювань таймера, у випадку з timerfd ця інформація повертається як результат виклику read(). Ця операція є блокувальною, тому очікування спрацювання timerfd зводиться до звичайного читання з нього. У класичних таймерах Unix або POSIX не існує способу виконати це атомарно. Стан таймера також можна перевірити в неблокувальному режимі, виконавши неблокувальне читання (стандартна операція введення/виведення).

Об'єкти в просторі імен файлової системи

Спеціальні типи файлів

Спеціальні файли пристроїв є визначальною характеристикою Unix: спочатку відкриття звичайного файлу з номером inode ≤40 (які традиційно зберігалися в каталозі /dev) натомість повертало дескриптор файлу, що відповідав певному пристрою та оброблявся драйвером пристрою. Пізніше ця схема магічних номерів inode була кодифікована у файли з типами S_IFBLK/S_IFCHR.

Відкриття спеціальних файлів підлягає тим самим перевіркам прав доступу файлової системи, що й відкриття звичайних файлів, що забезпечує єдиний механізм контролю доступу. Наприклад, виконання команд chown dmr /usr/dmr /dev/rk0; chmod o= /usr/dmr /dev/rk0 змінює власника та режим доступу до файлів одночасно для каталогу /usr/dmr і для пристрою /dev/rk0.

Для блокових пристроїв (жорстких дисків та стрічкових накопичувачів) через їхній розмір це означало унікальну семантику: вони мали блокову адресацію (див.Thompson, Ken; Ritchie, Dennis (3 листопада 1971). ), і програми мали бути написані спеціально для коректної роботи з ними. Це описують як «надзвичайно прикру обставину», а пізніші інтерфейси полегшують цю ситуацію .

У багатьох випадках магнітні стрічки зберігають унікальну семантику: деякі стрічки можна розділити на «файли», і драйвер сигналізує про стан кінця файлу після досягнення кінця розділу. Таким чином, послідовне виконання команд cp /dev/nrst0 file1; cp /dev/nrst0 file2 створить file1 та file2, що складатимуться з двох послідовних розділів стрічки. Драйвер забезпечує шар абстракції, який представляє дескриптор файлу стрічки так, ніби це звичайний файл, щоб відповідати парадигмі «Все є файлом». Для переміщення між такими розділами на стрічці використовуються спеціалізовані програми, як-от mt.

Названі канали (FIFO) відображаються як файли типу S_IFIFO у файловій системі, їх можна перейменувати та відкрити, як звичайні файли.

У похідних Unix, сокети домену Unix відображаються у файловій системі як файли типу S_IFSOCK; їх можна перейменовувати, проте неможливо відкрити за допомогою open() — натомість необхідно створити дескриптор сокета відповідного типу та виконати явне підключення через connect(). У системі Plan 9 сокети у файловій системі можна відкривати як звичайні файли.

Як заміна виділених системних викликів

Сучасні системи містять засоби високоефективного сповіщення про події введення-виведення: (BSD-похідні), (Linux), (Windows NT, Solaris) та (Solaris). Об'єкт керування зазвичай створюється (kqueue(), epoll_create()) та налаштовується (kevent(), epoll_ctl()) за допомогою спеціальних системних викликів. Екземпляр /dev/poll створюється шляхом безпосереднього відкриття файлу "/dev/poll", запису налаштованих об'єктів для спостереження та використання викликів ioctl() для додаткового налаштування.

Виділення пам'яті може здійснюватися шляхом запиту на анонімне відображення пам'яті — таке, що не відповідає жодному файлу. У сучасних системах це можна зробити, не вказуючи файл і використовуючи прапорець MAP_ANONYMOUS; у системі UNIX System V Release 4 це виконувалося шляхом відкриття пристрою /dev/zero та його відображення за допомогою mmap().

Файлові системи API

API операційних систем можуть бути реалізовані як звичайні системні виклики або як . У першому випадку стан системи можна перевірити лише за допомогою спеціалізованих програм, що постачаються в комплекті з ОС; будь-яка додаткова обробка даних користувачем вимагає або фільтрації та аналізу виводу цих програм, або їхнього виконання для запису потрібного стану, або ж має бути реалізована безпосередньо .

У другому випадку стан системи представляється так, ніби це звичайні файли та каталогиChristian Benvenuti (2006). .. У системах із інформацію про запущені процеси можна отримати, звернувшись (канонічно) до каталогу /proc. Він містить підкаталоги, названі відповідно до PID процесів, що виконуються в системі. Ці каталоги містять такі файли, як stat (Статус) із метаданими процесу, а також cwd, exe та root — символічні посилання на робочий каталог процесу, його виконуваний файл і кореневий каталог відповідно. Також там наявні каталоги на кшталт fd, які містять символічні посилання на відкриті процесом файли, названі за номерами їхніх дескрипторів.

Оскільки ці атрибути представлені як файли та символьні посилання, з ними можуть працювати стандартні утиліти. Це дозволяє, наприклад, перевірити ідентифікатор користувача процесу за допомогою grep Uid /proc/1392400/status, перейти до робочого каталогу процесу через cd /proc/1392400/cwd, переглянути список відкритих файлів за допомогою ls -l /proc/1392400/fd або навіть відкрити один із файлів, з якими працює цей процес, командою less /proc/1392400/fd/8. Такий підхід значно покращує ергономіку роботи порівняно з необхідністю аналізу (парсингу) даних із виводу спеціалізованих утиліт.Xiao, Yang; Li, Frank Haizhon; Chen, Hui (2011). ..

У Linux символічні посилання в procfs є «магічними»: вони можуть фактично поводитися як міжфайлові на файли, на які вони вказують. Така поведінка дозволяє відновлювати файли, які були видалені з файлової системи, але все ще залишаються відкритими певним процесом. Крім того, це дає змогу назавжди зберегти у файловій системі файли, створені з прапорцем O_TMPFILE, які в іншому випадку не можуть отримати назву.

4.4BSD-похідні sysctl — це відображення ключів/значень, керовані програмою sysctl, яка перераховує всі змінні з sysctl -a, значення однієї змінної з sysctl ne n orwarding, і встановлює його з sysctl -w ne n orwarding=1. Під Linux еквівалентний механізм забезпечується procfs під деревом /proc/sys: відповідні операції можна виконати з find /proc/sys/grep -r ^ /proc/sys, cat /proc/sys/net/ipv4/ip_forward та echo 1 > /proc/sys/net/ipv4/ip_forward.

Для забезпечення зручності або відповідності стандартам можуть надаватися спеціалізовані засоби інспектування (як-от ps та sysctl), що використовують ці файлові системи як джерела або приймачі даних.

та є подібними інтерфейсами Linux для подальшого налаштування ядра: запис mem у [/sys/power/state ініціює процедуру призупинення до ОЗП () а запис 2 у /sys/module/iwlwifi/parameters/led_mode активує блимання світлодіода Wi-Fi під час мережевої активності.

Такі файлові системи називають синтетичними, оскільки вміст їхніх файлів не зберігається ніде у незмінному вигляді: під час читання файлу відповідні структури даних ядра серіалізуються у вхідний буфер процесу, а під час запису — дані з вихідного буфера аналізуються ядром.Це призводить до порушення абстракції файлу, оскільки його метадані не є коректними: залежно від типу файлової системи, файл може повідомляти про розмір 0 або PAGE_SIZE, хоча фактичне читання даних повертає іншу кількість байтів.

Див. також — мережевий протокол для розподіленої операційної системи Plan 9

Об'єктно-орієнтований дизайн

Виноски

Коментарі

Примітки