Широко известный в узких кругах легковесный менеджер пакетов opkg получил распространение в embedded Linux не случайно. Opkg используется во многих встраиваемых дистрибутивах и проектах, например, в OpenEmbedded, Yocto Project, OpenWRT, Ångström, Arago Project и некоторых других. Менеджер прост в эксплуатации, для полноценной работы вполне достаточно встроенной справки, а на просторах всемирной паутины множество статей о том, как устроен сам пакет ipk (opkg работает с таким форматом): как его создать, как установить и т.д и т.п. Однако подавляющее большинство информации посвящено тому, как работать на уже установленной на целевую платформу (target) системе в online-режиме, но специфика Embedded подразумевает, что образ корневой файловой системы, а также ядро готовятся заранее на некоторой инструментальной платформе (host), отличной от целевой. Иными словами, собираем ядро и файловую систему на рабочем компьютере, упаковываем в образ, образ тиражируем на железо. Эта статья посвящена тому, как с помощью менеджера opkg установить пакеты в подготавливаемый образ rootfs.
Путь граблей и велосипедов
Много лет назад в бытность инженера одного небольшого завода, когда я запустил Linux на первой платке собственного производства, с помощью opkg установил из удаленного репозитория все требуемые пакеты, настроил все приложения, начальник лаборатории сказал: "Отлично! Теперь сделай то же самое на всех устройствах в партии". "Да не вопрос!" – ответил я. Система же есть, она запущена, она работает. Копируем все файлы из корня на внешний носитель, затем упаковываем в образ и радуемся жизни! В то время я не понимал, что при работе операционная система выполняет ряд локальных настроек, создает временные файлы, файлы конфигурации, генерирует какие-то ключи, а при первом запуске выполняет еще и скрипты инициализации. Хотя перенос файлов с одной работающей системы на другую методом тупого копирования с носителя и давал результат, но эффективность данного метода очень скоро для меня стала сомнительной. Получить "чистую" систему таким образом невозможно: система помнит свою предыдущую жизнь в другом аппаратном теле, и время от времени ее душат фантомные боли.
Следующим шагом для меня стало понимание структуры самого покета *.ipk. По сути вещей, пакет ipk является архивом, распаковать который можно легко с помощью команды:
ar -x *.ipk
В результате получим:
.
├── control.tar.gz
├── data.tar.gz
└── debian-binary
В архиве data.tar.gz содержатся файлы, которые должны быть помещены в корневую директорию target'а.
В архиве control.tar.gz содержатся служебные файлы: файл с описанием и скрипты. Идея простая: так как ipk – это всего лишь архив со скриптами, то мы можем всегда руками распаковать его в директорию с файловой системой, а потом запустить (если есть в этом необходимость) скрипты. Вот только все зависимости пакета нам придется устанавливать также вручную.
А если зависимости имеют еще зависимости? Возникает идея, может быть написать скрипт для автоматизации процесса? Как это часто бывает в мире linux, если перед тобой возникла задача, то, скорее всего, такая задача возникла не перед тобой одним, и, скорее всего, ты в этом деле не первый.
Далеко ходить не пришлось, на самом деле в сам менеджер пакетов opkg заложен такой режим, когда пакеты устанавливаются в неактивную файловую систему rootfs. При этом, архитектура host-машины (где запускаются утилиты opkg) и target-машины могут быть отличными. Такой режим называется Offline mode. В таком режиме opkg становится мощнейшим инструментом кросс-разработки.
Собираем opkg для host
Для работы в режиме Offline opkg должен запускаться на host'е. С давних пор на моем рабочем компьютере обосновалась Ubuntu (сейчас стоит Ubuntu 14.04 LTS), на ней и будем строить наш инструментарий. Мне не удалось найти репозиторий с opkg для Ubuntu, потому собираем набор утилит из исходников.
Получить исходные коды можно с git репозитория Yocto Project:
git clone git://git.yoctoproject.org/opkg.git
cd opkg
tar xzf opkg-0.3.1.tar.gz
cd opkg-0.3.1/
На самом деле настройка и компиляция проекта выполняется достаточно стандартным способом, но есть некоторые нюансы, и потому все по порядку.
Запускаем:
./autogen.sh
На заметку: если запустить ./autogen.sh
с параметром --clean
, то удалятся все труды по конфигурации проекта.
После выполнения ./autogen.sh
в директории с исходниками появляется скрипт configure
, он выполнит настройку пакета, определит и задаст системозависимые переменные. В результате работы скрипта создается Makefile. Посмотреть все опции скрипта можно стандартным способом:
./configure --help
Собирать пакет будем под текущую платформу, потому опции настройки кросс-компиляции пропускаем. Озаботимся инсталляцией. По умолчанию, выполнив make install
, скрипт раскидает все полезные файлы (бинарники, скрипты, документация) по корневой директории: /etc
, /usr/local
, а это нам совершенно ни к чему. Мы ведь не собираемся использовать opkg для настройки пакетов в текущей системе? Кроме того, установив менеджер в системные папки, для использования утилит потребуются права суперпользователя, на мой взгляд, это излишне при настройке образа embedded linux. Скрипт configure.sh
позволяет задать префикс для директории установки пакета. Указав в качестве префикса любую рабочую директорию, мы сообщим инсталлятору куда ставить пакет. При необходимости можно отдельно задать префикс для архитектурозависимых (бинарники и библиотеки) и архитектуронезависимых (скрипты и документация) файлов.
С фантазией у меня всегда было слабовато, потому для инсталляции в домашнем каталоге создадим каталог opkg_offline.
mkdir ${HOME}/opkg_offline
Выполним конфигурацию:
./configure --prefix=${HOME}/opkg_offline
При необходимости доставляем требуемые зависимости. Так мне на Ubuntu 14.04 для успешной сборки понадобилось доставить libarchive-dev
, libcurl4-gnutls-dev
, libssl-dev
, libgpgme11-dev
.
sudo apt-get install libarchive-dev
sudo apt-get install libcurl4-gnutls-dev
sudo apt-get install libssl-dev
sudo apt-get install libgpgme11-dev
Компилируем и устанавливаем opkg:
make
make install
opkg_offline
├── bin
│ ├── opkg
│ ├── opkg-check-config
│ └── opkg-key
├── lib
│ ├── libopkg.a
│ ├── libopkg.la
│ ├── libopkg.so -> libopkg.so.1.0.0
│ ├── libopkg.so.1 -> libopkg.so.1.0.0
│ ├── libopkg.so.1.0.0
│ └── pkgconfig
│ └── libopkg.pc
└── share
├── man
│ └── man1
│ ├── opkg.1
│ └── opkg-key.1
└── opkg
└── intercept
├── depmod
├── ldconfig
└── update-modules
Менеджер пакетов собран и установлен. Исполняемые файлы находятся в директории opkg_offline/bin. Для работы с ними можно в переменную PATH прописать путь, либо для каждой сессии терминала вызывать экспорт (export
), либо делать как я делаю – перейти в каталог opkg_offline и запустить непосредственно .
. opkg
Краткий курс анатомии
Коротко рассмотрим как работает менеджер пакетов в стандартном режиме. После выполнения команды opkg update
, утилита читает файлы конфигураций, которые по умолчанию расположены в и имеют расширение .conf. Из этих файлов система определяет тип архитектуры, например armv5hf-vfp или armv5tehf-vfp (поддерживаемых архитектур может быть несколько, для каждой можно задать приоритет), список репозиториев и некоторые настройки самой программы. Далее для каждого репозитория из списка скачивается архив типа opkg
*_Packages.gz
. Архивы по умолчанию помещаются в директорию var/cache/opkg/
. После распаковки содержимое помещается в var/lib/opkg/lists
. В каждом архиве лежит текстовый файл со списком пакетов в репозитории. Для каждого пакета помимо названия указана версия, архитектура, размер, краткое описание, лицензия, а самое главное – зависимости. На основании этих файлов менеджер пакетов по запросу может выдать информацию о требуемом пакете, а при его установке определить все зависимости и разрешить их.
Команда opkg list
выдаст все доступные для установки пакеты; команда opkg list-installed
покажет только установленные пакеты, команда opkg info
покажет информацию об указаном пакете, а если он установлен, то и время установки.
Для установки пакета следует выполнить opkg install packname
. В результате требуемый пакет из репозитория будет скачен во временную директрию и распокован. Все файлы из архива data.tar.gz разойдутся по своим местам в rootfs, а на основании содержимого control.tar.gz в каталоге var/lib/opkg/info
будут созданы служебные файлы: packname.control
– полная информация о пакете, packname.list
— список директорий, по которым разошлись файлы из data.tar.gz (по этому списку пройдется opkg при удалении пакета), и файлы скриптов, типа packname.postinst
, packname.preinst
, packname.prerm
, packname.postrm
, назначения которых понятны из названия. Информация об установленном пакете будет добавлена в файле var/lib/opkg/status
в виде (пример для популярного minicom):
Package: minicom
Version: 2.6.2-r0.2
Depends: libtinfo5 (>= 5.9), libc6 (>= 2.17)
Status: install ok installed
Architecture: armv7ahf-vfp-neon
Installed-Time: 1454529423
Важно обратить внимание на Status
. Если пакет был установлен по всем правилам: все файлы скопированы на свое место, все скрипты выполнены, то статус будет Status: install ok installed
. При работе в режиме offline все файлы будут скопированы, но скрипты не выполнятся, такие пакеты будут помечены как Status: install ok unpacked
.
На этот случай в opkg предусмотрен специальный механизм пост конфигурации пакетов. Запускается он командой opkg configure <packname>
. Если указать имя определенного пакета, то будут выполнены скрипты из var/lib/opkg/info для этого пакета; если имя опустить, то менеджер произведет конфигурацию для всех пакетов, у которых статус Status: install ok unpacked
. Таким образом, при установке пакетов на host в режиме offline, при первой загрузке операционной системы на target следует выполнить opkg configure
. Доверить это можно либо специальному скрипту, либо, если используется systemd, специальному сервису.
Работа с целевой rootfs
Настало время попробовать систему в деле. Для примера установим эмулятор терминала последовательного порта minicom.
Для установки пакетов нам понадобится распакованный образ корневой файловой системы целевой платформы rootfs. Предположим, что в rootfs установлен менеджер opkg, a в директории etc/opkg
существуют файлы конфигурации *.conf. Если же его там нет, или по какой-то причине мы не хотим использовать конфигурацию из rootfs, мы можем через параметр указать какой файл настроек использовать: -f etc/opkg/opkg.conf
. Путь к целевой файловой системе передаем через параметр --offline-root
. to/rootfs
Обновляем списки пакетов:
bin/opkg update --offline-root /path/to/rootfs
Просматриваем список доступных пакетов, ищем minicom.
bin/opkg list --offline-root ~/board/rootfs/angstrom/rootfs-v2015.10 | grep minicom
minicom - 2.7-r0.0 - Text-based modem control and terminal emulation program Minicom is a
minicom-dbg - 2.7-r0.0 - Text-based modem control and terminal emulation program - Debugging files
minicom-dev - 2.7-r0.0 - Text-based modem control and terminal emulation program - Development
minicom-doc - 2.7-r0.0 - Text-based modem control and terminal emulation program - Documentation
Смотрим информацию о пакете:
bin/opkg info minicom --offline-root ~/board/rootfs/angstrom/rootfs-v2015.10
Package: minicom
Version: 2.7-r0.0
Depends: libtinfo5 (>= 5.9), libc6 (>= linaro-2.20)
Status: unknown ok not-installed
Section: console/network
Architecture: armv7at2hf-vfp-neon
Maintainer: Angstrom Developers <angstrom-distro-devel@linuxtogo.org>
MD5Sum: e4d11b7277fbc1c7db6bbd97ac52ca2c
Size: 79354
Filename: minicom_2.7-r0.0_armv7at2hf-vfp-neon.ipk
Description: Text-based modem control and terminal emulation program Minicom is a text-based modem control and terminal emulation program for Unix-like operating systems
Устанавливаем пакет:
bin/opkg install minicom --offline-root ~/board/rootfs/angstrom/rootfs-v2015.10
В файле var/lib/opkg
появилась запись:
Package: minicom
Version: 2.7-r0.0
Depends: libtinfo5 (>= 5.9), libc6 (>= linaro-2.20)
Status: install user unpacked
Architecture: armv7at2hf-vfp-neon
Installed-Time: 1454594718
После того, как с созданного образа была запущена система и отработала команда opkg configure
, запись в файле изменилась:
Package: minicom
Version: 2.7-r0.0
Depends: libtinfo5 (>= 5.9), libc6 (>= linaro-2.20)
Status: install user installed
Architecture: armv7at2hf-vfp-neon
Installed-Time: 1454594718
Так как настраиваемая rootfs предназначена для встраиваемого компьютера, конечный размер образа имеет значение. Поэтому рекомендую, после того как все нужные пакеты были установлены, удалить скаченные списки и почистить кэш:
rm -rvf ~/board/rootfs/angstrom/rootfs-v2015.10/var/cache/opkg/*
rm -rvf ~/board/rootfs/angstrom/rootfs-v2015.10/var/lib/opkg/lists/*
На заметку: опция --volatile-cache
позволит очистить кэш автоматически при завершении работы.
Вместо заключения
Несмотря на работоспособность, у Offline mode есть некоторые недостатки. Дело в том, что команда opkg configure
запускает на выполнение только *.postinst
, но остается нерешенным вопрос с выполнением скриптов *.preinst
. В силу того, что *.preinst
встречается достаточно редко в пакетах, для меня является приемлемым в ручном режиме просмотреть скрипты, и при необходимости отработать их при первом запуске целевой системы (специальны service для systemd). Буду благодарен за совет.
Почитать по теме:
- IPK-пакет или с чем его едят
- OpenWrt.OPKG Package Manager. Наиболее внятный help.
- Yocto Project. Репозиторий. Исходники
Автор: Shamrel