Операционная система - это базовое системное программное обеспечение, управляющее работой вычислительного узла и реализующее универсальный интерфейс между аппаратным обеспечением, программным обеспечением и пользователем
Возможности по изменению аппаратного обеспечения часто ограничены, поэтому на практике стремятся извлечь максимальную производительность и гибкость за счёт программного обеспечения и грамотного администрирования ОС
Курс разделен на несколько блоков:
Linux (в части случаев GNU/Linux) - это семейство открытых и свободных Unix-подобных операционных систем на базе ядра Linux, включающих набор утилит и программ проекта GNU, а также другие системные и прикладные компоненты
Linux начал своё развитие в 1991 году, когда Линус Торвальдс, будучи студентом Хельсинкского университета, опубликовал первую версию ядра Linux как учебный и исследовательский проект
Со временем вокруг ядра Linux сформировалось большое сообщество разработчиков, а сам Linux стал использоваться в серверах, настольных системах, мобильных и других устройствах
Разделяют бесплатное ПО, открытое ПО и свободное ПО
Бесплатное ПО (Freeware) - программное обеспечение, распространяющееся бесплатно конечному пользователю в виде исполняемых файлов
Открытое ПО (Open-Source Software) - программное обеспечение с открытым исходным кодом, чаще всего распространяющимся по разрешительной лицензии
Свободное ПО (Free and Open-Source Software, FOSS) - открытое программное обеспечение, лицензия которого заставляет авторов производных от него работ лицензировать их под той же свободной лицензией
Linux является свободным программным обеспечением и распространяется под лицензией GNU General Public License 2.0. Это означает, что операционная система Linux гарантирует пользователю 4 свободы, сформулированные Ричардом Столлманом, основателем проекта GNU:
Лицензия GNU General Public License 2.0 накладывает обязательство на то, что производные работы также должны распространяться на условиях этой лицензии
Linux включает набор утилит и программ GNU, такие как Bash или GNU Compiler Collection, которые тоже являются свободным ПО
Linux распространяется не только в виде ядра, но и в виде дистрибутивов - готовых комплектов программного обеспечения, включающих ядро, системные утилиты, менеджер пакетов, установщик и часто графическую среду. Сейчас популярные дистрибутивы - это Debian, Ubuntu, Fedora, Arch Linux и другие
Дистрибутивы Linux бесплатные, но не все. Так, например, Red Hat Enterprise Linux распространяется по платной модели, имея открытый код, но за плату предлагается расширенная корпоративная поддержка и сервис
Ключевые отличия свободного ПО и проприетарного ПО заключаются:
В доступу к исходному коду
В модели поддержки. В свободном ПО поддержка часто осуществляется сообществом или сторонними компаниями, а в проприетарном ПО - официальным производителем
В поиске и исправлении уязвимостей. Открытый код позволяет независимый аудит безопасности, тогда как при использовании проприетарного ПО пользователь вынужден доверять разработчику
В гибкости и кастомизации. Свободное ПО можно модифицировать под конкретные нужды, проприетарное, как правило, нет
Долгое время наиболее популярной настольной операционной системой остаётся Microsoft Windows. Рассмотрим ключевые концептуальные отличия Linux от Windows:
Работа с файлами
В Linux все объекты, в том числе файлы, сетевые сокеты, устройства, каналы, - это файловые дескрипторы, поэтому взаимодействие с ними осуществляется через файловую систему
В Windows пользователь чаще взаимодействует с действиями и приложениями, а не с абстрактными объектами файловой системы
Иерархия файловой системы
Linux использует единую иерархию каталогов, начинающуюся с корня /, тогда как в Windows используется несколько корней: диски C:, D: и так далее
Права доступа
В Linux строгая модель прав доступа: владелец, группа и остальные; В Windows используется модель NTFS-разрешений, менее прозрачная для пользователя.
Обновления и установка ПО
В Linux программное обеспечение обычно устанавливается из централизованных репозиториев через менеджеры пакетов. В Windows чаще используются отдельные установщики для каждого приложения
В Linux и других Unix-подобных системах все объекты являются файловыми дескрипторами, то есть все действия совершаются через универсальный интерфейс
Файловый дескриптор - это идентификатор, за которым закреплен определенный поток ввода и вывода. Через файловые дескрипторы в Linux можно работать:
Получаем единый набор операций с файловым дескриптором: открытие, чтение, запись и закрытие
Всего можно выделить 7 типов файлов:
Регулярный файл
Регулярный файл - это файл в обычном его понимании, то есть именованная область памяти хранилища, которая структурирована иерархически
По умолчанию, Linux рекомендует использовать файловую систему ext4, которая использует индексные дескрипторы. Поэтому на диске файл представлен индексным дескриптором в начале блочного устройства

Когда файл создается, в таблице индексных дескрипторов появляется индексный дескриптор файла. При записи операционная система выделяет новые блоки на блочном устройстве и добавляет ссылки на эти блоки в индексном дескрипторе, а при удалении удаляется индексный дескриптор
При этом файл в Linux не хранит свое имя - это ответственность каталога
Каталог
Каталог - это таблица, содержащая имя файла, его индексный дескриптор и опционально другие данные. В разных операционных системах применяет разная терминология, в Windows применяется офисный термин “папка” (folder), а в Linux каталоги называются директориями (directory)
Каталоги позволяют задавать иерархическую структуру на блочном устройстве. Так как это таблица, где ключ - это имя файла или каталога, нельзя создать в одном каталоге файл и каталог с одним и тем же именем, в отличие от Windows

Linux позволяет создавать не просто файлы в каталоге, а жесткие ссылки на файлы в каталоге. При создании жесткой ссылки:
ln исходный_файл новый_файл
Файлы исходный_файл и новый_файл будут иметь те же содержимое и индексный дескриптор, однако храниться в разных каталогах одновременно. Удаление одного из них не приведет к потери ссылок на блоки, где хранятся данные. Чтобы удалился сам индексный дескриптор, нужно, что бы счетчик жестких ссылок достиг нуля
Жесткие ссылки нельзя создавать:
Символическая (или мягкая) ссылка
Символическая ссылка (symlink или softlink) - это еще один тип файла, который внутри хранит путь до другого файла в файловой системе. При обращении путь к ссылке подменяется операционной системой на содержащийся внутри путь файла, что позволяет обойти ограничения, связанные с жесткой ссылкой
Символическая ссылка может быть сломанной или битой, если она указывает на файл или каталог, который не существует
Символическую ссылку можно сделать с помощью команды ln:
ln -s исходный_файл имя_ссылки
Файлы-дырки
Файлы-дырки (filehole) не хранят ничего на жестком диске компьютера непосредственно, однако с помощью них осуществляется доступ к подключенным устройствам и объектам операционном системы
Файлами-дырками могут быть:
Особое место занимает каталог /dev/. В нем содержатся все устройства, в том числе виртуальные, к которым операционная система имеет доступ. Есть два типа организации этого каталога:
/dev/ для каждого устройстваТак /dev/ содержит:
/dev/console - консоль для вывода системных сообщений при запуске и завершении системы/dev/tty - консоль текущего процесса/dev/tty1, /dev/tty2, … - виртуальные консоли, доступные через Ctrl+Alt+F1 и так далее/dev/sda (аналогично /dev/sd+буква) - жесткий диск, подключенный через SATA/dev/nvme0n1 (аналогично /dev/nvme0n+цифра) - твердотельный накопитель с технологией NVMe, в данном случае nvme0 - это номер PCIe-шины/dev/nvme0n1p1 - первый раздел на этом накопителе
/dev/fb0 - буфер кадра в видеопамяти графического процессора/dev/mouse0 - мышь/dev/null - канал, в который можно перевести символьный поток (например, вывод процесса), чтобы уничтожить его/dev/zero - поток, который генерирует нули/dev/random - поток, который генерирует рандомные символы/dev/full - поток, который возвращает ошибку “Недостаточно места”Каждый процесс (кроме демонов) при создании получает 3 символьных файловых дескриптора: стандартный поток ввода с номером 0, стандартный поток вывода с номером 1 и стандартный поток ошибок с номером 2. На них есть символические ссылки /dev/stdin, /dev/stdout и /dev/stderr
Используя команду ls -l, можно посмотреть на информацию о файлах в каталоге, например:
crw-r--r-- 1 root root 10, 235 Feb 13 17:59 autofs
drwxr-xr-x 2 root root 180 Feb 13 17:59 block
crw-rw---- 1 root disk 10, 234 Feb 13 17:59 btrfs-control
drwxr-xr-x 3 root root 60 Feb 13 17:59 bus
drwxr-xr-x 2 root root 4920 Feb 13 17:59 char
crw------- 1 root root 5, 1 Feb 13 17:59 console
lrwxrwxrwx 1 root root 11 Feb 13 17:59 core -> /proc/kcore
drwxr-xr-x 14 root root 280 Feb 13 17:59 cpu
crw------- 1 root root 10, 259 Feb 13 17:59 cpu_dma_latency
Первый столбец обозначает тип файла и его модификаторы доступа. Первая буква - это тип файла, так:
- - это регулярный файлd - это директория (от directory)l - это символическая ссылка (от link)s - это сокет (от socket)b - это блочное устройство (от block)c - это символьное устройство (от character)p - это именованный канал (от pipe)Следующие 9 букв задают права доступа для файла. В Linux действует ролевая модель доступа, поэтому есть такие понятия:
Так модификаторы доступа делятся на три тройки букв, каждая тройка из которых показывает права для определенной выборки пользователей
r - право на чтение файла или чтение имен файлов внутри каталогаw - право на запись в файлx - право на исполнение файла или чтение свойств файлов внутри каталогаТак -rwxr-xr-x означает регулярный файл, читать и исполнять который могут все, а записывать только владелец
Права доступа проверяются слева направо. Так, если файл имеет права ----r-xr-x, то его владелец не сможет с ним ничего сделать, несмотря на то, что он находится в группе файла
Помимо этих 9 модификаторов есть еще 3 скрытых:
ls -l обозначается как --s------ (если установлен x для владельца) или --S------SGID (Set Group ID upon execution) - пользователи, которые могут запустить выполнение файл, запускают его с правами группы владельца. Для каталог этот флаг означает то, что новые файлы создают с той же группой, которая привязана к каталогу, а не основной группой для пользователя. В ls -l обозначается как -----s--- (если установлен x для пользователей группы) или -----S---
Биты SUID и SGID полезны для осуществления особых ограничений на файлы. Например, если в системе зарегистрированы пользователи, чьи пароли хранятся в недоступном ими файле, то можно сделать скрипт с битом SUID, которым владеет суперпользователь, и который только изменяет пароль в файле пользователя, который его вызвал
T-бит или липкий бит (Sticky Bit) - файлы в каталоге, имеющем липкий бит, могут быть удалены или переименованы только владельцем файла. В ls -l обозначается как --------t (если установлен x для остальных пользователей) или --------T
В ранних версиях ядра липкий бит использовался на исполняемых программах. Тогда было непозволительно долго ждать, когда программа, закончившая исполнение пару минут назад, снова загружалась в оперативную память. Поэтому программы с липким битом при первом исполнении загружались в оперативную память, а после завершения память не высвобождалась, благодаря чему при следующем исполнении ядро могло назначить эту область память процессу и не загружать программу повторно
Права можно установить для файла с помощью команды chmod (от change mode):
chmod права файл
Права указываются:
101101000 означает r-xr-x---, при этом 10-ый бит предназначен для T-бита, 11-ый бит - для SGID, 12-ый бит - для SUID754 означает rwxr-xr--, 2555 означает r-xr-sr-xrwxr-xr--С указанием выборки пользователей. Например:
chmod u+x file добавляет право на исполнение файла владельцуchmod u+w,o-w file добавляет право на запись владельцу и убирает право на запись пользователям вне группыchmod g+s file добавляет флаг SUIDchmod o+s file добавляет флаг Sticky Bitchmod g=rx file устанавливает права на чтение и запись группе вместо тех права, что были до этогоВторой столбец - это число жесткий ссылок на файл
Третий столбец из вывода ls -l указывает на владельца файла, а четвертый - на группу владельца (так как пользователь может состоять в нескольких группах). Сменить владельца можно с помощью команды chown (от change owner):
# меняет владельца на pelmeshke
chown pelmeshke /var/log/mylogs/app.log
# меняет владельца на pelmeshke и группу на supercoolusers
chown pelmeshke:supercoolusers /var/log/mylogs/app.log
# меняет владельца на pelmeshke рекурсивно
# для всех файлов и каталогов в /var/log/mylogs
chown -R pelmeshke /var/log/mylogs/
По умолчанию, при создании пользователя в Linux ядро создает группу с таким же именем. Для смены группы файла есть команда chgrp (от change group):
# меняет группу на supercoolusers
chgrp supercoolusers /var/log/mylogs/app.log
Файловая система - это способ организации информации на носителе данных
Файловая система выполняет такие функции:
Файловая система является посредником в общении между пользователем, использующим ОС, и жестким диском
Позднее число файловых систем стало настолько большим, что в архитектуре операционных систем стала появляется виртуальная файловая система - стандартизованный интерфейс между системными вызовами и конкретной файловой системой

Файловые системы могут использовать множество методов организации:
Подробнее об этом описано в курсе “Операционные системы”
Современные операционные системы используют файловые системы с индексными дескрипторами для дисков, на которых установлена система. Так, Windows использует NTFS (New Technology File System), а для Linux рекомендуется ext4 (от Fourth Extended, Четвертая расширенная файловая система)
В файловой системе ext4 в начале блочного устройства есть участок с названием суперблок (Superblock). Суперблок - это структура, состоящая из данных, которые определяют организацию данных:
| Поле | Тип данных | Назначение |
|---|---|---|
s_inodes_count |
__le32 |
Общее количество индексных дескрипторов |
s_blocks_count_lo |
__le32 |
Общее количество блоков (младшие 32 бита) |
s_r_blocks_count_lo |
__le32 |
Зарезервированные блоки (младшие 32 бита) |
s_free_blocks_count_lo |
__le32 |
Свободные блоки (младшие 32 бита) |
s_free_inodes_count |
__le32 |
Количество свободных индексных дескрипторов |
s_first_data_block |
__le32 |
Первый блок данных |
s_log_block_size |
__le32 |
Логарифм размера блока в килобайтах по основанию 2 |
s_log_cluster_size |
__le32 |
Логарифм размера кластера в килобайтах по основанию 2 |
s_blocks_per_group |
__le32 |
Блоков в группе |
s_clusters_per_group |
__le32 |
Кластеров в группе |
s_inodes_per_group |
__le32 |
Индексных дескрипторов в группе |
s_mtime |
__le32 |
Время последнего монтирования |
s_wtime |
__le32 |
Время последней записи |
s_mnt_count |
__le16 |
Счётчик монтирований после проверки диска |
s_max_mnt_count |
__le16 |
Максимальное число монтирований, после который нужна проверка диска |
s_magic |
__le16 |
Магическое число, для ext4 - это 0xEF53 |
s_state |
__le16 |
Состояние файловой системы |
s_errors |
__le16 |
Поведение при ошибках |
s_minor_rev_level |
__le16 |
Минорная версия |
s_lastcheck |
__le32 |
Время последней проверки |
s_checkinterval |
__le32 |
Интервал проверки |
s_creator_os |
__le32 |
Операционная система, создавшая раздел (Linux - это 0x0000, FreeBSD - это 0x0003) |
s_first_ino |
__le32 |
Первый незарезервированный индексный дескриптор |
s_inode_size |
__le16 |
Размер индексного дескриптора (обычно 256 байт) |
s_block_group_nr |
__le16 |
Номер группы (для копии суперблока) |
s_uuid |
__u8[16] |
UUID файловой системы |
s_volume_name |
char[16] |
Имя тома |
… и много других
Здесь __le16, __le32 - беззнаковые целые числа, записанные в Little-endian, размером 16 бит и 32 бита соответственно, __u8[16] - 16-байтный массив беззнаковый 8-битных чисел, а char[16] - символьная последовательность
Источник: https://docs.kernel.org/next/filesystems/ext4/super.html
Со временем появилась идея размещать блоки больших файлов рядом друг с другом, чтобы уменьшать движение читающей головки жесткого диска по секторам
Для решения этого появились группы блоков. Группы содержат свои битовые карты, таблицы индексных дескрипторов и блоки данных
Первая группа под индексом 0 хранит суперблок и таблицу дескрипторов блочных групп (Block Group Descriptors) - структуры с данными полями:
| Поле | Тип данных | Назначение |
|---|---|---|
bg_block_bitmap_lo |
__le32 |
Номер блока битовой карты блоков (младшие 32 бита) |
bg_inode_bitmap_lo |
__le32 |
Номер блока битовой карты дескрипторов (младшие 32 бита) |
bg_inode_table_lo |
__le32 |
Первый блок таблицы индексных дескрипторов (младшие 32 бита) |
bg_free_blocks_count_lo |
__le16 |
Количество свободных блоков в группе |
bg_free_inodes_count_lo |
__le16 |
Количество свободных дескрипторов в группе |
bg_used_dirs_count_lo |
__le16 |
Количество каталогов в группе |
bg_flags |
__le16 |
Флаги состояния группы |
bg_exclude_bitmap_lo |
__le32 |
Блок битовой карты снимков исключения (Exclusion Snapshot) |
bg_block_bitmap_csum_lo |
__le16 |
Контрольная сумма битовой карты блоков |
bg_inode_bitmap_csum_lo |
__le16 |
Контрольная сумма битовой карты дескрипторов |
bg_itable_unused_lo |
__le16 |
Количество неинициализированных индексных дескрипторов |
bg_checksum |
__le16 |
Контрольная сумма дескриптора группы |
… и другие поля
Последующие группы могут хранить также избыточные копии суперблока и таблицы дескрипторов групп, но система будет обращаться к ним в том случае, если начало диска было повреждено
Источник: https://docs.kernel.org/next/filesystems/ext4/group_descr.html
Далее идет битовая карта блоков (Block Bitmap). В ней один бит, равный 1, обозначает, занят ли конкретный блок с тем же индексом
Затем расположена подобная битовая карта для индексных дескрипторов (Inode Bitmap), где бит 1 обозначает, занят ли индексный дескриптор в таблице дескрипторов
Источник: https://docs.kernel.org/next/filesystems/ext4/bitmaps.html
После этого расположена сама таблица индексных дескрипторов. Таблица представляет собой массив дескрипторов, где индекс - это номер индексного дескриптора
Для специальных индексных дескрипторов выделены особые индексы:
0 для дескриптора, который не существует1 для списка бракованных блоков2 для корневого каталога /3 для пользовательской квоты4 для квоты групп
Квоты хранят информацию о том, сколько разрешено максимально иметь дескрипторов и/или блоков пользователям и группам
5 для загрузчика. Сейчас он редко используется, так как рекомендуется устанавливать загрузчик на другой раздел диска6 для каталога восстановления7 для зарезервированной группы дескрипторов для увеличения количества дескрипторов файловой системы8 для журнала, чтобы обеспечивать надежность данных во время сбоя9-ый и 10-ый дескрипторы зарезервированы и используются для функций, который обозначены ? в документации, а 11-ый дескриптор - первый не зарезервированный, но обычно используется для каталога /lost+found/, который предназначен для восстановленный утилитой fsck файлов после сбоя
Источник: https://www.kernel.org/doc/html//latest/filesystems/ext4/special_inodes.html
Наконец, после таблицы индексных дескрипторов дальше идут сами блоки данных

В файловой системе ext3 добавилась система журналирования - способ восстановления данных в результате нештатной работы ОС или диска
Всего есть три типа журналов в ext3:
В системе ext4 добавилось много новых функций, которые убирали ограничения старых версий системы:
Экстенты вместо блочной адресации
Вместо хранения списка отдельных блоков используются экстенты, что уменьшает фрагментацию и ускоряет работу с большими файлами
Хорошей практикой является разделение диска на 6 разделов:
/boot/, хранящий ядро и initramfs//home//var/, содержащего изменяемые файлыВ корневом каталоге Linux создает множество подкаталогов для работы системы, структура которых подчиняется стандарту (FHS) Filesystem Hierarchy Standard:
/bin/ - каталог с готовыми к исполнению основными программами (например, /bin/bash). Оболочки, такие как bash, ищут исполняемые файлы с именем там/sbin/ - системные исполняемые файлы для администрирования (например, fsck, mount), которые обычно предназначены для суперпользователя/boot/ - файлы, необходимые для загрузки системы: ядро Linux, initramfs, конфигурация загрузчика/dev/ - файловые дескрипторы устройств/etc/ (от Editable Text Configuration или Extended Tool Chest) - системные конфигурационные файлы такие, как настройки служб, сети, пользователей и всей системы
/home/ - домашние каталоги обычных пользователей/root/ - домашний каталог суперпользователя
/lib/, /lib64/ - системные библиотеки, необходимые для работы программ из /bin/ и /sbin//media/ - точки монтирования съемных носителей/mnt/ - временное монтирование файловых систем администратором/opt/ - дополнительные пакеты/proc/ - виртуальная файловая система с информацией о процессах и ядре, создающаяся динамически/sys/ - виртуальная файловая система с информацией о устройствах и драйверах./run/ - временные данные времени выполнения, например, текущие вошедшие пользователи или запущенные демоны/tmp/ - временные файлы, которые очищаются после перезагрузки. В некоторых случаях каталог /tmp/ может храниться непосредственно в оперативной памяти
/usr/ - пользовательские программы и данные (большинство установленного ПО):
/usr/bin - программы/usr/lib - библиотеки/usr/src/ - исходный код/usr/share - общие данные, которые не зависят от архитектуры/var/ - изменяемые данные, такие как:
/var/log/ - логи/var/lib/ - персистентная информация программ (например, базы данных)/var/lock/ - блокировки ресурсов/var/cache/ - кэш/var/spool/ - очереди печати, почтовых запросов и так далее/var/mail/ - данные почтовых серверов/var/tmp/ - временные файлы, которые нужно сохранить после перезагрузки
Процесс - совокупность набора исполняемых команд, ассоциированных с ним ресурсов и контекста исполнения, находящиеся под управлением операционной системы
Сам же процесс в Linux хранится структурой task_struct с множеством полей, таких как:
В Linux процессы порождаются с помощью других процессов, таким образом, образуя дерево

Дерево как структура было выбрано по нескольким причинам:
Процессы имеют только одного создателя - структура уже выходит иерархической, поэтому дерево самое подходящее отображение такой структуры
Обработка ошибок
Когда дочерний процесс умирает по своей причине или из-за исключения, кто-то должен прочитать его код выхода, сделать дамп памяти и другое, чтобы пользователь узнал, что не так случилось в ходе работы
Распространение сигналов
Для общения между процессами используются сигналы. Дерево позволяет сделать отправку одного сигнала группе процессов намного проще, например, сигнала SIGHUP (от SIGnal Hang UP) для завершения процесса и их детей
Первый процесс - это процесс init или systemD, который является корнем одного поддерева процессов
Для создания процессов могут использоваться три системных вызова:
pid_t fork(void) делает копию процесса. Новый процесс имеет те же указатель на таблицу страниц память (то есть ту же память, что и родитель), те же файловые дескрипторы, те же обработчики сигналов, и те же права доступа, что и родитель, но получает новый идентификатор
Для того, чтобы не копировать все адресного пространство, копируют лишь таблицы, а сами страницы помечают флагом “только для чтения”. При попытке записи родителем или ребенком конкретной страницы, возникнет прерывание отказа страницы, вследствие которого ядро скопирует страницу для ребенка. Такой подход называется “копия при записи” (Copy-on-Write)
fork() возвращает -1, если копирование не удалось, 0, если процесс является родителей, и идентификатор дочернего процесса в другом случае:
pid_t pid = fork();
switch (pid) {
case -1:
perror("Копия не удалась");
case 0:
puts("Этот процесс - ребенок");
default:
puts("Этот процесс - родитель");
printf("PID дочернего процесса - %jd\n", (intmax_t) pid);
}
Источник: https://www.man7.org/linux/man-pages/man2/fork.2.html
exec - семейство вызовов, которые заменяют код программы текущего процесса на выбранный в параметрах и удаляет память этого процесса (по сути дает новый указатель на таблицу страниц)
Обычно вызов exec делают сразу же после fork
Всего в этом семействе есть 7 системных вызовов:
int execl(const char *path, const char *arg, ... /*, (char *) NULL */)int execlp(const char *path, const char *arg, ... /*, (char *) NULL */)int execle(const char *file, const char *arg, ... /*, (char *) NULL, char *const envp[] */)int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[], char *const envp[]);int execve(const char *path, char *const _Nullable argv[], char *const _Nullable envp[])Буквы после exec обозначают тип принимаемых значений:
l - аргументы принимаются как список указателей, оканчивающийся нуль-терминаторомv - аргументы принимаются как указатель на массив указателей, оканчивающийся нуль-терминаторомe - новые переменные окружения для процесса указаны в аргументе envpp - если указанный путь до исполняемого файла не содержит /, то он ищется в директориях, указанных в переменной окружения PATHВсе эти вызовы, кроме execve, являются обертками над execve
execve("/bin/ls", newargv, newenviron);
/* Если ошибки не возникло, то исполнение
* не перейдет на строки ниже */
puts("Ошибка");
Источник: https://www.man7.org/linux/man-pages/man2/execve.2.html
clone() - более мощная версия fork(), которая дает больше контроля над тем, что разделяют родительский процесс и ребенок. Сигнатура у clone() такая:
int clone(typeof(int (void *_Nullable)) *fn,
void *stack,
int flags,
void *_Nullable arg, ...
/* pid_t *_Nullable parent_tid,
void *_Nullable tls,
pid_t *_Nullable child_tid */ );
Здесь передает указатель на функцию fn (процесс уничтожается, если функция возвращает значение), указатель на стек stack для дочернего процесса, флаги flags - результат побитового “ИЛИ” констант
Среди интересных есть флаги:
CLONE_PARENT - делает родителем нового процесса родителя текущего процесса, таким образом, делая их братьямиCLONE_SIGHAND - делает так, что ребенок и родитель имеют одну таблицу обработчиков сигналовCLONE_STOPPED - делает так, что ребенок находится в состоянии “Остановлен”CLONE_VM - делает так, что ребенок и родитель разделяют между собой адресное пространствоCLONE_THREAD - делает так, что ребенок помещен в ту же группу потоков, что и родительКак можно заметить, системный вызов clone() делает создание потоков намного проще
В результате clone() возвращает идентификатор потока в случае успеха
Помимо clone() есть также вызов __clone2() для архитектуры IA64 (на ней основана линейка процессоров Intel Itanium) и clone3(), принимающий структуру cl_args, благодаря которой возможно более гибкое создание процесса
Источник: https://www.man7.org/linux/man-pages/man2/clone.2.html
У процесса в Linux есть состояние в зависимости от того, исполняется ли он прямо сейчас, ждет потока ввода/вывода или находится вне оперативной памяти. Состояние помогает при управлении планировании исполнения процессов:

Подробнее о состояниях процессов описано в курсе “Операционные системы”
После того, как процесс окончил исполнения (то есть вызвал системный вызов _exit(status_code)), процесс переходит в состояние “Зомби”. В нем он будет находится до тех пор, пока родительский процесс не прочитает код выхода процесса. Родитель может сделать это несколькими способами:
Синхронно с помощью системных вызовов wait, waitid, waitpid
Эти системные вызовы приостанавливают исполнение до тех пор, пока дочерний процесс не окончит исполнение. wait ждет смерти любого дочернего процесса, в вызове waitpid можно выбрать идентификатор дочернего процесса, а waitid позволяет обрабатывать смену некоторых состояний дочернего процесса
Источник: https://www.man7.org/linux/man-pages/man2/wait.2.html
Асинхронно с помощью обработчика сигнала SIGCHLD:
signal(SIGCHLD, handler);
void handler(int sig) {
int status;
waitpid(-1, &status, WNOHANG);
}
Отдельное место в Linux занимают демоны. Демон (Daemon) - это фоновый процесс, который работает непрерывно и независимо от пользовательской сессии. Он ожидает событий или запросов и обрабатывает их без участия пользователя
Название “демон” происходит из греческой мифологии — демон был фоновым духом, действующим от имени других
Стандартные потоки ввода, вывода и ошибок у демонов перенаправлены в /dev/null. Вместо них демоны используют системный журнал или собственный файл с логами. Также демоны записывают свои идентификаторы процессов, чтобы другие процессы знали, как к ним обратиться
Первый демон, появляющийся при запуске Linux, - это поток [kthreadd] с идентификатором 2. Он является корнем поддерева фоновых потоков ядра, таких как [kswapd0] - демон для страничного обмена, [migration/0] - демон для переноса процессов между ядрами и так далее
Для создания демонов можно:
В терминале остановленный процесс (например, с помощью Ctrl+Z) можно обратно вывести в “Готовность” с помощью команды fg (от foreground), а можно вывести в “Готовность” в качестве демона с помощью команды bg
Альтернативно терминал позволяет запустить процесс в фоновом режиме, если после команды написать &:
python3 script.py &
В таком случае у демона будет стандартный поток вывода, который перенаправлен в терминал
Также после закрытия терминала дочерние фоновые процессы также завершаются. Чтобы этого избежать, можно применить команду disown:
python3 script.py &
disown %1
Или команду nohup (от no hang up):
nohup python3 script.py &
На языке C можно:
fork()_exit()setsid()SIGHUP на пустойfork() и завершить текущийumask(), сменить директорию на корень chdir("/"), закрыть наследованные файловые дескрипторы и перенаправить стандартные потоки в /dev/nullБолее современный способ состоит из создания службы - демона, управляемого другим процессом
В большинстве дистрибутивах (Ubuntu, Debian, Fedora, Arch Linux, CentOS, Red Hat Enterprise Linux) роль менеджера служб играет система systemd
Чтобы создать демон, управляемый systemd, нужно создать файл объявления:
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target # запустить после запуска демона networkd
[Service]
Type=simple
User=myappuser # запустить от имени myappuser
ExecStart=/usr/bin/myapp # исполняемый файл
Restart=on-failure # перезапустить при падении
StandardOutput=journal # записывать логи в журнал systemd
Далее он управляется с помощью команд:
systemctl start myapp # запустить сейчас
systemctl stop myapp # остановить
systemctl enable myapp # запускать при старте системы
systemctl status myapp # статус службы
systemctl restart myapp # перезапустить
Критика вокруг systemd заключается в том, что кодовая база systemd чересчур большая, система нарушает философию Unix “одна программа делает одно дело”, так как systemd пишет логи, занимается монтированием и так далее. Поэтому используют альтернативы:
SysV init, использующийся в Unix и дистрибутиве Slackware, является простой системой, но демоны запускаются последовательноrunit - минималистичная система, где сервис создается символической ссылкой /etc/sv/myapp/run на исполняемый файл, используется в Void Linux и Docker-контейнерахOpenRC - улучшенный SysV init, используется в Gentoo Linux и Alpine Linux