- Вопрос или проблема
- Ответ или решение
- 1. Причины возникновения ошибки
- Повреждение файловой системы
- Изменение прав доступа
- Запущенные процессы и блокировки
- 2. Рекомендации по устранению ошибки
- Проверка состояния файловой системы
- Проверка прав доступа к файлам
- Обработка кризисных ситуаций в Python
- 3. Настройка корректного завершения работы демона
- Заключение
Вопрос или проблема
Сегодня в 4:00 утра у меня была отключение электроэнергии.
В 8:00 я подключился к своему Raspberry Pi и снова запустил демон, который в данный момент не запускается автоматически.
sudo systemctl start getdata.service
Демон запустился, но ничего не записывается в журналы, как раньше.
Я остановил демон и запустил этот shell-скрипт вручную.
bernard@raspberrypi:~/p1meter $ sh getdata.sh
/home/bernard/p1meter
ФАЙЛ: ./data/Measures.2024-12-16.csv
Ошибка трассировки (последний вызов последним):
Файл "/home/bernard/p1meter/getdata.py3", строка 155, в <module>
OpenDataFile()
Файл "/home/bernard/p1meter/getdata.py3", строка 94, в OpenDataFile
f = open(sFile, "a")
^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Доступ запрещен: './data/Measures.2024-12-16.csv'
bernard@raspberrypi:~/p1meter $
Я обнаружил, что созданный (добавленный) файл больше не может быть записан!
Поэтому я решил переименовать выходной файл, используя команду mv
.
Когда я снова запускаю свой скрипт вручную, все работает правильно.
Я решил остановить программу и снова запустить ее, используя демон, и теперь все работает правильно.
Вопрос: Что происходит? Почему невозможно записать в этот выходной файл?
Мой используемый код на Python:
def OpenDataFile():
sFileDate = dt.strftime("%Y-%m-%d")
sFile = "./data/Measures." + sFileDate + ".csv"
f = open(sFile, "a")
f.write(sFileDate + ";" + sHeader)
f.write("\r\n")
Shell-скрипт выдает ошибку на строке open()
.
После отключения электроэнергии, что мне нужно сделать перед запуском демона, чтобы избежать проблем с записью файла? Есть ли системная команда для освобождения заблокированного файла?
Дополнительная информация…
Каждый раз, когда я останавливаю и снова запускаю службу, невозможно открыть выходной файл.
В службе выходной файл никогда не закрывается, потому что я записываю в выходной файл бесконечно. Выходной файл закрывается только в 12:00, когда начинается новый день.
Есть ли что-то, что нужно написать в программе Python, чтобы перехватить команду stop
демона для правильного закрытия открытого выходного файла? Нужно ли что-то добавить в конфигурационный файл systemd
?
Ответ или решение
Ответ на вопрос о возникновении ошибки разрешений Python в Linux (Errno 13) после отключения питания
После отключения питания в 4:00 утра и повторного запуска демона на вашем Raspberry Pi в 8:00, вы столкнулись с проблемой разрешений при попытке записи в файл Measures.2024-12-16.csv
. Ошибка, указанная в вашем выводе, PermissionError: [Errno 13] Permission denied
, говорит о том, что процесс не имеет прав на запись в данный файл. Давайте разберемся, почему это могло произойти и как избежать таких проблем в будущем.
1. Причины возникновения ошибки
Повреждение файловой системы
Отключение питания может привести к повреждению файловой системы, особенно если операционная система была записывающей что-либо в это время. Если файловая система была повреждена, это может затруднить доступ к файлам, в том числе и запись в них.
Изменение прав доступа
При перезапуске системы после аварийного завершения работы, права доступа к файлам и каталогам могут измениться. Возможно, файл Measures.2024-12-16.csv
или весь каталог data
стали доступны только для чтения. В результате, любой процесс, пытающийся записать в этот файл, будет получать отказ в доступе.
Запущенные процессы и блокировки
Если ваш демон работает в фоновом режиме и попадает в состояние блокировки, он может не освобождать файл, даже если на него не было записей. При попытке открытии файла из другого процесса может возникнуть ошибка доступа.
2. Рекомендации по устранению ошибки
Проверка состояния файловой системы
После непредвиденного отключения питания выполняйте проверку файловой системы с помощью команды:
sudo fsck /dev/sdXY
где sdXY
— это ваш диск. Это поможет выявить и устранить проблемы, связанные с повреждением.
Проверка прав доступа к файлам
Просмотрите права доступа к файлу и каталогу, где он находится:
ls -l ./data/Measures.2024-12-16.csv
ls -ld ./data
Если файл недоступен для записи, исправьте это с помощью команды:
chmod u+w ./data/Measures.2024-12-16.csv
Обработка кризисных ситуаций в Python
Для обработки исключений при работе с файлами добавьте конструкцию try-except
в вашу функцию:
def OpenDataFile():
sFileDate = dt.strftime("%Y-%m-%d")
sFile = "./data/Measures." + sFileDate + ".csv"
try:
with open(sFile, "a") as f: # Использование контекстного менеджера
f.write(sFileDate + ";" + sHeader)
f.write("\r\n")
except IOError as e:
print(f"Ошибка открытия файла: {e}")
# Дополнительная обработка
3. Настройка корректного завершения работы демона
Для корректного завершения работы и закрытия файлов, вы можете использовать метод signal
в вашем Python-скрипте для обработки сигналов остановки (например, SIGTERM):
import signal
import sys
def signal_handler(sig, frame):
# Закрытие файла считается безопасным
if f: # Предположим, что 'f' — это открытый файл
f.close()
print("Закрытие демона...")
sys.exit(0)
signal.signal(signal.SIGTERM, signal_handler)
Кроме того, в конфигурации вашего systemd-демона можно добавить опции, управляющие завершением работы:
[Service]
Type=simple
ExecStart=/path/to/your/getdata.sh
WorkingDirectory=/home/bernard/p1meter
#...
TimeoutStopSec=10
KillMode=control-group
Таким образом, вы можете избежать повторного возникновения ошибок связанные с аварийным завершением работы и обеспечить плавность операций записи ваших данных.
Заключение
Ваша ситуация была вызвана множеством факторов, связанных с непредвиденным отключением питания. Однако, следуя предоставленным рекомендациям, вы сможете минимизировать риски, а также улучшить обработку ошибок и стабильность работы вашего демона. Не забывайте периодически проверять состояние файловой системы и адаптировать код для корректного завершения работы.