Привет, Хабр! Это Виктор Сергеев, автор команды спецпроектов МТС Диджитал. В детстве я очень любил фантастику и обожал представлять себя в кабине космического корабля с кучей экранов, светящихся индикаторов и переключателей. Рабочее место современного радиолюбителя очень похоже на такой корабль, чему мы обязаны развитию недорогих одноплатников. Они же позволяют создавать портативные, но функциональные устройства, вроде хотспотов MMDVM (Multi-Mode Digital Voice Modem).

MMDVM представляет собой самую обычную «‎малинку» Raspberry Pi Zero W с дополнительной платой (HS shield), на которой реализован радиотракт. В рабочем режиме нагрузка на процессор не слишком велика, а большую часть времени он вообще находится в простое. Именно это обстоятельство позволяет добавить внутрь очень востребованный у радиолюбителей инструмент — HamClock. О нем и расскажу.

Несмотря на то, что MMDVM-хотспот можно с программной точки зрения построить разными способами, большинство радиолюбителей использует готовое решение, которое называется Pi-Star. Это отдельная и сильно доработанная версия Raspbian, предназначенная именно для организации работы хотспота и ни для чего более. Разработчик системы постарался сделать так, чтобы пользователь ничего не мог сломать, и принял целый ряд решений, которые затрудняют запуск стороннего ПО. Но об этом я узнал лишь в процессе настройки.

Начало истории

MMDVM AURSINC (источник изображения)

Все началось с того, что мне такую железку подарили со словами «‎у меня уже есть нормальный DMR-репитер, а эта игрушка более ни к чему». Решив посмотреть, как это работает, я залил на MicroSD-карту образ Pi-Star и подключил хотспот к сети FreeDMR, которая не требует отдельной регистрации. Погонял в паре с DMR-радиостанцией Anytone AT-D878UVII Plus, о которой я уже рассказывал здесь, на Хабре. Все прекрасно «завелось», и MMDVM-хотспот теперь работает в режиме 24/7, обеспечивая меня собственным крошечным цифровым репитером с небольшим радиусом действия.

Однажды, когда я общался со своим знакомым радиолюбителем, речь как раз зашла об MMDVM, и тот у меня поинтересовался, а можно ли как-нибудь установить на эту железку HamClock. Все равно хотспот работает круглосуточно, процессор у него не слишком занят и вполне может потянуть дополнительную нагрузку. Чтобы ответить на этот вопрос, я зашел на девайс по SSH и ввел команду:

$ cat /etc/os-release

PRETTY_NAME="Raspbian GNU/Linux 11 (bullseye)"                                                                  
NAME="Raspbian GNU/Linux"                                                                                       
VERSION_ID="11"                                                                                                 
VERSION="11 (bullseye)"                                                                                         
VERSION_CODENAME=bullseye                                                                                       
ID=raspbian                                                                                                     
ID_LIKE=debian                                                                                                  
HOME_URL="http://www.raspbian.org/"                                                                             
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"                                                            
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

«Обычный Raspbian», — подумал я и без тени сомнения сказал:

— Да, эта штука там точно заработает. Единственный момент: такая малинка не слишком быстрая, поэтому компиляция, вероятно, займет приличное количество времени. Да и само приложение в процессе работы, скорее всего, будет подтормаживать.

— Ну ты можешь это сделать и написать простую инструкцию?

— Без проблем.

Как вы уже можете догадаться, сложностей возникло приличное количество, иначе я бы вряд ли стал писать об этом на Хабр :)

Береги память смолоду

У одноплатных компьютеров вроде «‎малинки» есть особенность: роль накопителя данных в большинстве случаев выполняет MicroSD-карта. Ее устройство достаточно простое: контроллер и микросхема флеш-памяти типа NAND. Несмотря на развитие технологий, физику обмануть невозможно, и чем чаще вы записываете данные в ячейки, тем быстрее они изнашиваются.

Понятное дело, что количество перезаписей будет зависеть от типа памяти. К примеру, ячейка TLC NAND выдержит 1 000 циклов перезаписи, а SLC NAND спокойно переживет и 100 000. Контроллеры, конечно, тоже умные и умеют маскировать проблему, вовремя перенаправляя данные из сбойных ячеек в резервную область. Но и она не бесконечна, а значит, со временем точно так же деградирует, а накопитель выйдет из строя.

У Raspbian (считай, обычного Debian Linux) есть приличное количество способов убить вашу карту памяти. Ведение системного журнала означает, что ОС перманентно будет записывать события на диск. Ротация такого журнала приводит к постоянной перезаписи одних и тех же ячеек, а значит, повышенному их износу.

Раздел подкачки (swap) тоже весьма губительно сказывается на состоянии накопителя. Когда в процессе работы оперативная память исчерпана, система задействует swap в качестве временного хранилища. Это приводит к повышенному износу ячеек и преждевременной гибели карты. Такое случается очень часто, карты памяти могут легко выходить из строя за 2–6 месяцев, потом их нужно менять на новые.

Есть несколько способов продлить жизнь карты памяти. Можно отключить раздел подкачки и ведение логов. Разработчики встраиваемых систем часто применяют методику ReadonlyRoot — она заключается в том, чтобы монтировать большинство системных директорий только для чтения. С одной стороны, это позволяет минимизировать количество записей в ячейки NAND и продлевает им жизнь. А еще можно не беспокоиться о том, что вы выключили устройство, а оно что-либо не успело дописать из кэша на диск.

Именно этот прием был использован при создании Pi-Star, это звучит очень разумно и логично. С одной стороны, система не станет требовать частой замены SD-карты и спокойно справится с нештатным отключением хотспота. Но вот с другой стороны, чтобы внести любые изменения в систему, потребуется перемонтировать ФС для записи. Привычные приемы автозапуска скриптов и приложений могут вести себя иначе. Но это все в теории, а значит, пора переходить к практике.

Установка HamClock

Нельзя сказать, что она отличается какой-либо сложностью. Авторы создали удобный скрипт, который самостоятельно сделает все за пользователя. Он рассчитан на работу с Raspberry Pi, поэтому учитывает особенности архитектуры. По умолчанию в Pi-Star предусмотрена команда, которая позволяет пользователю перемонтировать корневой каталог на чтение и запись. Выполним ее перед скачиванием скрипта:

$ rpi-rw

Скачиваем скрипт при помощи curl:

$ curl -O https://www.clearskyinstitute.com/ham/HamClock/install-hc-rpi

Сделаем его исполняемым, одновременно игнорируя umask:

$ chmod u+x install-hc-rpi

Запускаем установку. Указываем, что хотим скомпилировать исключительно web-версию, выбираем желаемое разрешение экрана и можем спокойно идти готовить кофе или заниматься другими полезными делами. В ближайшие 30 минут «малинка» займется компиляцией HamClock, написанном на C++:

$ ./install-hc-rpi

После того как все установлено и скомпилировано, скрипт предложит прописать его в автозагрузку при помощи crontab. Соглашаемся, но, забегая вперед, скажу: автостарт не сработает по причине того, что HamClock при запуске попробует записать несколько файлов в директорию /home/pi-star/.hamclock и у него ничего не получится. Переходим к следующему этапу.

Жонглирование разделами

Как только вы записали образ Pi-Star на карту памяти, она занимает совсем немного места. Но при первом запуске система автоматически увеличивает раздел так, чтобы он занял все свободное пространство на диске. В итоге получается два каталога: на одном /boot, а второй будет корневым /. Оба они монтируются в /etc/fstab как ReadOnly, и это не дает возможности писать на них.

Есть немного костыльный, но рабочий способ. Например, уменьшить объем корневого раздела, а на освободившемся месте сделать еще один, который уже можно монтировать для чтения и записи. Если перенести на него директорию пользователя /home/pi-star, то это решит сразу все проблемы с невозможностью записи.

Сложность вышеуказанного метода лишь в том, что эту операцию не получится выполнить на смонтированном разделе. А поскольку он корневой, то реализовать это непосредственно из операционной системы не выйдет. А еще это Raspberry Pi, варианта загрузиться с LiveCD у нас тоже нет. Так что для успешного выполнения следующих операций потребуется отдельный компьютер с Linux. В моем случае я извлек MicroSD-карту из MMDVM и вставил ее в USB-картридер. Тот, в свою очередь, подключил к ноутбуку с установленной Ubuntu.

Первым делом я посмотрел на то, какие устройства присутствуют в системе. Вставленная карта памяти определилась как /dev/sdb. Давайте глянем на то, какие разделы у нас есть:

$ sudo fdisk -l

Disk /dev/sdb: 29.81 GiB, 32010928128 bytes, 62521344 sectors
Disk model:  USB CARD READER
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc958b717

Device     Boot  Start      End  Sectors  Size Id Type
/dev/sdb1         8192   532479   524288  256M  c W95 FAT32 (LBA)
/dev/sdb2       532480 62521343 61988864 29.6G 83 Linux

Видно, что корневой раздел занимает 29,6 Гб, начало находится с блока 532480. Запоминаем это значение. Перед тем как изменять размер, нужно в обязательном порядке выполнить проверку ФС на проблемы:

$ sudo e2fsck -f /dev/sdb2

Все прошло хорошо, ошибок нет. Приступаем к изменению размера ФС. Пусть корневой раздел составляет 28 Гб, а оставшиеся 1,6 Гб используем для домашнего каталога:

$ sudo resize2fs /dev/sdb2 -s 28G

После того как размер файловой системы поменялся, нужно модифицировать объем раздела. Вводим команду:

$ sudo fdisk /dev/sdb

В fdisk нет возможности указать уменьшение объема каталога. Но его можно удалить и создать заново. Для этого нужно нажать клавишу d и подтвердить удаление раздела 2 (/dev/sdb2). Появится вопрос — убрать ли метку ext4. Отвечаем отрицательно, ее нужно оставить.

После удаления раздела нажимаем n для создания нового. Тип — Primary, ну а значение стартового блока — 532480. Вместо финального значения пишем +28G и подтверждаем нажатием Enter. В итоге появится /dev/sdb2 с объемом 28 Гб. На диске останется 1,6 Гб нераспределенного пространства.

Создаем еще один раздел через нажатие n. Тип также выбираем Primary. Начальное и конечное значение блоков утилита подставит сама. В итоге мы получаем третий раздел /dev/sdb3 размером 1,6 Гб. Останется только нажать клавишу w и подтвердить с помощью Enter. Это действие запишет изменения на диск.

Проверяем:

$ sudo fdisk -l

Disk /dev/sdb: 29.81 GiB, 32010928128 bytes, 62521344 sectors
Disk model:  USB CARD READER
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc958b717

Device     Boot    Start      End  Sectors  Size Id Type
/dev/sdb1           8192   532479   524288  256M  c W95 FAT32 (LBA)
/dev/sdb2         532480 59252735 58720256   28G 83 Linux
/dev/sdb3       59252736 62521343  3268608  1.6G 83 Linux

Теперь нужно создать на новом разделе файловую систему:

$ sudo mkfs.ext4 /dev/sdb3

mke2fs 1.46.5 (30-Dec-2021)
Creating filesystem with 408576 4k blocks and 102336 inodes
Filesystem UUID: dc371ae8-868f-4059-a289-a76593efd0d0
Superblock backups stored on blocks:
       32768, 98304, 163840, 229376, 294912

Allocating group tables: done                           
Writing inode tables: done                           
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

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

$ sync

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

Монтирование пользовательского каталога

Поскольку мы переставили накопитель в другое устройство, его наименование изменилось. Теперь это не /dev/sdb, а /dev/mmcblk0 с тремя разделами:

  • /dev/mmcblk0p1 — /boot;

  • /dev/mmcblk0p2 — /;

  • /dev/mmcblk0p3 — unmounted.

В домашнем каталоге пользователя pi-star уже есть некоторое количество файлов и директорий, так что сначала нужно будет их перенести. Для этого нам нужно смонтировать /dev/mmcblk0p3 в любой временный каталог.

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

$ rpi-rw

Создаем временную директорию в /mnt:

$ sudo mkdir /mnt/ext

Монтируем новый раздел в этот каталог:

$ sudo mount /dev/mmcblk0p3 /mnt/ext

Убеждаемся в том, что все получилось:

$ sudo df -h

Filesystem      Size  Used Avail Use% Mounted on
/dev/root       2.9G  2.1G  709M  75% /
devtmpfs        111M     0  111M   0% /dev
tmpfs           239M     0  239M   0% /dev/shm
tmpfs            32M  5.2M   27M  17% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            64M     0   64M   0% /tmp
tmpfs           1.0M   32K  992K   4% /var/cache/samba
tmpfs            32K   16K   16K  50% /var/lib/dhcpcd
tmpfs            16K     0   16K   0% /var/lib/logrotate
tmpfs           1.0M     0  1.0M   0% /var/lib/nginx/body
tmpfs            64K     0   64K   0% /var/lib/php/sessions
tmpfs           4.0M  2.2M  1.9M  54% /var/lib/samba/private
tmpfs            16K     0   16K   0% /var/lib/sudo
tmpfs            64M  288K   64M   1% /var/log
/dev/mmcblk0p1  256M   49M  207M  20% /boot
tmpfs            48M     0   48M   0% /run/user/1000
/dev/mmcblk0p3  1.5G   24K  1.5G   1% /mnt/ext

Теперь нужно сделать пользователя pi-star владельцем этого каталога, чтобы тот получил возможность записывать туда данные:

$ sudo chown -R pi-star:pi-star /mnt/ext

Синхронизируем содержимое домашнего каталога с этой директорией при помощи rsync:

$ sudo rsync -a /home/pi-star /mnt/ext

Теперь все готово к тому, чтобы монтировать раздел /dev/mmcblk0p3 в качестве /home/pi-star. Открываем fstab:

$ sudo nano /etc/fstab

Вносим туда строчку:

/dev/mmcblk0p3      /home/pi-star   ext4    defaults,rw     0   0

Сохраняем, нажав Ctrl + O, потом выходим с помощью Ctrl + X. Отправляем MMDVM в перезагрузку:

$ sudo reboot

Если все сделано правильно, через пару минут можно вновь подключиться по SSH и убедиться в том, что каталог успешно смонтирован:

$ df -h

Filesystem      Size  Used Avail Use% Mounted on
/dev/root       2.9G  2.1G  709M  75% /
devtmpfs        111M     0  111M   0% /dev
tmpfs           239M     0  239M   0% /dev/shm
tmpfs            32M  5.2M   27M  17% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            64M     0   64M   0% /tmp
tmpfs           1.0M   32K  992K   4% /var/cache/samba
tmpfs            32K   16K   16K  50% /var/lib/dhcpcd
tmpfs            16K     0   16K   0% /var/lib/logrotate
tmpfs           1.0M     0  1.0M   0% /var/lib/nginx/body
tmpfs            64K     0   64K   0% /var/lib/php/sessions
tmpfs           4.0M  2.2M  1.9M  54% /var/lib/samba/private
tmpfs            16K     0   16K   0% /var/lib/sudo
tmpfs            64M  276K   64M   1% /var/log
/dev/mmcblk0p3  1.5G   31M  1.4G   3% /home/pi-star
/dev/mmcblk0p1  256M   49M  207M  20% /boot
tmpfs            48M     0   48M   0% /run/user/1000

Если откроете утилиту top, то увидите, что в списке процессов появился hamclock. Получается, что автозапуск через crontab успешно сработал и все уже функционирует. Но если вы попытаетесь открыть браузер и зайти по адресу приложения, вас ждет неудача:

http://[IP-адрес_MMDVM]:8081/live.html

Соединение не устанавливается, и причина этому в том, что нет соответствующего правила в iptables. Если вы пропишете его руками, оно будет работать исключительно до перезагрузки. Утилиты вроде iptables-persistent в случае с Pi-Star бесполезны. Все дело в том, что у Pi-Star собственное управление файерволом и именно оно контролирует все правила iptables.

Так что делаем так. Переключаемся в консоль суперпользователя:

$ sudo su

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

# rpi-rw

Создаем новый файл ipv4.fw в каталоге /root:

# nano /root/ipv4.fw

Пишем туда правило iptables:

iptables -I INPUT -p tcp --dport 8081 -j ACCEPT

Сохраняем при помощи Ctrl + O и выходим из редактора Ctrl + X. Остается самая важная часть — вызвать специальный скрипт, который перечитает все действующие правила iptables, обнаружит новое и активирует его:

# pistar-firewall

Отправляем MMDVM на перезагрузку:

# reboot

Через пару минут открываем браузер и наслаждаемся рабочим приложением HamClock:

Что в итоге

Pi-Star — отличный дистрибутив, который хорошо делает свое дело. Но вот если вы захотите установить на него что-то дополнительно, то, вероятнее всего, столкнетесь с трудностями. Основной, разумеется, будет корневая файловая система, смонтированная только для чтения.

Это решение показалось мне самым функциональным. Оно сохраняет возможность работы корневой ФС в том самом режиме ReadOnly, который был предусмотрен автором Pi-Star. При этом есть директория, которая будет всегда доступна для чтения и записи, а значит, сможет выполнять роль хранилища для различных приложений, включая HamClock.

Расскажите о своем опыте общения с устройствами, чья корневая файловая система была смонтирована в режиме ReadOnly? Как вы решали вопрос с автозапуском скриптов и приложений, хранением файлов? Жду в комментариях.

Комментарии (3)


  1. nitro80
    14.11.2024 06:58

    Неплохо бы в статье вообще рассказать, что это за hamclock такой


    1. NutsUnderline
      14.11.2024 06:58

      +1. скриншот должен быть во введении, а лучше -в КДПВ. Да и про MMDVM  несколько куценько: для людей в теме - много, для совсем не в теме - мало


  1. Grommy
    14.11.2024 06:58

    Спасибо, интересно, и нестандартный взгляд на привычную малинку!:))

    73!