- Работа с файлами
- Файловая система — способ организации и хранения файлов (ext4, btrfs, XFS)
- Inode (index node — индексный дескриптор) — это структура данных в файловой системе Unix/Linux, которая хранит метаданные о файле (всё, кроме его имени и содержимого).
- Виртуальная файловая система — это абстракция, которая представляет недисковые сущности (процессы, устройства, системную информацию) в виде обычных файлов и каталогов, предоставляя унифицированный файловый интерфейс для взаимодействия с ними.
ВАЖНО: в Linux ВСЁ — это файлы.
Есть 7 типов файлов:
-
Обычные (регулярные) файлы (
-вls -l)- Последовательность байтов (текст, бинарники, исполняемые файлы)
-
Директории (
d)- Файл, содержащий список записей вида
имя файла → inode - Как напоминание,
inode— структура, хранящая полную информацию о файле в ФС
- Файл, содержащий список записей вида
-
Символические ссылки (
l)- Ярлыки, содержащие путь к целевому файлу
-
Символьные устройства (
c- character device)- Это уже не фиксированный кусок информации - это поток байтов (терминалы,
/dev/random) - Не поддерживают
lseekи прочее из разряда Random Access (доступ последовательный)
- Это уже не фиксированный кусок информации - это поток байтов (терминалы,
-
Блочные устройства (
b- block)- Работают с блоками данных (диски:
/dev/sda,/dev/nvme0n1) - Поддерживают
lseek(произвольный доступ) - Нельзя скопировать обычным
cp
- Работают с блоками данных (диски:
-
Именованные пайпы (
p- pipe/FIFO)- Межпроцессное взаимодействие через FIFO-буфер
-
Сокеты (
s- socket)- Файлы для сетевого/межпроцессного взаимодействия
Примеры для каждого типа:
-(обычный):/etc/passwd,/bin/bashd(директория):/home,/tmpl(символическая ссылка):/usr/bin/python → python3.10c(символьное устройство):/dev/tty,/dev/nullb(блочное устройство):/dev/sda1,/dev/nvme0n1p2p(пайп): создаётся черезmkfifos(сокет):/run/systemd/journal/socket
Это файл, используемый ядром Linux как виртуальная память (swap). Когда физической памяти (RAM) не хватает, часть данных перемещается в swap, предотвращая падение системы.
# создаёт файл /swapfile размером 1 ГБ (1024 × 1 МБ).
dd if=/dev/zero of=/swapfile bs=1M count=1024
# форматирует файл как раздел подкачки
mkswap /swapfile
# активирует его
swapon /swapfilecd /dev
ls -lУвидим файлы устройств в флагами b и c.
Файл - это не обязательно выделенный отрезок на диске
- Это нечто более абстрактное, с чем можно проделывать операции типа "открыть", "закрыть", "читать", "писать", в зависимости от типа этого самого "файла"
Типы устройств:
c(символьные):/dev/tty,/dev/random,/dev/nullb(блочные):/dev/sda,/dev/nvme0n1
Виртуальные устройства:
/dev/null— игнорирует запись, возвращает EOF при чтении- Абстракция уровня ОС
/dev/zero— возвращает нулевые байты/dev/randomи/dev/urandom— генераторы случайных чисел
Пишем буквально в никуда:
echo "Hello" > /dev/null- Например, хочу подавить вывод stderr
Выводит ТОЛЬКО НУЛЕВЫЕ байты:
/dev/zeroУ этого файла нет физической оболочки - это "фейковая" сущность.
Вообще, папка dev содержит файлы девайсов и драйверов. Например, /dev/snd содержит файлы звуковой карты; nvme0... - твердотельные накопители (уже тип b) (суффиксы вида pX (partition X)).
dd - утилита, которая открывает поток и пишет данные с другого потока
Просто обнуляем весь диск:
dd if=/dev/zerо оf=/dev/nvme0n1р1- Хуже, чем
sudo rm / -f
Пример чтения из /dev/random:
dd if=/dev/random of=random_data.bin bs=1 count=16 # 16 байт случайных данныхЧтение с символьного устройства:
int fd = open("/dev/random", O_RDONLY);
unsigned char buffer[32];
read(fd, buffer, sizeof(buffer));Запись на устройство (терминал):
int fd = open("/dev/tty", O_WRONLY);
write(fd, "Hello\n", 6);Pipes — это механизм межпроцессного взаимодействия (IPC), который работает по принципу FIFO (First In, First Out). Однако pipes делятся на два основных типа, которые сильно отличаются по способу использования и "жизни".
- Неименованные (анонимные) пайпы (Unnamed pipes, или просто "pipes")
- Именованные пайпы (Named pipes, FIFO)
FIFO — named pipe, существует как файл в файловой системе.
mknod - утилита, позволяющая создавать файлы разных типов:
man mknod- Ему соответствует одноименный syscall
mknod.
Файл типа pipe (труба: можно писать в один конец и получать через другой конец - FIFO!):
mknod myfifo p- Можно только писать потоком и читать потоком
- Причем данные пишутся в ОЗУ, а на диск не пишется
Есть также syscall mkfifo:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);Пишем в пайп и читаем с него:
// write_to_fifo.cpp
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main() {
mkfifo("./test_fifo", 0666);
int fd = open("./test_fifo", O_WRONLY);
char* str = "Hello!";
write(fd, str, strlen(str));
close(fd);
return 0;
}// read_from_fifo.cpp
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("./test_fifo", O_RDONLY);
char str[10];
read(fd, str, 5);
printf("%s", str);
close(fd);
return 0;
}- Запускаем первую программу (
./write_to_fifo) - она зависает на моменте открытия (open): ждет появления читателя (этакое рандеву) - Запускаем вторую (
./read_from_fifo) - выводитHello, а первая программа заканчивает выполнение
Забудем про первую программу и сделаем через echo:
echo "Hello" > test_fifo- Тоже зависло
./read_from_fifo-
echoзавершилась. -
Неблокирующий режим:
open("myfifo", O_RDONLY | O_NONBLOCK)— возвращает управление сразу.readиwriteтоже не задерживают работу.
int fd = open("myfifo", O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
return 1;
}
// Дальше можно читать без блокировки- Данные хранятся в ядре (буфер до 64 КБ по умолчанию в Linux). Если буфер переполняется:
- Для записи: процесс блокируется до освобождения места.
- В неблокирующем режиме: вызов
writeвернёт ошибкуEAGAIN.
Pipes — однонаправленные каналы между процессами. Создаются с помощью pipe().
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
int main() {
int fd[2];
pipe(fd); // fd[0] - чтение, fd[1] - запись
if (fork() == 0) {
// child: пишет в pipe
close(fd[0]);
write(fd[1], "Hello", 6);
close(fd[1]);
return 0;
} else {
// parent: читает из pipe
close(fd[1]);
char buf[100];
read(fd[0], buf, sizeof(buf));
printf("Parent got: %s\n", buf);
close(fd[0]);
wait(NULL);
}
return 0;
}Broken pipe (SIGPIPE) возникает при записи в pipe, у которого нет читателей.
| Характеристика | Неименованные пайпы (Unnamed pipes) | Именованные пайпы (Named pipes, FIFO) |
|---|---|---|
| Создание | pipe() (в коде) или | (в shell) |
mkfifo() (в коде) или mkfifo (в shell) |
| Идентификация | Нет имени в файловой системе. Дескрипторы файлов в ядре ОС | Есть имя в файловой системе (например, /tmp/myfifo) |
| Внешний вид | Невидимы в файловой системе | Видны в ls -l с символом p (тип файла "pipe") |
| Связь процессов | Только родственные процессы (обычно родитель-потомок) | Любые, не родственные процессы |
| Механизм связи | Наследование дескрипторов при вызове fork() |
Открытие по имени файла |
| Время жизни | Пока жив хотя бы один из связанных процессов | Как у обычного файла (до явного удаления) |
| Типичное использование | Команды в shell: cmd1 | cmd2 |
Долговременное взаимодействие независимых программ |
| Принцип работы | FIFO (для обоих типов) | FIFO (для обоих типов) |
Как FIFO, только общение распространяется по сети.
- То есть это файлы, которые работают по принципу FIFO, но обращение к данным осуществляется посредством сетевой карты.
Рассмотрим другую "директорию".
cd /proc/Это псевдофайловая система (pseudo-filesystem) (то есть не хранится фактически на диске, но предоставляет интерфейс в виде файлов и каталогов к данным о состоянии ядра, процессах, устройствах и других системных ресурсах).
Мануал к ней:
man procТак, можно узнать почти все про текущие процессы. Например, можно узнать PID последнего выполняемого процесса
cat loadavg # нам нужно последнее числоРассмотрим все содержимое:
cd /proc/
ls -lЗдесь также много директорий, отвечающих за процессы (названия директорий - это сам PID процесса). Можно зайти в какой-нибудь процесс и узнать, например:
- установленные на процесс лимиты
cat ./limits cat maps— об этом будет позже — диапазоны адресов, выделенные под процесс (иначе говоря, карта памяти процесса)cd fd— симлинки на открытые файлы процесса
Как оказывается, программа top просто читает /proc/{PIDs}/statm (или stat):
- См.
man proc_pid_stat
strace topСписок открытых процессом файлов (list open files):
lsof -p {PID}Упрощенная реализация lsof:
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
DIR *dir = opendir("/proc/self/fd");
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
char path[256];
snprintf(path, sizeof(path), "/proc/self/fd/%s", entry->d_name);
char target[256];
int len = readlink(path, target, sizeof(target)-1);
target[len] = '\0';
printf("%s -> %s\n", entry->d_name, target);
}
closedir(dir);
return 0;
}Информация об устройствах, но в более читаемом виде. Тоже является фейковой ФС.
Все устройства, которые реально существуют:
cd /sys/dev/Информация о ядре:
cd /sys/kernel