nano permission denied: jak naprawić błąd zapisu pliku
Edytor nano zwraca błąd zapisu z powodu braku uprawnień, systemu plików read-only lub pełnego dysku. Sprawdź właściciela pliku, UID w kontenerze oraz wolne miejsce na partycji.
Dlaczego nano nie zapisuje pliku
Edytor nano nie zapisuje pliku z jednego z czterech powodów: brak uprawnień właściciela do pliku, ograniczenia katalogu nadrzędnego uniemożliwiające operację, system plików w trybie tylko do odczytu lub brak miejsca na dysku, albo uruchomienie wewnątrz kontenera z innym identyfikatorem użytkownika (UID). Dwa pierwsze przypadki to problemy z uprawnieniami, dwa ostatnie nie. Należy sprawdzać je w tej kolejności, ponieważ pierwsza przyczyna występuje najczęściej, jej weryfikacja wymaga tylko jednego polecenia, a rozwiązanie to sudoedit, a nie sudo nano.
Dopóki edytor pozostaje otwarty, dane nie są utracone. Tekst znajduje się w pamięci operacyjnej, więc można pozostawić plik otwarty, zapisać bufor w ścieżce, do której posiada się uprawnienia, a następnie przenieść go w docelowe miejsce. Ta metoda ratunkowa została opisana pod koniec niniejszego przewodnika.
Uruchom te testy przed zmianą jakichkolwiek uprawnień
Skieruj każde polecenie na rzeczywistą ścieżkę, którą edytujesz. Polecenia te odpowiadają na różne pytania, dlatego należy wykonać je wszystkie przed podjęciem jakichkolwiek działań. Zmiana uprawnień bez ustalenia, który test kończy się niepowodzeniem, zazwyczaj tworzy drugi problem nałożony na pierwszy.
id
ls -l /etc/nginx/nginx.conf
ls -ld /etc/nginx
namei -l /etc/nginx/nginx.conf
findmnt -no SOURCE,FSTYPE,OPTIONS -T /etc/nginx/nginx.conf
df -h /etc/nginx
df -i /etc/nginxid wyświetla identyfikator użytkownika oraz identyfikatory grup, do których aktualnie należysz. ls -l pokazuje właściciela, grupę oraz bity uprawnień samego pliku. ls -ld pokazuje te same informacje dla katalogu, w którym znajduje się plik, co jest osobnym zagadnieniem z osobną odpowiedzią. namei -l sprawdza każdy element ścieżki i wypisuje właściciela oraz uprawnienia dla każdego z nich, odpowiadając tym samym na oba pytania w jednym wyjściu. findmnt podaje nazwę systemu plików dla danej ścieżki oraz opcje, z jakimi został zamontowany. df -h raportuje wolne miejsce, a df -i raportuje wolne i-węzły (inodes), których wyczerpanie następuje niezależnie od miejsca na dysku. Jeśli te ciągi uprawnień nie są jeszcze znane, zacznij od jak odczytać ciąg uprawnień wyświetlany przez ls -l.
Przyczyna 1: plik należy do użytkownika root, a Ty nie masz uprawnień
Uprawnienia do odczytu i zapisu są rozdzielne, a większość plików w /etc jest dostępna do odczytu dla wszystkich użytkowników. Dlatego edytor nano otwiera plik, wyświetla jego zawartość i pozwala na edycję: żadna z tych operacji nie wymaga zapisu na dysku. Odmowa następuje w momencie próby zapisu, gdy jądro systemu porównuje identyfikator użytkownika oraz identyfikatory grup z właścicielem, grupą i bitami uprawnień pliku. Edytor nano jedynie przekazuje komunikat otrzymany od jądra, więc żadna opcja programu nie zmieni wyniku tej operacji.
id oraz ls -l łącznie wyjaśniają tę sytuację. Właścicielem pliku jest root, użytkownik nie posiada uprawnień roota, a bity uprawnień dla pozostałych użytkowników nie zezwalają na zapis. Ponowne naciśnięcie Ctrl-O nie rozwiąże problemu.
Dlaczego sudoedit jest właściwym sposobem edycji plików należących do roota
SUDO_EDITOR=nano sudoedit /etc/nginx/nginx.confPolecenie sudo tworzy tymczasową kopię pliku, przypisując ją do użytkownika, uruchamia nano na tej kopii z uprawnieniami użytkownika, a po zamknięciu edytora kopiuje wynik z powrotem na miejsce z uprawnieniami roota. Edytor nigdy nie działa jako root. sudo -e to to samo polecenie pod inną nazwą. Edytor jest wybierany kolejno z SUDO_EDITOR, następnie VISUAL, a potem EDITOR, dlatego export EDITOR=nano w profilu powłoki ustawia go jako domyślny w całym systemie. Jeśli w pliku sudoers wyłączono flagę env_editor, zmienne te są ignorowane, a edytor jest pobierany z ustawienia editor w sudoers.
sudo nano również zapisuje plik i w tym tkwi problem. Daje on pełnemu, interaktywnemu edytorowi uprawnienia roota do całego systemu plików na czas trwania sesji. W efekcie jedna literówka w ścieżce podczas zapisu może nadpisać inny plik systemowy z uprawnieniami roota. Praca jako zwykły użytkownik, który wywołuje sudo tylko do kroków tego wymagających to nawyk, który warto wyrobić, a sudoedit jest jego praktycznym zastosowaniem podczas edycji plików konfiguracyjnych.
Dwie zasady sudoedit często zaskakują użytkowników. Narzędzie odmawia edycji dowiązań symbolicznych oraz plików w katalogach, do których użytkownik ma prawo zapisu, chyba że jest rootem. Druga zasada istnieje, ponieważ każdy, kto może pisać do katalogu, mógłby podmienić plik w trakcie pracy edytora. Oba zachowania są domyślnymi ustawieniami sudoers (sudoedit_follow wyłączone, sudoedit_checkdir włączone). Plik, który jeszcze nie istnieje, zostanie utworzony automatycznie.
Przyczyna 2: co faktycznie kontroluje katalog nadrzędny
Porady dla innych edytorów wskazują, że zapis wymaga uprawnień do zapisu w katalogu, ponieważ wiele edytorów zapisuje plik poprzez utworzenie nowego i zmianę jego nazwy na nazwę starego pliku. nano nie działa w ten sposób. Otwiera on wskazany plik i zapisuje dane bezpośrednio w nim, więc w przypadku istniejącego pliku bit zapisu katalogu nie jest sprawdzany.
Katalog nadal decyduje o innych kwestiach, dlatego ls -ld znajduje się na liście kontrolnej:
- Utworzenie nieistniejącego jeszcze pliku wymaga uprawnień do zapisu i wykonywania w katalogu, ponieważ musi zostać do niego dodana nowa nazwa. Twój umask decyduje o uprawnieniach, z jakimi startuje nowy plik.
- Dostęp do pliku wymaga uprawnienia do wykonywania, zwanego również uprawnieniem do przeszukiwania, dla każdego katalogu na ścieżce. Brak tego uprawnienia w jednym katalogu blokuje wszystko, co znajduje się poniżej, a
namei -lwskazuje, w którym miejscu występuje problem. - Zapis z kopiami zapasowymi lub włączoną blokadą plików powoduje utworzenie drugiego pliku obok oryginału, więc te funkcje wymagają katalogu z uprawnieniami do zapisu. Kopie zapasowe to opcja
-Blubset backupw pliku nanorc, a blokowanie to-Glubset locking. Obie funkcje są wyłączone, chyba że zostały aktywowane przez użytkownika lub dystrybucję.
Uprawnienia katalogów mają takie samo znaczenie w innych miejscach systemu. Serwer SSH odrzuca klucz, gdy Twój katalog domowy lub katalog .ssh może być zapisywany przez innych użytkowników, co jest częstą przyczyną odrzucenia klucza przez SSH podczas logowania.
Ponieważ nano zapisuje dane w pliku, który już istnieje, plik zachowuje swój inode, czyli identyfikator na dysku przypisany do danej nazwy. Każdy proces trzymający plik otwarty nadal go śledzi, a pojedynczy plik zamontowany przez bind mount w kontenerze działa poprawnie. Edytory, które zapisują plik poprzez jego zastąpienie, przerywają takie montowanie, ponieważ montowanie śledzi inode, a nie nazwę.
Przyczyna 3: system plików jest w trybie tylko do odczytu lub wyczerpało się miejsce
findmnt raportowanie ro w opcjach oznacza, że operacja zapisu nie mogła się powieść. System plików został zamontowany w ten sposób za pomocą /etc/fstab lub poprzez montowanie typu bind w trybie tylko do odczytu, albo jądro systemu przełączyło go w ten tryb po wystąpieniu błędu dysku. Drugi przypadek jest poważny. sudo dmesg -T | tail -50 pokazuje błędy wejścia/wyjścia oraz błędy systemu plików, które doprowadziły do ponownego montowania; naprawa wymaga sprawdzenia systemu plików po jego odmontowaniu, co w przypadku VPS oznacza uruchomienie konsoli ratunkowej dostawcy.
Pełny system plików uniemożliwia zapis z innego powodu. df -h obejmuje typowy przypadek. df -i dotyczy sytuacji często pomijanej: inody pochodzą ze stałej puli utworzonej podczas formatowania systemu plików, a drzewo bardzo małych plików może wyczerpać ich pulę, podczas gdy df -h nadal wskazuje wolne gigabajty. Gdy miejsce jest zajęte, a nic oczywistego go nie blokuje, rozbieżności między df a du przy pełnym dysku wyjaśnia problem usuniętych, lecz nadal otwartych plików, które zajmują przestrzeń.
Jeden szczegół wyjaśnia mylący objaw w tym przypadku. ext4 rezerwuje część bloków dla użytkownika root podczas tworzenia systemu plików, dzięki czemu root może kontynuować zapis, gdy zwykli użytkownicy otrzymują odmowę. sudo wygląda wtedy na rozwiązanie, jednak dysk zapełnia się do końca, a problem powraca w gorszej formie.
Ponieważ nano skraca plik przed zapisaniem nowej zawartości, operacja zapisu, której zabraknie miejsca w trakcie, może pozostawić plik krótszym niż był pierwotnie. Należy skopiować ważną konfigurację przed edycją na systemie plików, który jest prawie pełny. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak zachowuje właściciela, grupę oraz uprawnienia kopii.
Przyczyna 4: edycja pliku wewnątrz bind mount w kontenerze
Własność plików jest określana numerycznie. Jądro przechowuje identyfikator użytkownika (UID), a wyświetlana nazwa zależy od tego, który plik /etc/passwd wykonuje wyszukiwanie. Dlatego ten sam plik może mieć inną nazwę na hoście, a inną wewnątrz kontenera lub być wyświetlany jako sama liczba. Należy porównywać numery, a nie nazwy: wykonaj id -u wewnątrz kontenera oraz ls -ln dla danego pliku.
Plik zamontowany przez bind mount zachowuje własność z hosta. Gdy plik na hoście należy do Twojego użytkownika, a proces w kontenerze działa jako inny użytkownik, zapis wewnątrz kontenera zostanie odrzucony, a sudo wewnątrz kontenera nie zmieni właściciela na hoście. Rozwiąż ten problem z poziomu hosta, ustawiając właściciela na identyfikator, z którym działa kontener, lub uruchom kontener jako użytkownik, który już posiada te pliki. Obrazy od linuxserver.io i podobne projekty udostępniają zmienne PUID i PGID, które określają, jako który użytkownik działa proces.
Warto znać jeszcze dwa przypadki dotyczące kontenerów. Montowanie w trybie tylko do odczytu za pomocą :ro lub uruchomienie kontenera z flagą --read-only uniemożliwia zapis niezależnie od uprawnień, a cat /proc/mounts wewnątrz kontenera wskazuje na tę flagę. W przypadku rootless Podman, przestrzeń nazw użytkownika (user namespace) mapuje identyfikatory użytkowników kontenera na zakres identyfikatorów hosta, więc plik, który wewnątrz kontenera wygląda na własność root, na zewnątrz należy do Twojego nieuprzywilejowanego konta.
Istnieje również przypadek edycji, która kończy się powodzeniem, a następnie znika. Plik zmieniony wewnątrz kontenera w ścieżce, która nie jest punktem montowania, znajduje się w warstwie zapisu kontenera, a ta warstwa jest usuwana podczas ponownego tworzenia kontenera. Zmień plik po stronie hosta w punkcie montowania lub w procesie budowania obrazu, jeśli zmiana ma być trwała.
Wyjście awaryjne: zapis do własnego katalogu
Nie należy próbować uzyskiwać uprawnień z poziomu edytora. Należy nacisnąć Ctrl-O, wyczyścić ścieżkę w monicie, wpisać ścieżkę wewnątrz katalogu domowego, na przykład /home/you/nginx.conf.new, i nacisnąć Enter. Następnie należy użyć Ctrl-X, aby wyjść. Praca jest teraz zapisana na dysku, należy do użytkownika i reszta operacji to zwykłe kopiowanie plików.
sudo cp /home/you/nginx.conf.new /etc/nginx/nginx.conf
sudo nginx -tW tym miejscu należy użyć cp zamiast mv. cp zapisuje dane bezpośrednio do istniejącego pliku, dzięki czemu zachowuje on swojego właściciela, grupę oraz uprawnienia. mv w obrębie tego samego systemu plików zastępuje plik nowym, co sprawia, że konfiguracja w /etc staje się własnością konta użytkownika, co prowadzi do kolejnego problemu z uprawnieniami, który trzeba rozwiązać.
Przed przeładowaniem jakichkolwiek usług należy sprawdzić wynik za pomocą narzędzia przypisanego do danego pliku. sudo nginx -t analizuje konfigurację Nginx, a sudo sshd -t analizuje konfigurację serwera SSH. Dwa pliki posiadają dedykowane edytory, które wykonują całą tę procedurę automatycznie: sudo visudo dla /etc/sudoers oraz crontab -e dla własnych zadań cron. Każdy z nich edytuje kopię tymczasową, sprawdza składnię i instaluje plik tylko wtedy, gdy analiza przebiegnie pomyślnie.
FAQ
Czy do edycji plików systemowych należy używać sudo nano czy sudoedit?
Należy używać sudoedit. Narzędzie to kopiuje plik do tymczasowej lokalizacji należącej do użytkownika, uruchamia edytor z uprawnieniami bieżącego użytkownika i zapisuje wynik jako root po zamknięciu edytora. Dzięki temu sam edytor nigdy nie posiada uprawnień roota. Należy ustawić SUDO_EDITOR, VISUAL lub EDITOR na nano, aby wybrać nano. sudo nano również działa, jednak nadaje interaktywnemu edytorowi dostęp roota do każdej ścieżki w systemie na czas trwania sesji. W efekcie jedna literówka w nazwie pliku podczas zapisu może doprowadzić do uszkodzenia pliku systemowego.
Czy do zapisu pliku w nano wymagane jest uprawnienie do zapisu w katalogu?
Nie w przypadku pliku, który już istnieje. nano zapisuje dane bezpośrednio w pliku, więc jądro sprawdza bit zapisu dla pliku oraz bit wykonywania dla każdego katalogu w ścieżce. Bit zapisu katalogu jest istotny, gdy plik jeszcze nie istnieje, ponieważ musi zostać utworzona nowa nazwa, oraz gdy włączone są kopie zapasowe lub blokowanie plików, ponieważ obie te funkcje tworzą drugi plik obok oryginału.
Właściciel jest poprawny, a dysk nie jest pełny. Co jeszcze może blokować zapis?
Cztery czynniki. System plików może być zamontowany w trybie tylko do odczytu, co pokazuje findmnt -no OPTIONS -T /etc/nginx/nginx.conf. Plik może posiadać atrybut niezmienności, co pokazuje lsattr, a usuwa sudo chattr -i; przy ustawionym atrybucie nawet root nie może zapisać pliku. Pula i-węzłów (inode) może być wyczerpana mimo dostępnego miejsca na dysku, co pokazuje df -i. SELinux lub AppArmor mogą blokować zapis, nawet jeśli bity uprawnień na to pozwalają; dziennik audytu rejestruje odmowę dla danej ścieżki.
Gdzie umieścić zmiany, jeśli plik w ogóle nie chce się zapisać?
Należy nacisnąć Ctrl-O i podać ścieżkę, do której użytkownik ma uprawnienia, na przykład w katalogu domowym lub innym miejscu z prawem zapisu. Bufor nadal znajduje się w pamięci, więc wpisane dane nie zostaną utracone. Po zapisaniu pliku należy przenieść go w docelowe miejsce za pomocą sudo cp, co zachowa właściciela i uprawnienia oryginalnego pliku, a następnie sprawdzić go za pomocą polecenia testowego danej usługi przed jej przeładowaniem.
Dlaczego edycje wewnątrz kontenera Docker znikają?
Jeśli ścieżka nie jest punktem montowania, edycja trafia do warstwy zapisu kontenera, która jest usuwana przy zastąpieniu kontenera. Plik należy edytować po stronie hosta w ramach bind mount lub wolumenu, albo uwzględnić go w obrazie. Jeśli ścieżka jest punktem bind mount, a zapis jest odrzucany, należy porównać id -u wewnątrz kontenera z numerycznym identyfikatorem właściciela z ls -ln: plik zachowuje uprawnienia z hosta, a proces w kontenerze musi być z nimi zgodny.