Аннотация
Запуск Raspberry Pi с полной поддержкой графики на microSD, навсегда остающейся в режиме read-only после установки системы. Отсутствие какой-либо записи данных на флэш-память повышает надёжность устройства, приближая его к промышленному классу изделий. Пошаговая инструкция. Небольшой театр инженерного абсурда для развлечения аудитории.
Мне понадобилось сетевое устройство с открытым кодом и выходом HDMI, и я решил попробовать Малиновый Прог. Да, я именно так предлагаю переводить Pi: Прог. Понятное дело, даже одноплатнику нужна операционка. И вот, захожу я на официальный сайт, ожидая встретить там подробное руководство по созданию суровой, неломаемой Вещи à la turnkey box. Но народ, как ни в чём не бывало, устанавливает Ubuntu (т.е. Raspbian Jessie) прямо на microSD, размещая и swap там же. Как обычный десктоп, face palm.
Но то цветочки. Малиновые ягодки — это проекты фоторамок из МалинПрога, требующие обязательного выключения кнопкой. Иначе фоторамка после сбоя питания может не заработать, вместо картинок предлагая воспользоваться fsck. Но и это не предел, под катом читателя ждёт настоящий шедевр инженерного абсурда, найденный автором на просторах сети.
Итак, по стандартной инструкции нормальный одноплатник превращается в раздутый десктоп со средним временем жизни год-полтора, пока изношенная флэшка не сдохнет, превратив в общем-то хороший девайс в кирпич. И большинство людей, похоже, это вполне устраивает. Меня — нет.
Куда мир катится
Прежде чем открывать спойлер, оденьте защитную маску, либо заранее возьмитесь руками за голову.
Ладно, не буду отрицать самостоятельной полезности аппаратного взбадривателя: это реальный лайф-хак для тех, у кого почасовая оплата идёт за сидение перед монитором. Или для поддержания в тонусе какого-нибудь особо тупого сурового промышленного терминала, из-под антивандальной брони которого торчит один разъём для мыши (для PS/2 должен подойти зелёный переходник). Да, если втиснуть раздутый десктоп в одноплатный компьютер, то в руках über-умельцев это грозное оружие, особенно с брутально торчащей из разъёма платой МК. Сразу видно: человек умеет работать руками. Но если нужен вечно включённый экран, на линуксе достаточно головы, резиденты данного ресурса прекрасно это знают. Для гостей портала я всё-таки дам инструкцию, мало ли чего.
/etc/lightdm/lightdm.conf
:
...
xserver-command=X -s 0 -dpms -nocursor
...
Флажок -nocursor
убирает долой из центра экрана неподвижную стрелку курсора. А вместо нейтрализации скринсейвера можно просто закомментировать его запуск в файле ~/.config/lxsession/LXDE/autostart
. Если это не помогает, можно повесить по cron(8)
с интервалом 718 минут команду xscreensaver-command -deactivate
.
Я поступил просто: принял LightDM с автовходом, но оставил в файле ~/.config/lxsession/LXDE/autostart
лишь вызов feh с префиксом '@' для перезапуска в случае аварии и соотв. параметрами. Т.е. как бы обычная графика, но без lxpanel
, без pcmanfm
, без xscreensaver
, с отключённым DPMS и скрытым курсором несуществующей мыши.
Минимальную графику очень легко получить командами apt-get
и правкой файла autostart
, причём в системе будет всё необходимое для жизнедеятельности стандартных приложений, включая X-сервер, менеджер окон, менеджер сеансов и менеджер дисплея с автовходом пользователя. Но пока это ещё не Вещь, а всего лишь одноплатный десктоп.
Задача
Сферический одноплатник в вакууме — это скучно. Не для того на Малиновом Проге целая гребёнка GPIO с I2C/PWM, а также всякие CSI-DSI и сторожевой таймер. Но я в качестве практического примера использую всё-таки сетевой демонстратор с HDMI-выходом, добавив возможность нескольким пользователям по очереди «захватывать» общий экран-табло и транслировать на него свой рабочий стол, не вставая с кресла. Экран повёрнут лицом в сторону гостей, в состоянии покоя тихонечко перебирает случайным образом картинки, выложенные в сети. Если надо показать гостю продукт, один из сидящих за стойкой администраторов временно превращает табло в «зеркало» своего монитора, но потом освобождает его для другого админинистратора. В моём случае это реальный бизнес-инструмент, висящий в реальном торговом зале. Кстати, благодарю пользователя Sauron за подсказку.
Однако, глянув на размер этой публикации, я решил отложить описание прикладного решения (т.е. собственно видеомодуля) в отдельную статью. Пока позвольте сфокусироваться на изначальной задаче: заставить Raspberry Pi загружаться и работать с microSD в режиме read-only, не боясь отключения питания и не запиливая флэш-память мусором.
Теория вопроса
Даже очень серьёзная файловая система с журналом в конечном итоге не может проконтролировать процессы, происходящие внутри SD-носителя при отключении питания. Например, серьёзные SSD-накопители для использования в ЦОД имеют конденсаторы, разряда которых как раз хватает на закрытие последней транзакции записи, и даже остаётся ещё немного. А что с отключением питания в microSD? Я уверен, там конденсаторов достаточной ёмкости нет, зато есть ненулевая вероятность того, что запись страницы NAND-памяти не успеет завершиться. И потом драйвер файловой системы от прочитанного придёт в такое недоумение, что потребуется ручное вмешательство оператора. Вот вам и фоторамка с fsck.
Насколько сложно перевести microSD Raspberry Pi в режим read-only методом Микеланджело, т.е. убирая лишние службы и пакеты? Достаточно просто, если нет графики (ссылка). Но стоит пустить в систему иксы с этими их многочисленными менеджерами всего, начинается долгий и нудный поединок с непредсказуемым результатом. Это вам не иголка в стоге сена, её хотя бы магнитом можно вытянуть. Представьте, что неизвестное количество иголок спрятаны в клубке из колючей проволоки, да ещё обильно присыпаны гвоздями. Какой там поиск иголок, не убиться бы насмерть.
Лемма: для выполнения даже самой элементарной новой функции линукс-система всегда подтянет кучу ненужных зависимостей, причём даже с «лёгкой» графикой рост системной энтропии получается кратный.
Теорема: в любом конечном наборе программных пакетов всегда найдётся бесконечно малый кусок кода, который попытается записать один бесконечно бесполезный бит на файловую систему, смонтированную в read-only, чем вызовет фатальную ошибку, повалит всю систему и перечеркнёт многочасовые усилия оператора.
Решение: UnionFS
Один немец несколько лет назад придумал очень красивый способ собрать все эти иголки в корыто с помощью UnionFS и просто сжигать их в печи при каждой перезагрузке. К сожалению, оригинальный пост уже погиб вместе с хостившим его доменом, но немец точно не одинок. Благодарные читатели сохранили идею, я считаю просто необходимым опубликовать её здесь.
Суть в том, что поверх постоянной «подложки» (read-only файловой системы на microSD) при каждом включении создаётся временная «нашлёпка» в ОЗУ, поглощающая всю ненужную энтропию и «сгорающая» при выключении питания устройства. Файловая система на microSD всё время остаётся read-only, и потому риск её повреждения снижается почти до нуля, как и риск преждевременного износа флэшки. Почему не строго до нуля? Знатоки EXT4, поправьте меня, но драйвер файловой системы всё-таки что-то записывает на носитель при каждом монтировании-демонтировании файловой системы, даже если она монтируется в read-only. И noatime
не поможет.
Недостатки
Какие минусы, помимо «сгорания» логов? Устройства без аппаратных часов при старте всегда считают, что на дворе 1 января 1970 года, и пребывают в этом заблуждении вплоть до подъёма сетевого стэка и доступности NTP. Поэтому на момент данной публикации целый ряд файловых объектов «нашлёпки» будут примерно на 46 лет моложе, чем им кажется. С другой стороны, несколько секунд от начала эпохи — уже не ноль.
Обновления безопасности накатывать на такую систему довольно неудобно. Но, опять же, взломать такую Вещь несколько сложнее, чем эксплуатировать уязвимость Adobe Flash в браузере обычного десктопа.
Пошаговая инструкция
Поскольку я впервые в жизни установил Rasbian Jessie и особо не верю в долговечность microSD даже в read-only, то решил записать все шаги подробно. Вдруг понадобится повторить.
DISCLAIMER
Извините за переносы строк. Все команды запускаются с правами
root
, но аккуратный читатель может использовать каждый разsudo
. Честно говоря, я не понимаю, зачем каждую команду запускать черезsudo
, будто это защитит от чего-то. Вот скажите, когда вы в последний раз *не были* уверены, что хотите удалить данный файл в корзину? Это как выпить пять бокалов пива по пол-литра, но на дорожку ещё налейте один 0.33, пожалуйста, а то мне уже хватит… Я дам неправильный совет: если уж взялись за эти игрушки, выходите наroot
командойsudo bash
, не занимайтесь самообманом.
1. Инициализация
Установите Raspbian Jessie Lite. Утилитой raspi-config
задайте региональные настройки и пароль пользователя pi
. Подключите сеть, Debian — дитя широкополосного доступа. Загрузку в графику пока не включайте.
apt-key update
apt-get update
2. Установка и удаление программ
С графикой, установка:
apt-get install --no-install-recommends tightvncserver xtightvncviewer xserver-xorg xinit lxde-core lxappearance lightdm feh xprintidle policykit-1 busybox-syslogd ntpdate watchdog unionfs-fuse
Удаление:
dpkg --purge rsyslog
apt-get remove --purge wolfram-engine triggerhappy cron anacron logrotate dphys-swapfile fake-hwclock
apt-get autoremove --purge
Пакеты tightvncserver, xtightvncviewer, xprintidle и feh
понадобились мне для частной задачи, можете обойтись без них.
Если без графики, вам *не* понадобятся также: xserver-xorg xinit lxde-core lxappearance lightdm policykit-1
.
3. Создание графического окружения
Теперь утилитой raspi-config
можно включить автозапуск в графическом режиме с автовходом, который будет с правами пользователя pi
. Чем зацикливаться на sudo
, лучше поставить сильный пароль пользователю pi
, и не использовать pi
для автоматического входа в графический интерфейс. Вместо этого создать пользователя pu
и запускать «иксы» с его правами. Причём командный интерпретатор (default shell) этого пользователя лучше либо отключить совсем (поставив /usr/sbin/nologin
), либо подменить специальным скриптом типа /usr/local/bin/pu
. Об этом я намерен рассказать в другой публикации, посвящённой видеотабло с удалённым управлением по SSH, ради чего и создаётся отдельная учётная запись с пониженными правами. Ещё раз благодарю Sauron et al.
adduser --home /home/pu --shell /usr/local/bin/pu --uid 990 --gecos "RPi p-u" --gid 1000 pu
mkdir -p /home/pu/.config/lxsession/LXDE
cp -p /etc/xdg/lxsession/LXDE/desktop.conf /home/pu/.config/lxsession/LXDE/desktop.conf
touch /home/pu/.config/lxsession/LXDE/autostart
chown -R pu:pi /home/pu
sed -i 's/^#?xserver-command=.*$/xserver-command=X -s 0 -dpms -nocursor/' /etc/lightdm/lightdm.conf
sed -i 's/^#?autologin-user=.*$/autologin-user=pu/' /etc/lightdm/lightdm.conf
Вместо двух последних команд можете открыть редактором /etc/lightdm/lightdm.conf
и задать значения двух параметров, первый я уже упоминал выше, второй говорит сам за себя:
...
xserver-command=X -s 0 -dpms -nocursor
...
autologin-user=pu
...
4. Сторожевой таймер (по желанию)
У меня Raspberry Pi 3 Model B, поэтому ядерный модуль сторожевого таймера зовут так:
modprobe bcm2835_wdt
echo "bcm2835_wdt " | sudo tee -a /etc/modules
Затем добавляем следующую строку в секцию [Install]
в конце файла /lib/systemd/system/watchdog.service
:
[Install]
WantedBy=multi-user.target
После этого включаем службу:
systemctl enable watchdog.service
Сторожевой таймер в минимальной конфигурации должен сработать, если зависло ядро. Но есть ещё много других вариантов, например, по чрезмерной нагрузке на систему, по истечению памяти, по перегреву системы, по отсутствию сигнального файла и т.д. См. также watchdog(8)
и watchdog.conf(5)
5. Параметры старта
Я отключил отображение малинового лого и swap-файл, включил быструю загрузку. Для этого добавил в /boot/cmdline.txt
буквально три слова logo.nologo fastboot noswap
. У меня в итоге получилось так:
logo.nologo dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait fastboot noswap
6. Запечатывание корневой файловой системы Raspberry Pi в read-only
Вот теперь мы добрались, наконец, до главного.
Ниже скрипт, который следует расположить под именем mount_unionfs
где-нибудь в /usr/local/bin
. Не забудьте включить биты выполнимости +x (chmod
755 или 555). Обратите внимание на суффиксы .orig
и .rw
, они должны совпадать с подготовкой (далее):
#!/bin/sh
DIR=$1
ROOT_MOUNT=$(awk '$2=="/" {print substr($4,1,2)}' < /etc/fstab)
if [ $ROOT_MOUNT = "rw" ]; then
/bin/mount --bind ${DIR}.orig ${DIR}
else
/bin/mount -t tmpfs ramdisk ${DIR}.rw
/usr/bin/unionfs-fuse -o cow,allow_other,suid,dev,nonempty ${DIR}.rw=RW:${DIR}.orig=RO ${DIR}
fi
Из других инструкций я решил воспользоваться советом и сделать следующее:
insserv -r bootlogs
insserv -r alsa-utils
rm -rf /var/lib/dhcp/
ln -s /tmp /var/lib/dhcp
Графические приложения очень любят записывать в /home
что-нибудь ненужное, поэтому в дополнение к /etc
и /var
я включил ещё и /home
. Подготовим разделы к переключению в режим UnionFS (внимание на суффиксы .orig
и .rw
):
cp -al /etc /etc.orig
mv /var /var.orig
mv /home /home.orig
mkdir /etc.rw /var /var.rw /home /home.rw
Наконец, файл fstab(5)
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat ro 0 2
/dev/mmcblk0p2 / ext4 ro 0 1
mount_unionfs /etc fuse defaults 0 0
mount_unionfs /var fuse defaults 0 0
mount_unionfs /home fuse defaults 0 0
none /tmp tmpfs defaults 0 0
7. Аудит системы и тест
Окиньте взглядом систему, уберите за собой .bash_history
, всякие лог-файлы и т.д. Учтите, что они сейчас могут находиться не там, где обычно (например, в /var.orig
вместо var
).
Перезагрузите систему и посмотрите, что получилось. Если была допущена ошибка, есть большие шансы, что система уйдёт в single user и просто запустит консоль root
. Если файловая система цела, перемонтировать её из read-only в read-write довольно просто:
mount -o rw,remount /
Если же система загрузилась нормально в read-only и выполняет все функции, поздравляю!
Это родилась Интернет-Вещь.
8. Распечатывание файловой системы
Если нужно распечатать систему, сперва верните коневую систему в состояние read-write (см. выше). Затем закомментируйте в fstab(5)
строки, начинающиеся со слова mount_unionfs
, после чего *обязательно* верните на место каталог /var.orig
со всем содержимым (и желательно /home.orig
тоже). Если не восстановить /var
, потеряете базу установленных пакетов, но ведь именно ради установки обновлений безопасности командой apt-get
вы только что распечатали систему, не так ли? Перед apt-get
перезагрузите систему и убедитесь в её адекватности. Как запечатывать обратно, знаете;)
Альтернативы
Уважаемых читателей, которые знают готовые промышленные образы операционных систем (с поддержкой read-only) для Raspberry Pi и других одноплатных компьютеров, приглашаю делиться в комментариях. Надеюсь, с вашей помощью я смогу информационно обогатить этот раздел и других читаталей, резидентов и гостей уважаемого портала Geektimes:)
Что касается аппаратных альтернатив самому Малиновому Прогу в контексте прикладной задачи (сетевой HDMI-свисток), то я случайно наткнулся на один обзор, который, впрочем, намерен обсудить отдельно. Чисто экономически Raspberry Pi весьма выгоден, это пока главное:)
Ссылки
Make Raspbian System Read-Only
blog.pi3g.com/2014/04/make-raspbian-system-read-onlyHow to make RaspberryPi truly read-only, reliable and trouble-free
k3a.me/how-to-make-raspberrypi-truly-read-only-reliable-and-trouble-freeStopping SD Card Corruption on Raspberry Pi’s Raspbian
ideaheap.com/2013/07/stopping-sd-card-corruption-on-a-raspberry-piRaspberry Pi как информационное табло — с помощью VNC на localhost
habrahabr.ru/post/212661*Easy Raspberry Pi Based Screensaver/Slideshow for Exhibitions/Store Front
www.instructables.com/id/Easy-Raspberry-Pi-Based-ScreensaverSlideshow-for-E
*у меня вызвал искреннее недоумение шаг 6ECIO(TM), a powerful USB programmable single chip computer based on PICmicro microcontroller technology
www.matrixtsl.com/product.php?Prod=ECIO28P
Автор: teleghost