chmod 755 чи u+x: числовий і символьний режими
Дізнайтеся, як chmod змінює дозволи Linux: що означають цифри й u/g/o, чому числовий режим ламає права в дереві та як capital X це виправляє.
Що змінює chmod
chmod змінює біти дозволів для файлу або каталогу та приймає ці біти в одному з двох форматів. Числовий формат — це вісімкове число, яке одночасно замінює всі біти дозволів. Символьний формат визначає клас користувачів і оператор та змінює лише вказані біти. Обидва формати зрештою використовують той самий системний виклик. Відмінність полягає в тому, що відбувається з бітами, які не було вказано.
Перегляд режиму доступу та його зміна — це різні завдання. Якщо літери у розгорнутому списку ще не очевидні, спочатку прочитайте що означає drwxr-xr-x, поле за полем. У цьому посібнику змінюються лише ці біти.
Усі наведені тут дії виконуйте від імені звичайного користувача, під яким ви входите в систему. Обліковий запис root обходить ці перевірки, тому демонстрація дозволів, виконана від root, нічого не доводить. Якщо ви все ще працюєте від root на новому сервері, створіть звичайного користувача з мінімально необхідними привілеями та поверніться до цього посібника.
Створіть одноразове тестове середовище
cd "$(mktemp -d)"
touch notes.txtmktemp -d створює порожній каталог у /tmp і виводить створений шлях, а підстановка команд одразу передає цей шлях до cd. Наведені нижче команди не змінюють жодного важливого для вас файла.
Одна команда показує результат кожної зміни:
stat -c '%a %A %n' notes.txt%a виводить режим як вісімкове число, %A виводить той самий режим у літерному форматі, який використовує довгий список, а %n виводить ім’я. У наступних блоках рядок, що починається з $, потрібно ввести, а рядок під ним показує вивід команди. Виконайте ці команди самостійно. Вивід у вашій системі має збігатися рядок у рядок, оскільки числовий режим не залежить від параметрів вашого середовища.
Числовий формат: одна вісімкова цифра для кожного класу
Перша цифра належить власнику файлу. Друга — групі файлу. Третя — всім іншим. Кожна цифра є сумою: по одному значенню для кожного біта. Установлюйте біти по одному та переглядайте, що повідомляє stat.
$ chmod 400 notes.txt
$ stat -c '%a %A %n' notes.txt
400 -r-------- notes.txt
$ chmod 200 notes.txt
$ stat -c '%a %A %n' notes.txt
200 --w------- notes.txt
$ chmod 100 notes.txt
$ stat -c '%a %A %n' notes.txt
100 ---x------ notes.txtЛітери відповідають цифрам. Після початкового символу типу файлу перша група з трьох літер належить власнику, наступна група з трьох — групі, а остання група з трьох — усім іншим. Додайте значення, щоб об’єднати біти в одному класі.
$ chmod 600 notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txt
$ chmod 700 notes.txt
$ stat -c '%a %A %n' notes.txt
700 -rwx------ notes.txt
$ chmod 750 notes.txt
$ stat -c '%a %A %n' notes.txt
750 -rwxr-x--- notes.txtЧисловий режим є абсолютним. Під час кожного запуску він записує всі дев’ять бітів, тому також записується клас, про який ви не думали.
$ chmod 755 notes.txt
$ stat -c '%a %A %n' notes.txt
755 -rwxr-xr-x notes.txt
$ chmod 600 notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txtДруга команда нічого не вказувала про групу або всіх інших, але їхні біти все одно змінилися. Це характерна особливість числового формату, і саме тому числовий формат не підходить для невеликого редагування. (chmod також працює з бітами setuid, setgid і sticky, які розташовані в четвертій цифрі перед цими. Це окрема тема, тому в цьому посібнику розглядаються лише три цифри.)
Символьний запис: клас, оператор, потім біти
Спочатку вкажіть клас. u — це власник, g — група, o — усі інші, а a — усі класи одночасно. Потім укажіть оператор: + додає біти, - видаляє біти, а = встановлює для цього класу рівно перелічені біти та очищає всі інші його біти. Після цього вкажіть самі біти: r, w або x.
$ chmod 640 notes.txt
$ stat -c '%a %A %n' notes.txt
640 -rw-r----- notes.txt
$ chmod u+x notes.txt
$ stat -c '%a %A %n' notes.txt
740 -rwxr----- notes.txt
$ chmod g-r notes.txt
$ stat -c '%a %A %n' notes.txt
700 -rwx------ notes.txt
$ chmod o=r notes.txt
$ stat -c '%a %A %n' notes.txt
704 -rwx---r-- notes.txtКожна команда змінювала один клас, не зачіпаючи інші. Об’єднуйте умови комами без пробілів. chmod застосовує їх зліва направо.
$ chmod u=rw,go=r notes.txt
$ stat -c '%a %A %n' notes.txt
644 -rw-r--r-- notes.txt
$ chmod go= notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txtgo= без символів після знака дорівнює видаляє всі біти для групи та всіх інших. Такий запис потрібен для файлу, який може читати лише його власник, наприклад для приватної частини пари ключів SSH.
chmod також може виводити результат своєї роботи. Це важливо в скрипті, коли за його виконанням ніхто не стежить.
chmod -v u+x notes.txt
chmod -v u+x notes.txt-v виводить окремий рядок для кожного переданого файлу. Виконайте обидві команди та порівняйте два рядки на екрані: у першому вказано ім’я файлу, режим до зміни та режим після зміни, а у другому зазначено, що режим збережено, оскільки біт, який потрібно було додати, уже був встановлений. -c виводить рядок лише тоді, коли файл справді змінено, тому цей варіант краще використовувати для запису в журнал.
chmod 755 проти u+x: який запис використовувати
Почніть із того самого файлу двічі та порівняйте, що залишає після себе кожен запис.
$ chmod 640 notes.txt
$ chmod 755 notes.txt
$ stat -c '%a %A %n' notes.txt
755 -rwxr-xr-x notes.txt
$ chmod 640 notes.txt
$ chmod u+x notes.txt
$ stat -c '%a %A %n' notes.txt
740 -rwxr----- notes.txtОбидві команди зробили файл виконуваним для його власника. Лише одна з них залишила права двох інших класів без змін. Використовуйте числовий режим, коли знаєте точний кінцевий стан і хочете примусово його встановити. Це правильний варіант у скрипті розгортання, який має забезпечити однаковий результат на машині, якої ви раніше не бачили. Використовуйте символьний режим, коли у вашому формулюванні є додати або видалити, оскільки числовий запис не дає змоги вказати залишити цю частину без змін.
Режим, із якого починається новий файл, визначає не chmod. Його визначає umask процесу, який створив файл. Виконайте umask і umask -S у власній оболонці, щоб переглянути поточне значення. Воно може відрізнятися в різних дистрибутивах, у вашій оболонці входу та в службі systemd, а також для різних облікових записів. umask визначає режим кожного нового файлу, тому саме вона задає початковий стан до виконання chmod.
Що означає біт виконання для каталогу
Це непорозуміння найчастіше призводить до втрати часу. Для звичайного файла біт виконання означає, що ядро може запустити файл. Каталог не містить інструкцій, тому в ньому немає чого запускати. Для каталогу біт виконання означає доступ для проходження: дозвіл розв’язувати ім’я всередині каталогу. Щоб дістатися до dir/file, цей біт потрібен для dir. Біт читання — це окремий дозвіл. Він дає змогу переглядати імена, які містить каталог. Можна мати один із цих дозволів без іншого. Це легше зрозуміти, коли побачиш таку поведінку на практиці.
$ mkdir vault
$ printf 'hello\n' > vault/secret.txt
$ chmod 600 vault/secret.txt
$ chmod 100 vault
$ echo vault/*
vault/*
$ cat vault/secret.txt
helloОболонка вивела шаблон без змін, оскільки розгортання vault/* потребує читання каталогу, а шаблон, якому нічого не відповідає передається як буквальний текст, а не спричиняє помилку. cat усе одно спрацював, оскільки ім’я було вказано явно, а доступ для проходження був дозволений. Тепер поміняйте ці два біти місцями.
$ chmod 400 vault
$ echo vault/*
vault/secret.txt
$ cat vault/secret.txt
cat: vault/secret.txt: Permission deniedІмена видно, а вміст недоступний. Читання дає список. Виконання дає шлях усередину. Майже кожному каталогу, з яким ви працюєте, потрібні обидва дозволи.
$ chmod 500 vault
$ cat vault/secret.txt
helloЧому chmod -R із числовим режимом пошкоджує дерево
-R проходить усе дерево та застосовує вказаний режим до кожного знайденого об’єкта. Для каталогу й файлу даних потрібні різні біти, тому одне абсолютне число не може бути правильним для обох типів. Створіть невелике дерево та подивіться, як це спричиняє помилку.
$ mkdir -p site/css
$ touch site/index.html site/css/main.css
$ printf '#!/bin/bash\necho hi\n' > site/deploy.sh
$ chmod 755 site site/css site/deploy.sh
$ chmod 644 site/index.html site/css/main.css
$ stat -c '%a %A %n' site site/css site/index.html site/css/main.css site/deploy.sh
755 drwxr-xr-x site
755 drwxr-xr-x site/css
644 -rw-r--r-- site/index.html
644 -rw-r--r-- site/css/main.css
755 -rwxr-xr-x site/deploy.shСаме так має виглядати каталог статичних файлів. Ось перша помилка під час рекурсивної зміни прав.
$ chmod -R 755 site
$ stat -c '%a %A %n' site/index.html site/css/main.css
755 -rwxr-xr-x site/index.html
755 -rwxr-xr-x site/css/main.cssНічого не зламалося, і саме в цьому проблема. Ця помилка непомітна, тому роками зберігається в інструкціях, які копіюють. Два файли даних тепер позначені як програми. Git зберігає біт виконання, тому наступний коміт передасть цю зміну всім, хто клонуватиме репозиторій, а rsync і tar — на кожну машину, куди ви скопіюєте дерево.
Друга помилка під час рекурсивної зміни прав одразу помітна. Якщо застосувати до каталогу режим без біта виконання, доступ до каталогу буде закрито.
$ chmod 644 site
$ stat -c '%a %A %n' site
644 drw-r--r-- site
$ echo site/*
site/css site/deploy.sh site/index.html
$ cd site
bash: cd: site: Permission denied
$ cat site/index.html
cat: site/index.html: Permission deniedІмена все ще відображаються, оскільки біт читання зберігся, але кожен шлях через каталог закритий, оскільки біта виконання немає. chmod -R 644 site робить це з кожним каталогом у дереві однією командою. Результат не завжди буде однаковим, оскільки chmod має проходити через ті самі каталоги, доступ до яких він забирає. Тому перевірте фактично застосовані права за допомогою find site -type d -exec stat -c '%a %n' {} +, а не робіть припущень. Перш ніж продовжити, відновіть попередні права.
$ chmod 755 site
$ chmod 644 site/index.html site/css/main.css
$ stat -c '%a %A %n' site site/index.html
755 drwxr-xr-x site
644 -rw-r--r-- site/index.htmlРекурсивна команда chmod не має операції скасування. chmod не записує значення, які він замінив, тому відновлення доведеться виконувати вручну, відтворюючи права на основі припущень про їхній попередній стан. Це така сама повільна й ненадійна робота, як відновлення файлів після випадкового rm -rf, і висновок той самий: перевірте ціль рекурсивної команди, перш ніж натиснути Enter.
Велика X: право на виконання для каталогів, але не для кожного файла
Символьні режими приймають X, як і x. X встановлює право на виконання лише там, де це має сенс: для каталогу або звичайного файла, який уже має право на виконання для певного класу. Це саме правило, якого ви хотіли дотриматися за допомогою -R.
$ chmod -R u=rwX,go=rX site
$ stat -c '%a %A %n' site site/css site/index.html site/css/main.css site/deploy.sh
755 drwxr-xr-x site
755 drwxr-xr-x site/css
644 -rw-r--r-- site/index.html
644 -rw-r--r-- site/css/main.css
755 -rwxr-xr-x site/deploy.shОдна команда — і каталоги залишилися доступними для проходження, а файли даних не змінилися. Скрипт зберіг право на виконання, оскільки вже його мав. Це друга частина правила X. X читає поточний режим файла, тому файл, який уже втратив усі права на виконання, не можна відновити за допомогою цієї команди.
$ chmod 644 site/deploy.sh
$ chmod -R u=rwX,go=rX site
$ stat -c '%a %A %n' site/deploy.sh
644 -rw-r--r-- site/deploy.sh
$ site/deploy.sh
bash: site/deploy.sh: Permission denied
$ chmod u+x site/deploy.sh
$ stat -c '%a %A %n' site/deploy.sh
744 -rwxr--r-- site/deploy.sh
$ site/deploy.sh
hiЦе саме правило працює і в іншому напрямку. X поширює право на виконання, яке файл уже має, на інший клас:
$ chmod go+X site/deploy.sh
$ stat -c '%a %A %n' site/deploy.sh
755 -rwxr-xr-x site/deploy.shОтже, малу x використовують для одного іменованого файла, який потрібно зробити виконуваним, а X — для обробки всього дерева. Якщо для кожного типу об’єктів потрібен точний режим, а не правило на основі поточного режиму, розділіть обхід за допомогою find.
find site -type d -exec chmod 755 {} +
find site -type f -exec chmod 644 {} +
chmod u+x site/deploy.sh-type d вибирає каталоги, а -type f — звичайні файли, тому кожен тип отримує потрібний режим. -exec ... + передає багато шляхів одним викликом chmod, а не запускає окремий процес для кожного файла. Це важливо для дерева з тисячами записів. Скрипт отримує своє право на виконання окремим рядком навмисно.
Перевірте результат, перш ніж завершити роботу
Дві команди дають змогу виявити важливі помилки після будь-якої рекурсивної зміни. Перша виводить каталоги, до яких більше не можна перейти.
find . -type d ! -perm -u+xДруга виводить файли, які може змінювати будь-який обліковий запис на машині.
find . -type f -perm -o+wУ -perm -o+w початковий - означає щонайменше ці біти, тому команда знаходить файл, у класі o якого встановлено біт запису, незалежно від інших встановлених бітів. Бажаний результат — коли жодна з команд нічого не виводить. Виконайте обидві команди з кореня дерева, яке щойно змінили за допомогою -R, а для кількох шляхів, які ви планували змінити, виконайте stat -c '%a %A %n'. Так ви переконаєтеся, що режим, який ви вважаєте встановленим, відповідає режиму, фактично збереженому ядром.
FAQ
У чому різниця між chmod 755 і chmod u+x?
Числовий режим є абсолютним. Він записує всі біти дозволів для файлу, тому також переписує класи, про які ви не думали. Символьний режим редагує дозволи. u+x додає один біт для власника й залишає всі інші біти без змін. Використовуйте числову форму, коли точно знаєте, яким має бути кінцевий стан файлу. Використовуйте символьну форму, коли потрібно додати або видалити один дозвіл. Виконайте stat -c '%a %A %n' <file> до й після будь-якої з цих команд, і різниця буде видна у виводі.
Чому chmod -R 755 для каталогу з веб-файлами є невдалим рішенням?
Тому що -R застосовує однаковий абсолютний режим до каталогів і звичайних файлів, хоча їм потрібні різні біти. Каталогу потрібен біт виконання, щоб його можна було обійти. Файлам даних, таким як HTML і CSS, він не потрібен, а позначення їх як виконуваних зафіксує цю зміну в наступному коміті git, і rsync скопіює її на наступну машину. Використовуйте chmod -R u=rwX,go=rX <dir>, щоб біт виконання додавався лише каталогам, або керуйте цим через find за допомогою -type d і -type f, щоб кожен тип отримував власний режим.
Що робить біт виконання для каталогу?
Він надає дозвіл на обхід, а не на виконання. Усередині каталогу немає об’єкта, який можна запустити. Біт виконання дозволяє визначити ім’я всередині каталогу, тому він потрібен для кожного каталогу в шляху, перш ніж ви зможете відкрити файл у кінці цього шляху. Біт читання є окремим і дозволяє отримати список імен. Один дозвіл може бути наданий без іншого: лише з бітом виконання можна відкрити файл, ім’я якого вам уже відоме, але shell не зможе розгорнути glob у цьому каталозі; лише з бітом читання можна побачити імена, але кожна спроба відкрити одне з них завершиться помилкою.
Коли слід використовувати велику X замість малої x?
Використовуйте X щоразу, коли команда є рекурсивною. X встановлює біт виконання для каталогів, а для звичайних файлів — лише тоді, коли один із бітів виконання вже встановлено. Тому одного проходу достатньо, щоб зробити дерево доступним для обходу, не перетворюючи файли даних на програми. Використовуйте малу x, коли вказуєте на один файл і маєте на увазі саме цей файл. Варто пам’ятати про одне обмеження: X не може відновити біт виконання, який уже всюди видалено з файлу, оскільки більше немає біта, за яким можна було б визначити відповідність. Відновіть його за допомогою chmod u+x <file>.
Чи змінює chmod власника файлу?
Ні. chmod змінює лише біти дозволів. Власник зберігається в chown для користувача та в chgrp для групи, а передавання файлу іншому користувачеві потребує root. Це важливо, оскільки біти перевіряються відносно користувача-власника та групи, записаних у файлі, а не відносно того, хто востаннє його записував. Виконайте stat -c '%U %G %a %n' <file>, щоб одночасно побачити власника, групу та режим, перш ніж вирішувати, яка саме з трьох команд вам потрібна.