diff --git a/.gitignore b/.gitignore
index 8f05654..20741e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,5 +5,5 @@ build/
node_modules/
**/*.iml
-
+bundle/ui-bundle.zip
diff --git a/README.adoc b/README.adoc
index 13661ad..7922064 100644
--- a/README.adoc
+++ b/README.adoc
@@ -1,11 +1,11 @@
-= ProgTech Book
-:url-project: https://github.com/progtech-course/book/actions/workflows
+= DevTools Book
+:url-project: https://github.com/devtools-course/book/actions/workflows
:workflow: site.yml
:img-ci-status: {url-project}/{workflow}/badge.svg
image:{img-ci-status}[CI Status]
-Материалы курса "Технологии Программирования".
+Материалы курса "Инструменты разработчика".
Проект распространяется под лицензией link:LICENSE[MPL-2.0].
diff --git a/antora-playbook.yml b/antora-playbook.yml
index a5f034b..957b173 100644
--- a/antora-playbook.yml
+++ b/antora-playbook.yml
@@ -1,19 +1,30 @@
site:
- title: ProgTech Book
- start_page: ptbook::index.adoc
+ title: DevTools Book
+ start_page: book::index.adoc
+
content:
sources:
- url: .
branches: [ '*' ]
ui:
bundle:
- url: https://github.com/progtech-course/antora-ui/releases/download/latest/ui-bundle.zip
+ url: https://github.com/devtools-course/antora-ui/releases/download/latest/ui-bundle.zip
+# url: /home/nbah/antora-ui-default/build/ui-bundle.zip
snapshot: true
supplemental_files: ./supplemental-ui
+
+asciidoc:
+ attributes:
+ experimental: ''
+ page-pagination: ''
+ allow-uri-read: ''
+ extensions:
+ - ./lib/remote-include-processor.js
+
antora:
extensions:
- require: '@antora/lunr-extension'
languages: [en, ru]
#runtime:
-# fetch: true
\ No newline at end of file
+# fetch: true
diff --git a/antora.yml b/antora.yml
index 7727657..3f554f2 100644
--- a/antora.yml
+++ b/antora.yml
@@ -1,5 +1,5 @@
-name: ptbook
-version: latest
-title: ProgTech Book
+name: book
+version: dev
+title: DevTools Book
nav:
- modules/ROOT/nav.adoc
diff --git a/bundle/.gitkeep b/bundle/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/lib/remote-include-processor.js b/lib/remote-include-processor.js
new file mode 100644
index 0000000..1b4364d
--- /dev/null
+++ b/lib/remote-include-processor.js
@@ -0,0 +1,68 @@
+'use strict'
+
+const { execFileSync } = require('node:child_process')
+const fs = require('node:fs')
+const { createHash } = require('node:crypto')
+
+/**
+ * An Asciidoctor include processor that handles remote (URL) includes. This version gets registered each time a
+ * document is loaded and is thus scoped to the document, which allows it to cache the contents of the URL for
+ * subsequent references. This extension relies on an internal API to look up and delegate to the default include
+ * processor once the URL is cached. It caches the URL in the ROOT component, so that component must be filtered
+ * out from the navigation in the UI template.
+ */
+function createExtensionGroup ({ contentCatalog }) {
+ return function () {
+ this.includeProcessor(function () {
+ this.prepend() // register in front of Antora's include processor
+ this.handles((target) => target.startsWith('https://') || target.startsWith('http://'))
+ this.process((doc, reader, target, attrs) => {
+ const cachedTarget = readUrl(contentCatalog, target)
+ if (cachedTarget === false) {
+ const cursor = reader.$cursor_at_prev_line()
+ const logMessage = doc.createLogMessage(`include uri not readable: ${target}`, { source_location: cursor })
+ doc.getLogger().error(logMessage)
+ reader.pushInclude(`Unresolved directive in ${reader.path} - include::${target}[]`, target, target, 1, attrs)
+ return
+ }
+ const nextIncludeProcessor = findNextIncludeProcessor(doc, this, cachedTarget)
+ nextIncludeProcessor && nextIncludeProcessor.process_method['$[]'](doc, reader, cachedTarget, Opal.hash(attrs))
+ })
+ })
+ }
+}
+
+function readUrl (contentCatalog, url) {
+ contentCatalog.getComponentVersion('ROOT', '') || contentCatalog.registerComponentVersion('ROOT', '')
+ const src = { component: 'ROOT', version: '', module: 'cache', family: 'partial', relative: sha1(url) + '.adoc' }
+ let file = contentCatalog.getById(src)
+ if (!file) {
+ try {
+ file = contentCatalog.addFile({ contents: execFileSync('curl', ['--silent', '-L', url]), src })
+ } catch {
+ file = contentCatalog.addFile({ contents: null, src })
+ }
+ }
+ return file.contents == null ? false : 'ROOT:cache:partial$' + src.relative
+}
+
+function sha1 (string) {
+ const shasum = createHash('sha1')
+ shasum.update(string)
+ return shasum.digest('hex')
+}
+
+function findNextIncludeProcessor (doc, currentIncludeProcessor, target) {
+ let skip = true
+ return doc.getExtensions().$include_processors().find((candidate) => {
+ candidate = candidate.instance
+ if (skip) return candidate === currentIncludeProcessor ? (skip = false) : false
+ return candidate.handles(target)
+ })
+}
+
+module.exports.register = (registry, context) => {
+ const toProc = (fn) => Object.defineProperty(fn, '$$arity', { value: fn.length })
+ registry.$groups().$store('remote-include-processor', toProc(createExtensionGroup(context)))
+ return registry
+}
diff --git a/modules/ROOT/images/linux/terminal-window.png b/modules/ROOT/images/linux/terminal-window.png
new file mode 100644
index 0000000..54755a7
Binary files /dev/null and b/modules/ROOT/images/linux/terminal-window.png differ
diff --git a/modules/ROOT/images/logos/kitty.svg b/modules/ROOT/images/logos/kitty.svg
new file mode 100644
index 0000000..6ca0eac
--- /dev/null
+++ b/modules/ROOT/images/logos/kitty.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/ROOT/images/logos/xterm.png b/modules/ROOT/images/logos/xterm.png
new file mode 100644
index 0000000..1ad01e8
Binary files /dev/null and b/modules/ROOT/images/logos/xterm.png differ
diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc
index 5b46499..980c53d 100644
--- a/modules/ROOT/nav.adoc
+++ b/modules/ROOT/nav.adoc
@@ -1,4 +1,13 @@
-.Intro
+.О проекте
* xref:authors.adoc[Авторы]
* xref:code-of-conduct.adoc[Code of conduct]
+* xref:dev-guides.adoc[Гайды по разработке]
+.Linux FS
+* xref:linux/file-types.adoc[Типы файлов]
+* xref:linux/fhs.adoc[FHS]
+* xref:linux/devices.adoc[]
+* xref:linux/ttys.adoc[]
+
+.Packages & Archives
+* xref:utils/rpm.adoc[]
diff --git a/modules/ROOT/pages/authors.adoc b/modules/ROOT/pages/authors.adoc
index b7a77e8..353905e 100644
--- a/modules/ROOT/pages/authors.adoc
+++ b/modules/ROOT/pages/authors.adoc
@@ -1,5 +1,5 @@
= Авторы
-:page-pagination:
+:description: Авторы проекта
Здесь можно найти информацию про людей, участвовавших в создании этого ресурса.
diff --git a/modules/ROOT/pages/code-of-conduct.adoc b/modules/ROOT/pages/code-of-conduct.adoc
index ed9f0c8..0b64800 100644
--- a/modules/ROOT/pages/code-of-conduct.adoc
+++ b/modules/ROOT/pages/code-of-conduct.adoc
@@ -1,5 +1,4 @@
= Code of conduct
-:page-pagination:
Все материалы на этом сайте являются открытыми и доступны всем. При их использовании ознакомьтесь с лицензией https://www.mozilla.org/en-US/MPL/2.0/[MPL-2.0], под которой распространяется проект.
diff --git a/modules/ROOT/pages/dev-guides.adoc b/modules/ROOT/pages/dev-guides.adoc
new file mode 100644
index 0000000..1e38792
--- /dev/null
+++ b/modules/ROOT/pages/dev-guides.adoc
@@ -0,0 +1,90 @@
+= Как разрабатывать сайт
+:page-authors: Иван Калинин
+
+== Инструменты
+
+Для разработки вам потребуется:
+
+* `npm` -- можно установить через пакетный менеджер, например `apt install node` (обычно поставляется в пакете `node`)
+* IDE с плагином для asciidoctor
+** Для JetBrains IDE советую установить плагин https://plugins.jetbrains.com/plugin/7391-asciidoc
+
+Склонируйте проект и из его корня исполните:
+[,shell]
+----
+npm install
+----
+
+== Просмотр сайта
+
+Чтобы запустить сборку сайта исполните:
+[,shell]
+----
+npx antora --stacktrace antora-playbook.yml
+----
+Полученный сайт будет лежать в папке `build`. Однако, у него могут не отображаться иконки на блоках и на каждое изменение необходимо вручную пересобирать.
+
+
+Для динамического превью нужно использовать докер:
+[.wrap,shell]
+----
+docker run --rm -p 35729:35729 -p 2020:2020 -v "${PWD}":/preview/antora -v "${PWD}/bundle:/preview/bundles" ghcr.io/vshn/antora-preview --antora='.' --style=ui-bundle
+----
+
+NOTE: Для подгрузки стилей скачайте `ui-bundle.zip` из https://github.com/progtech-course/antora-ui/releases/tag/latest[проекта] и поместите в папку `bundle` в корне проекта.
+
+Сайт будет доступен на http://localhost:2020. Однако, уже тут не будет работать фавиконка и настройки UI.
+
+Подробнее об образе можно прочитать в https://github.com/vshn/antora-preview[репозитории проекта].
+
+== Настройка плейбука
+
+При локальной разработке советую использовать следующую модификацию `antora-playbook.yml`:
+[.wrap,yaml]
+----
+site:
+ title: ProgTech Book
+ start_page: ptbook::index.adoc
+content:
+ sources:
+ - url: .
+ branches: [ '*' ]
+ui:
+ bundle:
+ url: https://github.com/progtech-course/antora-ui/releases/download/latest/ui-bundle.zip
+ snapshot: true
+ supplemental_files: ./supplemental-ui
+antora:
+ extensions:
+ - require: '@antora/lunr-extension'
+ languages: [en, ru]
+
+# runtime:
+# fetch: true
+----
+
+Изменения:
+
+. `url: .` -- используется локальный репо, а не исходники в гитхабе
+. `runtime: fetch: true` -- если обновился исходник с UI, то эта настройка перескачает его, иначе будет использоваться закэшированный
+
+WARNING: Не нужно это коммитить в репозиторий!
+
+== Возможности asciidoctor
+
+Посмотреть, как можно оформить материалы, можно на https://progtech-course.github.io/antora-ui[превью UI]. Исходники аскидоктора лежат https://github.com/progtech-course/antora-ui/blob/main/preview-src/index.adoc[здесь].
+
+Также поддерживается кастомная стилизация TODO:
+
+[.wrap,asciidoc]
+----
+// TODO
+[TIP.todo]
+====
+Нужна ссыль на mounting process
+====
+----
+
+CAUTION: При ее использовании просьба оставлять выше комментарий `// TODO` -- так IDE сможет трекать тудушки в проекте.
+
+При написании страницы добавляйте параметр `:description:` с кратким описанием, о чем написано на странице, а также указывайте себя в `:page-authors:`. При указании авторства пишите так же, как в заголовке xref:authors.adoc[authors.adoc] -- иначе не сработают автоматические ссылки.
diff --git a/modules/ROOT/pages/index.adoc b/modules/ROOT/pages/index.adoc
index c2fc019..9980fe9 100644
--- a/modules/ROOT/pages/index.adoc
+++ b/modules/ROOT/pages/index.adoc
@@ -1,8 +1,7 @@
-= ProgTech Book
-// :page-authors: Иван Калинин
-:page-pagination:
+= DevTools Book
+:description: Материалы курса "Инструменты разработчика"
-Здесь собраны материалы курса "Технологии программирования".
+Здесь собраны материалы курса "Инструменты разработчика".
image::crya.png[]
diff --git a/modules/ROOT/pages/linux/devices.adoc b/modules/ROOT/pages/linux/devices.adoc
new file mode 100644
index 0000000..2932c0a
--- /dev/null
+++ b/modules/ROOT/pages/linux/devices.adoc
@@ -0,0 +1,96 @@
+= Папка dev
+:page-authors: Иван Калинин
+:description: Устройство папки /dev
+
+В этой папке представлены различные девайсы, как блочного, так и символьного типа.
+
+== Создание файлов устройств
+Для создания такого рода файлов используется команда `mknod FILENAME TYPE MAJOR MINOR`. Параметр `TYPE` может принимать значения `b` или `c`, указывая тип девайса. Параметры `MAJOR` и `MINOR` кодируют какой конкретно девайс создается. Описания доступных комбинаций доступы в
+https://www.kernel.org/doc/Documentation/admin-guide/devices.txt[документации ядра Linux].
+
+== Character devices
+/dev/null::
+Null device. Любые данные записанные в него отбрасываются, а попытка прочитать его возвращает `EOF` символ.
+
+TIP: Используйте этот файл, чтобы проигнорировать stderr или stdout
+
+/dev/zero::
+Аналогично `/dev/null` отбрасывает данные при записи, однако при чтении возвращает бесконечный стрим символов `\0`.
+
+/dev/full::
+Аналогично `/dev/zero` при чтении возвращает бесконечный стрим символов `\0`, однако при записи кидает ошибку переполнения диска (`ENOSPC`).
+
+[.wrap,console]
+----
+$ echo 3 > /dev/full
+echo: write error: no space left on device
+----
+
+/dev/random и /dev/urandom::
+Оба файла используются для генерации псевдослучайных чисел. В качестве сида используется энтропия различных устройств системы. Как следствие, запись в эти устройства будет обновлять энтропию. Если ваша программа работает не в момент бутстрапа, то используйте `urandom`. Например, `std::random_device` https://en.cppreference.com/cpp/numeric/random/random_device/random_device#Notes[по умолчанию] использует именно `/dev/urandom`.
+
+// TODO
+[TIP.todo]
+====
+ссыль на рандомизацию и хэши?
+====
+
+WARNING: Устройства создают _бесконечный_ стрим случайных данных, поэтому всегда ограничивайте число считываемых данных. Например, через `head -c N`.
+
+/dev/mem::
+Это устройство представляет собой образ физической памяти (RAM). Адреса внутри этого устройства отражают реальные физические адреса в памяти.
+
+/dev/kmem::
+Аналогично прошлому устройству `kmem` представляется способ обращаться к памяти через файлы, однако `kmem` является представлением виртуальной памяти.
+
+/dev/port::
+Аналогично прошлым двум через это устройство можно обращаться напрямую к портам.
+
+IMPORTANT: Доступ к последним трем устройствам может быть (скорее всего так и есть, если вы не собирали ядро вручную) ограничен на уровне конфигураций ядра Linux.
+
+/dev/tty::
+Терминальные устройства. Про них написано в xref:linux/ttys.adoc[следующей статье].
+
+== Block devices
+
+/dev/sd[a-z]::
+Жесткие диски, использующие технологию SATA.
+
+/dev/nvme[0-N]::
+Жесткие диски, использующие технологию PCI.
+
+NOTE: Под каждую партицию жесткого диска создается отдельное устройство с суффиксом `pN`, где N -- номер партиции внутри диска.
+
+/dev/loop[0-N]::
+Виртуальные девайсы, используемые для монтирования файловых систем не на физические устройства. Например, такие устройства можно связать с регулярным файлом и использовать такой файл как модель жесткого диска.
+
+[,console]
+----
+$ dd if=/dev/zero of=file.img bs=1MiB count=10
+$ sudo losetup /dev/loop4 file.img
+$ sudo mkfs -t ext4 /dev/loop4
+$ sudo mkdir /myloopdev
+$ sudo mount /dev/loop4 /myloopdev
+----
+
+== Симлинки
+
+/dev/fd::
+Симлинка на `/proc/self/fd` -- папку с файловыми дескрипторами текущего процесса.
+
+/dev/stdin::
+Симлинка на `/proc/self/fd/0` -- стандартный поток ввода текущего процесса.
+
+/dev/stdout::
+Симлинка на `/proc/self/fd/1` -- стандартный поток вывода текущего процесса.
+
+/dev/stderr::
+Симлинка на `/proc/self/fd/2` -- стандартный поток ошибок текущего процесса.
+
+== Read more
+
+* https://media.ccc.de/v/32c3-7441-the_plain_simple_reality_of_entropy[Random & urandom devices (C) Filippo Valsorda at 32C3]
+* https://www.linuxjournal.com/article/2890[Block devices (C) Linux journal]
+* https://tldp.org/LDP/khg/HyperNews/get/devices/devices.html[Device drivers (C) KHG]
+* https://www.reddit.com/r/hardware/comments/b0zb64/ssd_pcie_vs_sata_real_difference_for_programming/[PCI VS SATA (C) Reddit]
+
diff --git a/modules/ROOT/pages/linux/fhs.adoc b/modules/ROOT/pages/linux/fhs.adoc
new file mode 100644
index 0000000..54942a4
--- /dev/null
+++ b/modules/ROOT/pages/linux/fhs.adoc
@@ -0,0 +1,150 @@
+= Filesystem Hierarchy Standard
+:page-authors: Иван Калинин
+:description: Filesystem Hierarchy Standard (Linux)
+
+*Filesystem Hierarchy Standard (FHS)* - это соглашение об устройстве файловой системы Linux, использующееся в большинстве популярных дистрибутивов Linux. Однако, есть дистрибутивы не следующие ему. Таким, например, является https://nixos.org/[NixOS]. Информацию про FHS можно прочитать в мануале:
+[,console]
+----
+$ man hier
+----
+
+== Три уровня бинарей
+
+// TODO
+[WARNING.todo]
+====
+Нужна ссыль на mounting process
+====
+Есть три папки, повторяющие структуру друг друга: `/`, `/usr`, `/usr/local`. Корневая папка используется для хранения файлов, необходимых для запуска или починики системы, в частности тут должны храниться файлы, доступные до момента монтирования файловых систем, отличных от корневой (`/`). Директории `/usr` и `/usr/local` уже содержат все остальные файлы, с которыми пользователь будет работать. Их отличие заключается в большинстве случаев в том, что `/usr` управляется пакетным менеджером системы (`dnf`, `apt`, etc.), а `/usr/local` предназначен для ручной установки.
+
+CAUTION: То, что `/usr` управляется системой, не означает, что вы не можете вручную менять файлы в этой папке. Однако, следует быть аккуратным, чтобы не наделать конфликтов.
+
+Каждая из директорий содержит следующие подпапки:
+
+* `bin` -- бинарники: команды для работы в консоли (e.g. _ls_)
+* `sbin` -- системные бинари (e.g. _reboot_)
+* `lib` -- библиотеки (e.g. _libc_)
+** `lib32` -- 32-битный код
+** `lib64` -- 64-битный код
+* `include` -- хедеры (e.g. _math.h_)
+* `share` -- файлы, не зависящие от архитектуры. В эту папку перенесли различные поддиректории, ранее лежавшие рядом с `bin`
+
+NOTE: Во многих новых дистрибутивах Linux папки `/bin`, `/lib`, `/sbin` не являются настоящими папками. На самом деле они -- симлинки на соответствующие папки в `/usr`. А `/usr/sbin` может быть симлинкой на `/usr/bin`.
+
+=== Папка `share`
+doc::
+Внутри подпапки `doc` располагается различная документация проекта: это могут быть лицензии, README файлы. Для каждого инструмента такие данные собраны в директорию, которая имеет название инструмента. Например, для `zsh` собрана такая информация:
+
+[,console]
+----
+$ ls /usr/share/doc/zsh
+BUGS completion-style-guide CONTRIBUTORS FAQ FEATURES
+LICENCE MACHINES NEWS README zsh-development-guide
+----
+
+man::
+В этой подпапке собраны man страницы. Для каждого языка лежит своя подпапка, например, для итальянского -- `it`.
+
+[TIP.todo]
+====
+Ссылка на маны
+====
+
+== Основные директории системы
+
+_Все директории ниже лежат в корневой папке._
+
+boot::
+Статические бинарники для загрузчика системы. Сам загрузчик должен лежать либо в корне, либо в этой папке.
+
+dev::
+Расшифровывается как _devices_. Здесь собраны файлы устройств. Подробнее о папке `dev` написано xref:linux/devices.adoc[тут].
+
+etc::
+Расшифровывается как _et cetera_. Здесь располагаются конфигурационные файлы, например, `/etc/passwd`
+
+// TODO
+[TIP.todo]
+====
+ссыли на прокфс & сисфс
+====
+
+proc::
+Точка монтирования _procfs_.
+
+sys::
+Точка монтирования _sysfs_.
+
+lost+found::
+"Потерянные" файлы.
+
+// TODO
+[TIP.todo]
+====
+больше про лост+фаунд
+====
+
+mnt::
+Расшифровывается как _mount_. Точка монтирования временных файловых систем, например, live образ ОС при установке.
+
+home::
+В этой папке располагаются домашние директории пользователей. Обычно для каждого пользователя своя директория с соответствующим именем, однако можно выбрать любое название.
+
+root::
+Домашняя папка для рута.
+
+tmp::
+Расшифровывается как _temporary_. Хранилище временных файлов, которые можно удалить в любой момент времени.
+
+opt::
+Расшифровывается как _optional_. Различные приложения и расширения для системы.
+
+run::
+Расшифровывается как _runtime_. Описывает систему с момента запуска. Раньше для этого использовали `/var/run`, поэтому теперь этот файл является симлинкой на `/run`.
+
+var::
+Расшифровывается как _variable_. Данные, изменяющиеся в процессе работы системы.
+
+=== Папка `run`
+
+cache::
+Кэши программ. Для каждой программы выделяется своя подпапка.
+
+lib::
+Переменные данные различных программ. Аналогично, для каждой программы своя подпапка.
+
+[,console]
+----
+$ sudo ls /var/lib/docker
+buildkit containers engine-id image network
+plugins policy rootfs runtimes swarm tmp volumes
+----
+
+local::
+Папка `var` для `/usr/local`.
+
+opt::
+Папка `/var` для `/opt`.
+
+lock::
+Тут хранятся lock-файлы.
+
+// TODO
+[TIP.todo]
+----
+Надо написать про лок файлы
+----
+
+log::
+Логи различных программ
+
+mail::
+Почты пользователей.
+
+== Команды
+
+Данный стандарт не только фиксирует названия и назначения директорий, но еще и требует наличие определенных файлов, которые должны выполнять определенные цели. Так в `/bin` требуется наличие файлов `kill`, `mkdir`, `more`, `su` и других.
+
+== Read more
+
+* https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html[FHS 3.0 (C) Linux Foundation]
diff --git a/modules/ROOT/pages/linux/file-types.adoc b/modules/ROOT/pages/linux/file-types.adoc
new file mode 100644
index 0000000..0ea98f8
--- /dev/null
+++ b/modules/ROOT/pages/linux/file-types.adoc
@@ -0,0 +1,106 @@
+= Типы файлов
+:page-authors: Иван Калинин
+:description: Типы файлов в Linux
+
+В Linux есть 7 типов файлов: регулярные, директории, ссылки, сокеты и пайпы, блочные и символьные устройства.
+
+WARNING: Рекомендуем выполнять примеры кода внутри папки `/tmp` (убедитесь, что она смонтирована на `tmpfs`)
+
+== Regular
+
+*Регулярные файлы* или просто файлы -- это просто набор байт, который хранит какую-то информацию. Чтобы создать файл с некоторым содержимым, можно использовать конструкцию `echo CONTENT > FILENAME` или можно создать пустой файл с помощью команды `touch FILENAME`. Такие файлы в `ls -l` будут отображаться как `-`.
+
+CAUTION: Команда `touch` прежде всего нужна для обновления информации о времени доступа и изменения файла.
+
+== Directory
+*Директории* или папки -- это узлы в файловой системе, которые содержат список других _вложенных_ файлов. Такие файлы в `ls -l` будут отображаться как `d`, также они часто окрашены в синий цвет.
+
+Создать директорию можно с помощью команды `mkdir DIRNAME`. Если вам необходимо вместе с папкой создать еще ее родителей, то используйте флаг `-p`.
+
+[,console]
+----
+$ mkdir folder/subfolder
+mkdir: cannot create directory ‘folder/subfolder’: No such file or directory
+$ mkdir -p folder/subfolder
+$ ls folder
+subfolder
+----
+
+== Links
+
+*Ссылочные* файлы или символические ссылки (симлинки) -- это файлы, хранящие в себе путь до другого файла. При использовании такого файла ОС будет сама подставлять заместо него файл, на который указывает записанный путь. Такие файлы в `ls -l` будут отображаться как `l`, также они часто окрашены в циановый цвет.
+
+Создать симлинку можно с помощью команды `ln -s PATH LINKNAME`. Прочесть содержимое самой симлинки можно с помощью `readlink`.
+
+
+[,console]
+----
+$ ls subfolder
+file.txt
+$ ln -s subfolder/file.txt symlink
+$ ls -l
+drwxr-xr-x. nbah nbah 60 B Thu Jun 18 21:44:45 2026 subfolder
+lrwxrwxrwx. nbah nbah 18 B Thu Jun 18 21:45:44 2026 symlink => subfolder/file.txt
+$ readlink symlink
+subfolder/file.txt
+$ bat symlink
+─────┬───────────────────────────────
+ │ File: symlink
+─────┼───────────────────────────────
+ 1 │ 4
+─────┴───────────────────────────────
+----
+
+== Named pipes
+
+*Именованные пайпы* -- это специальный вид файлов, позволяющий двум процессам отправлять сообщения. Пайп работает как односторонний канал отправки информации: существует только один слушатель, но при этом отправителей может быть несколько. Такие файлы в `ls -l` будут отображаться как `p`, также они часто окрашены в бледно-желтый цвет.
+
+Для создания таких файлов используется команда `mkfifo PIPENAME`.
+
+[,console]
+----
+$ mkfifo npipe
+$ ls -l
+prw-r--r--. nbah nbah 0 B Thu Jun 25 12:40:30 2026 npipe
+----
+
+Операции записи и чтения являются блокирующими. Это означает, что если на одном конце никого нет, то процесс на другом конце будет ждать пока кто-то не придет. Попробуем сделать запись в пайп: `echo Hello > npipe`. Заметим, что терминал "завис", тогда откроем второй терминал и попробуем прочитать файл: `cat npipe`. В этот же момент первый терминал проснулся, а во втором вывелось `Hello`. Аналогично произойдет, если сделать наоборот.
+
+При одновременной записи в пайп больших размеров данных никаких гарантий на порядок данные не предоставляется. Откроем один терминал и в нем создадим три файла с 100тыс строк:
+[.wrap,console]
+----
+$ for sym in a b c d e; do yes ${sym} | head -n 100000 > ${sym}.in; done
+----
+После попробуем записать их в пайп:
+[.wrap,console]
+----
+$ for sym in a b c d e; do cat ${sym}.in > npipe & ; done
+----
+Теперь в другом терминале запустим команду: `cat npipe | uniq -d`. Она прочтет из пайпа и "схлопнет" последовательные дубликаты в один символ.
+
+.Возможные результаты
+[%collapsible]
+====
+В первый раз получим: +
+`a c b c d e b c d e b c d e b d e`
+
+Во второй раз получим: +
+`d e d e b a c d e b a c d b a c b a c`
+====
+
+== Sockets
+// TODO
+[TIP.todo]
+====
+Пупупу
+====
+
+== Devices
+
+Файлы *устройств* представляют собой интерфейсы взаимодействия с устройствами, как если бы они были файлами. Они подразделяются на два вида: *блочные* (block) и *символьные* (character). Первые предоставляют буферизированный случайный доступ (buffered random access), когда как вторые предоставляют прямой доступ и не обязаны RA-устройствами. Также файловые системы могут быть смонтированы только на блочные устройства. Такие файлы в `ls -l` будут отображаться как `b` и `c`, a окрашены будут в бледно-желтый цвет.
+
+Подробно о девайсах описано xref:linux/devices.adoc[тут].
+
+
+// == Read more
+
diff --git a/modules/ROOT/pages/linux/ttys.adoc b/modules/ROOT/pages/linux/ttys.adoc
new file mode 100644
index 0000000..bc40390
--- /dev/null
+++ b/modules/ROOT/pages/linux/ttys.adoc
@@ -0,0 +1,38 @@
+= Терминальные устройства
+:page-authors: Иван Калинин
+:description: Терминалы. PTS и TTY устройства.
+
+== TTY
+
+Аббревиатура *tty* расшифровывается как _teletype_ -- физическое устройство, некогда использовавшееся для отправки и получения сообщений. В Linux tty-устройства отражают _виртуальные терминалы_, через которые пользователь взаимодействует с системой. Терминал в данном случае следует воспринимать не как окно, в которое вводят команды, а как некоторое устройство, через которое идет взаимодействие с пользователем.
+
+.Это не терминал в смысле tty-устройств
+image::linux/terminal-window.png[]
+
+Под терминалы создаются файлы `/dev/ttyN`. Чтобы сменить виртуальный терминал, используется команда `chvt TERMINAL_ID` или комбинация клавиш kbd:[Ctrl,Alt,F#] (`#` здесь отражает индекс терминала). Файл `/dev/tty` указывает на текущий контролирующий терминал.
+
+Графическая оболочка открывается поверх некоторого виртуального терминала и транслирует действия с графическим интерфейсом в команды для виртуального терминала. Обычно для этого используются устройства `/dev/tty2` или `/dev/tty7`.
+
+Чтобы узнать, с каким терминалом вы сейчас взаимодействуете, можно выполнить команду `tty`.
+
+== Console
+
+Файл `/dev/console` же отражает за системную консоль, которая используется при стартапе системы. Данный терминал управляется напрямую ядром и назначается init-процессу при загрузке системы.
+
+== PTS
+
+Графическое окно, которое открывается в операционной системе, на самом деле является запущенным *эмулятором*. Примерами такого могут быть `xterm`, `xterm-kitty`.
+
+[cols="2*", frame="none", grid="none"]
+|===
+|image:logos/kitty.svg[kitty,100,role=text-left]
+|image:logos/xterm.png[kitty,100,role=text-center]
+|===
+
+При запуске эмулятора создается пара из master и slave терминалов с помощью устройства `/dev/ptmx` -- pseudoterminal multiplexor device. Для второго создается устройство в папке `/dev/pts`, через которое происходит взаимодействие при работе в окне эмулятора.
+
+NOTE: Под `/dev/pts` монтируется отдельная файловая система: _devpts_.
+
+== Read more
+
+* https://www.kernel.org/doc/html/latest/admin-guide/devices.html#terminal-devices[Terminal devices (C) Linux kernel docs]
diff --git a/modules/ROOT/pages/utils/rpm.adoc b/modules/ROOT/pages/utils/rpm.adoc
new file mode 100644
index 0000000..cfca454
--- /dev/null
+++ b/modules/ROOT/pages/utils/rpm.adoc
@@ -0,0 +1,67 @@
+= RPM пакеты
+
+Дистрибутивы Red Hat семейства используют пакетный менеджер `rpm`. На базе него есть пакетные менеджеры `yum` и `dnf`.
+
+== Rpmbuild
+
+Для разработки `rpm` пакетов используется директория `~/rpmbuild`. Ее можно автоматически настроить с помощью команды `rpmdev-setuptree` из `rpmdevtools` или вручную:
+
+[,text]
+----
+🖿 /home/USER/rpmbuild
+├─ 🖿 BUILD
+├─ 🖿 RPMS
+├─ 🖿 SOURCES
+├─ 🖿 SPECS
+└─ 🖿 SPRMS
+----
+
+* `BUILD` -- директория в которой происходит сборка пакетов
+* `RPMS` -- директория для хранения `rpm`-пакетов
+* `SOURCES` -- директория для хранения архивов с исходниками для использования при сборке пакетов
+* `SPECS` -- директория для хранения `spec`-файлов
+* `SRPMS` -- директория для хранения `srpm`-пакетов
+
+== Spec файлы
+
+Для создания своего `rpm`-пакета необходимо создать архив с исходниками и файл описания сборки пакета. Последний должен иметь имя `.spec`. Его можно создать как вручную в папке `SPECS`, так и выполнив команду `rpmdev-newspec `. Рассмотрим основные компоненты спецификации:
+
+Преамбула::
+[%autowidth]
+|===
+| `Name` | Название пакета
+| `Version` | Версия исходного кода
+| `Release` | Номер релиза, newspec по дефолту выставит `1%{?dist}`
+| `Summary` | Краткое описание проекта
+| `License` | Лицензия под которой распространяется проект
+| `URL` | URL сайта проекта
+| `Source` | URL исходного кода
+| `BuildRequires` | Зависимости, необходимые для сборки пакета
+| `Requires` | Рантайм зависимости
+| `BuildArch` | Под какую архитектуру собран проект
+|===
+
+Тело::
+[%autowidth]
+|===
+| `%description` | Подробное описание проекта
+| `%prep` | Скрипт подготовки исходников к сборке
+| `%build` | Скрипт сборки проекта
+| `%install` | Скрипт установки проекта в `%{buildroot}`
+| `%files` | Индекс файлов, которые будут установлены
+| `%changelog` | Описания изменений проекта
+|===
+
+// TODO
+[TIP.todo]
+====
+Дописать
+====
+
+
+
+== Read more
+
+* https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/packaging_and_distributing_software/packaging-software_packaging-and-distributing-software[RPM documentation (C) Red Hat]
+* https://docs.fedoraproject.org/en-US/packaging-guidelines/RPMMacros/[Predefined macros (C) Fedora docs]
+* http://ftp.rpm.org/max-rpm/[Maximum RPM (C) Edward C. Bailey]
diff --git a/supplemental-ui/partials/author-header.hbs b/supplemental-ui/partials/author-header.hbs
index 6c94a63..070e25f 100644
--- a/supplemental-ui/partials/author-header.hbs
+++ b/supplemental-ui/partials/author-header.hbs
@@ -1 +1 @@
-