Bug 18689

Summary: Оконный менеджер для ReadySet
Product: Ximper Linux Reporter: Жора Змейкин <katze>
Component: ОбщееAssignee: Жора Змейкин <katze>
Status: ASSIGNED --- QA Contact: Кирилл Уницаев <fiersik>
Severity: normal    
Priority: P4 CC: vanomj, ximper
Version: не указана   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Whiteboard:
Заявки RT: Связано с:
Дата напоминания:
Bug Depends on:    
Bug Blocks: 18299    

Description Жора Змейкин 2025-11-13 02:29:56 MSK
Приложение ReadySet (OEM с первоначальной настройкой системы) необходимо где-то запускать. На данный момент это делает Cage, оконный менеджер (WM) рассчитанный для киосков. Однако он имеет массу проблем:
- Программная отрисовка приводит к спаму в логах, очень медленной производительности и полному зависанию
- По каким-то причинам на некотором поддерживаемом оборудовании он также не может задействовать DRM, что приводит к проблемам выше
- Приложение некорректно отображается на нескольких мониторах
- Невозможно сменить раскладку

Нам необходимо подобрать оконный менеджер Wayland, который:
- Развивается, получает исправления
- Нормально дружит с NVIDIA и другими картами
- Не боится программной отрисовки
- Может запускаться от root (опционально)
- Не привязан к рабочему окружению и лёгкий

Что рассмотрели:
- Cage был рассмотрен ранее
- X11 даже не рассматриваем, мы отказываемся от него и имеет много зависимостей
- Mutter привязан к GNOME и потащит много зависимостей
- Hyprland имеет проблемы с программной отрисовкой и NVIDIA
- Sway, вероятно, не дружит с NVIDIA. Разработчик выступает против неё

Сейчас рассматриваю KWin. Пакет kwin из репозитория Sisyphus имеет очень много зависимостей и у меня есть предположения, что многие из них ему не нужны вовсе. Это мне предстоит выяснить. Если удастся минимизировать количество зависимостей, то kwin станет отличным выбором, поскольку:
- Его стабильно развивает KDE, одно из самых больших сообществ
- В целом довольно прост в запуске, не требует никаких конфигов (только для раскладок)
- Производительный, работает много где, в том числе и с программной отрисовкой


Часть оконных менеджеров (в том числе kwin) открывают окно не на весь экран, поэтому необходимо зарепортить в ReadySet поддержку опции для полноэкранного запуска.
Comment 1 Жора Змейкин 2025-11-14 02:49:13 MSK
Оконные менеджеры и сам GTK очень любят создавать разные конфиг-файлы, поэтому запускать оконный менеджер будем от другого пользователя. ReadySet уже взаимодействует с Polkit и в будущем будем придерживаться того же.

Для удобного создания пользователя существует и features.in/deflogin в mkimage-profiles.

Столкнулся также с багом в KWin, который я зарепорчу позже. По умолчанию KWin рендерит курсор только из темы Breeze. И если тема отсутствует, то и курсор не рендерится. В качестве обходного пути можно либо подать конфиг-файл с другой темой курсора. либо кидать breeze курсоры в /usr/share/icons.


Всё остальное уже по рутине дня:
Передавал репозиторий хешера по ftp из билдера в виртуальную машину для тестирования KWin, научился устанавливать rpm пакеты с игнорированием зависимостей (--nodeps, ради тестов исключительно). Узнал, что при помощи `epm policy kwin` можно увидеть все источники. Узнал о существовании epmqf для определения к какому пакету принадлежит директория.

Много экспериментировал со spec-файлами и пересборкой, но пока не могу придти к чему-то. Зависимости всё равно остаются. даже не уменьшаются. AutoReq: no также не помогает. Я что-то упускаю, так что если завтра буду на одной и той же точке. то попробую изучить hasher, spec файлы и саму команду для сборки.
Comment 2 Жора Змейкин 2025-11-14 23:13:28 MSK
KWin имеет очень большое количество зависимостей и является практически самым тяжёлым оконным менеджером. В другом баге я ещё буду анализировать зависимости, которые возможно от него отвязать, но это всё равно маленькое число.

Будем смотреть в сторону Mutter (оказалось, у него не так много зависимостей) или Weston. Пока начал тестировать первое, заметил, что просто установить mutter недостаточно и для запуска требует какие-то ещё дополнительные зависимости. Буду разбираться.

apt-get сообщает, что в распакованном виде (со всеми зависимостями, поэтому пока это оценочные данные):
- Mutter - 834 мб
- KWin - 1000 мб
- Weston - 530 мб


Из другой рутины дня:
- Изучил как работать со spec-файлами, менять релиз и что нужно делать коммиты (gammit -a)
- Взял конфигурацию для ~/.config/eterbuild, чтобы отключить тот же sisyphus_check
- Тестировал работу KWin с разными зависимостями
- Зарепортил баг в ReadySet связанный с полноэкранным запуском:
- https://altlinux.space/alt-gnome/ReadySet/issues/37
Comment 3 Жора Змейкин 2025-11-15 23:58:03 MSK
Удалось установить Mutter, запустить его. Для этого потребовался mutter, mutter-gnome (без него выдаёт какую-то ошибку с GNOME схемами) и xkeyboard-config. Спасибо Кириллу за помощь с последней зависимостью, без него я бы долго искал в чём дело. Эта зависимость также нужна KWin для нормальной работы, начинаю задумываться, что её необходимо сделать обязательной для данных пакетов. Оконный менеджер запускается, работает, но есть очень сильные проблемы с тормозами. Буду разбираться. вероятно, не хватает библиотеки libwayland-egl (KWin без неё не запускается).

Удалось собрать новую версию KWin с минимальными зависимостями. С 1000 мб потребление уменьшилось до 550 мб, что практически на уровне с Weston! Для этого изучил CMakeLists.txt и отключил все дополнительные функции, что не нужны для работы с ReadySet. Нечто подобное нужно будет просмотреть и для Mutter.

Но стоит понимать, что это всё пока оценочные данные! Это значит, что необходимо более тщательно проверить работу оконных менеджеров, лёгкость удаления остаточных зависимостей, а также учесть общие зависимости ReadySet и оконных менеджеров. Чем я в итоге и займусь.


Из рутины дня:
- Узнал, как запускать приложения на разных оконных менеджерах
- Записал ещё несколько багов с KDE, попытаюсь воспроизвести и зарепортить
- Записал в заметки также зарепортить про xkeyboard-config
- Узнал, что иногда файлы хешера не удаляются, но удалить их можно через «hsh-rmchroot $TMP/hasher-sisyphus-64/». Правда Виталий Липатов сказал, что удалять файлы хешера не нужно, поэтому в данный момент я прислушаюсь к этому совету и не стану так делать без особой нужды.
- Узнал, что по умолчанию репозиторием хешера на нашей сборочнице является Sisyphus
- В планах расследовать, по каким причинам зависают виртуалки в Proxmox
- Жду, когда Кирилл закончит новую структуру ximper.mk :)
Comment 4 Жора Змейкин 2025-11-18 23:44:55 MSK
С оконным менеджером определился, это будет Mutter, так как он имеет больше всего общих зависимостей с ReadySet и на фоне других будет меньше всего загружать пакетов.

Изучил причину, по которой ReadySet не запускался в других окружениях. Оказалось из-за отсутствия зависимости gnome-control-center-data

Поэкспериментировал со сборкой минимальной версии Mutter, но эти усилия не стоят того, ибо сам по себе он уже довольно маленький.

Сейчас поставил себе задачу придумать способ автозапуска Mutter с ReadySet, желательно не от root. В отличии от Cage, в этом плане KWin/Mutter более «капризны» и требуют logind. В идеале хотелось бы сделать это с DynamicUser от systemd, с которым немного я и разбирался сегодня:
- https://0pointer.net/blog/dynamic-users-with-systemd.html
- https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
Comment 5 Жора Змейкин 2025-11-30 23:54:16 MSK
Я потратил довольно много времени на эксперименты с запуском Mutter и понял, что довольно много вещей в systemd и некоторых модулях просто не понимаю и я решил, что займусь изучением systemd.

Я использовал сразу несколько источников, чтобы вкратце узнать и историю systemd и его использование, работу и так далее:
- systemd для администраторов» от Lennart Poettering с русским переводом и уточнениями от Сергей Пташник (она очень маленькая, можно на одном дыхании прочитать)
- https://wiki.archlinux.org/title/Systemd
- https://habr.com/ru/companies/timeweb/articles/824146/
- https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html
- https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
- https://www.freedesktop.org/software/systemd/man/258/systemd.environment-generator.html
- https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
- https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html

В свободное время я также прочёл и анонс systemd, он был очень интересным:
- https://tux-the-penguin.blogspot.com/2010/09/systemd.html
- https://tux-the-penguin.blogspot.com/2010/09/systemd-ii.html

Из того, что я изучил, это:
- Синтаксис systemctl, как он запускает, останавливает процессы, взаимодействие с системой, службами и прочее
- Узнал про systemd-шаблоны
- Узнал, как systemd создаёт символические ссылки в своих директориях и как через это определяется порядок загрузки (есть специальные .d директории, например для WantsBy это .wants директория)
- Узнал как высчитываются неявные зависимости (например, если Type=dbus, то автоматически ставится After=dbus. Тоже самое и с дисковыми устройствами и не только)
- Узнал, как systemd держит под опекой процессы и не позволяет им сбежать. Делается это через CGROUP
- Узнал про секцию [Unit], в том числе:
  - Про разновидности зависимостей (Wants, Requires, Requisite, BindsTo, PartOf, Upholds). У всех них разное поведение, например, у BindsTo жёсткая привязка и в случае остановки одного юнита он также остановит и другие юниты.
  - Использование Conflicts, список юнитов, которые не могут быть запущены вместе с нашим юнитом
  - Другие параметры вроде PropagatesReloadTo/PropagatesStopTo/Also, которые распространяют операции reload/stop/enable|disable на другие юниты
  - Огромное количество различных возможных проверок, которые позволяют запускать юнит только в определённой среде, например, при определённой версии ядра, при наличии аккумулятора, определённой архитектуры, при работе от VM и так далее
  - systemctl edit или как делать дроп-ин файлы со своими изменениями. Способа сделать изменение в systemd файле два и один из них это либо дроп-ин, либо полное копирование. У каждого свои плюсы и минусы.
  - Узнал про Specifier, специальные переменные, которые можно подставлять
- Узнал про секцию [Service], в том числе:
  - Разные Type и как они работают. Например, Type=forking подходит для процессов, которые демонизируют себя после запуска. Или Type=idle, который запустится позже всех остальных.
  - Узнал, что есть возможность разными способами доложить systemd о том, что процесс был запущен. И для этого есть возможность настройки специальных таймаутов, которые не будут заставлять систему долго ждать запуска сервиса.
  - Много параметров, связанные с Exec. В том числе, ExecStart, ExecStop, ExecReload, а также их Pre/Post команды
  - Узнал про Restart= и как его можно настроить. Можно, например, не заставлять службу перезапускаться, если она завершила работу без ошибки
  - Можно устанавливать рабочую директорию, корневой образ и прочее
- Кроме этого есть ещё большое количество параметров, позволяющие запускать службу от другого пользователя или сделать свою песочницу (ограничить директории, сокеты, определённое поведение, вызовы, память и оочень многое другое)

Сейчас я практикую и уточняю некоторые нюансы, поэтому постараюсь в следующем отчёте уточнить некоторые моменты и дописать. Но в целом уже чувствую себя достаточно уверенным пользователем systemd, поэтому не боюсь начать работу с ним.
Comment 6 Жора Змейкин 2025-12-08 04:36:57 MSK
Удалось запустить Mutter через systemd, нашёл некоторые недостающие пакеты KDE для целостной системы (но это тема для другой баги). Параллельно изучал systemd. К тому же пришлось создать свою базу знаний, ибо искать по мануалам оказалось очень муторным и в некоторых местах не хватало русского перевода для понимания. Но из того, что успел сегодня закрепить и изучить:
- Каталоги, по которым systemd ищет юниты, сервисы и прочее (сервисные и пользовательские)
- Они могут отличаться: systemd-analyze --user unit-paths
- Синтаксис и его спецификаторы
- Как работают алиасы (например, default.target обычно имеет алиас multi-user.target или graphical.target). Алиасы не могут использоваться с командой preset.
- Как лучше создавать свои Drop-in конфигурации
- Как работает экранирование строк в именах юнитов (например, символ «/» заменяется на «-»)
- На практике с Mutter лучше выявил работу неявных зависимостей и зависимостей по умолчанию (можно также регулировать через DefaultDependencies=)
- Как работает сборка мусора у systemd (регулируется ещё через CollectMode=)
- Попрактиковал установку зависимостей и увидел на практике, как systemd создаёт символические ссылки в .wants директориях и прочих
- RequiresMountsFor= (или WantsMountsFor=, отличаются поведением) для зависимостей от mount-юнитов
- Через StopWhenUnneeded=True можно указать останавливать юнит, если он никому не нужен
- Через RefuseManualStart=, RefuseManualStop= можно ограничить пользователя произвольно запускать службу (например, она должна запускаться от другой службы)
- Через FailureAction=, SuccessAction= можно настроить действия, которые будут происходиьт при ошибке или успешной загрузке службы. Например, можно отправить в перезагрузку систему
- Попрактиковал настройку таймаутов через JobTimeoutSec=, JobRunningTimeoutSec=, можно также настраивать какие коды выхода будут приниматься для состояния Failed и Success через FailureActionExitStatus=, SuccessActionExitStatus=
- Можно настроить частоту запуска юнита через StartLimitIntervalSec=interval, StartLimitBurst=burst
- Попрактиковал Conditions (условия) и Asserts (требования). Первый просто не запускает службу в случае, если условия не подходят. Вторые переводят службу в faile.d
- Изучил секцию [Install]. Она влияет только на включение службы, но не её работу. Можно управлять зависимостью службы, например при enable сувать службу как WantedBy другой службы. Довольно частая практика, как я заметил
Comment 7 Жора Змейкин 2025-12-13 22:18:16 MSK
Изучил (на практике с Mutter тоже) один из самых больших мануалов — systemd.exec: это опции, общие для сервисов, сокетов, точек монтирования и swap-устройств.

Узнал больше о работе неявных зависимостей — например, LogNamespace= автоматически создаёт зависимость от socket-юнитов вроде systemd-journald@.service.

Узнал про множество переменных, устанавливающих пути. Среди них:
- ExecSearchPath= — переопределяет или дополняет $PATH, который используется при разрешении команд в ExecStart=.
- WorkingDirectory= — рабочий каталог, в котором будет запущен сервис.
- RootDirectory= — устанавливает корень через pivot_root или chroot.
- RootEphemeral= — даёт эфемерную копию корня, в которой будет работать сервис (reflink и btrfs).
- MountAPIVFS= — создаёт приватное пространство и примонтирует /proc, /sys, /dev и /run (пустой tmpfs), если они не примонтированы. Часто используется вместе с RootDirectory= или RootImage=.
- BindLogSockets= — дополнение к предыдущему: монтирует сокеты systemd-журнала.
- ProtectProc= — управляет hidepid= для procfs экземпляра и задаёт, какие директории с метаинформацией о процессах будут видны сервису. По умолчанию ограничений нет, но можно скрыть процессы других пользователей или все процессы, которые нельзя ptrace()-нуть. Эта настройка эффективна только при запуске от ненулевого пользователя (User= или DynamicUser=). Есть также похожая опция ProcSubset=.
- BindPaths=, BindReadOnlyPaths= — создают bind-маунты; нужно быть аккуратнее: директории должны быть доступны и на них не должно стоять конфликтующих Protect* опций.

Переменные, связанные с пользователями:
- User=, Group= — запуск от других пользователей. По умолчанию системный сервис стартует от root (если это не user-unit).
- DynamicUser= — одна из самых интересных опций: создаёт временного пользователя (с именем юнита), который не записывается в /etc/passwd или /etc/group и удаляется при остановке сервиса. При этом автоматически включаются защитные опции: RemoveIPC=, NoNewPrivileges=, RestrictSUIDSGID=, а также ProtectSystem=strict и ProtectHome=read-only (можно разрешать через StateDirectory=, CacheDirectory=, LogsDirectory=). Динамические UID/GID выделяются из диапазона 61184…65519. Можно одновременно задавать User=/Group=, но указанные имена не должны существовать заранее.
- SetLoginEnvironment= — по умолчанию true, контролирует установку переменных окружения $HOME, $LOGNAME и $SHELL.
- PAMName= — регистрирует процесс как PAM-сессию; полезно в сочетании с User=.

Переменные, связанные с безопасностью:
- NoNewPrivileges= — гарантирует, что процесс и его потомки не смогут получить новые привилегии через execve(). Не защищает от взаимодействия с внешними IPC-сервисами, которые сами способны повысить привилегии.
- SecureBits= — принимает keep-caps, keep-caps-locked, no-setuid-fixup, no-setuid-fixup-locked, noroot и noroot-locked.
- Также есть опции SELinuxContext=, AppArmorProfile=, SmackProcessLabel=.

Переменные-свойства (лимиты и приоритеты):
- LimitCPU=, LimitFSIZE=, LimitDATA=, LimitSTACK=, LimitCORE=, LimitRSS=, LimitNOFILE=, LimitAS=, LimitNPROC=, LimitMEMLOCK=, LimitLOCKS=, LimitSIGPENDING=, LimitMSGQUEUE=, LimitNICE=, LimitRTPRIO=, LimitRTTIME= — поддерживают мягкие и жёсткие лимиты.
- KeyringMode= — управление kernel session keyring: можно выделить новую связку ключей или подключить пользовательскую.
- OOMScoreAdjust= — корректировка OOM-score: от −1000 (практически запрет на убийство) до 1000 (максимальная вероятность убийства). По умолчанию 0.
- Nice= — приоритет планирования (от −20 до 19).
- CPUSchedulingPolicy= и CPUSchedulingPriority= — политика и приоритет CPU.
- CPUSchedulingResetOnFork= — сбрасывать повышенные CPU-приоритеты при fork().
- IOSchedulingClass= — класс планирования I/O: realtime, best-effort, idle (по умолчанию best-effort).
- IOSchedulingPriority= — приоритет I/O от 0 (высший) до 7 (по умолчанию 4 для best-effort).

Переменные изоляции (нужна поддержка ядра для некоторых опций):
- ProtectSystem= — принимает булево или full/strict. Если true, то /usr и загрузчик монтируются только для чтения; в full также /etc читается только для чтения; в strict — вся иерархия доступна только для чтения (за исключением /dev, /proc, /sys, которые отдельно настраиваются). Исключения задаются через ReadWritePaths=.
- ProtectHome= — при true директории /home, /root и /run/user становятся недоступными; при read-only — доступны только для чтения; при tmpfs — монтируются временные fs в режиме только для чтения.
- RuntimeDirectory=, StateDirectory=, CacheDirectory=, LogsDirectory=, ConfigurationDirectory= — специальные директории (например, RuntimeDirectory по умолчанию /run).
- RuntimeDirectoryMode=, StateDirectoryMode=, CacheDirectoryMode=, LogsDirectoryMode=, ConfigurationDirectoryMode= — режимы доступа для этих директорий.
- StateDirectoryQuota=, CacheDirectoryQuota=, LogsDirectoryQuota= — квоты, если файловая система поддерживает.
- RuntimeDirectoryPreserve= — сохранять RuntimeDirectory= при остановке/перезапуске; по умолчанию директория удаляется при остановке сервиса.
- ReadWritePaths=, ReadOnlyPaths=, InaccessiblePaths=, ExecPaths=, NoExecPaths=, TemporaryFileSystem= — ограничение доступа к файловой системе (например, разрешить исполнение только по определённым путям).
- PrivateTmp= — создать новое namespace для /tmp и /var/tmp.
- PrivateDevices= — изолировать /dev, дать сервису только псевдо-устройства (например /dev/null, /dev/random); включение также задаёт DevicePolicy=closed.
- PrivateNetwork= — создать новое сетевое пространство имён.
- PrivateIPC= — новое IPC-пространство.
- PrivateUsers= — новое пользовательское пространство.
- ProtectHostname= — создать новое UTS-namespace; можно указать собственный hostname для юнита; при значении private разрешается изменение hostname внутри namespace.
- ProtectClock= — запрещает запись в аппаратные или системные часы.
- ProtectKernelTunables= — делает переменные ядра доступными только для чтения. Рекомендуется включать для большинства сервисов.
- ProtectKernelModules= — запрещает загрузку модулей ядра (не защищает от автоподгрузки в некоторых сценариях).
- ProtectKernelLogs= — запрещает чтение/запись кольцевого буфера логов ядра.
- ProtectControlGroups= — ограничивает доступ к cgroups (только для чтения или изоляция).
- RestrictAddressFamilies= — ограничивает набор семейств сокетов.
- RestrictFileSystems= — ограничивает набор файловых систем, на которых процессы юнита могут открывать файлы; символ ~ инвертирует эффект. Есть предопределённые наборы, например @network или @basic-api (смотреть в systemd-analyze filesystems).
- RestrictNamespaces= — ограничивает namespaces.
- DelegateNamespaces= — делегирует namespace в пользовательский namespace; принимает идентификаторы типов (cgroup, ipc, net, mnt, pid, uts) или булево.
- PrivateBPF= — приватный экземпляр bpffs, чтобы скрыть системный bpffs.
- LockPersonality= — блокирует вызов personality(2).
- MemoryDenyWriteExecute= — запрещает области памяти одновременно записываемые и исполняемые; несовместимо с ПО, динамически генерирующим код (есть обходы через /dev/shm или memfd_create(), но их тоже можно подавить).
- RestrictSUIDSGID= — запрещает попытки установки битов SUID/SGID.
- PrivateMounts= и MountFlags= — изолируют юнит в приватном mount-namespace: любые точки монтирования, созданные процессом сервиса, будут приватными и не будут видны хосту.

Фильтрация системных вызовов:
- SystemCallFilter= — принимает список системных вызовов; по умолчанию блокируемый вызов приводит к SIGSYS, можно изменить через SystemCallErrorNumber=.
- SystemCallArchitectures= — задаёт архитектуры, для которых фильтр действует (полезно при кросс-запусках).
- SystemCallLog= — перечисляет системные вызовы, которые будут логироваться — полезно для аудита.

Переменные окружения:
- Environment= — задаёт переменные окружения для сервиса. (Не использовать для передачи секретов.)
- EnvironmentFile= — читает переменные из файла; в файле допустимы комментарии ; и #. В мануале также описан весь его синтаксис.
- PassEnvironment=, UnsetEnvironment= — передаёт или исключает переменные окружения менеджера сервисов в запускаемые процессы.

Общая философия — предоставлять процессам минимально необходимый набор переменных окружения. Для каждого процесса список переменных формируется из следующих источников (в порядке применения/приоритета):
- Переменные, глобально настроенные менеджером сервисов через DefaultEnvironment=, опцию командной строки ядра systemd.setenv= или через systemctl set-environment.
- Переменные, определённые самим менеджером сервисов.
- Переменные, установленные в блоке окружения менеджера сервисов (с учётом PassEnvironment= для системного менеджера).
- Переменные, заданные через Environment= в unit-файле.
- Переменные, прочитанные из файлов, указанных через EnvironmentFile=.
- Переменные, установленные PAM-модулями, если действует PAMName=.

Менеджер сеанса определяет переменные: $PATH, $LANG, $USER, $LOGNAME, $HOME, $SHELL, $INVOCATION_ID, $XDG_RUNTIME_DIR, $RUNTIME_DIRECTORY, $STATE_DIRECTORY, $CACHE_DIRECTORY, $LOGS_DIRECTORY, $CONFIGURATION_DIRECTORY, $CREDENTIALS_DIRECTORY и прочие — весь список подробно в руководстве.

Переменные для логирования и стандартных потоков:
- StandardInput= — куда подключается stdin: null (по умолчанию), tty, tty-force, tty-fail, data, file:path, socket или fd:name. При подключении к TTY используется TTYPath=; tty-force принудительно переключает управляющий TTY; tty-fail как tty, но выдаёт ошибку, если терминал занят.
- StandardOutput= — куда подключается stdout: inherit, null, tty, journal, kmsg, journal+console, kmsg+console, file:path, append:path, truncate:path, socket или fd:name. inherit дублирует дескриптор, journal — в systemd-журнал, kmsg — в буфер логов ядра.
- StandardError= — для stderr, список идентичен.
- StandardInputText=, StandardInputData= — для передачи текстовых/двоичных данных в stdin.
- LogLevelMax= — максимальный уровень логирования: emerg, alert, crit, err, warning, notice, info, debug. Помогает отсеивать лишние сообщения.
- LogExtraFields= — дополнительные поля метаданных журнала.
- LogRateLimitIntervalSec=, LogRateLimitBurst= — ограничение скорости логов; использовать аккуратно, можно потерять важные сообщения.
- LogFilterPatterns= — фильтрация логов по паттернам.
- LogNamespace= — запуск в отдельном namespace журнала.
- SyslogIdentifier= — syslog tag (по умолчанию — имя процесса).
- SyslogLevel= — уровень syslog: emerg, alert, crit, err, warning, notice, info, debug.
- TTYPath=, TTYReset=, TTYVHangup=, TTYColumns=, TTYRows= — настройка TTY.

Из других интересных фактов:
- chroot не обеспечивает изоляцию, а только меняет корневой каталог.
- Надо быть внимательнее с drop-in файлами systemd: часто забывал переписывать старую переменную, и новая переменная лишь дополняла существующую. Существует также systemctl show/systemd-delta
- Для многих операций с пользователями требуется включённый kernel.unprivileged_userns_clone.
- Для загрузки учётных данных существуют LoadCredential=ID[:PATH], LoadCredentialEncrypted=ID[:PATH] — один из безопасных способов передачи секретов, подробнее также описано в руководстве.
Comment 8 Жора Змейкин 2025-12-15 23:59:24 MSK
Изучил systemd.target. Если говорить кратко – это просто определённая цель, при помощи которой можно управлять зависимостями или запускать группу служб. Его часто используют в других службах, чтобы дождаться, когда запустится определённая группа служб, например, network-online.target

Также изучил systemd.preset. У него очень простой синтаксис (enable, disable или ignore), его основная цель это определить то, какие юниты должны быть включено по умолчанию, а какие отключены. Некоторые дистрибутивы могут класть пресеты вместе с установкой пакетов.

Вновь экспериментировал с DynamicUser= и ReadySet, похоже определённая изоляция не даёт пока запустить. Разбираюсь с этим. Параллельно изучил, как работают systemd kill и как systemd их контролирует.
Comment 9 Жора Змейкин 2026-01-15 22:59:08 MSK
Появился значительный прогресс. Сервисный пользователь временно откладывается из-за проблем в самом ReadySet. Оконный менеджер Mutter, к сожалению, оказался не самым удачным выбором, хоть он и умеет работать из под root, но запускать его из под systemd задача очень неблагодарная. По неопределённым причинам Mutter выдаёт сбой графики и после запуска сразу же зависает, если пытаться запустить его не в открытой сессии с готовым XDG_SESSION_ID. Смена бэкенда отрисовки не помогало, как и подключение PAMName=login (это важно, потому что при помощи PAM можно инициализировать и начальные переменные окружения). Я мог это реализовать через автовход в getty, но если что-то пойдёт не так, то в системе может остаться потенциальная уязвимость. Примечательно, что другие оконные менеджеры такого не показывают со своей стороны. Подозреваю, что Mutter очень зависит от правильной инициализации PAM, графики и других важных переменных, что обычно делает GDM при старте (но тащить его ради ReadySet было бы нецелесообразно). В то время как systemd предоставляет довольно чистую от параметров окружения среду (это была одна из причин, почему я начал такое плотное изучение данной системы инициализации)

Я протестировал Weston и заметил, что он лёгкий и работает отлично как на программной графике, так и на Intel встройке. Тестирование NVIDIA видеокарты предстоит, но я уверен, что там всё хорошо (исходя из отзывов). Weston отлично запускается из под systemd и из под сервисных пользователей.

На данный момент Weston будет работать от рута (из-за ReadySet). По умолчанию он запускается в режиме рабочего стола, но это можно исправить через weston.ini конфиг, который я поместил в папку вместе с ready-set-services (/usr/share/ready-set-service/weston.ini). В конфигурации я прописал автоматический запуск ReadySet и отслеживание, когда он завершит свою работу (watch=true, иначе Weston будет работать вечно). Без PAM-инициализации также очень странно захватывались tty, поэтому я добавил PAMName=login.

Поменял service-файл, который ранее использовался для Cage. Теперь блок ExecStart отвечает только за запуск Weston с ReadySet, а для выполнения операций после завершения ReadySet используется уже другой скрипт, прописанный уже в ExecStop. Он выполняет:
1. Удаление systemd.unit=setup.target из параметров ядра в GRUB (он будет прописан там после установки системы, чтобы запускался наш ReadySet)
2. Удаление weston.desktop сессии, это нужно для следующего шага
3. Запуск текущего Display Manager. Как раз прошлый шаг и нужен был, чтобы пользователь не мог зайти в Weston. Ранее у нас выполнялась команда перезагрузки, но я считаю это действие не особо нужным, ибо вход в нового пользователя и так по новой всё инициализирует. Единственное, возможно текущий уровень выполнения systemd нужно сразу менять, а не после перезагрузки, но я потом внимательнее это рассмотрю.
4. Обновление GRUB и удаление Weston, ready-set и ready-set-service.

Последние операции я изначально хотел сделать асихронными, но я не проверял, как на такое реагирует systemd. Поэтому оставил операции последовательными, чтобы их нельзя было так легко прервать условным выключением системы. Мне не очень нравится текущий костыль с удалением параметра ядра из GRUB и его обновлением, по-хорошему у нас для этого есть `systemctl set-default`, но это не приоритетная задача на данный момент и к этому можно будет вернуться позже. Есть также проблемы с тем, что некоторые лишние зависимости всё равно остаются. В теории можно было бы использовать `apt-get autoremove`, но это более долгая операция, поэтому не стоит.

Но текущее решение работает без критических проблем, проверял на разных сборках. Есть некоторые вещи, которые мне ещё не нравятся, но их решить возможно. Например, сейчас нельзя переключать раскладки (но конфигурацию для этого я подготовил), а также в /root директории появляются GTK-конфиги (это можно исправить средствами systemd). Довольно много времени также потратил на проверку разных систем изоляции, чтобы это было достаточно безопасно и не оставляло всякий хлам в системе. Я попробую их встроить, когда выйдет новая версия ReadySet (ибо изменений там тоже хватает).

Вот текущий Merge Request:
https://gitlab.eterfund.ru/ximperlinux/ready-set-service/merge_requests/1

Потратил довольно много времени на изучение systemd и некоторых его особенностей. Например, освоил инструмент systemd-nspawn в качестве более лучшей альтернативы chroot, созданная для отладки и тестирования. Узнал про разницу /etc/default и /etc/sysconfig, изучал параметры agetty и практиковал на них знания по systemd шаблонам (а ещё понял, почему systemd может экранировать некоторые элементы). Узнал, как эффективнее пользоваться journalctl, получать дополнительные метаданные в логах и лучше сортировать по определённым службам. Кажется, Weston поддерживает программный сторожевой таймер, который можно будет интегрировать со службой на случай, если оконный менеджер зависнет. Я попробую протестировать это чуть позже. Изучил ограничение ресурсов через cgroups и игрался с DynamicUser. Всё таки сервисного пользователя через это я думаю можно будет создать в будущем.

Описания некоторых параметров окружений, которые полезно знать:
- $XDG_SESSION_ID - короткий идентификатор сеанса, подходящий для использования в именах файлов. Каждый ID будет назначен только один раз во время работы машины. Следовательно, его можно использовать для уникальной маркировки файлов или других ресурсов сеанса. Без этой переменной рабочие окружения не понимают, за что им зацепляться и где запускаться. В особенности Mutter. Но с этой задачей инициализации спокойно справляется и PAM.

- $XDG_RUNTIME_DIR - путь к приватному для пользователя и доступному для записи каталогу, который привязан ко времени входа пользователя на машину. Он автоматически создаётся при первом входе пользователя и удаляется при окончательном выходе пользователя. Если не инициализировать PAM (или запускать сервис в изолированном окружении), то может быть полезным указывать.

- $XDG_AREA - Если была выбрана область (area) для входа (вторичные домашние каталоги пользователя внутри основного домашнего каталога), эта переменная устанавливается в имя области (без какого-либо префикса пути). В противном случае она не установлена. Принимает в качестве параметра имя файла. Если указано и пользователь входит в свою учётную запись, переменная окружения $HOME будет установлена в ~/Areas/, дополненное указанной строкой, но только если этот каталог существует. Эта функциональность может использоваться для поддержания нескольких отдельных вторичных домашних каталогов внутри основного домашнего каталога пользователя. Обычно область (area) для входа указывается во время входа, если учётная запись это разрешает (учётные записи, предоставляемые pam_systemd_home(8), делают это), но этот параметр может использоваться для определения области по умолчанию, если она не указана.
Comment 10 Жора Змейкин 2026-02-08 01:27:04 MSK
Провёл тестирование своего Merge Request с последней версией ready-set 0.3.1. Теперь не работает, ReadySet в целом не запускается, ибо ему нужна предварительная настройка. Займусь позже.

> (ready-set-ruler:4156): org.altlinux.ReadySet-ERROR **: 02:16:23.748: utils.vala:90: Failed to generate rules: Error opening directory '/usr/share/ready-set/rules.d': No such file or directory
> 
> (ready-set:4064): org.altlinux.ReadySet-ERROR **: 02:16:23.748: application.vala:85: Failed to generate rules: Дочерний процесс убит по сигналу 5
Comment 11 Жора Змейкин 2026-02-15 23:51:44 MSK
Пришлось исследовать новое обновление, выяснил многое. Начнём с того, что теперь нужно вручную настраивать конфиг-файл или передавать определённые плагины и параметры через CLI. Плагины есть уже в репозитории, например:
- ready-set-plugin-keyboard       - плагин выбора раскладки клавиатуры
- ready-set-plugin-language       - плагин выбора языка
- ready-set-plugin-user-passwdqc  - плагин создания пользователя (passwdqc)
- ready-set-plugin-user-pwquality - плагин создания пользователя (libpwquality)
- ready-set-plugin-welcome        - приветственная страница

Файл конфига загружается из:
- /etc/ready-set/config
- /usr/share/ready-set/config

Плагины ищутся в:
- $LIBDIR/ready-set/plugins/   (.plugin + .so)
- $DATADIR/ready-set/plugins/  (метаданные)

Так что при желании можно написать свои плагины.

Изучил CLI:
-s, --steps=STEPS                - Порядок этапов (через запятую)
--steps-no-apply=STEPS_NO_APPLY  - Этапы, но без применения
-c, --context=CONTEXT            - Контекстные переменные (key=value)
-C, --conf-file=CONF-FILE        - Путь к конфигу
-i, --idle                       - Запуск без применения изменений
-F, --fullscreen                 - Полноэкранный режим (как раз в новой версии добавили)
-u, --user=USER                  - Пользователь для polkit-правил

В основном полезно знать CLI для тестов.

Теперь про контекстные переменные. Они задаются в секции [Context] конфига или через -c key=value в CLI:
- user-with-root        (bool)   - показывать поле пароля root
- hide-autologin        (bool)   - скрыть переключатель автологина
- no-password-security  (bool)   - отключить проверку сложности пароля
- passwd-conf-path      (string) - путь к конфигу passwdqc (по умолчанию /etc/passwdqc.conf)

Ещё появился новый бинарник: /usr/libexec/ready-set-ruler. Он управляет polkit-правилами для плагинов:
--generate-rules -u <user>       - копирует шаблоны из /usr/share/ready-set/rules.d/ в /etc/polkit-1/rules.d/, заменяя --READY-SET-USER-- на указанного пользователя
--clear-rules                    - удаляет сгенерированные правила
--restart-polkit                 - перезапускает polkit после изменений

Каждый плагин при установке кладёт шаблон в /usr/share/ready-set/rules.d/:
- Keyboard - org.freedesktop.locale1.*
- Language - org.freedesktop.locale1.*
- User     - org.freedesktop.accounts.*, запуск ready-set-set-root-password

Polkit-правила не нужны при запуске от root. Polkit по умолчанию разрешает всё для uid 0. Правила нужны только для непривилегированных пользователей. Я думаю нужно переспросить Рирушу, точно ли невозможно пользоваться ReadySet без root прав.

В ready-set-service я учёл новую систему, теперь через CLI я подгружаю нужные плагины и это работает. Плюс скорректировал зависимости. В ближайшее время обновлю MR. Но пришлось учесть ещё один фактор и он связан с плагинов keyboard.

Плагин keyboard зависает, а ранее он не работал корректно на других рабочих окружениях. То есть он был создан исключительно под GNOME. В качестве временного варианта, я в ready-set-service скрыл плагин keyboard для других окружений. Но как я понял, это поправимо.

Если интересно, то вот почему происходит зависание ReadySet с keyboard плагином:
Функция get_current_inputs() (plugins/keyboard/utils.vala:116-128) при отсутствии контекстной переменной keyboard-input-sources обращается к GSettings:
> var settings = new Settings ("org.gnome.desktop.input-sources");
> var variant = settings.get_value ("sources");

На KDE/Hyprland схема org.gnome.desktop.input-sources отсутствует или не отвечает.

Хотя плагин должен работать на других окружениях:
page.vala:67-76 вызывает set_x_11_keyboard через D-Bus (org.freedesktop.locale1), что работает на многих DE, но запись в GSettings всё равно происходит.

Ещё сравнил отличие USER-PASSWDQC и USER-PWQUALITY. В действительности оба плагины одновременно ставить нельзя, это тоже баг, эти пакеты должны быть либо помечены как конфликтные, либо ReadySet должен выдавать предупреждение.

Оба плагина регистрируют один и тот же GType UserAddin из user-common.
При одновременной установке возникает:
> GLib-GObject-CRITICAL: cannot register existing type 'UserAddin'

Разница между ними минимальна, но libpasswdqc уже предустановлен в сборки, поэтому будем использовать его. У USER-PASSWDQC нет прогресс-бара и оценка более бинарная (BAD/GOOD), в то время как у pwquality оценка проходит от 0 до 100 и есть прогресс-бар. Но это всё бессмысленно и переусложняет только настройку, поэтому я просто отключу проверку пароля.

Посмотрел также реализацию автологина в новой версии. Реализован в plugins/user/plugin.vala:52:
> user.set_automatic_login (context.get_boolean ("user-autologin"));

Вызывает метод AccountsService D-Bus, который записывает автологин в конфиг дисплейного менеджера (GDM/LightDM/SDDM), если память не изменяет. Предстоит проверить.

Также выяснил, что alterator-xkb (в установщике) при выборе раскладке записывает данные в /etc/X11/xorg.conf.d/00-keyboard.conf. Если это остаётся в установленной системе - то в теории это можно использовать для переключения раскладки в Weston, но пока я оставил Alt+Shift с русской и английской раскладкой.
Comment 12 Жора Змейкин 2026-02-28 23:25:37 MSK
> Также выяснил, что alterator-xkb (в установщике) при выборе раскладке записывает данные в /etc/X11/xorg.conf.d/00-keyboard.conf. Если это остаётся в установленной системе - то в теории это можно использовать для переключения раскладки в Weston, но пока я оставил Alt+Shift с русской и английской раскладкой.

Странно, в ALT Regular KDE это присутствует, но в нашей сборке этого нет (отсутствует именно комбинация клавиш). Постараюсь расследовать. В остальном текущие изменения работают как надо, также исследовал, насколько трудным будет написать свой модуль клавиатуры для Hyprland и KDE Plasma, так как вариант в альтераторе мне совершенно не нравится из-за привязанности к X11. Для написания плагинов нужно знать Vala, GTK4/Libadwaita и Blueprint (декларативное описание UI). Архитектура простая, оно базируется на libpeas-2, реализовывается метод build_pages() и точка входа peas_register_types(). В конечном итоге можно адаптировать и текущий keyboard плагин.