Перейти к содержимому

Как это работает

Всё, что hostsctl рендерит, лежит между двумя строками-маркерами:

# >>> hostsctl begin >>>
# generated by hostsctl 2026-08-11 17:15
# source: /Users/you/.config/hostsctl/config.yaml — edit that, not this block
# --- local — Local development ---
127.0.0.1 k8s.orb.local # orbstack
# <<< hostsctl end <<<

Строки вне маркеров копируются в новый файл без изменений. Это центральный инвариант, и именно его проверяют интеграционные тесты на копии настоящего /etc/hosts: системные строки, блоки других утилит и ручные правки переживают apply.

Если найден маркер начала без маркера конца, блоком считается всё до конца файла. Иначе обрезанный блок заставлял бы каждый apply дописывать новый.

  1. Собрать блок из конфига и кеша блоклистов.
  2. Составить новый файл: всё вне маркеров плюс новый блок на месте старого (или в конце, если блока не было).
  3. Отказаться, если в результате нет 127.0.0.1 localhost.
  4. Снять копию текущего файла в каталог бэкапов.
  5. Записать временный файл рядом с целью, сделать fsync, перенести на него права и владельца цели, выполнить rename поверх.
  6. Почистить старые снимки, сбросить DNS-кеш.

Из-за пятого шага прерванный apply не может оставить наполовину записанный /etc/hosts: rename в пределах одной файловой системы атомарен, поэтому файл — либо старый, либо новый.

В блоке есть отметка времени генерации, но hostsctl оставляет старую, если больше в блоке ничего не изменилось. Без этого diff показывал бы изменение каждую минуту, status вечно требовал бы apply, а сам apply переписывал бы /etc/hosts и плодил бэкапы на пустом месте. Заодно отметка начинает означать то, что от неё и ждут: когда блок менялся в последний раз.

  • Строка на каждый адрес. Имя на трёх адресах — три строки, потому что другого способа выразить это в /etc/hosts нет.
  • Точный повтор пары «адрес + имя» схлопывается один раз, с предупреждением. Больше ничего не выбрасывается.
  • Одно имя в двух группах сохраняется и вызывает предупреждение — это законно и обычно ошибка.
  • Имя, которое уже встречается вне управляемого блока, даёт предупреждение с указанием файла и строки. Ту строку hostsctl не трогает, а в /etc/hosts выигрывает первое совпадение — так что запись выше блока тихо перебивает запись внутри него.

Блок, оставленный старым shell-скриптом hosts-sync, утилита видит, но по своей воле не удаляет. apply предупреждает, что он есть и что его записи могут выигрывать; удаление требует явного --drop-legacy либо hostsctl migrate, который сначала импортирует старые файлы в конфиг. См. Миграцию.

hostsctl check показывает то, что система молча проигнорирует, вместо тихого отказа: wildcards, порт или путь в имени хоста, адрес, который не парсится, имя, уже заданное вне управляемого блока. Ошибка останавливает apply и даёт код выхода 3, предупреждение печатается и ничего не блокирует.

Полный список по уровням — в правилах проверки.