BashTex | Linux
2.5K subscribers
77 photos
13 videos
487 links
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux.

Подойдет для разработчиков, системных администраторов и DevOps

Реклама: @dad_admin
Download Telegram
KillMode=: почему systemctl stop иногда оставляет процессы

Остановить сервис через:

systemctl stop myapp.service


не всегда означает, что исчезнет только один процесс. У systemd есть отдельная настройка, определяющая, какие процессы будут остановлены вместе с unit.

Это KillMode=.

▪️Например:

[Service]
ExecStart=/opt/myapp/start.sh
KillMode=control-group


По умолчанию systemd работает с control group сервиса. При остановке он может завершить все процессы внутри cgroup, а не только основной PID.
Проверить:

systemctl show myapp.service -p KillMode


▪️Самый интересный вариант - process

[Service]
KillMode=process

В этом режиме сигнал отправляется только основному процессу сервиса.

Если start.sh породил:

myapp
├─ worker1
└─ worker2


дочерние процессы могут продолжить работу после остановки unit.

▪️control-group

[Service]
KillMode=control-group


systemd отслеживает cgroup целиком:

myapp.service
├─ PID 1200
├─ PID 1201
└─ PID 1202


При остановке unit процессы внутри группы также попадут под завершение.

▪️Проверить, кто реально принадлежит сервису

systemctl status myapp.service


или:

systemctl show myapp.service -p ControlGroup


Затем:

systemd-cgls


Можно увидеть дерево процессов по cgroup.

▪️Ещё один режим

KillMode=mixed


При остановке SIGTERM получает основной процесс, а при последующем принудительном завершении systemd применяет его ко всей control group.

Это позволяет дать главному процессу шанс корректно завершиться, не оставляя дочерние процессы навсегда.

▪️Почему это важно

Особенно легко получить «призраков» при запуске приложения через shell-обёртку:

ExecStart=/bin/bash /opt/start.sh


Если скрипт запускает фоновые процессы, нужно понимать, в какой cgroup они окажутся и как KillMode повлияет на их завершение.

systemctl stop - это не просто отправка SIGTERM одному PID. В systemd процесс существует внутри cgroup, и политика KillMode определяет масштаб остановки.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
failglob - почему Bash должен падать при нераскрывшемся glob

Обычно Bash спокойно оставляет glob как есть, если совпадений нет:

rm /var/log/app/*.old


Если .old-файлов нет, команда фактически получит:

rm: cannot remove '/var/log/app/*.old': No such file or directory


Но в автоматизации это может быть проблемой: скрипт продолжит выполнение, хотя вы рассчитывали, что glob что-то нашёл.

▪️failglob меняет поведение

shopt -s failglob

files=(/var/log/app/*.old)


Если совпадений нет, Bash сам выдаст ошибку:

bash: no match: /var/log/app/*.old


То есть проблема обнаруживается на этапе раскрытия glob, ещё до запуска команды.

▪️Особенно полезно в скриптах:

#!/usr/bin/env bash

set -e
shopt -s failglob

for file in /backup/*.tar.gz; do
process "$file"
done


Без failglob цикл может получить буквально строку /backup/*.tar.gz.

С failglob скрипт сразу сигнализирует, что ожидаемых файлов нет.

▪️Но есть нюанс

failglob не всегда нужен. Если отсутствие файлов - нормальная ситуация, лучше использовать nullglob:

shopt -s nullglob

files=(/backup/*.tar.gz)

for file in "${files[@]}"; do
process "$file"
done


Тогда при отсутствии совпадений массив просто будет пустым.

Итого получается:

failglob → отсутствие совпадения считается ошибкой. nullglob → отсутствие совпадения превращается в пустой список.

Для критичных автоматизаций failglob помогает не пропустить логическую ошибку, замаскированную обычным поведением Bash.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
PSI: /proc/pressure/* - как понять, чего реально не хватает системе

load average показывает, что в системе есть очередь на выполнение или I/O. Но он плохо отвечает на другой вопрос: насколько пользователи и процессы реально страдают от этого дефицита?

Для этого в Linux есть PSI - Pressure Stall Information:


cat /proc/pressure/cpu
cat /proc/pressure/memory
cat /proc/pressure/io


Например:


full avg10=0.00 avg60=0.01 avg300=0.00 total=...


▪️some - хотя бы часть задач была вынуждена ждать ресурс.
▪️full - все задачи соответствующей группы одновременно стояли из-за этого ресурса.

avg10, avg60, avg300 - процент времени за последние 10, 60 и 300 секунд, когда происходило такое ожидание.

Например:


some avg10=18.5
full avg10=7.2


Это уже гораздо интереснее, чем просто увидеть высокий RAM usage.

Если memory some растёт - процессы регулярно упираются в нехватку памяти.

Если начинает расти memory full - система уже попадает в периоды, когда все учитываемые задачи одновременно не могут нормально продвигаться из-за memory pressure.

То же самое для I/O:


cat /proc/pressure/io


Если I/O PSI высокий, а CPU почти не испытывает pressure, проблема может быть не в загрузке процессора, а в storage latency.

А CPU PSI позволяет увидеть ситуацию, когда CPU формально загружен не на 100%, но runnable-задачи всё равно регулярно ждут свою очередь.

Проверить всё сразу:


for f in /proc/pressure/*; do
echo "=== $f ==="
cat "$f"
done


PSI полезен именно как метрика задержки из-за конкуренции за ресурсы, а не просто их потребления.

Поэтому вместо вопроса «CPU/RAM/Disk загружены?» иногда правильнее спросить:
«Какой ресурс заставляет процессы ждать?»

BashTex 📱 #perfomance #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
systemd-delta: как найти, чем на самом деле переопределён unit

Иногда вы открываете unit-файл и видите одну конфигурацию, а systemd ведёт себя иначе.

Причина часто в drop-in override, созданном через systemctl edit.

Например, основной unit:

/usr/lib/systemd/system/nginx.service


а дополнительная настройка лежит здесь:

/etc/systemd/system/nginx.service.d/override.conf


▪️Посмотреть переопределения

systemd-delta


Команда показывает отличия между vendor-конфигурацией и локальными изменениями.
Можно проверить конкретный unit:

systemd-delta nginx.service


Если сервис был переопределён, вы увидите соответствующий drop-in.

▪️Почему это важно

Допустим, в основном unit указано:

[Service]
Restart=no

А где-то в /etc/systemd/system/nginx.service.d/override.conf:
[Service]
Restart=always


Открыв только /usr/lib/systemd/system/nginx.service, вы будете смотреть на неполную картину.

systemd при запуске учитывает оба слоя.

▪️Посмотреть итоговую конфигурацию

Для проверки того, что systemd реально использует:

systemctl show nginx.service


Например:

systemctl show nginx.service -p Restart -p RestartUSec


А список связанных drop-in можно увидеть так:

systemctl cat nginx.service


Здесь systemd покажет основной unit и применённые drop-in-файлы.

▪️Практический сценарий

Сервис неожиданно перезапускается:

systemctl status nginx


В основном unit Restart= не настроен.

Вместо того чтобы сразу менять конфигурацию, проверяем:

systemd-delta nginx.service


И обнаруживаем старый override:

/etc/systemd/system/nginx.service.d/override.conf


Именно он мог изменить поведение сервиса.

▪️Важный нюанс

systemd-delta особенно полезен после обновлений дистрибутива.

Пакет может заменить vendor unit в /usr/lib/systemd/system/, но локальный override в /etc/systemd/system/ продолжит действовать.

Поэтому при странном поведении unit полезно проверить не только сам файл, но и что поверх него было добавлено или изменено.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8🔥2🗿1
file vs расширение - как Linux определяет тип файла на самом деле

В Linux расширение файла само по себе ничего не определяет.

Для системы:

backup.tar.gz
backup.jpg
backup.txt


это просто имена файлов. Можно спокойно сделать:
mv image.jpg image.txt
и содержимое файла от этого никак не изменится.

▪️Откуда тогда file знает тип

Утилита file смотрит не на расширение, а на содержимое файла.

file image.txt
file archive.bin
file unknown


Например:

unknown: PNG image data, 1920 x 1080, 8-bit/color RGB


Даже если файл называется:

photo.txt

file всё равно может определить его как PNG.

▪️Главный источник - magic bytes

Многие форматы имеют характерную сигнатуру в начале файла.

Например, PNG начинается с:

89 50 4e 47 0d 0a 1a 0a

Проверить первые байты можно:

xxd -l 16 photo.png

А file сопоставляет такие сигнатуры с базой magic:

file --version

и использует правила из базы magic.

▪️Можно обмануть расширение

cp image.png document.txt
file document.txt


Результат всё равно будет примерно таким:

document.txt: PNG image data


Потому что имя изменилось, а байты остались прежними.

▪️Но не всё определяется только первыми байтами
file может анализировать не только сигнатуру.

Для ELF:

file /bin/ls


может показать архитектуру, разрядность и тип исполняемого файла.

Для текстовых файлов утилита анализирует содержимое и может определить кодировку, тип текста и другие признаки.

▪️Практический сценарий

Скачали файл с подозрительным расширением:

download.exe


Не стоит сразу доверять имени.

Сначала:

file download.exe


А затем, если это бинарник:

readelf -h download.exe


или:

xxd -l 32 download.exe


Так можно понять, что реально лежит внутри файла.

▪️Важный нюанс
file не является универсальным детектором содержимого.

Если формат не имеет узнаваемой сигнатуры или несколько форматов используют похожую структуру, результат может быть приблизительным.

И ещё важнее: file определяет тип по содержимому, но не говорит, что файл безопасен.

Файл может называться document.pdf, определяться как PDF и при этом содержать вредоносную нагрузку.

В Linux расширение - часть имени.

А реальный формат гораздо чаще определяется тем, какие байты находятся внутри файла.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
du vs df: почему Linux показывает разный размер диска

Иногда ситуация выглядит странно:

df -h /


показывает, что занято 80 GB.

А:

du -sh /


находит только 55 GB.

Кажется, что Linux «потерял» 25 GB. На самом деле du и df измеряют разные вещи.

▪️Что считает df
df смотрит на файловую систему и её блоки:

df -h /


Он показывает, сколько места файловая система считает занятым и свободным.

▪️Что считает du
du обходит дерево каталогов и суммирует пространство, связанное с найденными файлами:

du -xhd1 / 2>/dev/null


-x здесь важен: он не позволяет уйти на другие файловые системы.

▪️Одна из главных причин расхождения
Процесс может держать открытым файл, который уже удалили.

Например:

rm /var/log/app.log


Имя файла исчезло из каталога, но процесс всё ещё держит его открытым.
Для du такого файла уже не существует.
А файловая система продолжает считать его блоки занятыми.
Проверить:

lsof +L1


Можно увидеть что-то вроде:

app   1234  ...  /var/log/app.log (deleted)


Пока процесс не закроет этот дескриптор, место может не освободиться.

▪️Есть и другие причины
Например, du без -x может пересекать mount points и давать неожиданный результат.
Или часть пространства файловой системы зарезервирована и не доступна обычным пользователям.

Посмотреть файловую систему подробнее:

findmnt /
df -h /
df -i /


▪️Практический сценарий
На сервере внезапно заканчивается место:

df -h /


Показывает:

/dev/sda2   100G   95G   5G   95% /


Но:

du -xsh /


показывает только 70G.

Первое, что стоит проверить:

lsof +L1


Если там огромный (deleted) лог, причина найдена.

▪️Важный нюанс
df отвечает примерно на вопрос:

«Сколько блоков файловой системы сейчас занято?»

А du:

«Сколько места занимают доступные мне файлы в этом дереве?»

Поэтому при расхождении df и du не стоит сразу запускать rm -rf по большим каталогам.

Сначала нужно понять, куда именно делось пространство.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Sparse files: почему файл на 100 ГБ может занимать несколько мегабайт

Размер файла и реально занятое место на диске не всегда совпадают.

Можно создать файл, который логически имеет размер 100 ГБ, но физически занимает всего несколько мегабайт.
Для этого используются sparse files.

▪️Создаём sparse-файл

truncate -s 100G test.img


Теперь:

ls -lh test.img


покажет:

-rw-r--r-- 1 user user 100G test.img


Но:

du -h test.img


может показать всего несколько килобайт.

ls смотрит на логический размер, а du - на реально выделенные filesystem blocks.

▪️Что произошло
Файл содержит большой диапазон нулей, для которого файловая система не обязана физически выделять блоки.

Условно:

логический файл:

[данные][ огромная область нулей ][данные]
↓ ↓ ↓
блоки hole блоки

Эта незаполненная область называется hole.

▪️Можно посмотреть оба размера

stat test.img

Обратите внимание на:

Size:
Blocks:

Size — логический размер файла.
Blocks — сколько filesystem blocks реально выделено.

▪️Почему это важно
Sparse files часто используются для образов виртуальных машин и контейнеров:

VM disk image → 100 GB
actual allocated space → 12 GB

Пока виртуальная машина не записала данные в свободные области, физическое место не требуется.

Но если эти области постепенно заполняются, реальное потребление диска начинает расти.

▪️Как проверить sparse-файл

du -h test.img
du --apparent-size -h test.img


Второй вариант показывает размер так, будто sparse-областей нет.

Например:

8.0K    test.img
100G test.img


▪️Практический сценарий

Есть сервер виртуализации, и администратор видит:

ls -lh /var/lib/images/*


Образы занимают:

500G

Но:

du -sh /var/lib/images

показывает:

180G

Это не обязательно ошибка подсчёта.
Часть образов может быть sparse.

▪️Важный нюанс
Копирование sparse-файла не всегда сохраняет holes.
Например, некоторые способы копирования могут превратить разреженный файл в обычный и реально записать нулевые блоки.

Проверить результат можно снова через:

du -h file
du --apparent-size -h file


Поэтому при работе с большими VM-образами важно различать логический размер файла и реально выделенное дисковое пространство.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
inotify vs polling: почему постоянный find может быть плохим мониторингом

Иногда нужно отследить появление нового файла в каталоге.

Самый простой вариант:

while true; do
find /var/incoming -type f
sleep 1
done

Работает. Но каждые несколько секунд мы заново обходим каталог, даже если за это время ничего не произошло.
Для событийного мониторинга в Linux есть inotify.

▪️Следим за изменениями без постоянного обхода

Например, с inotifywait:

inotifywait -m /var/incoming

При создании файла можно получить:

/var/incoming/ CREATE report.csv


А с -e можно ограничить интересующие события:

inotifywait -m \
-e create -e moved_to \
/var/incoming


Теперь процесс ждёт события вместо постоянного запуска find.

▪️Можно сразу обрабатывать новые файлы

inotifywait -m -e create -e moved_to --format '%w%f' \
/var/incoming |
while read -r file; do
process "$file"
done


Когда файл появляется или перемещается в каталог, вызывается обработчик.

▪️Почему polling хуже
При polling:

find → sleep → find → sleep → find


мы постоянно проверяем состояние файловой системы, даже когда ничего не меняется.

При inotify:
wait → event → обработка → wait
процесс большую часть времени просто ожидает событие.

▪️Но есть важный нюанс
inotify не является очередью событий для бесконечного количества изменений.

У ядра есть ограничение на очередь событий:

cat /proc/sys/fs/inotify/max_queued_events


Если приложение не успевает читать события, очередь может переполниться.

Тогда появляется:

IN_Q_OVERFLOW


И приложение уже не может считать, что знает обо всех произошедших изменениях.

Поэтому для критичных систем иногда нужен дополнительный механизм сверки состояния.

▪️Практический сценарий
Есть каталог, куда другой сервис складывает файлы:

/var/incoming/


Вместо постоянного:

find /var/incoming ...


можно реагировать непосредственно на CREATE или MOVED_TO.

Но если файл сначала создаётся и затем постепенно записывается, одного события создания недостаточно.

Нужно учитывать момент, когда файл полностью готов к обработке.

Именно поэтому в production важно следить не только за самим событием, но и за способом передачи файла.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Please open Telegram to view this post
VIEW IN TELEGRAM
😁6
Minor и major page fault: почему page fault не всегда означает проблему с диском

Когда процесс обращается к виртуальной памяти, нужная страница не всегда уже находится в памяти именно в том состоянии, которое ожидает процесс.

Тогда возникает page fault - обращение к ядру для обработки этого случая.
Но сам факт page fault ещё не означает, что система полезла на диск.

▪️Смотрим статистику процесса

ps -o pid,comm,min_flt,maj_flt -p 1234


Или:

pidstat -r -p 1234 1


Там можно увидеть количество minor и major faults.

▪️minor fault

При minor page fault данные уже находятся в RAM, но процессу нужно, например, создать или настроить соответствующее отображение страницы.
Дисковый I/O для загрузки этой страницы не требуется.

Поэтому большое количество minor faults само по себе не означает медленный диск.

▪️major fault

При major fault для продолжения работы процесса требуется получить данные из более медленного источника, например с диска.
Условно:

minor
процесс → kernel → RAM → продолжение

major
процесс → kernel → storage → RAM → продолжение


Именно major faults интересны при поиске проблем с памятью и I/O.

▪️Смотрим процесс в реальном времени

pidstat -r -p 1234 1


Можно увидеть примерно:

PID   minflt/s   majflt/s
1234 15230.00 0.00


Здесь процесс создаёт много minor faults, но major faults нет.

Это совершенно другая ситуация, чем:

PID   minflt/s   majflt/s
1234 1200.00 85.00


Во втором случае часть обращений действительно приводит к ожиданию загрузки данных.

▪️Практический сценарий
Приложение внезапно начинает тормозить.
top показывает:

CPU: 20%
RAM: 60%


Но:

pidstat -r -p 1234 1


показывает заметный majflt/s.
Тогда стоит дополнительно посмотреть I/O:

iostat -xz 1


Возможно, процесс регулярно ждёт чтения данных со storage.

▪️Важный нюанс
Не стоит использовать количество page faults как самостоятельную метрику производительности.

Высокий minflt/s может быть совершенно нормальным для приложения с определённым характером работы с памятью.
Гораздо интереснее смотреть на major faults вместе с latency и I/O activity.

То есть:

page fault
↓
minor или major?
↓
если major → есть ли реальный I/O?
↓
где процесс проводит время?


Сам по себе page fault - это не ошибка. Это механизм, который Linux постоянно использует при работе с виртуальной памятью.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
nohup vs session vs terminal - что реально происходит после закрытия SSH

Запустили процесс по SSH:

./backup.sh &


Закрыли SSH-сессию - а потом обнаружили, что процесс исчез.
Почему?

Проблема не в самом SSH. Нужно понимать связь между терминалом, session, shell и сигналами.

▪️Что происходит при SSH-подключении
Условно:

sshd
↓
shell
↓
terminal / PTY
↓
команды


Shell создаёт процессы в своей session и process group, а SSH предоставляет им псевдотерминал.
Когда соединение закрывается, терминал исчезает. Это может привести к отправке SIGHUP процессам, связанным с терминалом.
Именно здесь обычный background-процесс может неожиданно завершиться.

▪️& не делает процесс независимым

./backup.sh &


& лишь запускает команду в фоне для текущего shell.
Это не означает, что процесс переживёт закрытие SSH.
Проверить дерево:

ps -o pid,ppid,sid,pgid,tty,stat,cmd


Здесь особенно интересны:

PID   PPID   SID   PGID   TTY


Можно увидеть, к какой session и terminal относится процесс.

▪️Что делает nohup

nohup ./backup.sh >backup.log 2>&1 &


nohup не создаёт магическую «вечную» копию процесса.

Он в первую очередь меняет обработку SIGHUP и перенаправляет стандартные потоки, если они всё ещё связаны с терминалом.
Проверить:

ps -o pid,ppid,sid,pgid,tty,cmd -p <PID>


Процесс всё ещё может находиться в той же session.

Но получение SIGHUP уже не должно завершить его обычным способом.

▪️А что такое session
Session - это уровень выше process group.

У неё есть лидер - обычно shell, запущенный после входа по SSH.

Посмотреть:

ps -o pid,ppid,sid,pgid,tty,cmd


Например:

PID   PPID   SID   PGID   TTY
1000 900 1000 1000 pts/0
1050 1000 1000 1050 pts/0


Оба процесса находятся в одной session, хотя имеют разные process groups.

▪️Почему setsid - это уже другое
Можно создать новую session:

setsid ./backup.sh


Теперь процесс не находится в старой session SSH.

Это уже принципиально отличается от простого:

./backup.sh &


Но для полноценного фонового запуска всё равно нужно учитывать stdin/stdout/stderr и дальнейшее поведение приложения.

▪️Практический вариант
Если нужен простой запуск долгой команды:

nohup ./backup.sh </dev/null >backup.log 2>&1 &


Если нужна полноценная интерактивная среда, которая переживает отключение SSH:

tmux


В tmux процесс продолжает работать внутри отдельной terminal/session среды, а вы можете подключиться к ней позже.

▪️Важный нюанс

nohup, setsid и tmux решают разные задачи.

&       → background job
nohup → защита от SIGHUP + перенаправление потоков
setsid → новая session
tmux → отдельная управляемая terminal session


Поэтому вопрос «почему процесс умер после выхода из SSH?» лучше начинать не с nohup, а с:

ps -o pid,ppid,sid,pgid,tty,stat,cmd


Сначала смотрим, к какой session, process group и terminal он вообще был привязан.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
veth - как Linux соединяет два network namespace

Network namespace изолирует сетевой стек процесса. У каждого namespace могут быть свои интерфейсы, маршруты и таблица соседей.

Но как соединить два таких изолированных сетевых мира?

Для этого в Linux есть veth pair - виртуальный Ethernet-кабель с двумя концами.

▪️Создаём два namespace

ip netns add ns1
ip netns add ns2


Теперь создаём пару:

ip link add veth1 type veth peer name veth2


Получили:

veth1 <──────────> veth2


То, что отправлено в один конец, появляется на другом.

▪️Разносим концы по namespace

ip link set veth1 netns ns1
ip link set veth2 netns ns2


Теперь:

namespace ns1        namespace ns2

veth1 <──────────> veth2


В каждом namespace находится только свой конец виртуального кабеля.

▪️Назначаем адреса

ip -n ns1 addr add 10.10.0.1/24 dev veth1
ip -n ns2 addr add 10.10.0.2/24 dev veth2

ip -n ns1 link set veth1 up
ip -n ns2 link set veth2 up


Теперь можно проверить связь:

ip netns exec ns1 ping 10.10.0.2


Пакет проходит примерно так:

process
↓
network stack ns1
↓
veth1
↓
veth2
↓
network stack ns2
↓
process


Никакого физического интерфейса между namespace здесь нет.

▪️Почему это используется в контейнерах

Контейнер получает собственный network namespace.
Один конец veth помещается внутрь контейнера:

container
eth0
│
│ veth
│
host


Второй конец остаётся на host и обычно подключается к Linux bridge.
Например:

container eth0
│
veth
│
bridge
├── veth
├── veth
└── host


Так несколько изолированных namespace получают доступ к одной L2-сети.

▪️Проверяем, где находится интерфейс
На host:

ip link


В namespace:

ip -n ns1 link


Можно увидеть, что veth1 и veth2 физически не существуют как один интерфейс — это два связанных виртуальных endpoint’а.

▪️Важный нюанс
veth сам по себе не маршрутизирует трафик.
Он просто соединяет два сетевых пространства на уровне Ethernet.
Если нужно выйти из namespace в интернет, поверх veth обычно добавляют bridge, routing, NAT или другой сетевой механизм.

То есть veth - это буквально виртуальный кабель:

namespace A
│
veth A
│
└──────── veth B
│
namespace B


А уже дальше Linux решает, куда отправлять пакеты.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
Почему Permission denied: как найти каталог, на котором ломаются права

Иногда файл имеет правильные права, пользователь состоит в нужной группе, но Permission denied всё равно появляется.

Причина может быть выше по пути: чтобы открыть /var/www/site/config.php, процесс должен иметь право x на каждый каталог в этом пути.

Разберем, как быстро найти место, где ломается доступ.

1️⃣namei показывает права на весь путь

namei -l /var/www/site/config.php


В выводе будут отдельно показаны:

drwxr-xr-x root root /
drwxr-xr-x root root var
drwxr-x--- root www-data www
drwx------ root root site
-rw-r----- root www-data config.php


Сразу видно, на каком уровне пользователь может упереться в права.

2️⃣Почему важен x у каталога

Для каталога x означает не «запуск», а возможность проходить через него и обращаться к объектам внутри.
Например:

chmod 644 /var/www/site


Файлы внутри могут быть доступны для чтения, но войти в каталог без x уже нельзя.
Проверить можно:

sudo -u www-data cat /var/www/site/config.php


3️⃣Проверяем конкретного пользователя
Если доступ должен быть у www-data:

sudo -u www-data namei -l /var/www/site/config.php


А группы:

id www-data


Это помогает понять, действительно ли процесс запускается с теми группами, которые вы ожидаете.

4️⃣ACL тоже могут менять картину

Обычных ls -l иногда недостаточно. Проверить ACL:

getfacl /var/www/site/config.php


Там могут быть дополнительные разрешения для конкретного пользователя или группы.

5️⃣Почему ls -l файл не всегда помогает
Команда:

ls -l /var/www/site/config.php


показывает права самого файла.

Но если проблема находится в /var/www/site, информация о файле сама по себе этого не объяснит.

Именно поэтому namei -l удобен при странных Permission denied: он показывает всю цепочку каталогов, через которую процесс должен пройти до нужного файла.

BashTex 📱 #bash #systemd
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5