Руководство пользователя и разработчика RPM

Руководство пользователя и разработчика RPM

Версия для печати

(Многостраничная версия)

Red Hat RPM Guide - русский перевод

RPM Guide

Eric Foster-Johnson
Copyright © 2005 Eric Foster-Johnson

От переводчика:

Данный текст в его исходном варианте выложен Red Hat под лицензией Open Publication License. Надеюсь, что эта лицензия подразумевает возможность самодеятельного перевода с указанием авторов и правообладателей. Если это, паче ожидания, не так, сообщите мне, пожалуйста, об этом на

vlad_goreletsky(at)lexpr.ru

Там, где обсуждается система пакетного менеджмента, обычно употребляется аббревиатура RPM. Там, где речь идет о пакетах или утилите rpm, используется rpm или src.rpm

Замечания по орфографии принимаются. Замечания по стилю не принимаются. Любой из вас может сделать это лучше, если знает как.

В тексте по отношению к оригинальному множество сокращений. Много слов иногда ничего не добавляют к ЗНАНИЮ. Тут возможны претензии, но таков уж мой произвол. Считаю, что потенциальные читатели в основном люди занятые.

Влад Горелецкий

Источник: http://www.lexpr.ru/node/11


Полное руководство Red Hat Package Manager


Раздел 1. Введение в RPM

1.1 Необходимость системы управления пакетами
1.2 Цели разработки RPM
1.2.1 Легкость использования
1.2.2 Ориентирование на понятие "пакет"
1.2.3 Возможность обновления пакетов
1.2.4 Межпакетные зависимости
1.2.5 Возможность запросов
1.2.6 Верификация пакетов
1.2.7 Поддержка различных архитектур
1.2.8 "Чистые" исходные коды
1.3 Терминология RPM

Раздел 2. Обзор RPM

2.1.1 Введение в структуру файла пакета
2.1.2 Формат файла rpm
2.1.3 Бинарные rpm и rpm с исходным кодом
2.2 База данных RPM
2.3 Команды RPM

Раздел 3. Использование RPM

3.1 Утилита rpm
3.2 Установка и обновление пакетов
3.2.1 Режим установки
3.2.2 Режим обновления
3.2.3 Обновление в режиме freshen
3.2.5 Установка через сеть
3.2.6 Установка пакетов с исходным кодом
3.3 Удаление пакетов
3.4 Другие опции rpm

Раздел 4. Использование базы данных RPM

4.1 Запросы к БД RPM
4.1.1 Запросы о пакетах
4.1.3 Как повысить информативность запроса
4.1.4 Какому пакету принадлежит файл?
4.2 Получение информации о пакетах
4.2.1 Описание пакета
4.2.2 Группы пакетов
4.2.3 Список файлов пакета
4.2.4 Список конфигурационных файлов пакета
4.2.5 Список файлов документации пакета
4.2.6 Список статуса файлов пакета
4.2.7 Список скриптов
4.2.8 Список изменений
4.2.9 Комбинирование запросов
4.2.10 Пользовательские запросы
4.2.11 Прочие запросы
4.3 Получение информации из файла rpm-пакета
4.4 Верификация установленных пакетов
4.4.1 Верификация системы в целом
4.4.2 Настройка проверок
4.5 Работа с БД RPM
4.5.1 Создание резервной копии БД RPM
4.5.2 Перестройка БД RPM
4.5.3 Создание новой БД RPM

Раздел 5. Зависимости пакетов

5.1 Введение в концепцию зависимостей
5.1.1 Возможности
5.1.2 Зависимости версий
5.1.3 Конфликты
5.1.4 Неактуальные возможности
5.2.1 Проверка зависимостей вида Requires
5.2.2 Проверка зависимостей вида Provides
5.2.3 Проверка на конфликты
5.2.4 Какой пакет требует данную возможность?
5.2.5 Какой пакет предоставляет данную возможность?
5.3 Триггеры

Раздел 6. Транзакции

6.1 Введение в транзакции
6.1.1 Когда транзакции необходимы
6.1.2 Возврат транзакции
6.2 Транзакции с командой rpm
6.2.1 Идентификаторы транзакций
6.2.2 Откат транзакций
6.3 Сохранение старых пакетов

Раздел 7. Программное обеспечение для управления RPM

7.1 Нахождение программного обеспечения в формате rpm-пакетов
7.1.1 rpmfind и rpm2html
7.2 Сайты, посвященные RPM, в Интернете
7.3 Утилиты расширенного менеджмента пакетов
7.3.1 Yum
7.3.2 Рекомендуемые плагины yum
7.3.3 Графические фронтенды программ управления пакетами

Раздел 8. Создание rpm-пакетов: обзор

8.1 Подготовка к сборке пакета
8.1.1 Планирование - что хотим собрать
8.1.2 Консолидация программного обеспечения
8.1.3 Воспроизводимая сборка ПО
8.1.4 Планирование обновлений
8.1.5 Удовлетворение зависимостей
8.2 Сборка rpm-пакета
8.2.1 Разворачивание структуры директорий
8.2.2 Размещение исходного кода в дереве сборки
8.2.3 Создание spec-файла
8.2.4 Сборка пакета с помощью утилиты rpmbuild
8.2.5 Верификация собранных пакетов

Раздел 9. Работа со spec-файлом

9.1 Чтение spec-файла
9.2 Начинаем создавать spec-файл
9.3 Информация о пакете в spec-файле
9.3.1 Описание пакета
9.3.2 Установка пути сборки
9.3.3 Имена файлов архивов с исходным кодом
9.3.4 Имена патчей
9.4 Контроль сборки
9.4.1 Подготовка к сборке
9.4.2 Сборка ПО
9.4.3 Инсталляция ПО
9.4.4 Очистка после сборки
9.4.5 Определение установочных скриптов
9.5 Заполнение списка файлов
9.5.1 Использование шаблонов
9.5.2 Имена каталогов
9.5.3 Пометка файлов как файлов документации или конфигурационных
9.5.4 Определение атрибутов файлов
9.5.5 Верификация секции %files
9.5.6 Автоматизированное создание списка файлов
9.5.7 Обработка ошибок для неупакованных файлов
9.6 Добавление записей в журнал изменений
9.7 Макросы
9.7.1 Встроенные макросы
9.7.2 Макросы, специфичные для spec-файла
9.7.3 Определение нового макроса
9.7.4 Параметры макросов
9.8 Создание spec-файла в XML формате

Раздел 10. Расширенные возможности RPM

10.1 Зависимости пакета
10.1.1 Имена зависимостей
10.1.2 Установка предварительных требований
10.1.3 Зависимости сборки
10.1.4 Автоматизация создания списка зависимостей
10.2 Установка триггеров
10.3 Написание проверочных скриптов
10.4 Создание субпакетов
10.4.1 Предоставление информации о субпакетах
10.4.2 Скрипты в субпакетах
10.4.3 Сборка субпакетов
10.5 Создание пакетов с переопределяемыми путями
10.5.1 Задание префикса
10.5.2 Редактирование секции files
10.5.3 Проблемы создания пакетов с переопределяемыми путями
10.6 Условная сборка
10.6.1 Условные макросы
10.6.2 Условные блоки
10.6.3 Архитектурно-зависимые условия

Раздел 11. Контролирование сборки с помощью утилиты rpmbuild

11.1.1 Настройка сборки
11.1.2 Тестирование сборки
11.1.3 Отладка сборки
11.1.4 Очистка
11.1.5 Сборка для других платформ
11.2 Сборка rpm-пакетов без внешнего spec-файла
11.2.1 Опции rpmbuild для работы с tar-архивами
11.2.2 Ожидаемая структура архива
11.3 Работа с пакетами, содержащими исходный код (src.rpm)
11.3.1 Пересборка бинарных пакетов из src.rpm
11.3.2 Перекомпиляция бинарных пакетов из src.rpm
11.4 Подписывание собранных пакетов
11.4.1 Проверка установки программного обеспечения GPG
11.4.2 Конфигурирование подписи
11.4.3 Подписывание пакетов с помощью утилиты rpmbuild
11.4.4 Подписывание с помощью утилиты rpm
11.4.5 Верификация подписей
11.4.6 Импорт публичного ключа

Раздел 12. Вспомогательное программное обеспечение сборщика пакетов

12.1.1 Использование плагинов vim для облегчения редактирования spec-файлов
12.1.2 Добавление функций с помощью emacs-плагина rpm-spec-mode
12.1.3 Отладка spec-файла с помощью rpmlint
12.1.4 Использование rpm2cpio для извлечения файлов из нагрузки пакетов

Раздел 13. Пакетостроение - генеральная линия партии или колхоз "Светлый путь"

13.1 Наука о граблях - как избегать повторения наиболее общих ошибок
13.1.1 Просматривайте тематические рассылки
13.1.2 Используйте rpmbuild
13.1.3 Не пытайтесь победить систему
13.1.4 Отключите автоматическую генерацию зависимостей
13.1.5 Не помещайте в секцию %files каталоги
13.1.6 Разомкните циклические зависимости
13.2 Наука об изучении опыта передовиков производства. Следуйте лучшей практике
13.2.1 Передовой опыт: подготовка к сборке
13.2.2 Передовой опыт: сборка

Раздел 14. Автоматизация операций RPM с помощью скриптов

14.1 Скриптинг
14.2 Отличительные черты скриптовых языков
14.3 Как определить, когда нужна программа, а когда - скрипт?
14.4 Основы shell-скриптинга
14.4.1 Создание скрипта
14.4.2 Запуск скрипта
14.4.3 Проблемы при запуске скрипта
14.4.4 Преобразование скрипта в команду
14.4.5 Передача параметров в скрипт
14.5 Файлы в rpm-пакетах
14.6 Запросы к БД RPM
14.6.1 Запрос списка пакетов, установленных единовременно
14.6.2 Чтение html-документации о пакете

Раздел 15. Программирование RPM на C

15. Программирование RPM на C
15.1.1 Установка окружения для C-программирования
15.1.2 Установка окружения программирования RPM
15.1.3 Использование библиотеки RPM
15.1.4 Компиляция и линковка RPM программ
15.1.5 Получение информации о RPM окружении
15.2 Мощь popt
15.2.1 Псевдонимы popt
15.2.2 Программирование с popt
15.2.3 Обработка ошибок
15.2.4 Работающий пример
15.2.5 Обработка опций командной строки rpm
15.3 Работа с rpm-файлами
15.3.1Открытие rpm-файла
15.3.2 Чтение начального идентификатора rpm и сигнатуры
15.3.3 Чтение хэдера
15.3.4 Короткий путь к информации хэдера
15.3.5 Закрытие rpm-файла
15.4 Программирование с БД RPM
15.4.1 Итераторы БД
15.4.2 Сет зависимости
15.5 Сравнение rpm-файла и установленного пакета

Раздел 16. Программирование RPM на Python

16.1.1 Установка окружения для программирования на Python
16.1.2 Использование Python в графических приложениях
16.2 Иерархия Python API
16.3 Программирование с БД RPM
16.3.1 Доступ к БД RPM
16.3.2 Запросы к БД RPM
16.3.3 Работа с хэдером пакета
16.3.4 Запросы о конкретных пакетах
16.3.5 Вывод информации о пакетах
16.3.6 Уточнение запросов
16.4 Чтение файлов пакетов
16.4.1 Чтение хэдера из файла пакета
16.4.2 Установка флагов верификации
16.5 Сравнение зависимостей
16.6 Установка и обновление пакетов
16.6.1 Построение сета транзакции
16.6.2 Элементы транзакции
16.6.3 Проверка и переопределение порядка элементов транзакции

16.6.4 Запуск транзакции

Раздел 17. Программирование RPM на Perl

17. Программирование RPM на Perl
17.1 Получение и использование RPM-модулей Perl
17.2 Работа с rpm-файлами
17.2.1 Открытие rpm-файла
17.2.2 Получение значений полей хэдера из файла пакета
17.2.3 Удобные методы
17.2.4 Вывод имени и версии
17.2.5 Проверка, является ли файл пакета пакетом с исходными кодами
17.3 Работа с БД RPM
17.3.1 Открытие БД RPM
17.3.2 Поиск пакетов
17.3.3 Обход списка пакетов
17.3.4 Дополнительные функции поиска
17.3.5 Получение информации о пакетах
17.3.6 Сравнение версий
17.3.7 Закрытие БД

Раздел 18. Использование RPM в не-Red Hat Линуксах

18.1 О проблемах установки rpm-пакетов в не-Red Hat Линуксах
18.1.1 Версии системы RPM
18.1.2 Разделение ПО по пакетам
18.1.3 Зависимости
18.1.4 Пути установки
18.1.5 Если ничего не помогает, соберите пакет из исходников
18.2 Решение проблем сборки пакетов
18.2.1 Создание пакетов, специфичных для конкретного дистрибутива
18.2.2 Работа с автоматической генерацией зависимостей
18.2.3 Работа с различающимися макросами
18.2.4 Создание пакетов с переопределимыми путями
18.2.5 Построение окружения сборки RPM
18.3 Работа с не-rpmbased дистрибутивами и утилита alien
18.4 Стандартизация RPM

Раздел 19. Использование RPM в других операционных системах

19.1 Запуск RPM на других операционных системах
19.1.1 Получение RPM для целевой системы
19.1.2 Запуск RPM под Windows
19.2 Разворачивание RPM на других операционных системах
19.2.1 Скачивание кода
19.2.2 Извлечение ПО
19.2.3 Информация в файле INSTALL
19.2.4 Библиотеки, необходимые RPM
19.2.5 Инструменты для сборки RPM
19.2.6 Сборка RPM
19.2.7 Решение проблем
19.3 Установка и настройка системы RPM
19.3.1 Разворачивание БД RPM
19.3.2 Создание окружения RPM
19.4 Создание rpm-пакетов для не-Linux систем
19.4.1 Настройка окружения сборки
19.4.2 Кросс-сборка пакетов

Раздел 20. Изменение поведения RPM

20.1 Настройка поведения с помощью RPM-макросов
20.1.1 Определение макросов
20.1.2 Пользовательские макросы
20.2 Конфигурирование RPM
20.2.1 Просмотр текущих установок
20.2.2 Расположение rpmrc-файлов
20.2.3 Изменение установок
20.3 Добавление псевдонимов popt
20.3.1 Определение псевдонимов
20.3.2 Пользовательские псевдонимы

Раздел 21. Справочник по командам RPM

21.1.1 Команда rpm в режиме запросов
21.1.2 Команда rpm в режимах установки и обновления (upgrade, freshen, install)
21.1.3 Команда rpm в режиме удаления
21.1.4 Команда rpm в режиме подписи
21.1.5 Команда rpm в режиме верификации
21.1.6 Команда rpm в режиме работы с БД RPM
21.1.7 Разные опции
21.2.1 Утилита rpmbuild. Сборка посредством указания spec-файла
21.2.2 Утилита rpmbuild. Сборка из tar-архива
21.2.3 Пересборка пакетов из пакетов с исходным кодом
21.2.4 Изменение хода сборки

Раздел 22. Синтаксис spec-файла

22.1 Поля, содержащие информацию о пакете
22.1.1 Комментарии
22.1.2 Параметры сборки
22.1.3 Поля, содержащие информацию о зависимостях
22.1.4 Файлы с исходным кодом
22.2.1 Макросы определения переменных
22.2.2 Макросы условий
22.2.3 Встроенные макросы
22.3.1 Подготовка к сборке
22.3.2 Сборка
22.3.3 Установка
22.3.4 Очистка
22.3.5 Скрипты стадий установки и удаления
22.4 Файлы
22.4.1 Создание пакетов с переопределимыми путями
22.5 Журнал изменений

Раздел 23. Эволюция функциональности RPM

23 Эволюция функциональности RPM

Раздел 24. Формат файла rpm-пакета

24.1 Файл пакета
24.1.1 Начальный идентификатор
24.1.2 Подпись
24.1.3 Хэдер
24.1.3.1 Поля хэдера
24.1.3.2 Скрытые поля хэдера
24.1.3.3 Поля подписи
24.1.3.4 Поля для установочной информации
24.1.3.5 Поля информации о файлах
24.1.3.6 Поля зависимостей
24.1.4 Нагрузка

Раздел 25. Ресурсы, посвященные RPM

25.1.1 Сайт rpm.org
25.1.2 Сайты для поиска пакетов rpm
25.1.3 Сайты, посвященные утилитам RPM

Как не относящиеся к делу пропущены разделы 26 - Текстовые редакторы и вспомогательные средства разработки в Linux, 27 - Лицензирование RPM (текст GPL)




Ветка форума, в которой обсуждается данная работа





11.4.5 Верификация подписей

Для того, чтобы убедиться, что пакет не был модифицирован с момента его подписывания, используется механизм проверки подписи. Процедура верификации также проверяет соответствие ключа ключу определенного вендора.

Утилита rpm (не rpmbuild) работает в режиме проверки подписи, если применяется опция -K:

rpm -K package.rpm

Для изменения режима (отключения какой-то определенной проверки) используются опции, указанные в таблице ниже.

Опция

Использование

--nogpg

Отключает проверку подписи GPG

--nomd5

Отключает проверку подписи MD5

--nopgp

Отключает проверку подписи PGP

Также может применятся опция --checksig, она является синонимом -K.

Когда команда проверки находит в пакете правильные подписи, выводится примерно следующее:

# rpm -K xtoolwait-1.3-3.src.rpm

xtoolwait-1.3-3.src.rpm: (sha1) dsa sha1 md5 gpg OK

Это сообщение означает, что пакет с момента подписывания не изменялся. Эта проверка также показала, что ключ производителя пакета соответствует его публичному ключу.

Для вывода более подробной информации нужно задействовать опцию -v:

$ rpm -Kv vixie-cron-3.0.1-69.src.rpm

vixie-cron-3.0.1-69.src.rpm:

Header V3 DSA signature: OK, key ID db42a60e

Header SHA1 digest: OK
(ecbb244ab022ecd23114bb1d6c9bdeb74f8d9520)

MD5 digest: OK (fb0a75eca1d526d391c36dc956c23bdd)

V3 DSA signature: OK, key ID db42a60e

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

# rpm --checksig xtoolwait-1.3-3.src.rpm

xtoolwait-1.3-3.src.rpm: (SHA1) DSA sha1 md5 (GPG) NOT OK (MISSING KEYS: GPG#db42a60e)

Позиции, не прошедшие проверку, выделены в выводе символами верхнего регистра, например, DSA, в то время как прошедшие проверку подписи обозначаются символами в нижнем регистре. В данном примере сигнатуры sha1 и md5 совпали с ожидаемыми.

Наиболее вероятные причины ошибок при проверке:

1. Пакет не был правильным образом подписан. При этом он может быть легитимным.

2. Пакет был модифицирован и он больше не легитимен.

3. Система RPM не содержит публичного ключа вендора, который используется при проверке.

Из этого понятно, что само наличие ошибки ничего не говорит нам о легитимности пакета или наоборот. Поэтому первым шагом при возникновении таких ошибок должен быть импорт публичного ключа вендора пакетов.

Далее - Импорт публичного ключа
Назад - Подписывание с помощью утилиты rpm
Содержание


11.4.6 Импорт публичного ключа

Опция --import утилиты rpm импортирует публичный ключ заданного вендора. Формат ключа следующий (некоторые строки пропущены для экономии места):

The following public key can be used to verify RPM packages built
and signed by Red Hat, Inc. using `rpm -K' using the GNU GPG
package.

Questions about this key should be sent to security@redhat.com.

-----BEGIN PGP PUBLIC KEY BLOCK-----

Version: GnuPG v1.0.0 (GNU/Linux)

Comment: For info see http://www.gnupg.org

mQGiBDfqVEqRBADBKr3Bl6PO8BQ0H8sJoD6p9U7Yyl7pjtZqioviPw
XP+DCWd4u8HQzcxAZ57m8ssA1LK1Fx93coJhDzM130+p5BG9mY
SPShLabR3N1KXdXAYYcowTOMGxdwYRGr1Spw8QydLhjVfU1VSl4x
t6bupPbFJbyjkg5Z3P7BlUOUJmrx3wCgobNVEDGaWYJcch5z5B1of
/41G8kEAKii6q7Gu/vhXXnLS6m15oNnPVybyngiw/23dKjSti/PYrrL2
11P2ed0x7zm8v3gLrY0cue1iSba+8glY+p31ZPOr5ogaJw7ZARgoS
8BwjyRymXQp+8Dete0TELKOL2/itDOPGHW07SsVWOR6cmX4VlRR
cWB5KejaNvdrE54XFtOd04NMgWI63uqZc4zkRa+kwEZtmbz3tHSd
WCCE+Y7YVP6IUf/w6YPQFQriWYFiA6fD10eB+BlIUqIw80EqjsBKm
CwvKkn4jg8kibUgj4/TzQSx77uYokw1EqQ2wkOZoaEtcubsNMquu
LCMWijYhGBBgRAgAGBQI36lRyAAoJECGRgM3bQqYOhyYAnj7hVDY
/FJAGqmtZpwVp9IlitW5tAJ4xQApr/jNFZCTksnI+4O1765F7tA==
=3AHZ

-----END PGP PUBLIC KEY BLOCK-----

В качестве параметра команде импорта нужно задать имя файла, содержащего ключ:

rpm --import key_file

Для импорта ключа необходимо иметь права root. Проверка после импорта ключа может выглядеть так:

# rpm --import RPM-GPG-KEY

# rpm --checksig xtoolwait-1.3-3.src.rpm

xtoolwait-1.3-3.src.rpm: (sha1) dsa sha1 md5 gpg OK

Если после импорта ключа проблема все еще остается, дальнейшие действия - на совести администратора. Некоторые администраторы никогда не устанавливают таких пакетов.

Для получения списка доступных ключей используйте команду:

$ rpm -qa | grep -i gpg

gpg-pubkey-db42a60e-37ea5438

В текущем случае установлен один публичный ключ. Установленный ключ можно удалить, если он представляет собой пакет, как в данном примере. Используйте команду rpm -e.

Для импорта публичного ключа Red Hat найдите файл RPM-GPG-KEY на дистрибутивном диске и выполните импорт с помощью rpm --import .

Далее - Раздел 12. Вспомогательное программное обеспечение сборщика пакетов
Назад - Верификация подписей
Содержание


13.1.1 Просматривайте тематические рассылки

Множество людей уже предпринимали попытки разрешения серьезных проблем использования RPM, поэтому, если вы столкнулись с трудностями, велика вероятность того, что кто-то уже сталкивался с тем же самым. Почтовая рассылка и форумы, посвященные RPM, помогут во многих, если не в большинстве, случаев.

Весьма полезены для разработчика списки почтовой рассылки
http://www.rpm.org/mailing_list, а также архив рассылки http://groups.yahoo.com/group/rpm-list/messages .

Задавайте вопросы в такой форме, которая породит наиболее дружественный и полезный ответ. Правильная форма вопроса включает следующие компоненты:

1. Сначала - домашняя работа. Убедитесь, что на ваш вопрос нет уже готового ответа.
2. Опишите проблему и симптомы как можно подробнее.
3. Используйте ясные заголовки сообщений. Это то, что люди видят в первую очередь. Если тема сообщения мутная, велика вероятность, что ключевой человек, тот, кто реально способен ответить, не будет читать само сообщение.
4. Используйте в сообщениях только простой текст, не HTML.
5. Облегчите людям возможность ответа, включая адрес в тело сообщения.

Кроме мэйл-листа полезной может оказаться новостная группа linux.redhat.rpm .

Далее - Используйте rpmbuild
Назад - Импорт публичного ключа
Содержание


13.1.2 Используйте rpmbuild

В RPM версий до 4.1 сборка выполнялась командой rpm -b . Если что-то идет не так, проверьте, может быть в текущей системе уже используется rpmbuild вместо rpm -b .

Как ни странно, список людей, попадающих в столь простой тупик, все время пополняется.

Далее - Не пытайтесь победить систему
Назад - Просматривайте тематические рассылки
Содержание


13.1.3 Не пытайтесь победить систему

Если вы вдруг обнаружили, что ваши spec-файлы приобретают все бОльшую и бОльшую сложность, и, с другой стороны, вы отключаете одну возможность RPM за другой, велика вероятность, что имеют место попытки победить систему великого и непобедимого социализма. Вряд ли это хорошая идея.

RPM работает определенным образом. Можно быть несогласным со светлым путем, однако попытки заставить двигаться путем, чуждым системе, приведут к коллапсу (вопрос чьему).

Есть набор правил, и, что важнее, набор соглашений, которым должна следовать RPM. Следуйте им и вы, и ваши внуки будут жить при коммунизме.

Далее - Отключите автоматическую генерацию зависимостей
Назад - Используйте rpmbuild
Содержание


13.1.4 Отключите автоматическую генерацию зависимостей

Когда собирается пакет, rpmbuild автоматически генерирует список зависимостей от разделяемых библиотек и системных команд. Это поведение можно изменить.

Для отключения генерации зависимостей в spec-файл нужно поместить специальную директиву:

Autoreq: 0

Более корректной возможностью, однако, является переопределение макросов %{__find_requires} и %{__find_provides}, или одного из них по необходимости. Для придания макросу пустого значения требуется вставить в spec-файл команду:

%define __find_requires %{nil}

Эта возможность лучше, так как позволяет отключить только интересующую вас проверку, а не все сразу. Кроме того, можно применить простые и весьма специфичные настройки процесса генерации зависимостей. Например, можно определить макросы для нормальной проверки зависимостей, исключая некоторые проблематичные файлы (пакеты). В следующем примере макросы разворачиваются в shell-скрипты, которые выполняют проверку зависимостей:

$ rpm --eval "%__find_provides"

/usr/lib/rpm/find-provides

rpm --eval "%__find_requires"

/usr/lib/rpm/find-requires

Вы можете переписать эти скрипты для выполнения поиска зависимостей каким-либо специфическим образом.

Далее - Не помещайте в секцию %files каталоги
Назад - Не пытайтесь победить систему
Содержание


13.1.5 Не помещайте в секцию %files каталоги

До тех пор, пока вам это действительно не станет необходимо, не помещайте в список секции %files имен каталогов, потому что rpmbuild автоматически добавляет все файлы под указанным каталогом в пакет. Если вы случайно указали системную директорию, например, /usr/bin, пакет станет владельцем всех файлов в этом каталоге.

Для предотвращения такого события желательно в точности указывать полные имена файлов. Часто для этого используют возможности получения списка из текстового файла и вывод команды find.

Если пакет нуждается во включении в список его файлов каталога, используйте директиву %dir .

Далее - Разомкните циклические зависимости
Назад - Отключите автоматическую генерацию зависимостей
Содержание


13.1.6 Разомкните циклические зависимости

Если два пакета зависят один от другого, не стоит помещать эту информацию в spec-файл обоих пакетов (директива Requires). Если это все же произошло, пакеты не захотят устанавливаться один без другого без форсирования процедуры.

Эту коллизию можно обойти, используя директиву PreReq вместо Requires. Например, если пакет А зависит от пакета В и пакет В зависит от пакета А, поместите следующее в spec-файл пакета В:

PreReq: A

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

rpm Uvh ./A.rpm ./B.rpm

Далее - Передовой опыт: подготовка к сборке
Назад - Не помещайте в секцию %files каталоги
Содержание


13.2.1 Передовой опыт: подготовка к сборке

Перед тем, как начать собирать rpm-пакет, необходимо выполнить несколько шагов в духе генеральной линии. Для того, чтобы быть уверенным, что все действительно готово.

13.2.1.1 Создайте пакет с исходным кодом
Наличие пакета с исходным кодом позволяет превращать исходники в пакеты для любой системы, любой архитектуры с помощью инструкций, заложенных в spec-файл. Возникает два полезных эффекта - все время отслеживается эволюция ПО и можно в любой момент получить бинарный rpm, пересобрав src.rpm.

Иными словами, создайте поколения rpm-пакетов, следуя соглашениям системы RPM и превратите такой подход в обычный для вас путь разработки.

13.2.1.2 Начинайте с чистых исходников
Кроме планирования процесса сборки, следует помнить, что нужно начинать с чистых, неизмененных исходных текстов приложения, из которого формируется пакет. Старт с чистого листа означает, что можно воспроизвести все детали процесса эволюции ПО, вплоть до отката в самое начало, если это потребуется.

Для всех изменений кода используются патчи. Таким образом, все внесенные изменения у вас в руках.

Некоторые rpm-пакеты имеют сотню и более патчей, которые rpmbuild применяет к коду в процессе сборки. Несмотря на это, при добавлении новых патчей процесс никак не изменяется.

Сохранение патчей отдельно от изначального исходного кода делает несложной задачу отката к прежним состояниям и задачу интеграции в пакет новых версий ПО.

13.2.1.3 Решите, что именно содержится в каждом пакете
Нет никакой практической необходимости помещать все ваше ПО в один пакет. Вместо этого разработчики, как правило, стремятся поделить большие проекты на несколько пакетов, возможно зависимых друг от друга. Например, сама система RPM имеет один пакет для базовой системы, один для разработчиков RPM, rpm-devel, и один для ПО сборки пакетов, rpm-build. Также имеются средства интеграции, например прикладной программный интерфейс для Python в пакете rpm-python.

Почему такое разделение важно? Возьмем, например, rpm-python. Этот пакет зависит от самого Python. Зачем заставлять пакет системы RPM зависеть от Python? Разделение на более мелкие структурные единицы позволяет избегать подобных коллизий.

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

- мы делим ПО на пакеты, так как это адаптирует принятую модель к пользователю;
- мы делим ПО на пакеты, так как маленькие пакеты просты, а это облегчает их создание и сопровождение.

Система RPM следует генеральной линии, особенно в части первого пункта. Некоторые пользователи сами расширяют возможности RPM, что позволяет разработчикам выносить эти дополнительные возможности за рамки базовой системы и сохранять их в rpm-devel. Большинство пользователей относятся к категории, использующей RPM, потому что всем нужно устанавливать пакеты, но некоторые пользователи эти пакеты собирают. Таким образом, разделение ПО на более компактные пакеты работает на расширение пользовательских перспектив.

Если разделение пакета на более мелкие не упрощает вещи, а усложняет, значит в конкретном случае это была, возможно, нездоровая идея.

13.2.1.4 Создайте тестовую базу данных RPM
В процессе сборки пакетов RPM так или иначе обращается к БД RPM. Но вы не обязаны работать с общесистемной БД. Если имеется тестовая БД RPM, можно устанавливать и тестировать пакеты в рамках этой БД. Для осуществления такого подхода задействуйте опции --justdb, --dbpath, --prefix, и --badreloc . Эти опции позволяют установить пакеты только в БД, в альтернативную БД, в другой "корневой" каталог.

Опция --test позволяет понять, что происходит при установке, на самом деле не выполняя ее.

Осуществляя скрупулезный подход к сборке и тестированию, разработчик должен создать тестовую БД на основе в точности известного набора пакетов с нуля. Это позволит проверить поведение пакетов в других системных окружениях. Наилучшим путем в этом направлении будет установка пакетов в альтернативную "корневую" директорию, которая не совпадает с системным корнем.

Можно также скопировать системную БД RPM в такую директорию и использовать ее. При этом пути к файлам в БД будут совпадать с реальными системными путями.

Независимо от того, как вы создаете тестовую БД, пересоздавайте базу всякий раз, когда выполняется тот или иной тест. Это необходимо для уверенности в том, что начальные условия нам известны, и они одинаковы. Обычно это сводится к копированию исходной тестовой БД в каталог, где происходят тесты.

Далее - Передовой опыт: сборка
Назад - Разомкните циклические зависимости
Содержание


13.2.2 Передовой опыт: сборка

Сборка пакета не так проста, как бы мы этого хотели. Часто приходится делать одно и то же снова и снова, чтобы получить работающий rpm. Эта глава рассказывает о лучшей для применения практике сборки.

13.2.2.1 Используйте инструменты
Использование инструментов часто помогает ускорить процесс сборки, а также помогает пониманию механизмов работы RPM. Утилиты, применимые в сборке, например, Red Hat плагин для Eclipse IDE, есть живое доказательство этой полезности.

Даже так называемые "реальные Линукс-хакеры", могущие смоделировать работающую систему виртуальной памяти с помощью одной команды cat, не пренебрегают утилитами, поскольку время - настоящая ценность.

Пример утилиты, имеющей действительную пользу - программа gendiff, входящая в RPM. Она позволяет избегнуть необходимости хранить отдельную директорию оригинальных исходников. gendiff позволяет создать патч на каталог исходников, если было изменено много файлов внутри каталога.

Для работы gendiff нужно сохранить копии всех файлов, которые вы хотите модифицировать. Задайте сохраняемым файлам одинаковое расширение, например, .orig . После редактирования файлов запускается gendiff таким образом:

$ gendiff directory_name .orig > patch_name.patch

Файл патча patch_name.patch будет содержать все изменения для всех файлов в каталоге.

13.2.2.2 Никогда не собирайте пакеты из-под root
Никогда не собирайте пакеты из-под пользователя root (Never, never, never build RPMs logged in as the root user - весьма эмоционально, прим. перев.). Поскольку для тестирования собранных пакетов их требуется установить, а это происходит с правами root, этот аспект приходится держать в голове. Но все-таки опасность велика. В spec-файле присутствует множество скриптов и команд и даже одна ошибка в одной команде может обрушить систему, если эта команда выполняется с правами суперпользователя. Права root допускают возможность модификации файлов, в том числе системных, удаление файлов и запись нового содержания поверх существующего. Вряд ли это допустимо для системы, в которой вы собираете пакеты.

13.2.2.3 Создайте цифровую подпись
В RPM версии 4.1 и новее гораздо большее значение придано цифровой подписи пакетов. Команда rpm в поведении по умолчанию проверяет подпись каждого пакета, к которому обращается.

Мы должны подписать каждый собранный пакет хотя бы для того , чтобы не обмануть ожиданий пользователя. Кроме того, необходимо поместить публичный ключ на свой сайт и на сервера публичных ключей во избежании имперсонализации ваших пакетов.

13.2.2.4 "Умное" копирование
Возможно, ваш дистрибутив содержит сотни rpm-пакетов и каждый их них имеет spec-файл. Почему бы не просмотреть эти спецификации? Вместо старта с пустого spec-файла множество определений могут быть перенесены в виде готовых решений. Однако, не все spec-файлы идеальны. Вряд ли стоит копировать не оптимальные подходы и решения.

13.2.2.5 Определение BuildRoot
Директива BuildRoot задает каталог, в котором будет собираться ПО. В соответствии со стандартным подходом мы должны определить каталог под каталогом _tmppath. Например:

BuildRoot: %{_tmppath}/%{name}-buildroot

Однажды заданный, путь к каталогу сборки заставляет rpmbuild инициализировать переменную окружения RPM_BUILD_ROOT этим значением.

В команде rpmbuild можно использовать опцию --buildroot для переопределения директивы BuildRoot из spec-файла.

Использование BuildRoot требует, чтобы обычный пользователь имел в определяемый каталог право записи, иначе не будет возможности собирать пакеты из-под обычного пользователя. Важное значение BuildRoot имеет в отношении разделения деревьев сборки для разных пакетов.

Всегда определяйте BuildRoot.

13.2.2.6 Добавляйте запись в журнал изменений для каждой новой версии сборки
Каждый раз, когда собирается новая версия пакета, в секцию %changelog должна быть добавлена запись. Благодаря этому администраторы систем могут отслеживать последовательность изменений и устанавливать те версии, в которых нужные изменения есть (или наоборот, нет ненужных изменений).

Эта информация также помогает понять, нуждается ли пакет в обновлении.

Важной информацией в журнале изменений являются сообщения об исправлении различных уязвимостей.

13.2.2.7 Задайте группу пакета
Все пакеты категорированы по группам. Имена групп позволяют, например, облегчить пользователю поиск нужных пакетов. Они выводятся графическими утилитами управления пакетами в свойствах пакетов.

Если ваше приложение представляет собой общесистемную консольную утилиту, поместите ее в группу System Environment/Shells и не помещайте ее в группы Development/Languages или System Environment/Daemons. Это сравнительно незначительная деталь во всем стеке информации о пакете, но она помогает поиску в огромном массиве пакетов дл я Linux.

Официальный список групп пакетов Red Hat для RPM версии 4.1 содержится в файле /usr/share/doc/rpm-4.1/GROUPS и где-нибудь в похожей локации для других версий RPM.

Далее - Раздел 14. Автоматизация операций RPM с помощью скриптов
Назад - Передовой опыт: подготовка к сборке
Содержание


Red Hat RPM Guide - русский перевод

RPM Guide

Eric Foster-Johnson
Copyright © 2005 Eric Foster-Johnson

От переводчика:

Данный текст в его исходном варианте выложен Red Hat под лицензией Open Publication License. Надеюсь, что эта лицензия подразумевает возможность самодеятельного перевода с указанием авторов и правообладателей. Если это, паче ожидания, не так, сообщите мне, пожалуйста, об этом на

vlad_goreletsky(at)lexpr.ru

Там, где обсуждается система пакетного менеджмента, обычно употребляется аббревиатура RPM. Там, где речь идет о пакетах или утилите rpm, используется rpm или src.rpm

Замечания по орфографии принимаются. Замечания по стилю не принимаются. Любой из вас может сделать это лучше, если знает как.

В тексте по отношению к оригинальному множество сокращений. Много слов иногда ничего не добавляют к ЗНАНИЮ. Тут возможны претензии, но таков уж мой произвол. Считаю, что потенциальные читатели в основном люди занятые.

Влад Горелецкий


Полное руководство Red Hat Package Manager


Раздел 1. Введение в RPM

1.1 Необходимость системы управления пакетами
1.2 Цели разработки RPM
1.2.1 Легкость использования
1.2.2 Ориентирование на понятие "пакет"
1.2.3 Возможность обновления пакетов
1.2.4 Межпакетные зависимости
1.2.5 Возможность запросов
1.2.6 Верификация пакетов
1.2.7 Поддержка различных архитектур
1.2.8 "Чистые" исходные коды
1.3 Терминология RPM

Раздел 2. Обзор RPM

2.1.1 Введение в структуру файла пакета
2.1.2 Формат файла rpm
2.1.3 Бинарные rpm и rpm с исходным кодом
2.2 База данных RPM
2.3 Команды RPM

Раздел 3. Использование RPM

3.1 Утилита rpm
3.2 Установка и обновление пакетов
3.2.1 Режим установки
3.2.2 Режим обновления
3.2.3 Обновление в режиме freshen
3.2.5 Установка через сеть
3.2.6 Установка пакетов с исходным кодом
3.3 Удаление пакетов
3.4 Другие опции rpm

Раздел 4. Использование базы данных RPM

4.1 Запросы к БД RPM
4.1.1 Запросы о пакетах
4.1.3 Как повысить информативность запроса
4.1.4 Какому пакету принадлежит файл?
4.2 Получение информации о пакетах
4.2.1 Описание пакета
4.2.2 Группы пакетов
4.2.3 Список файлов пакета
4.2.4 Список конфигурационных файлов пакета
4.2.5 Список файлов документации пакета
4.2.6 Список статуса файлов пакета
4.2.7 Список скриптов
4.2.8 Список изменений
4.2.9 Комбинирование запросов
4.2.10 Пользовательские запросы
4.2.11 Прочие запросы
4.3 Получение информации из файла rpm-пакета
4.4 Верификация установленных пакетов
4.4.1 Верификация системы в целом
4.4.2 Настройка проверок
4.5 Работа с БД RPM
4.5.1 Создание резервной копии БД RPM
4.5.2 Перестройка БД RPM
4.5.3 Создание новой БД RPM

Раздел 5. Зависимости пакетов

5.1 Введение в концепцию зависимостей
5.1.1 Возможности
5.1.2 Зависимости версий
5.1.3 Конфликты
5.1.4 Неактуальные возможности
5.2.1 Проверка зависимостей вида Requires
5.2.2 Проверка зависимостей вида Provides
5.2.3 Проверка на конфликты
5.2.4 Какой пакет требует данную возможность?
5.2.5 Какой пакет предоставляет данную возможность?
5.3 Триггеры

Раздел 6. Транзакции

6.1 Введение в транзакции
6.1.1 Когда транзакции необходимы
6.1.2 Возврат транзакции
6.2 Транзакции с командой rpm
6.2.1 Идентификаторы транзакций
6.2.2 Откат транзакций
6.3 Сохранение старых пакетов

Раздел 7. Программное обеспечение для управления RPM

7.1 Нахождение программного обеспечения в формате rpm-пакетов
7.1.1 rpmfind и rpm2html
7.2 Сайты, посвященные RPM, в Интернете
7.3 Утилиты расширенного менеджмента пакетов
7.3.1 Yum
7.3.2 Рекомендуемые плагины yum
7.3.3 Графические фронтенды программ управления пакетами

Раздел 8. Создание rpm-пакетов: обзор

8.1 Подготовка к сборке пакета
8.1.1 Планирование - что хотим собрать
8.1.2 Консолидация программного обеспечения
8.1.3 Воспроизводимая сборка ПО
8.1.4 Планирование обновлений
8.1.5 Удовлетворение зависимостей
8.2 Сборка rpm-пакета
8.2.1 Разворачивание структуры директорий
8.2.2 Размещение исходного кода в дереве сборки
8.2.3 Создание spec-файла
8.2.4 Сборка пакета с помощью утилиты rpmbuild
8.2.5 Верификация собранных пакетов

Раздел 9. Работа со spec-файлом

9.1 Чтение spec-файла
9.2 Начинаем создавать spec-файл
9.3 Информация о пакете в spec-файле
9.3.1 Описание пакета
9.3.2 Установка пути сборки
9.3.3 Имена файлов архивов с исходным кодом
9.3.4 Имена патчей
9.4 Контроль сборки
9.4.1 Подготовка к сборке
9.4.2 Сборка ПО
9.4.3 Инсталляция ПО
9.4.4 Очистка после сборки
9.4.5 Определение установочных скриптов
9.5 Заполнение списка файлов
9.5.1 Использование шаблонов
9.5.2 Имена каталогов
9.5.3 Пометка файлов как файлов документации или конфигурационных
9.5.4 Определение атрибутов файлов
9.5.5 Верификация секции %files
9.5.6 Автоматизированное создание списка файлов
9.5.7 Обработка ошибок для неупакованных файлов
9.6 Добавление записей в журнал изменений
9.7 Макросы
9.7.1 Встроенные макросы
9.7.2 Макросы, специфичные для spec-файла
9.7.3 Определение нового макроса
9.7.4 Параметры макросов
9.8 Создание spec-файла в XML формате

Раздел 10. Расширенные возможности RPM

10.1 Зависимости пакета
10.1.1 Имена зависимостей
10.1.2 Установка предварительных требований
10.1.3 Зависимости сборки
10.1.4 Автоматизация создания списка зависимостей
10.2 Установка триггеров
10.3 Написание проверочных скриптов
10.4 Создание субпакетов
10.4.1 Предоставление информации о субпакетах
10.4.2 Скрипты в субпакетах
10.4.3 Сборка субпакетов
10.5 Создание пакетов с переопределяемыми путями
10.5.1 Задание префикса
10.5.2 Редактирование секции files
10.5.3 Проблемы создания пакетов с переопределяемыми путями
10.6 Условная сборка
10.6.1 Условные макросы
10.6.2 Условные блоки
10.6.3 Архитектурно-зависимые условия

Раздел 11. Контролирование сборки с помощью утилиты rpmbuild

11.1.1 Настройка сборки
11.1.2 Тестирование сборки
11.1.3 Отладка сборки
11.1.4 Очистка
11.1.5 Сборка для других платформ
11.2 Сборка rpm-пакетов без внешнего spec-файла
11.2.1 Опции rpmbuild для работы с tar-архивами
11.2.2 Ожидаемая структура архива
11.3 Работа с пакетами, содержащими исходный код (src.rpm)
11.3.1 Пересборка бинарных пакетов из src.rpm
11.3.2 Перекомпиляция бинарных пакетов из src.rpm
11.4 Подписывание собранных пакетов
11.4.1 Проверка установки программного обеспечения GPG
11.4.2 Конфигурирование подписи
11.4.3 Подписывание пакетов с помощью утилиты rpmbuild
11.4.4 Подписывание с помощью утилиты rpm
11.4.5 Верификация подписей
11.4.6 Импорт публичного ключа

Раздел 12. Вспомогательное программное обеспечение сборщика пакетов

12.1.1 Использование плагинов vim для облегчения редактирования spec-файлов
12.1.2 Добавление функций с помощью emacs-плагина rpm-spec-mode
12.1.3 Отладка spec-файла с помощью rpmlint
12.1.4 Использование rpm2cpio для извлечения файлов из нагрузки пакетов

Раздел 13. Пакетостроение - генеральная линия партии или колхоз "Светлый путь"

13.1 Наука о граблях - как избегать повторения наиболее общих ошибок
13.1.1 Просматривайте тематические рассылки
13.1.2 Используйте rpmbuild
13.1.3 Не пытайтесь победить систему
13.1.4 Отключите автоматическую генерацию зависимостей
13.1.5 Не помещайте в секцию %files каталоги
13.1.6 Разомкните циклические зависимости
13.2 Наука об изучении опыта передовиков производства. Следуйте лучшей практике
13.2.1 Передовой опыт: подготовка к сборке
13.2.2 Передовой опыт: сборка

Раздел 14. Автоматизация операций RPM с помощью скриптов

14.1 Скриптинг
14.2 Отличительные черты скриптовых языков
14.3 Как определить, когда нужна программа, а когда - скрипт?
14.4 Основы shell-скриптинга
14.4.1 Создание скрипта
14.4.2 Запуск скрипта
14.4.3 Проблемы при запуске скрипта
14.4.4 Преобразование скрипта в команду
14.4.5 Передача параметров в скрипт
14.5 Файлы в rpm-пакетах
14.6 Запросы к БД RPM
14.6.1 Запрос списка пакетов, установленных единовременно
14.6.2 Чтение html-документации о пакете

Раздел 15. Программирование RPM на C

15. Программирование RPM на C
15.1.1 Установка окружения для C-программирования
15.1.2 Установка окружения программирования RPM
15.1.3 Использование библиотеки RPM
15.1.4 Компиляция и линковка RPM программ
15.1.5 Получение информации о RPM окружении
15.2 Мощь popt
15.2.1 Псевдонимы popt
15.2.2 Программирование с popt
15.2.3 Обработка ошибок
15.2.4 Работающий пример
15.2.5 Обработка опций командной строки rpm
15.3 Работа с rpm-файлами
15.3.1Открытие rpm-файла
15.3.2 Чтение начального идентификатора rpm и сигнатуры
15.3.3 Чтение хэдера
15.3.4 Короткий путь к информации хэдера
15.3.5 Закрытие rpm-файла
15.4 Программирование с БД RPM
15.4.1 Итераторы БД
15.4.2 Сет зависимости
15.5 Сравнение rpm-файла и установленного пакета

Раздел 16. Программирование RPM на Python

16.1.1 Установка окружения для программирования на Python
16.1.2 Использование Python в графических приложениях
16.2 Иерархия Python API
16.3 Программирование с БД RPM
16.3.1 Доступ к БД RPM
16.3.2 Запросы к БД RPM
16.3.3 Работа с хэдером пакета
16.3.4 Запросы о конкретных пакетах
16.3.5 Вывод информации о пакетах
16.3.6 Уточнение запросов
16.4 Чтение файлов пакетов
16.4.1 Чтение хэдера из файла пакета
16.4.2 Установка флагов верификации
16.5 Сравнение зависимостей
16.6 Установка и обновление пакетов
16.6.1 Построение сета транзакции
16.6.2 Элементы транзакции
16.6.3 Проверка и переопределение порядка элементов транзакции

16.6.4 Запуск транзакции

Раздел 17. Программирование RPM на Perl

17. Программирование RPM на Perl
17.1 Получение и использование RPM-модулей Perl
17.2 Работа с rpm-файлами
17.2.1 Открытие rpm-файла
17.2.2 Получение значений полей хэдера из файла пакета
17.2.3 Удобные методы
17.2.4 Вывод имени и версии
17.2.5 Проверка, является ли файл пакета пакетом с исходными кодами
17.3 Работа с БД RPM
17.3.1 Открытие БД RPM
17.3.2 Поиск пакетов
17.3.3 Обход списка пакетов
17.3.4 Дополнительные функции поиска
17.3.5 Получение информации о пакетах
17.3.6 Сравнение версий
17.3.7 Закрытие БД

Раздел 18. Использование RPM в не-Red Hat Линуксах

18.1 О проблемах установки rpm-пакетов в не-Red Hat Линуксах
18.1.1 Версии системы RPM
18.1.2 Разделение ПО по пакетам
18.1.3 Зависимости
18.1.4 Пути установки
18.1.5 Если ничего не помогает, соберите пакет из исходников
18.2 Решение проблем сборки пакетов
18.2.1 Создание пакетов, специфичных для конкретного дистрибутива
18.2.2 Работа с автоматической генерацией зависимостей
18.2.3 Работа с различающимися макросами
18.2.4 Создание пакетов с переопределимыми путями
18.2.5 Построение окружения сборки RPM
18.3 Работа с не-rpmbased дистрибутивами и утилита alien
18.4 Стандартизация RPM

Раздел 19. Использование RPM в других операционных системах

19.1 Запуск RPM на других операционных системах
19.1.1 Получение RPM для целевой системы
19.1.2 Запуск RPM под Windows
19.2 Разворачивание RPM на других операционных системах
19.2.1 Скачивание кода
19.2.2 Извлечение ПО
19.2.3 Информация в файле INSTALL
19.2.4 Библиотеки, необходимые RPM
19.2.5 Инструменты для сборки RPM
19.2.6 Сборка RPM
19.2.7 Решение проблем
19.3 Установка и настройка системы RPM
19.3.1 Разворачивание БД RPM
19.3.2 Создание окружения RPM
19.4 Создание rpm-пакетов для не-Linux систем
19.4.1 Настройка окружения сборки
19.4.2 Кросс-сборка пакетов

Раздел 20. Изменение поведения RPM

20.1 Настройка поведения с помощью RPM-макросов
20.1.1 Определение макросов
20.1.2 Пользовательские макросы
20.2 Конфигурирование RPM
20.2.1 Просмотр текущих установок
20.2.2 Расположение rpmrc-файлов
20.2.3 Изменение установок
20.3 Добавление псевдонимов popt
20.3.1 Определение псевдонимов
20.3.2 Пользовательские псевдонимы

Раздел 21. Справочник по командам RPM

21.1.1 Команда rpm в режиме запросов
21.1.2 Команда rpm в режимах установки и обновления (upgrade, freshen, install)
21.1.3 Команда rpm в режиме удаления
21.1.4 Команда rpm в режиме подписи
21.1.5 Команда rpm в режиме верификации
21.1.6 Команда rpm в режиме работы с БД RPM
21.1.7 Разные опции
21.2.1 Утилита rpmbuild. Сборка посредством указания spec-файла
21.2.2 Утилита rpmbuild. Сборка из tar-архива
21.2.3 Пересборка пакетов из пакетов с исходным кодом
21.2.4 Изменение хода сборки

Раздел 22. Синтаксис spec-файла

22.1 Поля, содержащие информацию о пакете
22.1.1 Комментарии
22.1.2 Параметры сборки
22.1.3 Поля, содержащие информацию о зависимостях
22.1.4 Файлы с исходным кодом
22.2.1 Макросы определения переменных
22.2.2 Макросы условий
22.2.3 Встроенные макросы
22.3.1 Подготовка к сборке
22.3.2 Сборка
22.3.3 Установка
22.3.4 Очистка
22.3.5 Скрипты стадий установки и удаления
22.4 Файлы
22.4.1 Создание пакетов с переопределимыми путями
22.5 Журнал изменений

Раздел 23. Эволюция функциональности RPM

23 Эволюция функциональности RPM

Раздел 24. Формат файла rpm-пакета

24.1 Файл пакета
24.1.1 Начальный идентификатор
24.1.2 Подпись
24.1.3 Хэдер
24.1.3.1 Поля хэдера
24.1.3.2 Скрытые поля хэдера
24.1.3.3 Поля подписи
24.1.3.4 Поля для установочной информации
24.1.3.5 Поля информации о файлах
24.1.3.6 Поля зависимостей
24.1.4 Нагрузка

Раздел 25. Ресурсы, посвященные RPM

25.1.1 Сайт rpm.org
25.1.2 Сайты для поиска пакетов rpm
25.1.3 Сайты, посвященные утилитам RPM

Как не относящиеся к делу пропущены разделы 26 - Текстовые редакторы и вспомогательные средства разработки в Linux, 27 - Лицензирование RPM (текст GPL)




Ветка форума, в которой обсуждается данная работа





14.1 Скриптинг

Скриптинг, то есть написание сценариев действий, доступно в скриптовых языках. Так обычно называют инерпретируемые языки сценариев. В таких языках легко писать новые команды, помогающие в нелегком труде автоматизации. Используемые в большей степени системными администраторами и в меньшей - прикладными программистами, скрипты помогают в некоторой части администрирования избавиться от скучно-утомительных ежедневных процедур. Администратору, работающему с RPM, скрипты помогут также хранить многосложные команды, например, нетривиальные форматы запросов к БД RPM.

Скрипты - это текстовые файлы. Они содержат команды на используемом языке. Множество таких скриптов несут в своем тексте общесистемные команды. Для запуска скрипта вызывается строка, которая запускает соответствующий языку интерпретатор, а он, в свою очередь, читает сценарий строка за строкой и выполняет написанные команды.

Несмотря на внешнее сходство, скриптинг как вид деятельности все же отличают от программирования, как из-за сложности решаемых задач, так и благодаря формату исполняемых файлов. Кроме того, большинство программ должны быть превращены в машинный код с помощью компиляторов и ассемблеров. Отдельные части программ могут быть соединены процедурами связывания.

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

Не обращайте много внимания на тонкости и используйте для работы ПРАВИЛЬНЫЕ инструменты.

Далее - Отличительные черты скриптовых языков
Назад - Передовой опыт: сборка
Содержание


14.2 Отличительные черты скриптовых языков

Эксперты расходятся в оценках отличий скриптовых языков от компилируемых. Ясно, что языки, подобные Python, размывают границы, прежде казавшиеся четкими.

Изначально скрипты представляли собой небольшие текстовые файлы, в которых вызывались системные команды. Скрипты исполнялись интепретаторами команд, которые умеют перебирать строки с командами одну за другой.

Современные скриптовые языки, вроде Tcl, разбирают скрипт во время запуска и преобразуют текст в промежуточный байт-код. Однажды скомпилированный, скрипт уже трудно отличить от программы.

В скриптовых языках:

* Нет нужды в компиляции. Инерпретатор может уметь преобразовывать текст в промежуточный код, но этого не требуется делать в отдельной стадии. Такой код, если это предусмотрено конструкцией языка, будет сгенерирован при первом запуске скрипта.

* Возможности скриптового языка обычно представлены в виде более высокого уровня абстрагирования от системы, чем в компилируемом языке программирования. Например, программирование сокетов требует в Tcl существенно меньше кода, чем на С. Tcl предоставляет более высокоуровневые интерфейсы для работы с сетью, поэтому код намного проще.

* Команды в сценарии - это в большинстве своем команды, доступные оператору в командной строке операционной системы. Скрипты могут также содержать свои собственные команды.

* Язык, на котором пишут скрипты, называется скриптовым. А какой язык считать таковым? Это скорее соглашение большинства, чем что-то более серьезное.

В таблице представлены короткие списки скриптовых языков и языков программирования (компилируемых). Впрочем, эти списки не могут запретить вам программировать на Perl или Python.

Скриптовые языки

Языки программирования

Bash (Bourne Again shell), Csh (C shell), JavaScript, Ksh (Korn shell), Lua, MS-DOS batch files, Perl, Python, Ruby, Sh (Bourne shell), Tcl

Assembler, C, C++, C#, FORTRAN, Forth, Java, LISP, Modula-2, Modula-3, Oberon, Pascal

Далее - Как определить, когда нужна программа, а когда - скрипт?
Назад - Скриптинг
Содержание


14.3 Как определить, когда нужна программа, а когда - скрипт?

Если уж граница между языками программирования и скриптовыми размылась, соответственно размылась и граница между прикладными задачами. Однако, существует простое правило - используйте ту технику, которая делает ваш труд более продуктивным. Кроме того, никого не волнует, как вы назвали то, что написали - скриптом или программой (зачем автор написал эти главы? - прим. перев.).

И, наконец, некоторые предложения для формирования генеральной линии:

* Если есть потребность выполнять много операций над огромным массивом rpm-пакетов, напишите программу. Она будет быстрее, чем shell-скрипт, который вынужден снова и снова вызывать команду rpm.

* Если вы дружите с каким-либо конкретным языком, используйте его.

* Если нужно выполнять сложные композиции операций - используйте программу.

* Программы во многих случаях предпочтительнее, если нужен сложный графический интерфейс, хотя у Python и Perl есть такие штуки, как PyQt и Perl/Tk

Далее - Основы shell-скриптинга
Назад - Отличительные черты скриптовых языков
Содержание


14.4 Основы shell-скриптинга

Просьба не беспокоиться читателей, никогда не писавших скрипты - это не такое уж мудреное дело. Скрипт, в нашем случае shell-скрипт, это текстовый файл, наполненный командами, которые мы можем отдавать системе с клавиатуры. Различия, которые на самом деле есть, мы рассмотрим ниже.

Далее - Создание скрипта
Назад - Как определить, когда нужна программа, а когда - скрипт?
Содержание


14.4.1 Создание скрипта

Для начала создадим скрипт, состоящий всего из одной команды. Создайте текстовый файл, и введите в качестве текста следующее:

rpm -qa | grep rpm

Этот скрипт содержит двусоставную команду: rpm -qa выводит список всех пакетов, установленных в системе, grep rpm отфильтровывает для вывода только строки, в которых встречается буквосочетание rpm. Это очень простой скрипт, но на простом примере можно показать особенности работы со скриптами.

Сохраните файл под именем listrpmpkgs, поскольку он выводит список неких пакетов.

Далее - Запуск скрипта
Назад - Основы shell-скриптинга
Содержание


14.4.2 Запуск скрипта

Однажды создав скрипт, вы можете использовать его вновь и вновь. Для запуска можно применить команду sh, как показано ниже, передавая команде имя файла скрипта в качестве параметра:

$ sh listrpmpkgs

librpm404-devel-4.0.4-8x.27

librpm404-4.0.4-8x.27

rpm404-python-4.0.4-8x.27

rpm-4.1-1.06

rpm-devel-4.1-1.06

gnorpm-0.9-1

rpm-python-4.1-1.06

redhat-rpm-config-8.0-1

rpm-build-4.1-1.06

rpmrebuild-1.0-0

Введите в командной строке команду, записанную в скрипте. Вывод в этих двух случаях не должен отличаться:

$ rpm -qa | grep rpm

librpm404-devel-4.0.4-8x.27

librpm404-4.0.4-8x.27

rpm404-python-4.0.4-8x.27

rpm-4.1-1.06

rpm-devel-4.1-1.06

gnorpm-0.9-1

rpm-python-4.1-1.06

redhat-rpm-config-8.0-1

rpm-build-4.1-1.06

rpmrebuild-1.0-0

Далее - Проблемы при запуске скрипта
Назад - Создание скрипта
Содержание


14.4.3 Проблемы при запуске скрипта

Запуск скрипта в предыдущем примере требует программы sh (экземпляра командной оболочки Linux). Также файл listrpmpkgs должен быть доступен. Например, если вы сохранили файл в каталоге /home2/bin, тогда для запуска придется использовать команду:

$ sh /home2/bin/listrpmpkgs

Согласитесь, не очень-то удобно. Кроме того, необходимо все время держать в голове расположение файла. Для того, чтобы это работало лучше, нужно преобразовать скрипт в команду.

Далее - Преобразование скрипта в команду
Назад - Запуск скрипта
Содержание


14.4.4 Преобразование скрипта в команду

Для преобразования скрипта в комнаду, сделайте три простых шага:

1. Добавьте специальную строку в начало файла, чтобы система определяла текст как командный скрипт.

2. Установите права доступа на файл, так, чтобы он был исполняемым.

3. Скопируйте скрипт в каталог с исполняемыми файлами.

В shell-скриптах для комментариев используются символы # в начале строки. Если первая строка начинается с символов #!, командный интерпретатор распознает с помощью этого маркера файл командного скрипта. Текст в строке после символов #! указывает на необходимый для исполнения интерпретатор. В большом количестве случаев мы видим строку #!/bin/sh в начале файла.

Отредактируйте файл скрипта listrpmpkgs, добавив строку, указывающую на интерпретатор:

#!/bin/sh

rpm -qa | grep rpm

Далее, измените права на файл для предоставления возможности его выполнения. Для проверки прав используется команда ls -l:

$ ls -l listrpmpkgs

-rw-rw-r-- 1 ericfj ericfj 31 Nov 7 20:02 listrpmpkgs

$ chmod u+x listrpmpkgs

$ ls -l listrpmpkgs

-rwxrw-r-- 1 ericfj ericfj 31 Nov 7 20:02 listrpmpkgs

Теперь мы имеем команду, которую можно запускать локально. Например:

$ ./listrpmpkgs

librpm404-devel-4.0.4-8x.27

librpm404-4.0.4-8x.27

rpm404-python-4.0.4-8x.27

rpm-4.1-1.06

rpm-devel-4.1-1.06

gnorpm-0.9-1

rpm-python-4.1-1.06

redhat-rpm-config-8.0-1

rpm-build-4.1-1.06

rpmrebuild-1.0-0

Следующий шаг - скопировать файл в каталог с исполняемыми файлами, который отмечен в системных путях. Для просмотра каталогов системного окружения запустите следующую команду:

$ echo $PATH

/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/ericfj/bin:/usr/java/j2sdk1.4.0_01/bin

Выберите один из указанных каталогов. Каталог /usr/local/bin - стандартное место для хранения локально созданных команд. Если имеется в виду команда, которая будет использоваться одним пользователем, разумно задействовать каталог под домашним каталогом этого пользователя. /home/ericfj/bin в примере выше - такой каталог. Скопируйте файл скрипта в один из каталогов и все будет готово к запуску.

Введите команду:

$ listrpmpkgs

librpm404-devel-4.0.4-8x.27

librpm404-4.0.4-8x.27

rpm404-python-4.0.4-8x.27

rpm-4.1-1.06

rpm-devel-4.1-1.06

gnorpm-0.9-1

rpm-python-4.1-1.06

redhat-rpm-config-8.0-1

rpm-build-4.1-1.06

rpmrebuild-1.0-0

В отличие от ОС Windows, Linux-скрипты не обязаны иметь специальные расширения в именах файлов.

Если вы хотите сделать скрипт доступным для всех пользователей, выполните:

$ chmod a+x listrpmpkgs

В этом случае, скрипт будет доступен для запуска всем.

Далее - Передача параметров в скрипт
Назад - Проблемы при запуске скрипта
Содержание


14.4.5 Передача параметров в скрипт

Скрипт listrpmpkgs, как мы успели заметить, не обладает развитыми вомзожностями. Он содержит и выполняет только одну команду. Мы не можем изменить его поведение, не написав другой скрипт.

Один из путей повышения мощности скрипта - научить его воспринимать опции командной строки. Подобно тому, как поведение утилиты rpm зависит от множества опций, мы можем изменять поведение скриптов, если сможем передавать в них информацию в виде параметров команды.

В языке shell определен ряд специальных переменных, с помощью которых можно передавать значения в сценарий. В таблице ниже перечисляются эти переменные.

Переменная

Использование

$0

Хранит имя самого скрипта, полученное из командной строки

$1

Первая опция

$2

Вторая опция

$3

Третья опция

$4

Четвертая опция

$5

Пятая опция

$6

Шестая опция

$7

Седьмая опция

$8

Восьмая опция

$9

Девятая опция

$*

Все опции

$#

Число заданных опций

Если вы используете C-shell, тогда вместо $# применяется $#argv .

В контексте нашего скрипта, что можно передать команде, которую он содержит, в качестве параметра? Команда всегда ищет строки, в которых есть буквосочетание rpm. Заменив шаблон на переменную, сможем искать что угодно:

#!/bin/sh

rpm -qa | grep $*

Так теперь выглядит текст скрипта и ищет он подстроки, которые будут заданы в команде после имени файла. Переименуем его в rpmgrep и запустим, например, так:

$ ./rpmgrep python

python-devel-2.2.1-17

gnome-python2-gtkhtml2-1.99.11-8

gnome-python2-canvas-1.99.11-8

gnome-python2-1.99.11-8

rpm404-python-4.0.4-8x.27

orbit-python-1.99.0-4

gnome-python2-bonobo-1.99.11-8

gnome-python2-gconf-1.99.11-8

libxslt-python-1.0.19-1

libxml2-python-2.4.23-1

python-optik-1.3-2

python-2.2.1-17

rpm-python-4.1-1.06

mod_python-3.0.0-10

python-tools-2.2.1-17

($* хранит все опции командной строки в виде строки с пробелами. Но shell не поддерживает больше 9 параметров, если не использовать оператор shift, а grep не поддерживает мультишаблонный поиск, для этого есть egrep. Поэтому, если ввести несколько параметров через пробел, например, ./rpmgrep rpm python, скрипт завершит работу с сообщением об ошибке. Итог - в данном случае в параметре передается "что-то, что ввели после имени файла в виде последовательности символов, не содержащей пробелов" - прим. перев. )

Далее - Файлы в rpm-пакетах
Назад - Преобразование скрипта в команду
Содержание


14.5 Файлы в rpm-пакетах

Когда есть необходимость работать со множеством файлов rpm-пакетов, например, с пакетами, не установленными в систему, вы можете обнаружить, что вводите одни и те же команды вновь и вновь при переходе к следующему пакету. Стандартная задача - вам нужно знать, какие зависимости имеются у пакета. Можно, конечно, ввести команду rpm с соответствующими опциями несколько раз, а можно написать коротенький скрипт с нужными опциями:

#!/bin/sh

rpm -qp --requires $*

Этот скрипт принимает имя файла rpm-пакета в качестве параметра. Назовем скрипт rpmdepend и запустим таким образом:

$ rpmdepend vim-common-6.1-14.i386.rpm

rpmlib(PayloadFilesHavePrefix) <= 4.0-1

rpmlib(CompressedFileNames) <= 3.0.4-1

/bin/sh

/usr/bin/awk

libc.so.6

libc.so.6(GLIBC_2.0)

libc.so.6(GLIBC_2.1)

Смысл: мы получили список зависимостей пакета, не обращаясь к БД RPM, из самого пакета.

Другая часто встречающаяся задача - вывод листинга файлов пакета вместе с информацией о пакете. Это реально помогает в работе, поскольку многие пакеты имеют ничего не говорящие об их функциональности имена, например dia или anakonda.

#!/bin/sh

rpm -qilp $* | less

Этот скрипт (назовем его rpminfo) может вывести много строк, поэтому вывод перенаправлен в просмотрщик less. Например:

$ ./rpminfo perl-XML-Dumper-0.4-22.noarch.rpm

Name : perl-XML-Dumper Relocations: /usr

Version : 0.4 Vendor: Red Hat, Inc.

Release : 22 Build Date: Tue 06 Aug 2002 01:53:30 PM CDT

Install date: (not installed) Build Host: vegeta.devel.redhat.com

Group : System Environment/Libraries Source RPM: perl-XML-Dumper-0.4-22.src.rpm

Size : 10015 License: GPL

Signature : DSA/SHA1, Tue 06 Aug 2002 02:11:39 PM CDT, Key ID fd372689897da07a

Packager : Red Hat, Inc.

URL : http://www.cpan.org

Summary : Perl module for dumping Perl objects from/to XML

Description :
XML::Dumper dumps Perl data to XML format. XML::Dumper can also read XML data that was previously dumped by the module and convert it back to Perl. Perl objects are blessed back to their original packaging; if the modules are installed on the system where the perl objects are reconstituted from xml, they will behave as expected. Intuitively, if the perl objects are converted and reconstituted in the same environment, all should be well.

/usr/lib/perl5/vendor_perl/5.8.0/XML/Dumper.pm

/usr/share/man/man3/XML::Dumper.3pm.gz

Таким образом, мы узнали функции пакета и какие файлы он установит в систему.

Далее - Запросы к БД RPM
Назад - Передача параметров в скрипт
Содержание


2.1.1 Введение в структуру файла пакета

RPM предоставляет возможности установки, обновления и удаления пакетов. В обычном случае каждый пакет представляет собой приложение и некоторое количество ассоциированных с ним файлов. Например, веб-сервер Apache в полной комплектации это сам сервер, множество файлов конфигурации, обширная документация, дополнения, etc. Все это помещается в один RPM пакет.
Одно из преимуществ системы RPM - это то, что каждый rpm-файл (а это один файл с точки зрения операционной системы) содержит весь комплект файлов приложения. Например, следующий файл содержит пакет xcopilot:

xcopilot-0.66-3.i386.rpm

В соответствии с соглашениями об именовании, обсуждаемыми в Разделе 2, этот пакет представляет программу xcopilot версии 0.6.6, сборка 3, целевая архитектура i386.
С помощью одной команды этот файл можно скопировать на другую систему и установить его, и, также с помощью одной команды его можно будет удалить.

Далее - Формат файла RPM
Назад - Содержание


14.6 Запросы к БД RPM

Кроме извлечения информации непосредственно из файлов rpm-пакетов, с помощью скриптов можно автоматизировать запросы к БД RPM. Этот подход сильно облегчает составление сложных запросов с использованием опции --queryformat , особенно если нет времени запоминать все форматы.

Далее - Запрос списка пакетов, установленных единовременно
Назад - Файлы в rpm-пакетах
Содержание


14.6.1 Запрос списка пакетов, установленных единовременно

Если вы хотите получить список пакетов, установленных в рамках одной транзакции и имеющих одинаковый идентификатор транзакции, можно использовать скрипт rpmtran, показанный ниже:

#!/bin/sh

tid=`rpm -q --qf "%{INSTALLTID}\n" $*`

rpm -q --tid $tid

Этот скрипт использует формат запроса для получения идентификатора транзакци (transaction ID, TID) определенного пакета. Имя пакета передается в параметре командной строки. Затем выводится список всех пакетов с таким TID. Это пакеты, установленные одновременно. Пример использования:

$ ./rpmtran tcl

itcl-3.2-74

tclx-8.3-74

tcl-8.3.3-74

tix-8.2.0b1-74

tkinter-2.2.1-17

Далее - Чтение html-документации о пакете
Назад - Запросы к БД RPM
Содержание


2.1.2 Формат файла rpm

rpm-пакеты содержат некоторое количество служебной информации и файлы, которые должны быть установлены в систему. Файл пакета, таким образом, состоит из нескольких частей, в частности бинарного заголовка, в котором в жестко заданных полях в определенном формате хранится информация о пакете, и cpio-архива, представляющего собой дерево каталогов и файлов проекта.
Например, служебное поле NAME хранит имя пакета, а опциональное поле PRE - прединсталляционный скрипт, который будет выполнен до копирования файлов в систему.

Полный формат rpm-файла - это четыре секции. Первая секция - начальный идентификатор, помечающий файл как rpm-пакет. Секция идентификатора создается соответствующей версией системы RPM, установленной в ОС, которая использовалась для сборки. Последующие секции, это: сигнатура, бинарный хедер и нагрузка. Из них только секция нагрузки несет в себе файлы и каталоги.

Сигнатура следует за начальным идентификатором. Подобно любой цифровой подписи сигнатура позволяет оценить в последствии целостность пакета. С помощью сигнатуры нельзя понять, содержит ли пакет ошибки :), но можно установить, верный ли rpm-архив вы загрузили.
Сигнатура является результатом выполнения некоторой функции над хедером и нагрузкой. Это может быть криптофункция вроде PGP или хэш-функция, например дайджест MD5.

Хедер содержит ноль или более полей данных, описывающих пакет. В служебные поля заключается информация о правах на программное обеспечение, версия, описание пакета и некоторые другие сведения.

Нагрузка содержит файлы, которые реально используются в проекте. Когда отдана команда на установку пакета, эти файлы копируются в систему в нужные места. Все дерево каталогов и файлов пакета заархивировано и сжато gzip.

Для извлечения архива из пакета используется утилита rpm2cpio (описывается далее в этом разделе в главе "Другие RPM команды").

Далее - Бинарные rpm и rpm с исходным кодом
Назад - Введение в структуру файла пакета
Содержание


14.6.2 Чтение html-документации о пакете

Можно комбинировать команды rpm с другими командами. Например, rpm -qd выводит файлы документации, содержащиеся в пакете. Если имеется документация в формате HTML, можно отобразить документ в Web-браузере. В соответствии с соглашениями, индекс документации должен называться index.php . С учетом этого обстоятельства создадим скрипт rpmmoz, запускающий браузер для просмотра найденных документов:

#!/bin/sh

html_file=`rpm -qd $* | grep index.php | head -n 1 `

echo "Launching Web browser with $html_file"

htmlview $html_file &

Скрипт ищет документацию пакета с заданным именем, находит первый по порядку index.php и запускает для его просмотра фоновый процесс браузера (Mozilla или что у вас сконфигурировано по умолчанию). После запуска скрипта в консоли можно увидеть следующее:

$ ./rpmmoz rpm-devel

Launching Web browser with /usr/share/doc/rpm-devel-4.1/apidocs/html/index.php

Далее - Раздел 15. Программирование RPM на C
Назад - Запрос списка пакетов, установленных единовременно
Содержание


15. Программирование RPM на C

С-библиотека RPM позволяет разработчику выполнять все операции rpm из своих собственных программ на C или C++.
Сама по себе утилита rpm работает быстро и она проста для пользователя. Зачем тогда выполнять операции RPM из сторонних программ?

Можно привести по меньшей мере несколько резонов:

* Скорость: если есть нужда выполнять операции над большим массивом пакетов, например, верификацию большого числа пакетов, выполнение функций из одной программы несколько ускорит процесс по сравнению с запуском rpm для каждого пакета.

* Пользовательские опции: если вы хотите делать что-то, что rpm не предоставляет, или что сделать не просто, вы можете захотеть сделать это по-своему.

* Удобство: если необходимо обработать много пакетов быстро и с нестандартными опциями, возможно, удобнее это сделать из программы, спроектированной специально для выполнения узкоспециализированной операции. Перед написанием такой программы убедитесь, что никто не написал скрипт, решающий данную задачу. Поправить готовый скрипт, конечно, выгоднее по затратам, чем написать приложение.

* Установка программ: мир Windows имеет промышленные стандарты для графических установщиков программ, как, например, InstallShield или InstallAnywhere. С другой стороны, RPM ориентирована на автоматизацию установки с помощью rpm. Соединяя положительные черты того и другого, напишите графическое приложение для установки вашего приложения с помощью доступных в RPM функций.

* Интеграция с окружением: вы можете захотеть наилучшим образом интегрировать RPM со средами GNOME или KDE.

* Работа с другими языками: вы можете захотеть получить доступ к функциям C-библиотеки RPM из языков, отличных от C, Python или Perl, например, из Ruby или Tcl. Используя библиотеку, можно создать привязки для этих языков.

Далее - Установка окружения для C-программирования
Назад - Чтение html-документации о пакете
Содержание


15.1.1 Установка окружения для C-программирования

Как минимум, нужно иметь компилятор, gcc, и текстовый редактор.
Пакет gcc имеет ряд зависимостей. Убедитесь, что все они установлены.
В качестве текстовых редакторов разработчики используют vi или emacs, или один из редакторов в графической системе, таких как gedit (а кто-то любит mcedit - прим. перев.).
Установленное окружение сборки потребует лишь доступ к RPM библиотеке из пакета разработки RPM.

Далее - Установка окружения разработки RPM
Назад - Программирование RPM на C
Содержание


15.1.2 Установка окружения программирования RPM

Для разработки программ, использующих библиотеку RPM, необходимо установить пакет rpm-devel. По версии он должен совпадать с пакетом rpm, установленным в вашей системе.

Для уверенности в совместимости следует линковать те же библиотеки, что использует утилита rpm. Установите их из вашего дистрибутива Linux. Для древних версий дистрибутивов Red Hat используйте ftp://ftp.rpm.org/pub/rpm/dist/ . Этот сайт хранит версии всех библиотек RPM вплоть до 1996 года (по понятиям истории Linux - верхний палеолит).

Далее - Использование библиотеки RPM
Назад - Установка окружения для C-программирования
Содержание


15.1.3 Использование библиотеки RPM

Все программы на C, использующие библиотеку RPM, нуждаются во включении заголовочного файла rpmcli.h, определяющего высокоуровневый API. Он базируется на опциях командной строки для утилиты rpm. Таблица ниже описывает другие нужные файлы для построения основных подсистем системы RPM.

Файл

Определяет

rpmdb.h

Функции доступа к БД RPM

rpmio.h

Процедуры ввода/вывода RPM

popt.h

Функции обработки опций командной строки

Кроме того, некоторое количество заголовочных файлов определяют основные объекты данных в RPM и функции для работы с этими объектами. Таблица ниже описывает эти файлы.

Файл

Определяет

rpmts.h

Объекты транзакций

rpmte.h

Элементы транзакций (пакеты)

rpmds.h

Информация о файлах

header.h

Заголовки пакетов

В большинстве rpm-дистрибутивах заголовочные файлы RPM расположены где-то в районе /usr/include/rpm . Для установки более точного места расположения используйте команду:

$ rpm ql rpm-devel

Далее - Компиляция и линковка RPM программ
Назад - Установка окружения программирования RPM
Содержание


15.1.4 Компиляция и линковка RPM программ

Программы, использующие rpmlib API, это обычные программы на C . Нам нужно включить заголовочные файлы, функции из которых требуются, и выполнить операцию связывания (линковку) для правильных библиотек.

15.1.4.1 Подключаемые файлы
Подключаемые файлы RPM находятся в каталоге /usr/include/rpm , нужно включить этот каталог в группу каталогов, которые компилятор обходит в поисках хэдеров, с помощью опции -I :

$ gcc I/usr/include/rpm c rpm1.c

Это, в частности, означает, что разработчик может установить хэдеры в другой каталог, изменив в команде путь к нему.

Для облегчения отладки, вы, возможно, захотите включить опцию -Wall (выводить все предупреждения) и -g (компилировать с отладочной информацией). Например:

$ gcc -Wall -g I/usr/include/rpm c rpm1.c

15.1.4.2 Библиотеки
Основная библиотека RPM - librpm.a , или ее разделяемая версия. Для выполнения каких-либо значимых операций нужны и другие библиотеки:

Библиотека

Использование

rpm

Основная библиотека RPM

rpmdb

Библиотека БД RPM

rpmio

Библиотека ввода/вывода

popt

Библиотека для разбора опций командной строки

Если из своей программы вы собираете rpm-пакеты, потребуется еще библиотека rpmbuild . Для компиляции и линковки простой программы потребуется отдать команду, подобную следующей:

gcc -I/usr/include/rpm -o program program.c lrpmbuild \
-lrpm -lrpmdb -lrpmio lpopt

В некоторых версиях Linux или в других ОС, возможно потребуется включить вспомогательные библиотеки:

gcc -I/usr/include/rpm -o program program.c L/opt/lib/rpm \
-lrpmbuild -lrpm -lrpmdb -lrpmio lpopt -lelf -lbz2 -lz

Если библиотеки установлены в нестандартный каталог, необходимо использование опции -L для указания путей:

gcc -I/usr/include/rpm -o program program.c L/opt/lib/rpm \
-lrpmbuild -lrpm -lrpmdb -lrpmio lpopt -lelf -lbz2 -lz

Начиная с версии RPM 4.2 подключается только библиотека rpm . Все остальные библиотеки будут включены автоматически, если они нужны.

Далее - Получение информации о RPM-окружении
Назад - Использование библиотеки RPM
Содержание


15.1.5 Получение информации о RPM окружении

Значительная часть конструкции системы RPM лежит в области системно-зависимых конфигураций. К системно-зависимым параметрам относится, например, информация о платформе, о совместимых платформах, о расположении различных файлов. Файлы настройки RPM - rc и macros поддерживают сотни опций, настраивающих RPM на определенную систему, и многие настройки не могут быть оставлены в значениях по умолчанию.

RPM программы на C нуждаются в доступе к системным настройкам RPM для проверки правильности установок, адекватных системной архитектуре и текущей инсталляции. Для запуска программы, системные установки должны быть считаны (возможно, из всех конфигурационных файлов). Для выполнения этой операции вызывается rpmReadConfigFiles :

int rpmReadConfigFiles(const char *files, const char *target);

Параметр files содержит разделенный двоеточиями список файлов, которые отвечают за системную конфигурацию. Параметр target содержит целевую платформу. Для использования установок по умолчанию достаточно, чтобы оба параметра имели значение NULL .

Функция rpmReadConfigFiles возвращает 0 в случае успеха и -1 в случае ошибки.

Единожды считав конфигурационные файлы, мы можем получить доступ к значениям переменных конфигурации, или, например, распечатать их.

15.1.5.1. Вывод конфигурации
Для вывода конфигурации используется rpmShowRC :

int rpmShowRC(FILE* output);

Чтобы задать выходной файл, устанавливается значение единственного параметра, например, для стандартного вывода:

rpmShowRC( stdout );

Функция rpmShowRC всегда возвращает 0.

Для контролирования вывода rpmShowRC и других библиотечных функций используют установку уровня многословности вывода с помощью функции rpmSetVerbosity :

rpmSetVerbosity(RPMMESS_NORMAL);

Возможные варианты многословности вывода:

Уровень

Что означает

RPMMESS_FATALERROR

Сообщения о критических ошибках и все не менее значимое

RPMMESS_ERROR

Сообщения об ошибках вообще и все не менее значимое

RPMMESS_WARNING

Все предупреждения и все не менее значимое

RPMMESS_QUIET

То же, что и RPMMESS_WARNING

RPMMESS_NORMAL

Только существенные сообщения

RPMMESS_VERBOSE

Все информационные сообщения

RPMMESS_DEBUG

Вся отладочная информация и все не менее значимое

Пример программы, использующей вышеописанные функции:

/* Show the rpmrc settings. */

#include <stdio.h>

#include <stdlib.h>

#include <rpmlib.h>

int main(int argc, char * argv[]) {

int status = rpmReadConfigFiles( (const char*) NULL,

(const char*) NULL);

if (status != 0) {

printf("Error reading RC files.\n");

exit(-1);

}

else {

printf("Read RC OK\n");

}

rpmSetVerbosity(RPMMESS_NORMAL);

rpmShowRC( stdout );

exit(0);
}

Скомпилируйте программу с помощью команды:

$ cc -I/usr/include/rpm -o rpm1 rpm1.c -lrpm -lrpmdb -lrpmio lpopt

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

15.1.5.2. Разворачивание значений макросов
В совокупности rc-файлы и файлы макросов содержат множество определений, которые можно использовать для обращения к значениям установок. Термин макроопределение или макрос используются потому, что значение может быть не просто строкой. Может быть макрос, ссылающийся на другие макросы, возможны и другие сложноподчиненные случаи. Базовый синтаксис макросов:

%name_of_macro

Например:

%_target

Множество макросов начинаются с нижнего подчеркивания.

Всегда можно раскрыть макрос с помощью команды rpm --eval :

$ rpm --eval %_target

i386-linux

Обратиться к значению макроса можно так:

%{_target}

Такой синтаксис облегчает задачу включения макросов в комбинации с обычным текстом и другими макросами.

15.1.5.2. Разворачивание макросов внутри кода
Для получения значения макроса в C-программе используют rpmExpand. Функция rpmExpand может развернуть один или несколько макросов, возвращая развернутое значение. Функции можно передать различное число параметров. Список должен быть инициализирован значением NULL .

char* rpmExpand (const char *arg,...);

Для очистки после возврата данных из rpmExpand следует использовать free .

Программа в примере ниже забирает из командной строки первый параметр и пытается его развернуть как макрос:

/* Show some macro settings. */

#include <stdio.h>

#include <stdlib.h>

#include <rpmlib.h>

#include <rpmmacro.h>

int main(int argc, char * argv[]) {

int status = rpmReadConfigFiles( (const char*) NULL,

(const char*) NULL);

if (status != 0) {

printf("Error reading RC files.\n");

exit(-1);

}

char* value = rpmExpand(argv[1], (const char*) NULL);

printf("Value of macro is [%s]\n", value);

exit(0);

}

Скомпилируйте программу как показано выше. При запуске после имени исполняемого файла введите имя макроса для разворачивания. Например:

$ ./rpmexpand %_target

Value of macro is [i386-linux]

Можно задать несколько имен макросов в связке:

$ ./rpmexpand %_builddir/%_target

Value of macro is [/usr/src/redhat/BUILD/i386-linux]

Для проверки работы программы можно использовать rpm --eval :

$ rpm --eval %_builddir/%_target

/usr/src/redhat/BUILD/i386-linux

Далее - Мощь popt
Назад - Компиляция и линковка RPM программ
Содержание


15.2 Мощь popt

Popt предоставляет мощную библиотеку для разбора командных строк. Она позволяет утилите rpm иметь массу опций, сочетание которых может применятся весьма эффективно. Popt можно использовать в качестве самостоятельной библиотеки, или применять ее для разбора опций командных строк rpm.

Основное назначение библиотеки - разобрать значение опций командной строки для C-программы, передав их в виде аргументов (argc, argv). Они используются в так называемой таблице опций, которая хранит и описывает все возможные значения.

Основные преимущества popt по сравнению с более простыми библиотеками, типа getopt, это возможность обработки комплексных аргументов и возможность определения псевдонимов. Утилита rpm поддерживает три вида поведения для опции -i, они зависят от контекста (установка пакета, получение информации о пакете в составе сложного запроса, выполнение стадии инсталляции как части процесса сборки). Все эти случаи надо уметь обрабатывать.

Popt поддерживает традиционную для Unix форму коротких опций, типа -U, и обычную для GNU форму, как --upgrade. Используя popt, можно для любой опции определить обе формы, длинную и короткую. Кроме того, опции командных строк могут быть отдельными флагами, например, -v для многословного вывода, или опциями, через которые передаются различные значения, например, -f для передачи имени файла, которое может быть любым.

Далее - Псевдонимы popt
Назад - Получение информации о RPM окружении
Содержание


15.2.1. Псевдонимы popt

Возможность определять псевдонимы (алиасы - обычный жаргонизм разработчиков) есть важная особенность popt. Псевдонимы позволяют определять опции как ссылки на группу других опций. В качестве простейшего примера: --upgrade и U выполняют одно и то же действие, одну опцию можно рассматривать как ссылку на другую.

У RPM имеется специальный файл (обычно /usr/lib/rpm/rpmpopt-%version), определяющий несколько сотен псевдонимов popt для конфигурации опций командной строки rpm. Например:

Rpm alias requires --qf \

"[%{REQUIRENAME} %{REQUIREFLAGS:depflags} %{REQUIREVERSION}\n]" \

--POPTdesc=$"list capabilities required by package(s)"

Этот пример определяет rpm --requires как реальный запрос с использованием опций --qf или --queryformat.

Далее - Программирование с popt
Назад - Мощь popt
Содержание


15.2.2. Программирование с popt

Для использования popt в программе, мы должны заполнить таблицу опций и вызвать poptGetContext. Функция poptGetContext разбирает опции командной строки и возвращает poptContext, неопределенный тип данных, которые нужно передавать в качестве параметров в разные функции popt. poptContext хранит состояние процедуры разбора. Это позволяет вызывать библиотеку, передавая ее функциям различные и многочисленные наборы аргументов. Каждый набор имеет собственный контекст, благодаря чему все данные можно держать отдельно во избежании смешивания с другими.

Базовый синтаксис poptGetContext:

poptContext poptGetContext (const char * name,

int argc,

const char ** argv,

const struct poptOption * options,

int flags );

Использование функций popt требует включения хэдера popt.h:

#include <popt.h>

Flags должен быть битовой маской, возможные значения перечислены ниже.

Флаг

Значение

POPT_CONTEXT_NO_EXEC

Игнорировать исполняемые расширения

POPT_CONTEXT_KEEP_FIRST

Обрабатывать argv[0] (имя самой команды) как опцию

POPT_CONTEXT_POSIXMEHARDER

Не позволять опциям следовать за аргументами

Когда использование poptContext завершилось, необходимо освободить память вызовом poptFreeContext:

poptContext poptFreeContext(poptContext context);

Также возможно заполнить контекст из установок, записанных в файле, с помощью poptReadConfigFile:

int poptReadConfigFile(poptContext context,

const char * file_name);

15.2.2.1. Заполнение таблицы опций
Программа нуждается в доступе к таблице, которая определяет все возможные опции. Эта "таблица" - массив структур, где каждая структура задает одну опцию. Формат структуры для отдельной опции такой:

struct poptOption {

const char * longName;

char shortName;

int argInfo;

void * arg;

int val;

const char * descrip;

const char * argDescrip;

};

Соответственно, longName определяет длинную форму опции, shortName - короткую, однобуквенную форму. Для того, чтобы задать отсутствие короткой опции, надо поместить в это поле нулевой символ, '\0'. Например, опция --rebuilddb не имеет короткого варианта.

Поле descrip содержит короткое описание опции, argDescrip - типы значений, или NULL, если опция не имеет передаваемых значений.

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

Тип

Значение

Определяет

POPT_ARG_NONE

0

Данные не передаются в аргументе, это отдельная опция, как -v

POPT_ARG_STRING

1

Аргумент обрабатывается как строка

POPT_ARG_INT

2

Аргумент обрабатывается как целое

POPT_ARG_LONG

3

Аргумент обрабатывается как длинное целое

POPT_ARG_INCLUDE_TABLE

4

Аргумент помещается в таблицу

POPT_ARG_CALLBACK

5

Аргумент помещается в вызывающую функцию

POPT_ARG_INTL_DOMAIN

6

Устанавливает домен перевода

POPT_ARG_VAL

7

Использовать значение из поля val для аргумента

POPT_ARG_FLOAT

8

Аргумент обрабатывается как число с плавающей точкой

POPT_ARG_DOUBLE

9

Аргумент обрабатывается как число с плавающей точкой двойной точности

Используйте эти константы, определенные в popt.h, вместо указывания реальных чисел.

В зависимости от типа определенного в поле argInfo, popt будет интерпретировать неспецифицированное поле указателя arg различными путями. Использование указателя позволяет библиотеке автоматически обновлять переменные программы, базируясь на установках опций командной строки.

Вы можете задать в поле arg значение NULL. В этом случае popt не будет задавать никаких значений.

Тип POPT_ARG_NONE указывает, что опция не имеет значений, как, например, -v.

Если тип аргумента POPT_ARG_NONE, popt установит arg в значение 1, если опция присутствует в командной строке.

15.2.2.2. Обработчики обратного вызова (callback-функции) popt
Тип POPT_ARG_CALLBACK указывает, что в поле arg хранится указатель на callback-функцию, определенную следующим образом:

typedef void (*poptCallbackType) (poptContext con,

enum poptCallbackReason reason,

const struct poptOption * opt,

const char * arg,

const void * data);

Reason будет одним из следующих значений:

enum poptCallbackReason {

POPT_CALLBACK_REASON_PRE = 0,

POPT_CALLBACK_REASON_POST = 1,

POPT_CALLBACK_REASON_OPTION = 2

};

Поле data содержит значение поля descrip из структуры poptOption. В этом поле вы можете установить указатель на какие-то произвольные данные.

Callback-функции удобны, если вы используете вложенные таблицы опций. В этом случае вы можете поместить код обработки для вложенных опций в callback.

15.2.2.3. Специальные флаги таблицы опций
В дополнение ко всему вышеперечисленному, вы можете определить специальные битовые флаги, определяющие расширенную информацию для обработки каждой опции. Сочетание этих флагов с типом значения происходит с использованием логического оператора OR:

* POPT_ARGFLAG_ONEDASH позволяет использовать longName с одним или двумя дефисами, например, -upgrade или --upgrade.

* Для опций типа битовых масок флаги POPT_ARGFLAG_OR, POPT_ARGFLAG_NOR, POPT_ARGFLAG_AND, POPT_ARGFLAG_NAND, и POPT_ARGFLAG_XOR говорят popt применять заданную операцию, то есть соответственно OR, NOR, AND, NAND, или XOR, к значению, если оно установлено. Флаг POPT_ARGFLAG_NOT вначале инвертирует значение.

* Также можно использовать макрос POPT_BIT_SET для установки бита, а POPT_BIT_CLR - для очистки бита.

* Флаг POPT_ARGFLAG_OPTIONAL указывает на то, что значение аргумента опционально.

* Флаг POPT_ARGFLAG_DOC_HIDDEN говорит popt скрыть эту опцию при отображении справочной информации. Другими словами, это опция для внутреннего использования.

* Редко используемый флаг POPT_ARGFLAG_STRIP заставляет popt игнорировать опцию.

* Флаг POPT_ARGFLAG_SHOW_DEFAULT говорит popt показать значение опции, которым она инициализирована по умолчанию, при выводе справочной информации.

15.2.2.4. Магические опции
В программировании RPM разработчики обычно завершают таблицу опций тремя специальными опциями: POPT_AUTOALIAS, POPT_AUTOHELP, и POPT_TABLEEND. Опция POPT_AUTOALIAS определяет таблицу псевдонимов:

#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \

0, "Options implemented via popt alias/exec:", NULL },

Эта опция ссылается на таблицу poptAliasOptions. Вы можете использовать тип argInfo POPT_ARG_INCLUDE_TABLE для включения другой таблицы опций. Эти опции будут заполнены псевдонимами popt. Кроме того, внутри RPM программ еще одна таблица, rpmcliAllPoptTable, хранит группы опций, общие для всех RPM программ и всех режимов работы rpm.

Опция POPT_AUTOHELP поддерживает стандартную опцию help. Макрос POPT_AUTOHELP автоматически поддерживает использование опций -?, --help, и --usage:

#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \

0, "Help options:", NULL },

Опция POPT_TABLEEND определяет пустую опцию для обозначения конца таблицы. Включение пустой опции в конце - обязательное требование:

#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }

15.2.2.5. Разбор опций командной строки
Когда контекст определен, далее нужно обойти параметры командной строки. Для обхода используется poptGetNextOpt:

int poptGetNextOpt(poptContext context);

Если встречаются ошибки, poptGetNextOpt в качестве кода возврата возвращает отрицательный код ошибки. Если при обходе появилась пустая опция (признак конца таблицы опций), возвращается -1. Коды ошибок:

Код

Означает

POPT_ERROR_NOARG

Опция требует аргумента, но он отсутствует

POPT_ERROR_BADOPT

Аргумент не может быть разобран

POPT_ERROR_OPTSTOODEEP

Псевдонимы имеют слишком большой уровень вложенности

POPT_ERROR_BADQUOTE

Начальные и конечные кавычки не заданы

POPT_ERROR_BADNUMBER

Аргумент не может быть приведен к номеру

POPT_ERROR_OVERFLOW

Номер агрумента выходит из диапазона возможных значений

POPT_ERROR_ERRNO

Системный вызов вернул ошибку в errno

15.2.2.6. Обзор опций командной строки
В нормальных обстоятельствах poptGetNextOpt разбирает все опции командной строки и возвращает -1. Если вы нуждаетесь в упрощении, можно задать указатели на переменные, переданные в таблицу опций. Если необходимы некоторые специальные действия при обработке опций, которые не выполняет popt, например, нужно обработать опции с типом POPT_ARG_NONE, тогда poptGetNextOpt возращает однобуквенную опцию.

В этом случае можно вызвать poptGetNextOpt в цикле:

while ((option = poptGetNextOpt(context) ) {

/* Do something... */

}

Внутри цикла мы можем вызвать poptGetOptArg для получения значения аргумента:

char * poptGetOptArg(poptContext context);

Для перезапуска обработки опций используется poptResetContext:

void poptResetContext(poptContext context);

В целом, popt просто ищет аргументы, начинающиеся с черточки -. В большинстве приложений командной строки имеется экстрааргумент в конце команды, например, список файлов. popt не обрабатывает их, но может предоставить возможности такой обработки. Для обхода экстрааргументов вызывается poptGetArg:

char * poptGetArg(poptContext context);

Чтобы получить все экстрааргументы, нужно вызывать функцию до тех пор, пока она не вернет NULL.

Чтобы перейти к следующему аргументу, используют poptPeekArg, при этом не отмечая аргумент, как прошедший обработку:

char * poptPeekArg(poptContext context);

Или же можно получить весь список экстрааргументов путем вызова poptGetArgs:

char ** poptGetArgs(poptContext context);

Далее - Обработка ошибок
Назад - Псевдонимы popt
Содержание


15.2.3. Обработка ошибок

Внутри цикла обработки опций можно вызвать poptBadOption для получения опции, которая оказалась "плохой", и poptStrerror для вывода сообщения, соответствующего данной ошибке.

В poptBadOption необходимо передать контекст и битовую маску флагов. Для указания отсутствия флагов передается 0, или POPT_BADOPTION_NOALIAS, который заставляет popt вернуть не значение, определенное в алиасах, а саму опцию. Для лучшего протоколирования ошибки в этом случае poptBadOption вернет опцию, максимально похожую на то, что ввел пользователь, если нет возможности вернуть в точности то, что он ввел.

Синтаксис:

char * poptBadOption(poptContext context, int flags);

Для получения стандартного сообщения о конкретной ошибке, в
poptStrerror нужно передать ее код:

const char * poptStrerror(const int error_code);

Скомбинировав возможности можно вывести ошибку и ее код, как показано в примере:

fprintf( stderr, "Error with option [%s]\n %s",

poptBadOption(context, POPT_BADOPTION_NOALIAS),

poptStrerror(error_code);

Для вывода стандартной помощи (сообщения об использовании) применяется функция poptPrintUsage:

void poptPrintUsage(poptContext context,

FILE *output,

int flags);

Эта функция выводит помощь, когда пользователь задал в командной строке неверные опции или не минимально достаточный их набор.

Далее - Работающий пример
Назад - Программирование с popt
Содержание


15.2.4. Работающий пример

Сведем всю уже имеющуюся у нас информацию в программу, демонстрирующую возможности popt.

Программа popt1.c :

/* Processes command-line options. */

#include

#include

#include


/* Data values for the options. */

static int intVal = 55;

static int print = 0;

static char* stringVal;

void callback(poptContext context,

enum poptCallbackReason reason,

const struct poptOption * option,

const char * arg,

const void * data)

{

switch(reason)

{

case POPT_CALLBACK_REASON_PRE:

printf("\t Callback in pre setting\n"); break;

case POPT_CALLBACK_REASON_POST:

printf("\t Callback in post setting\n"); break;

case POPT_CALLBACK_REASON_OPTION:

printf("\t Callback in option setting\n"); break;

}

}

/* Set up a table of options. */

static struct poptOption optionsTable[] = {

{ (const) "int", (char) 'i', POPT_ARG_INT, (void*) &intVal, 0,

(const) "follow with an integer value", (const) "2, 4, 8, or 16" },

{ "callback", '\0',
POPT_ARG_CALLBACK|POPT_ARGFLAG_DOC_HIDDEN,

&callback, 0, NULL, NULL },

{ (const) "file", (char) 'f', POPT_ARG_STRING, (void*) &stringVal, 0,

(const) "follow with a file name", NULL },

{ (const) "print", (char) 'p', POPT_ARG_NONE, &print, 0,

(const) "send output to the printer", NULL },

POPT_AUTOALIAS

POPT_AUTOHELP

POPT_TABLEEND

};

int main(int argc, char *argv[]) {

poptContext context = poptGetContext(

(const char*) "popt1",

argc,

argv,

(const struct poptOption* ) &optionsTable,

0);

int option = poptGetNextOpt(context);

printf("option = %d\n", option);

/* Print out option values. */

printf("After processing, options have values:\n");

printf("\t intVal holds %d\n", intVal);

printf("\t print flag holds %d\n", print);

printf("\t stringVal holds [%s]\n", stringVal);

poptFreeContext(context);

exit(0);

}

Этот пример определяет collback, но, с другой стороны, использует простейший подход для обработки опций командной строки. Программа просто позволяет popt поместить значения опций в таблицу опций. В большинстве случаев потребуется более сложный подход к обработке опций.

Скомпилируем программу:

gcc -I/usr/include/rpm -o popt1 popt1.c -lpopt

При запуске программы используйте различные опции. Если использовать все опции, получим примерно следующий вывод:

$ ./popt1 --int 42 -p --file filename1

Callback in option setting

Callback in option setting

Callback in post setting

option = -1

После обработки опции имеют значения:

intVal holds 42

print flag holds 1

stringVal holds [filename1]

Этот пример использует короткую форму print, -p, и длинные формы для двух других опций. Библиотека popt также предоставляет вывод помощи с использованием макроса POPT_AUTOALIAS. Для получения помощи нужно ввести --help или -?:

$ ./popt1 --help

Usage: popt1 [OPTION...]

-i, --int=2, 4, 8, or 16 follow with an integer value

-f, --file=STRING follow with a file name

-p, --print send output to the printer

Options implemented via popt alias/exec:

Help options:

-?, --help Show this help message

--usage Display brief usage message

Далее - Обработка опций командной строки rpm
Назад - Обработка ошибок
Содержание


15.2.5. Обработка опций командной строки rpm

C-библиотека RPM широко использует popt для обработки опций командной строки утилиты rpm. Функции библиотеки RPM, например, rpmcliInit, которая устанавливает окружение командной строки rpm, требуют наличие таких записей в таблице опций, которые определяют опции командной строки для вашей программы.

Для написания простой программы, обрабатывающей стандартные опции командной строки rpm, потребуется определить следующую таблицу опций:

static struct poptOption optionsTable[] = {

{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,

"Common options for all rpm modes and executables:",

NULL },

POPT_AUTOALIAS

POPT_AUTOHELP

POPT_TABLEEND

};

Затем инициализируйте свою программу с помощью вызова rpmcliInit:

poptContext rpmcliInit(int argc, char *const argv[],

struct poptOption * optionsTable);

При вызове rpmcliInit устанавливаются все переменные для стандартных опций командной строки rpm.

Например, чтобы увидеть значение флага многословности, нужно вызвать rpmIsVerbose:

int rpmIsVerbose();

После того, как программа, использующая rpmcliInit, завершила работу, вызовите rpmcliFini для очистки глобальных данных:

poptContext rpmcliFini(poptContext context);

rpmcliFini возвращает NULL.

Далее - Работа с rpm-файлами
Назад - Работающий пример
Содержание


15.3. Работа с rpm-файлами

C-библиотека RPM предоставляет функции как доступа к БД RPM, так и чтения файлов rpm-пакетов. Таким образом, из своих программ с помощью библиотеки мы можем выполнять все действия утилит rpm и rpmbuild. Однако, есть задачи, которые таким путем выполнить легче, чем некоторые другие. Например, если требуется разработать приложение для комплексной установки множества пакетов или программу, которая будет поддерживать множество различных систем в актуальном состоянии так, чтобы выполнялись требования по версиям пакетов, возможно, что вам захочется взглянуть на такие инструменты, как Python RPM API, вместо C-библиотеки RPM.

Далее - Открытие rpm-файла
Назад - Обработка опций командной строки rpm
Содержание


15.3.1. Открытие rpm-файла

Первое, что требуется для чтения rpm-файла, это открыть его. Используйте Fopen:

FD_t Fopen(const char * path,

const char * fmode);

Fopen работает как стандартная C-функция fopen(3).

Далее - Чтение начального идентификатора rpm и сигнатуры
Назад - Работа с rpm-файлами
Содержание


15.3.2. Чтение начального идентификатора rpm и сигнатуры

Вспомним структуру файла rpm-пакета (Формат файла rpm) - начальный идентификатор, подпись (сигнатура), заголовок пакета (бинарный хэдер), нагрузка (cpio-архив с файлами пакета).
Наиболее важная информация о rpm-файле находится в хэдере. Она-то в основном и требуется для работы с пакетами. Однако, чтобы установить указатель смещения в позицию начала чтения хэдера, все равно потребуеся прочитать начальный идентификатор и подпись, даже если они не интересуют вашу программу. Для чтения начального идентификатора применяют функцию readLead:

int readLead(FD_t fd, struct rpmlead *lead);

Функция readLead возвращает 0 в случае успешного считывания начального идентификатора и 1 в случае ошибки. Считанными данными заполняется структура rpmlead:

struct rpmlead {

unsigned char magic[4];

unsigned char major;

unsigned char minor;

short type;

short archnum;

char name[66];

short osnum;

short signature_type;

char reserved[16];

};

Для чтения до конца сигнатуры вызывается rpmReadSignature:

rpmRC rpmReadSignature(FD_t fd,

Header * header,

sigType sig_type);

Возможные коды возврата показаны ниже:

Code

RPMRC_OK

RPMRC_BADMAGIC

RPMRC_FAIL

RPMRC_BADSIZE

RPMRC_SHORTREAD

После завершения чтения подписи можно считывать содержимое полей хэдера.

Далее - Чтение хэдера
Назад - Открытие rpm-файла
Содержание


15.3.3 Чтение хэдера

Информация, заключенная в хэдере, содержит имя пакета, версию, пост- и пре-инсталляционные скрипты, и тому подобные данные. Для чтения содержания хэдера вызывается headerRead. В случае успеха функция возвращает так называемый объект хэдера. Из объекта можно читать значения переменных.

Header headerRead(FD_t fd,

enum hMagic magicp);

Наиболее сложным в вызове headerRead является необходимость передачи в функцию флага "магического" числа. Этот флаг должен иметь значение HEADER_MAGIC_YES если хэдер имеет набор магических чисел, или HEADER_MAGIC_NO - если не имеет. Если предположение о нужном значении флага было неверным, функция вернет ошибку. Для обхода этой проблемы можно получить старший номер версии RPM из начального идентификатора для сравнения:

Header header = headerRead(fd, (lead.major >= 3) ?

HEADER_MAGIC_YES : HEADER_MAGIC_NO);

Для чтения значений переменных из хэдера используют headerGetEntry. В ее вызове нужно передать объект хэдера и идентификатор поля. В результате функция вернет тип поля, указатель на значения поля, и счетчик значений в этом поле.

nt headerGetEntry(Header header,

int_32 tag,

hTYP_t type,

void **pointer,

hCNT_t data_size);

headerGetEntry возвращает 1 в случае успеха и 0 в случае ошибки. В случае успеха указатель будет указывать на полученные данные с типом параметра, установленным в одно из значений:

enum rpmTagType_e {

RPM_NULL_TYPE = 0,

RPM_CHAR_TYPE = 1,

RPM_INT8_TYPE = 2,

RPM_INT16_TYPE = 3,

RPM_INT32_TYPE = 4,

RPM_STRING_TYPE = 6,

RPM_BIN_TYPE = 7,

RPM_STRING_ARRAY_TYPE = 8,

RPM_I18NSTRING_TYPE

}

Если тип оказался RPM_STRING_ARRAY_TYPE или RPM_BIN_TYPE, потребуется освободить указатель, для чего вызывается headerFreeData:

void* headerFreeData(const void *pointer,

rpmTagType type);

Для передачи нам нужны указатель на данные и флаг типа. Можно вызвать headerFreeData для обоих. Функция не делает ничего, если тип не требует освобождения указателя.

Вызывая headerGetEntry, мы должны знать имя поля, из которого хотим получить значения. Это имя является идентификатором для --queryformat. Заголовочный файл rpmlib.h содержит список имен полей.

Пример ниже показывает, как можно получить запись строкового типа из хэдера:

/* Function to read a string header entry. */

char* readHeaderString(Header header, int_32 tag_id) {

int_32 type;

void* pointer;

int_32 data_size;

int header_status = headerGetEntry(header,

tag_id,

&type,

&pointer,

&data_size);

if (header_status) {

if (type == RPM_STRING_TYPE) {

return pointer;

}

}

return NULL;

}

Для чтения значений из поля передаем объект хэдера и ID поля. Например:

char* name = readHeaderString(header, RPMTAG_NAME);

char* version = readHeaderString(header, RPMTAG_VERSION);

char* release = readHeaderString(header, RPMTAG_RELEASE);

Для получения имени, версии и релиза можно вызвать функцию headerNVR:

int headerNVR(Header header,

const char **nameptr,

const char **versionptr,

const char **releaseptr);

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

Header headerFree(Header header);

Вызов headerFree возвращает NULL, это можно использовать для установки исходного указателя в NULL во избежании случайного использования. Например:

header = headerFree(header);

Далее - Короткий путь к информации хэдера
Назад - Чтение начального идентификатора rpm и сигнатуры
Содержание


15.3.4. Короткий путь к информации хэдера

Имеется возможность читать из хэдера с использованием специального метода rpmReadPackageFile:

int rpmReadPackageFile(rpmts ts,

FD_t fd,

const char *filename,

Header *header);

Для передачи в качестве аргументов потребуются сет транзакции и открытый файл. Имя файла используется только для вывода ошибок. В случае успеха rpmReadPackageFile заполняет объект хэдера из файла пакета. Возвращаемое значение - 0 в случае успеха.

Для передачи сета транзакции его нужно создать с помощью rpmtsCreate. Эта функция описывается далее в главе "Программирование с БД RPM".

В большом количестве случаев возможен вызов rpmReadPackageFile без вызова readLead, rpmReadSignature, и headerRead, поскольку rpmReadPackageFile также проверяет целостность пакета.

Далее - Закрытие rpm-файла
Назад - Чтение хэдера
Содержание


2.1.3 Бинарные rpm и rpm с исходным кодом

Существует два типа пакетов rpm - бинарные и с исходным кодом. Бинарные пакеты содержат исполняемые файлы, скомпилированные для определенной процессорной архитектуры. Например, веб-сервер Apache, скомпилированный для работы на платформе Intel Pentium не будет работать на Sharp Zaurus, в котором используется процессор ARM. Для использования на обоих системах необходимо иметь два бинарных пакета и только один пакет с исходным кодом.

Бинарные пакеты
Бинарные пакеты содержат полный набор приложений и библиотек, собранных под определенную процессорную архитектуру. Работа этих приложений часто зависит от других приложений (библиотек), которые в свою очередь содержатся в иных бинарных rpm-пакетах.
Хотя большАя часть пакетов включает приложения, некоторые пакеты содержат только библиотеки функций. Например, библиотека SDL, поддерживающая графические потребности множества игр, может быть упакована в rpm файл. Пакеты библиотек позволяют поддерживать работу множества приложений с помощью одной библиотеки (так называемые shared libraries). Поэтому как правило библиотеки входят в пакеты, не содержащие приложений.
В дополнение к бинарным пакетам для определенных архитектур, RPM поддерживает концепцию платформно-независимых бинарных пакетов, так называемых noarch-пакетов, предоставляющих библиотеки, или, например, коллекции скриптов, работа которых не зависит от конкретной платформы. Приложения, написанные на Perl, Python или shell не связаны необходимостью компиляции. Многие приложения Java также не зависят от платформы.

Пакеты с исходным кодом
Упоминавшийся выше пакет xcopilot содержит приложение xcopilot. Оно используется для синхронизации данных с КПК Palm. Исходный код этого приложения содержится, например, в пакете:

xcopilot -0.66-3.src.rpm

В соответствии с соглашениями об именовании, имя файла пакета с исходным кодом оканчивается постфиксом src.rpm.
src.rpm-пакет должен содержать все необходимые средства, потребные для сборки бинарного пакета. Наличие такого пакета означает, что можно пересобрать бинарный пакет в любое время, сделав необходимые изменения/исправления, либо под другую процессорную архитектуру. И это одна из главных целей системы пакетного менеджмента RPM.
Поскольку в пакете с исходным кодом содержится вся информация для сборки, есть возможность пересобирать бинарные пакеты в Linux-среде, отличной от исходной. Например, скрипты настройки процесса сборки могут адаптировать этот процесс в зависимости от версий найденных в системе библиотек.
Если при в процессе сборки руководствоваться указаниями, обычно содержащимися в пакетах с исходным кодом, получаемые бинарные пакеты будут максимально адекватны системному окружению.

Далее - База данных RPM
Назад - Структура пакета RPM
Содержание


15.3.5 Закрытие rpm-файла

После завершения работы с rpm-файлом, закройте его с помощью Fclose:

int Fclose(FD_t fd);

Fclose в основном действует также, как стандартная C-функция fclose(3). FD_t есть классификатор типа данных RPM.

Подсистема ввода/вывода RPM, определенная в rpmio.h, включает функции, которые имитируют (а также в большинстве случаев являются обертками) функции ввода/вывода ANSI C. Сюда относятся: Fopen, Fclose, Fread, Fwrite, Ferror, Fflush, Fileno, и Fseek.

Необходимость реализовать RPM функции в виде рапперов обусловлена тем, что функции ввода/вывода должны содержать дополнительные возможности. Например, Fopen кроме имен файлов поддерживает также HTTP и FTP URL.

Далее - Программирование с БД RPM
Назад - Короткий путь к информации хэдера
Содержание


15.4. Программирование с БД RPM

Многие функции библиотеки RPM используют так называемые сеты транзакций. В особенности это касается функций работы с БД RPM.

Создать сет транзакции можно вызовом rpmtsCreate:

rpmts rpmtsCreate(void);

RPM использует сеты транзакций для группирования операций с БД RPM. RPM API эволюционирует таким образом, что сеты транзакций становятся все более важной деталью конструкции. Сеты транзакций, кроме того, позволяют автоматизировать обращение к БД RPM, если оно требуется по ходу задачи.

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

rpmts rpmtsFree(rpmts ts);

Вызов rpmtsFree всегда возвращает NULL.

Далее - Итераторы БД
Назад - Закрытие rpm-файла
Содержание


15.4.1. Итераторы БД

С момента создания сета транзакции мы можем обходить информацию об установленных пакетах в БД RPM с помощью итератора. Для создания итератора вызывается rpmtsInitIterator:

rpmdbMatchIterator rpmtsInitIterator(const rpmts ts,

rpmTag rpmtag,

const void *keypointer,

size_t keylen);

В вызове следует задать, какой тэг (какое поле, заданное его именем) мы будем перебирать. Как правило, это имя пакета, RPMTAG_NAME. Вместе с идентификатором поля мы должны передать имя пакета. keypointer изменяется в зависимости от того, какой тэг передан.

Для строковых данных можно передать 0 в параметре keylen. Например, ниже приводится конструкция, в которой rpmtsInitIterator ищет все пакеты, называющиеся sendmail:

rpmdbMatchIterator iter;

iter = rpmtsInitIterator(ts, RPMTAG_NAME, "sendmail", 0);

rpmdbMatchIterator позволяет обходить множество пакетов, в данном случае обходятся пакеты, в именах которых имеется заданный шаблон. После вызова rpmtsInitIterator следующим шагом будет вызов rpmdbNextIterator:

Header rpmdbNextIterator(rpmdbMatchIterator iter);

Эта функция возвращает следующий в итераторе объект хэдера. Если в итераторе больше нет пакетов, отвечающих условиям, вернется NULL.

Если Header - не NULL, из объекта можно получить записи, как было показано в предыдущих главах. Используйте цикл для обхода всех пакетов, отвечающих шаблону:

while ( (installed_header = rpmdbNextIterator(iter) ) != NULL) {

/* Do something... */

}

Нет нужды освобождать объект после использования, так как каждый следующий вызов rpmdbNextIterator пересоздает Header.

Особенности работы итератора подлежат подстройке под ваши нужды. Для добавления шаблона в итератор используется rpmdbSetIteratorRE:

int rpmdbSetIteratorRE(rpmdbMatchIterator iter,

rpmTag tag,

rpmMireMode mode,

const char * pattern);

Вызов rpmdbSetIteratorRE изменяет переданный итератор таким образом, чтобы использовался дополнительный шаблон. Параметр mode именует тип шаблона. Он может быть одним из:

Тип

Означает

RPMMIRE_DEFAULT

То же, что и регулярное выражение, с добавлением \., .*, и ^..$

RPMMIRE_GLOB

Шаблон в стиле glob с использованием fnmatch

RPMMIRE_REGEX

Регулярное выражение с использованием regcomp

RPMMIRE_STRCMP

Сравнение строк с использованием strcmp

Для получения дополнительной информации по данным типам шаблонов воспользуйтесь man-ами для fnmatch(3), glob(7), regcomp(3), regex(7), и strcmp(3).

После использования итератор должен быть освобожден:

rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator iter);

Вызов rpmdbFreeIterator возвращает NULL.

Далее - Сет зависимости
Назад - Программирование с БД RPM
Содержание


15.4.2. Сет зависимости

Для сравнения версий пакета применяется сет зависимости. Утилита rpm, например, использует сет зависимости для этой операции.

Можно, конечно, сравнивать версии напрямую, то есть вызывать
headerGetEntry для получения значения полей версии и релиза, превращать эти строки в числа и затем сравнивать, но этот подход будет источником проблем. Такое "пользовательское" сравнение не будет столь точным, как способ, описанный в этой главе. В особенности потому, что номера версий не представляют собой числа в действительности, например, 1.12.4 по сути строка, а не число.

Для реализации всей непростой логики сравнения версий можно использовать код этой главы или вызов rpmvercmp. Не пытайтесь сравнивать версии с помощью доморощенных реализаций.

Для создания сета зависимости данного объекта хэдера (заданного пакета) вызывается rpmdsThis. Вызов rpmdsThis создает сет зависимости, который хранит имя пакета, информацию о Эпохе/Версии/Релизе и флаги.

rpmds rpmdsThis(Header header,

rpmTag tagID,

int_32 Flags);

Для сравнения пакетов вы можете передать RPMTAG_REQUIRENAME в качестве tagID. Настоящий tagID игнорируется механизмом сравнения. В действительности важны флаги, задающие, будет ли определятся равенство Эпохи/Версии/Релиза или же будет определяться меньшинство Эпохи/Версии/Релиза в данном сете. Для выполнения этой настройки передаются битовые флаги:

(RPMSENSE_EQUAL|RPMSENSE_LESS)

После создания сета зависимости можно вызывать функцию rpmdsNVRMatchesDep для сравнения Имени, Версии, Релиза, то есть записей Name, Version, Release в хэдере пакета по сравнению с данными из сета зависимости.

int rpmdsNVRMatchesDep(const Header header,

const rpmds dependency_set,

int nopromote);

После проверки зависимостей rpmdsNVRMatchesDep возвращает 1 если зависимость перекрывается или 0 в противном случае. В терминах сравнения пакетов это означает, что при возврате 1 файлы установленного пакета такие же или старее, чем пакета сравнения, при возврате 0 установленные файлы новее. В параметре nopromote можно передать 1 для предотвращения влияния Эпохи на результат сравнения.

Также для сравнения версий двух пакетов можно вызвать rpmVersionCompare:

int rpmVersionCompare(Header header1, Header header2);

Если хэдер 1 представляет более старую версию, чем хэдер 2, возвращается -1. Если версии одинаковые, возвращается 0. Если хэдер 1 представляет более новую версию, чем хэдер 2, возвращается 1.

Для получения имени пакета из сета зависимости используется rpmdsN:

const char* rpmdsN(const rpmds dependency_set);

Можно использовать rpmdsN для получения имени при вызове rpmtsInitIterator, если вы работаете с сетом зависимости при поиске в БД RPM.

После использования сет зависимости должен быть освобожден:

rpmds rpmdsFree(rpmds dependency_set);

rpmdsFree возвращает NULL, как и прочие функции очистки.

Далее - Сравнение rpm-файла и установленного пакета
Назад - Итераторы БД
Содержание


15.5. Сравнение rpm-файла и установленного пакета

Сведя вместе знания о приемах работы с rpm-файлами и БД RPM можно создать немало полезных программ. Код утилиты для сравнения файла rpm-пакета и установленного пакета показан ниже - программа vercompare.c.

/* Compares a package file with an installed package,

telling which one is newer.

Usage:

vercompare pkg_files+

Compile as

cc -I/usr/include/rpm -o vercompare vercompare.c -lrpm -lrpmdb -lrpmio -lpopt
*/

#include <stdlib.h>

#include <rpmcli.h>

#include <rpmdb.h>

#include <rpmds.h>

#include <rpmts.h>

/* Set up a table of options using standard RPM options. */

static struct poptOption optionsTable[] = {

{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
"Common options for all rpm modes and executables:",
NULL },

POPT_AUTOALIAS

POPT_AUTOHELP

POPT_TABLEEND

};

int main(int argc, char * argv[])

{

poptContext context;

const char ** fnp;

rpmdbMatchIterator iter;

Header file_header, installed_header;

rpmts ts;

rpmds dependency_set;

FD_t fd;

rpmRC rpmrc;

int rc;

context = rpmcliInit(argc, argv, optionsTable);

if (context == NULL) {

exit(EXIT_FAILURE);

}

ts = rpmtsCreate();

for (fnp = poptGetArgs(context); fnp && *fnp; fnp++) {

/* Read package header, continuing to next arg on failure. */

fd = Fopen(*fnp, "r.ufdio");

if (fd == NULL || Ferror(fd)) {
rpmError(RPMERR_OPEN, "open of %s failed: %s\n", *fnp,
Fstrerror(fd));

if (fd) {

Fclose(fd);

}

continue;

}

rpmrc = rpmReadPackageFile(ts, fd, *fnp, &file_header);

Fclose(fd);

if (rpmrc != RPMRC_OK) {
rpmError(RPMERR_OPEN, "%s cannot be read\n", *fnp);

continue;

}

/* Generate "name <= epoch:version-release" depset for package */

dependency_set = rpmdsThis(file_header, RPMTAG_REQUIRENAME,
(RPMSENSE_EQUAL|RPMSENSE_LESS));

rc = -1; /* assume no package is installed. */

/* Search all installed packages with same name. */

iter = rpmtsInitIterator(ts, RPMTAG_NAME, rpmdsN(dependency_set), 0);

while ((installed_header = rpmdbNextIterator(iter)) != NULL) {

/* Is the installed package newer than the file? */

rc = rpmdsNVRMatchesDep(installed_header, dependency_set, 1);

switch (rc) {

case 1:

if ( rpmIsVerbose() )

fprintf(stderr, "installed package is older (or same) as %s\n",
*fnp);

break;

case 0:

if ( rpmIsVerbose() )

fprintf(stderr, "installed package is newer than %s\n",
*fnp);

break;

}

}

/* Clean up. */

iter = rpmdbFreeIterator(iter);

dependency_set = rpmdsFree(dependency_set);

if (rc < 0 && rpmIsVerbose() )

fprintf(stderr, "no package is installed %s\n", *fnp);

}

ts = rpmtsFree(ts);

context = rpmcliFini(context);

return rc;

}

Программа vercompare.c выполняет чтение из файла rpm-пакета и поиск в БД RPM. В коде вводятся сеты транзакций и сеты зависимости. Используйте пример для создания собственных RPM программ.

Для запуска программы ей надо передать в качестве параметров имена одного или нескольких rpm-файлов. Программа извлечет имена пакетов из файлов и запросит БД RPM о пакетах с такими именами. Для каждого такого пакета vercompare даст заключение, является ли данный пакет старее установленного, идентичным установленному или новее установленного.

Например, если установлен пакет jikes-1.17-1 и имеется файл пакета более новой версии, тогда при запуске программы увидим примерно следующее:

$ ./vercompare -v jikes-1.18-1.i386.rpm

installed package is older (or same) as jikes-1.18-1.i386.rpm

Если происходит сравнение с более старой версией rpm-файла, получится такой результат:

$ ./vercompare -v jikes-1.14-1-glibc-2.2.i386.rpm

installed package is newer than jikes-1.14-1-glibc-2.2.i386.rpm

И, наконец, если установленный пакет имеет такую же версию, получим следующее:

$ ./vercompare -v jikes-1.17-glibc2.2-1.i386.rpm

installed package is older (or same) as jikes-1.17-glibc2.2-1.i386.rpm

Этот аспект сравнения можно изменить путем передачи флагов в rpmdsThis.

Если нужно организовать многословный вывод, используем -v.

Функции интерфейса командной строки RPM используют те же общие опции, что и утилиты rpm и rpmbuild. Вы можете использовать эти функции для высокоуровневого доступа к RPM. Например, для активации опции запроса используйте rpmcliQuery:

int rpmcliQuery(rpmts transaction_set,
QVA_t qva,
const char **argv);

Установите переменную QVA_t так, чтобы она указывала на глобальную переменную rpmQVKArgs, которая инициализирована из глобальной таблицы опций для режима запросов, rpmQueryPoptTable. Передайте rpmcliQuery список имен файлов или имен пакетов.

Для поддержки опций запросов необходимо иметь записи в локальной таблице опций poptOption. Для доступа к этим опциям добавьте следующую запись:

{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQueryPoptTable, 0,
"Query options (with -q or --query):",
NULL },

С опциями pmQueryPoptTable можно создать программу, которая будет работать как команда pm --query, используя следующий код:

poptContext context;

QVA_t qva = &rpmQVKArgs;

rpmts ts;

int ec;

context = rpmcliInit(argc, argv, optionsTable);

if (context == NULL) {

/* Display error and exit... */

}

ts = rpmtsCreate();

if (qva->qva_mode == 'q') {

/* Make sure there's something to do. */

if (qva->qva_source != RPMQV_ALL && !poptPeekArg(context)) {
fprintf(stderr, "no arguments given for --query");

exit(EXIT_FAILURE);

}

ec = rpmcliQuery(ts, qva, (const char **) poptGetArgs(context));

}

ts = rpmtsFree(ts);

context = rpmcliFini(context);

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

С помощью небольшого куска кода можно добавить в программу функционал, обеспечивающийся опцией --verify. Для этого необходимо включить определения командной строки из глобальной таблицы rpmVerifyPoptTable:

/* Add in --verify options. */

{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmVerifyPoptTable, 0,
"Verify options (with -V or --verify):",
NULL },

Далее можно проверить режим верификации и поддержку опций с помощью кода, подобного этому:

if (qva->qva_mode == 'V') {

rpmVerifyFlags verifyFlags = VERIFY_ALL;

/* Verify flags are negated from query flags. */

verifyFlags &= ~qva->qva_flags;

qva->qva_flags = (rpmQueryFlags) verifyFlags;

/* Make sure there's something to do. */

if (qva->qva_source != RPMQV_ALL && !poptPeekArg(context)) {

fprintf(stderr, "no arguments given for --verify");

exit(EXIT_FAILURE);

}

ec = rpmcliVerify(ts, qva, (const char **)
poptGetArgs(context));

}

Рабочая лошадь этого кода - высокоуровневая функция rpmcliVerify, она выполняет всю ту работу, которую выполняет утилита rpm под опцией --verify.

int rpmcliVerify(rpmts transaction_set,
QVA_t qva,

const char **argv);

И вновь, установите переменную QVA_t чтобы она указывала на глобальную переменную rpmQVKArgs, которая инициализирована значениями из глобальной таблицы опций rpmQueryPoptTable.

Соберем это все вместе и получим программу rpmq.c, которая выполняет все то же, что и команды rpm --query и rpm --verify:

/*
rpm --query and --verify modes in standalone program.
Compile as
cc -I/usr/include/rpm -o rpmq rpmq.c -lrpm -lrpmdb -lrpmio -lpopt
See option usage by invoking
./rpmq --help
*/

#include <stdlib.h>

#include <rpmcli.h>

#include <rpmdb.h>

#include <rpmds.h>

#include <rpmts.h>

/* Set up a table of options. */

static struct poptOption optionsTable[] = {
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
"Common options for all rpm modes and executables:",
NULL },

{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQueryPoptTable, 0,
"Query options (with -q or --query):",
NULL },

/* Add in --verify options. */

{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmVerifyPoptTable, 0,
"Verify options (with -V or --verify):",
NULL },

POPT_AUTOALIAS

POPT_AUTOHELP

POPT_TABLEEND

};

int main(int argc, char * argv[])

{

poptContext context;

QVA_t qva = &rpmQVKArgs;

rpmts ts;

int ec;

context = rpmcliInit(argc, argv, optionsTable);

if (context == NULL) {
poptPrintUsage(context, stderr, 0);

exit(EXIT_FAILURE);

}

ts = rpmtsCreate();

/* Check for query mode. */

if (qva->qva_mode == 'q') {

/* Make sure there's something to do. */

if (qva->qva_source != RPMQV_ALL && !poptPeekArg(context)) {
fprintf(stderr, "no arguments given for --query");

exit(EXIT_FAILURE);

}

ec = rpmcliQuery(ts, qva, (const char **) poptGetArgs(context));

}

/* Check for verify mode. */

else if (qva->qva_mode == 'V') {
rpmVerifyFlags verifyFlags = VERIFY_ALL;

/* Verify flags are negated from query flags. */

verifyFlags &= ~qva->qva_flags;

qva->qva_flags = (rpmQueryFlags) verifyFlags;

/* Make sure there's something to do. */

if (qva->qva_source != RPMQV_ALL && !poptPeekArg(context)) {
fprintf(stderr, "no arguments given for --verify");

exit(EXIT_FAILURE);

}

ec = rpmcliVerify(ts, qva, (const char **) poptGetArgs(context));

}

else {

poptPrintUsage(context, stderr, 0);

exit(EXIT_FAILURE);

}

ts = rpmtsFree(ts);

context = rpmcliFini(context);

return ec;

}

Для такой функциональности не так уж много кода, не так ли? Эта эффективность достигается благодаря использованию высокоуровневых функций для доступа к интерфейсу командной строки.

Программа rpmq выполняет все те же задачи, что и команды rpm --query и rpm --verify. Например, поддерживаются форматы расширенных запросов:

$ ./rpmq -q --qf "%{NAME} %{INSTALLTID:date}\n" jikes

jikes Fri 25 Oct 2002 06:49:38 PM CDT

Далее - Раздел 16. Программирование RPM на Python
Назад - Сет зависимости
Содержание


16.1.1 Установка окружения для программирования на Python

Установка программного окружения Python принципиально не отличается от установки программного окружения C. Следует установить пакеты разработки Python, пакет, предоставляющий Python API к системе RPM и текстовый редактор, понимающий синтаксис Python.

Базовый пакет языка - python. Для использования в RPM-разработке требуется версия не ниже 2.2. Пакет, обеспечивающий доступ к RPM из Python - rpm-python.

Далее - Использование Python в графических приложениях
Назад - Сравнение rpm-файла и установленного пакета
Содержание


2.2 База данных RPM

База данных RPM хранит информацию обо ВСЕХ пакетах, установленных в системе. Эта база может использоваться для запросов, касающихся того, что установлено, для информирования о версиях установленного ПО, для оценки целостности пакетов и системы, по крайней мере с точки зрения набора пакетов.
Файлы базы данных живут в директории /usr/lib/rpm и их набор включает примерно следующее:

Basenames
Conflictname
__db.001
__db.002
__db.003
Dirnames
Filemd5s
Group
Installtid
Name
Packages
Providename
Provideversion
Pubkeys
Requirename
Requireversion
Sha1header
Sigmd5
Triggername

Эти файлы созданы системой управления базой данных RPM. Файлы __db.001 и ему подобные - это файлы блокировки СУБД RPM. Остальные файлы - компоненты БД в формате Berkeley DB. Наиболее значимый файл - Packages. В нем хранятся значения полей хедера для каждого пакета, индексированные по внутреннему номеру пакета.
Другие файлы, как, например, Name, Providename, Group помогают оптимизировать запросы с помощью их типизации и ускорить работу БД с точки зрения пользователя.

Далее - Команды RPM
Назад - Бинарные rpm и rpm с исходным кодом
Содержание


16.1.2. Использование Python в графических приложениях

Python поддерживает ряд различных инструментов для создания графического интерфейса пользователя. Чтобы разработать GUI-приложение, придется выбрать один из них. Доступны:

* PyGTK. Это привязки Python к библиотеке GTK+, использующейся для построения интегрированной графической среды GNOME. PyGTK используется в графических утилитах системных настроек Red Hat system-config-*. PyGTK предоставляет полный доступ к виджетам GTK+. Для получения подробной информации используйте www.daa.com.au/~james/pygtk/.

* PyQt предоставляет привязки к графической библиотеке Qt, которая используется для построения интегрированной графической среды KDE. Подобно PyGTK пакет делает доступным все богатство виджетов Qt программе на Python.
Для получения подробной информации используйте www.riverbankcomputing.co.uk/pyqt/.

* Tkinter - стандартный компонент Python, базирующийся на наборе графических инструментов Tk, разработанных для визуализации интерфейса пользователя программ на языке Tcl. Преимущество интегрированности Tkinter в Python подкреплено широкой кроссплатформенностью.
Tkinter пригоден для простых в смысле оформления интерфейсов.
Для получения более подробной информации используйте www.python.org/topics/tkinter/.

После того, как нужные компоненты выбраны и установлены, следующим шагом будет освоение Python API для RPM.

Далее - Иерархия Python API
Назад - Установка окружения для программирования на Python
Содержание


16.2 Иерархия Python API

RPM Python API предоставляет высокоуровневый интерфейс к функциональности RPM, разделенный на несколько логически выделенных областей.

Класс

Обеспечивает

rpm

Базовый модуль доступа к RPM API

rpmts

Работа с сетами транзакций

rpmte

Работа с элементами транзакций (пакеты в сете транзакций)

rpmmi

Определяет итераторы для работы с БД RPM

Rpmds

Работа с сетами зависимости

Rpmfi

Работа с rpm-файлами

Header

Работа с хэдером

RPM Python API хорошо интегрирован в стандартный Python API. Например, можно использовать класс Python os для чтения rpm-файла.

Примеры этого раздела используют RPM 4.1 Python API.

Далее - Программирование с БД RPM
Назад - Использование Python в графических приложениях
Содержание


16.3 Программирование с БД RPM

По сравнению с RPM C API, Python API намного проще в использовании.

Практически все скрипты на Python, работающие с RPM, нуждаются в работе с сетами транзакций. Создание сета транзакции происходит следующим образом:

import rpm

ts = rpm.TransactionSet()

При этом БД RPM открывается автоматически, если это требуется.

Для более подробного ознакомления с приемами работы, используйте исходный код anaconda, программы инсталляции дистрибутивов Red Hat, написанной на Python.

Далее - Доступ к БД RPM
Назад - Иерархия Python API
Содержание


16.3.1 Доступ к БД RPM

Сеты транзакций предоставляют ряд методов работы с БД RPM на уровне движка базы данных. Используйте эти методы, если нуждаетесь во взаимодействии с БД в целом, в отличие от доступа к данным по какому-то одному пакету. Скажем, с помощью этих методов можно инициализировать или перестроить базу. Кроме того, можно получать доступ к альтернативным БД помимо БД по умолчанию.

16.3.1.1 Установка расположения БД
Сет транзакции открывает БД RPM основываясь на ее расположении по умолчанию. Для задания альтернативного расположения БД используется addMacro, как показано ниже:

rpm.addMacro("_dbpath", path_to_rpm_database)

Возможна работа с несколькими БД путем определения макроса
_dbpath, создания сета транзакции и последующего удаления макроса. После такой последовательности можно создать другой сет транзакции для БД по умолчанию. Например:

# Open the rpmdb-redhat database

rpm.addMacro("_dbpath", "/usr/lib/rpmdb/i386-redhat-linux/redhat")

solvets = rpm.TransactionSet()

solvets.openDB()

rpm.delMacro("_dbpath")

# Open default database

ts = rpm.TransactionSet()

Этот пример использует пакет rpmdb-redhat, который содержит данные обо всех пакетах Red Hat. Прямой вызов openDB открывает БД RPM. В большинстве случаев в скриптах Python прямой вызов openDB не требуется. Вместо этого сет транзакции откроет БД если это необходимо.

Вызов delMacro удаляет макрос, позволяя следующему вызову TransactionSet использовать БД по умолчанию.

Не вызывайте closeDB в сете транзакции. Этот метод действительно закроет БД, но также закроется возможность автоматического открытия при необходимости.

16.3.1.2 Инициализация, перестройка и верификация БД
Сет транзакции предоставляет метод initDB для инициализации новой БД RPM. Действие сходно с действием команды rpm --initdb:

ts.initDB()

Метод rebuildDB регенерирует БД, подобно команде rpm --rebuilddb:

ts.rebuildDB()

Метод rebuildDB перестраивает индекс базы.

Метод verifyDB проверяет читаемость базы и индексов функциями библиотеки Berkeley DB:

ts.verifyDB()

Вызов этого метода - то же самое, что вызов команды db_verify для каждого файла БД в каталоге /var/lib/rpm.

С момента создания сета транзакции мы получаем возможность запрашивать БД RPM.

Далее - Запросы к БД RPM
Назад - Программирование с БД RPM
Содержание


16.3.2 Запросы к БД RPM

Для создания шаблонного итератора используется метод dbMatch экземпляра сета транзакции. Подобно C API шаблонный итератор позволяет программе перебирать пакеты, которые соответствуют шаблону по заданному критерию.

Вызов dbMatch без параметров означает, что будут перебираться все установленные пакеты. Базовый синтаксис:

import rpm

ts = rpm.TransactionSet()

mi = ts.dbMatch()

for h in mi:

# Do something with header object...

В этом примере вызов dbMatch возвращает шаблонный итератор. Цикл for обходит весь итератор, возвращая один объект хэдера за раз.

Кроме данного синтаксиса можно вызывать метод next для получения следующего объекта хэдера. Например:

import rpm

ts = rpm.TransactionSet()

mi = ts.dbMatch()

while mi:

h = mi.next()

# Do something with the header object

Прямой вызов метода next в будущих версиях Python API поддерживаться не будет.

Следующий листинг показывает пример скрипта на Python (rpmqa.py), который выводит имя, версию и релиз для всех установленных пакетов.

#!/usr/bin/python

# Acts like rpm -qa and lists the names of all the installed packages.

# Usage:

# python rpmqa.py

import rpm

ts = rpm.TransactionSet()

mi = ts.dbMatch()

for h in mi:

print "%s-%s-%s" % (h['name'], h['version'], h['release'])

При вызове скрипта мы увидим примерно следующий вывод (часть вывода убрана ради экономии места):

$ python rpmqa.py

libbonoboui-2.0.1-2

attr-2.0.8-3

dhclient-3.0pl1-9

file-3.37-8

hdparm-5.2-1

ksymoops-2.4.5-1

imlib-1.9.13-9

logwatch-2.6-8

mtr-0.49-7

openssh-clients-3.4p1-2

pax-3.0-4

python-optik-1.3-2

dump-0.4b28-4

sendmail-8.12.5-7

sudo-1.6.6-1

mkbootdisk-1.4.8-1

telnet-0.17-23

usbutils-0.9-7

wvdial-1.53-7

docbook-dtds-1.0-14

urw-fonts-2.0-26

db4-utils-4.0.14-14

libogg-devel-1.0-1

Если на скрипт установлены права выполнения, можно избежать вызова интерпретатора вместе с именем скрипта:

$ ./rpmqa.py

Далее - Работа с хэдером
Назад - Доступ к БД RPM
Содержание


16.3.3 Работа с хэдером пакета

16.3.3.1 Класс hdr
Получить запись из объекта хэдера можно, используя возможности Python для работы со словарями. Это гораздо удобнее, чем вызов headerGetEntry в C-программе. Базовый синтаксис доступа к записи:

value = h['tag_name']

Например, для получения имени пакета делаем так:

name = h['name']

Также можно использовать стек предопределенных имен тэгов, которые использует C API. Эти константы определены в модуле rpm и их можно задействовать таким образом:

name = h[rpm.RPMTAG_NAME]

Для записей хэдера, содержащих массив строк, например, список файлов пакета, данные, возвращаемые методом будут представлять собой список Python:

print "Files:"

files = h['FILENAMES']

for name in files:

print name

Кроме того, можно использовать file info для организации более компактного кода. Например:

print "Files:"

fi = h.fiFromHeader()

print fi

Зависимости, возможности, несовместимости и конфликты всякий раз получаются как три отдельных, но ссылающихся друг на друга списка. Например, три списка для зависимостей, три для возможностей и так далее. Эту информацию можно извлекать, используя сет зависимости таким образом:

print h.dsFromHeader('providename')

print h.dsFromHeader('requirename')

print h.dsFromHeader('obsoletename')

print h.dsFromHeader('conflictname')

16.3.3.2 Вывод информации с помощью sprintf
Кроме возможностей Python по работе со словарями для форматирования вывода можно использовать метод sprintf, при этом применяется в точности такой же синтаксис, как для установки формата запросов при запуске утилиты rpm в режиме запросов:

h.sprintf("%{tag_name}")

Можно добавлять специальные директивы форматирования к имени тега:

print "Header signature: ", h.sprintf("%{DSAHEADER:pgpsig}")

print "%-20s: %s" % ('Installed on', h.sprintf("%{INSTALLTID:date}") )

Эти подходы можно включать в пользовательские функции, выводящие записи хэдера со специфическим форматированием:

def nvr(h):

return h.sprintf("%{NAME}-%{VERSION}-%{RELEASE}")

Далее - Запросы о конкретных пакетах
Назад - Запросы к БД RPM
Содержание


16.3.4 Запросы о конкретных пакетах

Когда для объекта хэдера вызывается dbMatch, пустые параметры означают, что надо обойти весь список установленных пакетов, имеющийся в БД RPM. Также можно запросить информацию об отдельном пакете (пакетах), используя dbMatch. Для этого в качестве параметров необходимо передать имя тега и его значение:

mi = ts.dbMatch(tag_name, value)

Например, запрос всех пакетов, имеющих в имени шаблон sendmail, будет выглядеть так:

mi = ts.dbMatch('name', 'sendmail')

Вызов dbMatch возвращает rpmdbMatchIterator. Вы можете запросить сформировать итератор по нескольким тегам, но наиболее часто встречаются запросы по шаблону имени.

Ниже показан пример скрипта (rpmq.py), который запрашивает пакеты с определенным шаблоном в имени и затем выводит имя, версию и релиз всех пакетов, которые соответствуют шаблону:

#!/usr/bin/python

# Acts like rpm -q and lists the N-V-R for installed

# packages that match a given name.

# Usage:

# python rpmq.py package_name

import rpm, sys

ts = rpm.TransactionSet()

mi = ts.dbMatch( 'name', sys.argv[1] )

for h in mi:

print "%s-%s-%s" % (h['name'], h['version'], h['release'])

При вызове этого скрипта ему нужно передать имя пакета, которое интерпретатор Python будет хранить в sys.argv[1] в вызове dbMatch:

$ python rpmq.py sendmail

sendmail-8.12.5-7

Далее - Вывод информации о пакете
Назад - Работа с хэдером пакета
Содержание


16.3.5 Вывод информации о пакете

Для демонстрации эффективности Python API приведем пример скрипта (rpminfo.py), выполняющего ту же работу, что и команда rpm qi, но умеющего извлекать больше информации о пакете:

#!/usr/bin/python

# Lists information on installed package listed on command line.

# Usage:

# python rpminfo.py package_name

import rpm, sys

def printEntry(header, label, format, extra):

value = header.sprintf(format).strip()

print "%-20s: %s %s" % (label, value, extra)

def printHeader(h):

if h[rpm.RPMTAG_SOURCEPACKAGE]:

extra = " source package"

else:

extra = " binary package"

printEntry(h, 'Package', "%{NAME}-%{VERSION}-%{RELEASE}", extra)

printEntry(h, 'Group', "%{GROUP}", '')

printEntry(h, 'Summary', "%{Summary}", '')

printEntry(h, 'Arch-OS-Platform', "%{ARCH}-%{OS}-%{PLATFORM}", '')

printEntry(h, 'Vendor', "%{Vendor}", '')

printEntry(h, 'URL', "%{URL}", '')

printEntry(h, 'Size', "%{Size}", '')

printEntry(h, 'Installed on', "%{INSTALLTID:date}", '')

print h['description']

print "Files:"

fi = h.fiFromHeader()

print fi

# Dependencies

print "Provides:"

print h.dsFromHeader('providename')

print "Requires:"

print h.dsFromHeader('requirename')

if h.dsFromHeader('obsoletename'):

print "Obsoletes:"

print h.dsFromHeader('obsoletename')

if h.dsFromHeader('conflictname'):

print "Conflicts:"

print h.dsFromHeader('conflictname')

ts = rpm.TransactionSet()

mi = ts.dbMatch( 'name', sys.argv[1] )

for h in mi:

printHeader(h)

Функция printEntry передает в sprintf значение тега в формате "%{NAME}". Можно также передавать более сложные значения, например, "%{NAME}-%{VERSION}".

При запуске скрипта ему передается имя пакета. Вывод будет примерно следующий:

$ python rpminfo.py jikes

Package : jikes-1.18-1 binary package

Group : Development/Languages

Summary : java source to bytecode compiler

Arch-OS-Platform : i386-Linux-(none)

Vendor : (none)

URL : http://ibm.com/developerworks/opensource/jikes

Size : 2853672

Installed on : Mon Dec 2 20:10:13 2002

The IBM Jikes compiler translates Java source files to bytecode. It

also supports incremental compilation and automatic makefile

generation,and is maintained by the Jikes Project:

http://ibm.com/developerworks/opensource/jikes/

Files:

/usr/bin/jikes

/usr/doc/jikes-1.18/license.htm

/usr/man/man1/jikes.1.gz

Provides:

P jikes

P jikes = 1.18-1

Requires:

R ld-linux.so.2

R libc.so.6

R libc.so.6(GLIBC_2.0)

R libc.so.6(GLIBC_2.1)

R libc.so.6(GLIBC_2.1.3)

R libm.so.6

R libstdc++-libc6.2-2.so.3

Далее - Уточнение запросов
Назад - Запросы о конкретных пакетах
Содержание


16.3.6 Уточнение запросов

Метод шаблонов, применяемых для генерации шаблонных итераторов, позволяет совершенствовать запросы. Сужение области действия готового итератора позволит получить иформацию только о тех пакетах, которые мы действительно имели в виду. Синтаксис:

mi.pattern(tag_name, mode, pattern)

Два основных способа сужения области действия запроса: 1. задать более чем один тег для уточнения, например, имя и версию; 2. отфильтровать результаты запроса, используя богатые возможности типизации шаблонов. Параметр mode указывает на тип шаблона, который будет использоваться. Тип может быть одним из следующих:

Тип

Означает

rpm.RPMMIRE_DEFAULT

То же, что регулярное выражение, но с добавлением \., .*, и ^..$

rpm.RPMMIRE_GLOB

Шаблон в стиле globe с использованием fnmatch

rpm.RPMMIRE_REGEX

Регулярные выражения с использованием regcomp

rpm.RPMMIRE_STRCMP

Сравнение строк с использованием strcmp

Например, для запроса всех пакетов, имена которых начинаются на py, используем следующий код:

import rpm

ts = rpm.TransactionSet()

mi = ts.dbMatch()

mi.pattern('name', rpm.RPMMIRE_GLOB, 'py*' )

for h in mi:

# Do something with the header...

Следующий пример (rpmglobe.py) показывает запрос в стиле glob.

#!/usr/bin/python

# Acts like rpm -q and lists the N-V-R for installed packages

# that match a given name using a glob-like syntax

#

# Usage:

# python rpmglob.py "package_fragment*"

import rpm, sys

ts = rpm.TransactionSet()

mi = ts.dbMatch()

if not mi:

print "No packages found."

else:

mi.pattern('name', rpm.RPMMIRE_GLOB, sys.argv[1] )

for h in mi:

print "%s-%s-%s" % (h['name'], h['version'], h['release'])

При запуске скрипта увидим следующее:

$ python rpmglob.py "py*"

pyxf86config-0.3.1-2

python-devel-2.2.1-17

pygtk2-devel-1.99.12-7

pygtk2-libglade-1.99.12-7

pygtk2-1.99.12-7

pyOpenSSL-0.5.0.91-1

python-optik-1.3-2

python-docs-2.2.1-17

python-2.2.1-17

python-tools-2.2.1-17

Кроме работы с БД RPM функционал Python API позволяет непосредственно анализировать файлы rpm-пакетов.

Далее - Чтение хэдера из файла пакета
Назад - Вывод информации о пакете
Содержание


16.4.1 Чтение хэдера из файла пакета

Подобно рассмотренным функциям C, например, rpmReadPackageFile, Python API предоставляет удобный способ чтения для создания объекта хэдера из файла rpm-пакета. Метод hdrFromFdno считывает хэдер из файла в соответствии с переданным дескриптором:

h = ts.hdrFromFdno(fdno)

Метод hdrFromFdno опирается на низкоуровневый дескриптор вместо высокоуровневого объекта файла языка Python. В RPM библиотеке C FD_t - это FILE**.

Следующий пример показывает функцию, открывающую файл, считывающую хэдер и затем закрывающую файл.

def readRpmHeader(ts, filename):

""" Read an rpm header. """

fd = os.open(filename, os.O_RDONLY)

h = ts.hdrFromFdno(fd)

os.close(fd)

return h

ts = rpm.TransactionSet()

h = readRpmHeader( ts, 'n-r-v.rpm' )

Метод hdrFromFdno обрабатывает ряд исключений, основываясь на событиях, диагностируемых при открытии или чтении файла:

def readRpmHeader(ts, filename):

""" Read an rpm header. """

fd = os.open(filename, os.O_RDONLY)

h = None

tryL

h = ts.hdrFromFdno(fd)

except rpm.error, e:

if str(e) == "public key not available":

print str(e)

if str(e) == "public key not trusted":

print str(e)

if str(e) == "error reading package header":

print str(e)

h = None

os.close(fd)

return h

ts = rpm.TransactionSet()

h = readRpmHeader( ts, 'n-r-v.rpm' )

Решение о том, будут ли исключения прерывать исполнение кода, зависит от разработчика.

Далее - Установка флагов верификации
Назад - Уточнение запросов
Содержание


16.4.2 Установка флагов верификации

Начиная с RPM версии 4.1 файлы пакетов проверяются в автоматическом режиме, что может вызывать проблемы, особенно в отношении rpm старых версий или неподписанных электронной подписью.

В большинстве случаев автоматическая проверка - это преимущество, поскольку повышается доверие к пакету. Тем не менее, вы можете переопределить флаги верификации, чтобы изменить поведение по умолчанию. Для этой операции вызывается метод сета транзакции setVSFlags:

ts.setVSFlags(flags)

Например, если имеются проблемы со старыми пакетами, не имеющими правильных подписей, установите игнорирование соответствующих проверок с помощью кода:

# Set to not verify DSA signatures.

ts.setVSFlags(rpm.RPMVSF_NODSA)

В таблице ниже перечислены флаги, которые можно передать setVSFlags. Это битовые маски. Их можно объединять для установки более чем одного флага. Для этого используется бинарный OR. Вместо зарезервированного Python слова or используется | .

Флаг

Означает

rpm.RPMVSF_NEEDPAYLOAD

Установить смещение в начало нагрузки (то есть пропустить хэдер)

rpm.RPMVSF_NOHDRCHK

Не проверять хэдер

rpm.RPMVSF_ NODSA

Не проверять подписи DSA для хэдера и нагрузки

rpm.RPMVSF_ NODSAHEADER

Не проверять подпись DSA для хэдера

rpm.RPMVSF_ NOMD5

Не проверять MD5 дайджест для хэдера и нагрузки

rpm.RPMVSF_ NORSA

Не проверять подписи RSA для хэдера и нагрузки

rpm.RPMVSF_ NOSHA1HEADER

Не проверять дайджест SHA1 для хэдера

rpm._RPMVSF_NODIGESTS

Не проверять дайджесты

rpm._RPMVSF_NOSIGNATURES

Не проверять подписи

Для отключения всех проверок передайте -1 в setVSFlags:

ts.setVSFlasgs(-1)

Далее - Сравнение зависимостей
Назад - Чтение хэдера из файла пакета
Содержание


16.5 Сравнение зависимостей

Сет зависимости кроме всего прочего позволяет сравнить версии двух пакетов. Наиболее употребим этот подход в случае, если нужно сравнить версии установленного пакета и какого-либо имеющегося на диске пакета с целью определения возможности апдейта.

Для получения сета зависимости по умолчанию используют метод dsOfHeader в отношении объекта хэдера. Получив сет зависимости двух хэдеров, можно их сравнить:

file_h = ts.hdrFromFdno(fd)

file_ds = file_h.dsOfHeader()

inst_ds = inst_h.dsOfHeader()

if file_ds.EVR() >= inst_ds.EVR():

print "Package file is same or newer, OK to upgrade."

else:

print "Package file is older than installed version."

Пример скрипта (vercompare.py), который сравнивает файл rpm пакета с данными установленного пакета и выводит информацию о том, чья версия новее:

#!/usr/bin/python

# Reads in package header, compares to installed package.

# Usage:

# python vercompare.py rpm_file.rpm

#

import rpm, os, sys

def readRpmHeader(ts, filename):

""" Read an rpm header. """

fd = os.open(filename, os.O_RDONLY)

h = ts.hdrFromFdno(fd)

os.close(fd)

return h

ts = rpm.TransactionSet()

h = readRpmHeader( ts, sys.argv[1] )

pkg_ds = h.dsOfHeader()

for inst_h in ts.dbMatch('name', h['name']):

inst_ds = inst_h.dsOfHeader()

if pkg_ds.EVR() >= inst_ds.EVR():

print "Package file is same or newer, OK to upgrade."

else:

print "Package file is older than installed version."

Этот скрипт берет имя файла rpm пакета в качестве параметра из командной строки, получает хэдер пакета, ищет в базе данных RPM все пакеты с таким именем, получает объект хэдера для каждого, сравнивает все хэдеры в поисках новейшего и выводит сообщение.

Модифицируйте скрипт, например, добавив сообщение о том, что такой пакет не установлен.

Далее - Установка и обновление пакетов
Назад - Установка флагов верификации
Содержание


16.6 Установка и обновление пакетов

Благодаря существованию RPM имеется целый спектр возможностей. Можно установить или обновить пакет с помощью утилиты rpm. Можно сделать то же самое из программы, написанной с помощью C API или Python API. На Python API это сделать существенно легче. Большая часть операций реализуется с помощью сета транзакции.

Для установки или обновления пакета создайте сет транзакции, постройте транзакцию с элементами транзакции, которые будут представлены пакетами, нуждающимися в установке, проверьте неразрешенные зависимости и запустите сет. Запуск сета транзакции установит или обновит пакеты.

Далее - Построение сета транзакции
Назад - Сравнение зависимостей
Содержание


16.6.1 Построение сета транзакции

Установка или обновление пакетов должны быть выполнены в рамках контекста сета транзакции. Для установки или обновления набора пакетов выполняется addInstall с соответствующими хэдерами. Синтаксис:

ts.addInstall(header, key_data, mode)

Когда вызывается addInstall, ему передаются объект хэдера, определенные ключевые данные и флаг режима. Флаг должен быть i для установки и u - для обновления, или a - для специального режима, в котором пакет доступен для прохождения проверок сета транзакции, но не устанавливается (не обновляется). Флаг а используется сравнительно редко. В большинстве случаев нужно использовать u, подобно тому, что при установке с помощью утилиты rpm пакеты должны устанавливаться с ключом -U.

Параметр ключевых данных key_data позволяет осуществить обратный вызов.

Для удаления пакетов используется addErase вместо addInstall:

ts.addErase(package_name)

Для выбора пакета, который должен быть установлен (обновлен), используйте следующий код:

h = readRpmHeader( ts, sys.argv[1] )

ts.addInstall(h, sys.argv[1], 'u')

Этот пример передает имя файла пакета в addInstall, забирая его из командной строки.

Вызов addInstall добавляет объект хэдера и ассоциированный с ним файл пакета для обновления. Имя файла пакета передается в sys.argv[1] в качестве key_data для обратного вызова из сета транзакции.

Далее - Элементы транзакции
Назад - Установка и обновление пакетов
Содержание


2.3 Команды RPM

Основные команды

Основная утилита системы RPM - rpm (странно, не правда ли). Одна из главных целей системы есть упрощение управления пакетами. Для достижения этой цели все операции кроме сборки предоставлены через эту утилиту. Параметры командной строки переключают утилиту для работы в одном из доступных режимов.

На вопрос, что доступно администратору в rpm, можно ответить: вагон типичных функций пакетного менеджмента и вагон и маленькая тележка нетипичных/малоизвестных операций.

В нижеследующей таблице приводится список основных режимов работы rpm.

Режим работы Короткая нотация Длинная нотация
Обновление/установка -U --upgrade
Установка -i --install
Удаление -e --erase
Режим запросов -q --query
Верификация -V --verify
Проверка подписи -K --cheking
Обновление в режиме freshen -F --freshen
Инициализация БД Нет --initdb
Перестройка БД Нет --rebuilddb

Используя таблицу как руководство, можно исследовать характер работы опций утилиты. Для установки (а если уже установлен - обновления) пакета используется, например, команда:

# rpm -U foo-0.1-1.i386.rpm

В целях получения некоторой обратной связи администраторы обычно используют эту команду в форме:

# rpm -Uhv foo-0.1-1.i386.rpm

где v - многословное поведение, а h - указание выводить прогресс-бар из пятидесяти символов #.

Для удаления пакета:

# rpm -e foo

Обратите внимание, имя пакета без версии и постфикса, так как rpm обращается за информацией о пакете в БД. При установке же используется имя файла rpm.

Для запроса списка всех установленных пакетов:

# rpm -qa

Этот список может занимать не один экран. Хотите иметь возможность полистать его? Не проблема:

# rpm -qa | less

Прочие команды
В дополнение к rpm, о которой мы не узнали еще и десятой части, имеются некоторые дополнительные команды, такие как rpmbuild (для сборки) и rpm2cpio.
Сборка пакетов будет обсуждаться в Разделе 8 этой книги.
Команда rpm2cpio экспортирует файл rpm в формат архиватора cpio. А cpio умеет вычленять из архива отдельные файлы. Например, для получения списка файлов в rpm-пакете можно использовать примерно следующее:

# rpm2cpio foo-0.1-1.i386.rpm | cpio -t

Опция -i скажет архиватору cpio извлечь все файлы. Опция -d задаст создание при необходимости локальных директорий, опция -v переведет в многословный режим работы.

Далее - Раздел 3. Использование RPM
Назад - База данных RPM
Содержание


16.6.2 Элементы транзакции

Сеты транзакций состоят из элементов транзакций. Элемент транзакции составляет одну элементарную часть транзакции и содержит один пакет для одной операции (установка или удаление) в каждом сете. Таким образом: один элемент приходится на один пакет на одну операцию. Можно обходить сет транзакции для получения каждого элемента. Имея элемент, можно вызывать его методы для получения зависимостей или проверки записей хэдера.

Таблица ниже показывает информационные методы, которые можно вызывать для элемента транзакции. Большинство методов возвращает единственное значение.

Метод

Возвращает

A

Возвращает архитектуру пакета

E

Возвращает эпоху

O

Возвращает операционную систему

R

Возвращает номер релиза

V

Возвращает версию

N

Возвращает имя пакета

NEVR

Возвращает имя-эпоху-версию-релиз

DS

Возвращает сет зависимости пакета для указанного тэга

FI

Возвращает сет информации о пакете

Для сложных проверок метод DS возвращает сет зависимости пакета для заданного имени поля:

ds = te.DS(tag_name)

Возможные поля (значения tag_name): Providename, Requirename, Obsoletename или Conflictname. Например:

ds = te.DS('Requirename')

Метод FI возвращает сет информации о пакете:

fi = te.FI(tag_name)

Для метода FI необходимо передавать в качестве tag_name 'Basenames'.

Пример ниже (te.py) показывает, как обходить сет транзакции для получения элементов транзакции:

#!/usr/bin/python

# Adds all package files on command line to a transaction

# and prints out the transaction elements.

# Usage:

# python te.py rpm_file1.rpm rpm_file2.rpm ...

#

import rpm, os, sys

def readRpmHeader(ts, filename):

""" Read an rpm header. """

fd = os.open(filename, os.O_RDONLY)

h = ts.hdrFromFdno(fd)

os.close(fd)

return h

ts = rpm.TransactionSet()

# Set to not verify DSA signatures.

ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)

for filename in sys.argv[1:]:

h = readRpmHeader(ts, filename)

print "Installing %s-%s-%s" % (h['name'], h['version'], h['release'])

ts.addInstall(h, filename, 'i')

print "This will install:"

for te in ts:

print "%s-%s-%s" % (te.N(), te.V(), te.R() )

ts.check()

ts.order()

print "This will install:"

for te in ts:

print "%s-%s-%s" % (te.N(), te.V(), te.R() )

Скрипт te.py устанавливает транзакцию и печатает элементы, никогда не выполняя транзакцию. Цель в данном случае - показать, что находится в транзакции. Вторая группа печатного вывода показывает результаты проверок и сортировки порядка транзакции.

Далее - Проверка и переопределение порядка элементов транзакции
Назад - Построение сета транзакции
Содержание


16.6.3 Проверка и переопределение порядка элементов транзакции

После того, как методом addInstall или addErase набраны пакеты для установки (удаления), вызываются два метода для проверки и выстраивания правильного порядка установки (удаления). Это методы check и order.

16.6.3.1 Проверка зависимостей
Метод check проверяет зависимости в сете транзакции.

unresolved_dependencies = ts.check()

Метод возвращает None, если все зависимости разрешены, или сложный список для каждой неразрешенной зависимости. В целом, если метод вернул что-либо помимо None, транзакция не может быть выполнена.

Список, возвращаемые методом check в случае неразрешенных зависимостей, имеет следующий формат:

((N,V,R), (reqN, reqV), needsFlags, suggestedPackage, sense)

Первый элемент списка - имя, версия, релиз пакета, который вы пытаетесь установить. Следующая последовательность - имя и версия пакета, от которого зависит устанавливаемый (или с которым конфликтует). Версия не выводится, если зависимость от библиотеки или другого файла (а не пакета целиком).

needsFlags говорят о том, что произошло - имеет место зависимость или конфликт. Значение флага - битовая маска, которая может содержать флаги для rpm.RPMSENSE_EQUAL, rpm.RPMSENSE_GREATER и rpm.RPMSENSE_LESS. Эти флаги могут дать понять, что имеется зависимость от пакета версии старше, чем 4.1, например.

Параметр suggestedPackage именует пакет, который разрешает зависимость. Эта переменная будет иметь значение None, если не известен пакет, разрешающий зависимость.

Также можно понять, является ли зависимость требованием или конфликтом с помощью rpm.RPMSENSE_CONFLICTS или rpm.RPMSENSE_REQUIRES. Это возможные значения sense.

Пример. Следующий список показывает зависимость от пакета:

(('eruby-devel', '0.9.8', '2'), ('eruby-libs', '0.9.8'), 8, None, 0)

А этот - зависимость от разделяемой библиотеки:

(('jpilot', '0.97', '1'), ('libpisock.so.3', None), 0, None, 0)

Данный формат вывода будет меняться в будущих версиях. Для установления текущей версии формата просмотрите онлайн-документацию Python API.

16.6.3.2 Обратный вызов метода check
В вызов check опционально может быть добавлена callback-функция. Эта функция будет вызываться для каждой неразрешенной зависимости в сете транзакции. Вы можете использовать этот обратный вызов для обработки ситуации. Базовый синтаксис:

def checkCallback(ts, TagN, N, EVR, Flags):

# Do something

Подобную callback-функцию можно использовать, например, для автоматического добавления пакетов в транзакцию (тех пакетов, от которых имеется неразрешенная зависимость). Информацию о пакетах можно брать из базы данных пакетов Red Hat, пакета rpmdb-redhat. Используя вышеописанный трюк, можно открыть транзакцию, используя более чем одну БД одновременно. Определите макрос _dbpath как путь "/usr/lib/rpmdb/i386-redhat-linux/redhat", или какой-то еще, где расположена БД из пакета rpmdb-redhat, и создайте сет транзакции. Тогда обратный вызов check найдет данные по пакетам в экстра-базе данных и добавит их текущую, реальную БД RPM.

Также check callback можно использовать для поиска файлов, от которых имеются зависимости, на диске или в сетевом архиве. Нижеследующий код показывает обратный вызов, который может быть заполнен в попытке удовлетворить зависимости по ходу проверки. Этот обратный вызов устанавливает формат поиска в альтернативной БД или где-либо еще. Данный скелет должен быть заполнен реальными данными для того, чтобы осуществлялся настоящий поиск пакетов для разрешения зависимостей.

def checkCallback(ts, TagN, N, EVR, Flags):

if TagN == rpm.RPMTAG_REQUIRENAME:

prev = ""

Nh = None

if N[0] == '/':

dbitag = 'basenames'

else:

dbitag = 'providename'

# What do you need to do.

if EVR:

print "Must find package [", N, "-", EVR, "]"

else:

print "Must find file [", N, "]"

if resolved:

# ts.addIntall(h, h, 'i')

return -1

return 1

В зависимости от того, какие параметры вы передадите в обратный вызов, код должен искать пакет как таковой, или пакет, который предоставляет нужный файл. Если имеется альтернативная БД пакетов, используйте dbMatch для поиска. Если же вы работаете с директорией, в которой лежат rpm-пакеты, потребуется построить полные имена пакетов, соединяя имена, версии и релизы.

16.6.3.3 Изменение порядка пакетов в сете транзакции
Добавление пакетов в сет может быть осуществлено в любом порядке. Метод order выстраивает свой порядок установки (удаления) в соответствии с зависимостями. Перед вызовом order должен быть выполнен check.

Далее - Запуск транзакции
Назад - Элементы транзакции
Содержание


16.6.4 Запуск транзакции

После инициализации сета транзакции, запуск операций осуществляется вызовом run. Требуется два параметра:

ts.run(callback, client_data)

Параметр callback должен быть функцией Python. Параметр client_data - любые данные, которые вы хотите поместить в обратный вызов. Поскольку в сете транзакции может быть много пакетов, это не должны быть данные, относящиеся к определенному пакету. В качестве client_data не может быть передано значение None.

16.6.4.1 Обратные вызовы метода run
Callback, который был передан в run, необходим. Обратный вызов должен сработать правильно, иначе транзакция завершится с ошибкой. Вы должны предоставить callback.

Поскольку callback будет вызываться не один раз, это отличный способ получить обратную связь для определения степени выполнения транзакции (особенно в разработке графических приложений для прогресс-баров).

Базовый синтаксис обратного вызова для сета транзакции:

def runCallback(reason, amount, total, key, client_data):

# Do your stuff...

key - это данные, предоставленные вами для метода addInstall. client_data - данные, которые будут передаваться в run.

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

Значение

На что указывает

rpm.RPMCALLBACK_UNKNOWN

Неизвестная ошибка

rpm.RPMCALLBACK_INST_PROGRESS

Прогресс установки

rpm.RPMCALLBACK_INST_START

Старт установки

rpm.RPMCALLBACK_INST_OPEN_FILE

Callback должен открыть файл пакета

rpm.RPMCALLBACK_INST_CLOSE_FILE

Callback должен закрыть файл пакета

rpm.RPMCALLBACK_TRANS_PROGRESS

Прогресс транзакции

rpm.RPMCALLBACK_TRANS_START

Старт транзакции

rpm.RPMCALLBACK_TRANS_STOP

Стоп транзакции

rpm.RPMCALLBACK_UNINST_PROGRESS

Прогресс удаления

rpm.RPMCALLBACK_UNINST_START

Старт удаления

rpm.RPMCALLBACK_UNINST_STOP

Стоп удаления

rpm.RPMCALLBACK_REPACKAGE_PROGRESS

Прогресс пересборки

rpm.RPMCALLBACK_REPACKAGE_START

Старт пересборки

rpm.RPMCALLBACK_REPACKAGE_STOP

Стоп пересборки

rpm.RPMCALLBACK_UNPACK_ERROR

Ошибка распаковки

rpm.RPMCALLBACK_CPIO_ERROR

Ошибка cpio при попытке разархивировать нагрузку

Ваш callback должен обрабатывать по меньшей мере два случая: rpm.RPMCALLBACK_INST_OPEN_FILE и rpm.RPMCALLBACK_INST_CLOSE_FILE.

С reason, равным rpm.RPMCALLBACK_INST_OPEN_FILE, необходимо открыть файл rpm-пакета и вернуть дескриптор. Этот дескриптор необходимо хранить в глобально-доступной переменной, или по крайней мере в зоне видимости, так как потребуется файл закрыть, когда reason будет rpm.RPMCALLBACK_INST_CLOSE_FILE.

16.6.4.2 Кодируем пример callback-функции
Код ниже показывает работающий пример callback для установки или обновления пакетов.

# Global file descriptor for the callback.

rpmtsCallback_fd = None

def runCallback(reason, amount, total, key, client_data):

global rpmtsCallback_fd

if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:

print "Opening file. ", reason, amount, total, key, client_data

rpmtsCallback_fd = os.open(client_data, os.O_RDONLY)

return rpmtsCallback_fd

elif reason == rpm.RPMCALLBACK_INST_START:

print "Closing file. ", reason, amount, total, key, client_data

os.close(rpmtsCallback_fd)

Этот callback подразумевает, что в вызов addInstall передается в качестве пользовательских данных имя файла rpm-пакета. client_data в метод run игнорируется, но это хорошее место для передачи объекта. Можно, например, использовать эту возможность для того, чтобы избежать хранения дескриптора файла в глобальной переменной.

16.6.4.3 Обновление пакета
Пример ниже содержит скрипт (rpmupgrade.py) для обновления или установки пакета.

#!/usr/bin/python

# Upgrades packages passed on the command line.

# Usage:

# python rpmupgrade.py rpm_file1.rpm rpm_file2.rpm ...

#

import rpm, os, sys

# Global file descriptor for the callback.

rpmtsCallback_fd = None

def runCallback(reason, amount, total, key, client_data):

global rpmtsCallback_fd

if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:

print "Opening file. ", reason, amount, total, key, client_data

rpmtsCallback_fd = os.open(key, os.O_RDONLY)

return rpmtsCallback_fd

elif reason == rpm.RPMCALLBACK_INST_START:

print "Closing file. ", reason, amount, total, key, client_data

os.close(rpmtsCallback_fd)

def checkCallback(ts, TagN, N, EVR, Flags):

if TagN == rpm.RPMTAG_REQUIRENAME:

prev = ""

Nh = None

if N[0] == '/':

dbitag = 'basenames'

else:

dbitag = 'providename'

# What do you need to do.

if EVR:

print "Must find package [", N, "-", EVR, "]"

else:

print "Must find file [", N, "]"

if resolved:

# ts.addIntall(h, h, 'i')

return -1

return 1

def readRpmHeader(ts, filename):

""" Read an rpm header. """

fd = os.open(filename, os.O_RDONLY)

h = ts.hdrFromFdno(fd)

os.close(fd)

return h

ts = rpm.TransactionSet()

# Set to not verify DSA signatures.

ts.setVSFlags(-1)

for filename in sys.argv[1:]:

h = readRpmHeader(ts, filename)

print "Upgrading %s-%s-%s" % (h['name'], h['version'], h['release'])

ts.addInstall(h, filename, 'u')

unresolved_dependencies = ts.check(checkCallback)

if not unresolved_dependencies:

ts.order()

print "This upgrade will install:"

for te in ts:

print "%s-%s-%s" % (te.N(), te.V(), te.R())

print "Running transaction (final step)..."

ts.run(runCallback, 1)

else:

print "Error: Unresolved dependencies, transaction failed."

print unresolved_dependencies

Этот скрипт ожидает, что имя файла rpm-пакета будет передано в параметре командной строки, получив имя он выполняет обновление пакета (а если это новый пакет - то установку).

При запуске скрипта увидим следующее:

# rpm -q jikes

jikes-1.17-1

# python rpmupgrade.py jikes-1.18-1.i386.rpm

Upgrading jikes-1.18-1

This upgrade will install:

jikes-1.18-1

jikes-1.17-1

Running transaction (final step)...

Opening file. 4 0 0 jikes-1.18-1.i386.rpm 1

Closing file. 2 0 2854204 jikes-1.18-1.i386.rpm 1

# rpm -q jikes

jikes-1.18-1

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

$ python rpmupgrade.py jikes-1.18-1.i386.rpm

Upgrading jikes-1.18-1

This upgrade will install:

jikes-1.18-1

jikes-1.17-1

Running transaction (final step)...

error: cannot get exclusive lock on /var/lib/rpm/Packages

error: cannot open Packages index using db3 - Operation not permitted (1)

error: cannot open Packages database in /var/lib/rpm

Если пакет имеет зависимости от файла, например, разделяемой библиотеки, вывод будет таким:

# python rpmupgrade.py jikes-1.17-glibc2.2-1.i386.rpm jpilot-0_97-1_i386.rpm
Upgrading jikes-1.17-1

Upgrading jpilot-0.97-1

Must find file [ libpisock.so.3 ]

Error: Unresolved dependencies, transaction failed.

(('jpilot', '0.97', '1'), ('libpisock.so.3', None), 0, None, 0)

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

# python rpmupgrade.py eruby-devel-0.9.8-2.i386.rpm

Upgrading eruby-devel-0.9.8-2

Must find package [ eruby-libs - 0.9.8 ]

Error: Unresolved dependencies, transaction failed.

(('eruby-devel', '0.9.8', '2'), ('eruby-libs', '0.9.8'), 8, None, 0)

Далее - Раздел 17. Программирование RPM на Perl
Назад - Проверка и переопределение порядка элементов транзакции
Содержание


17. Программирование RPM на Perl

Perl - один из наиболее популярных скриптовых языков. Его охотно используют системные администраторы, разработчики системного ПО и пользователи. Perl работает на Linux, UNIX и Windows.

Из-за своей продолжительной биографии, связанной с обработкой текстовых файлов, Perl пользуется особой любовью системных администраторов. Он поддерживает подключаемые пакеты, которые называются модулями. Можно найти тысячи модулей для обработки текстов, работы с сетью и других задач. Имеется столько готовых инструментов, что даже люди, не жалующие Perl из-за его синтаксиса частенько прибегают к использованию модулей Perl, экономя время.

На search.cpan.org можно найти множество модулей Perl, пригодных для решения различных задач.

Далее - Получение и использование RPM-модулей Perl
Назад - Запуск транзакции
Содержание


17.1 Получение и использование RPM-модулей Perl

Несмотря на обилие модулей, ни один из них, вероятно, не удовлетворит всех ваших потребностей, хотя со временем модули постепенно консолидируются в бОльшие модули, причем конечное число их используется почти всеми разработчиками. Например, модуль RPM2, написанный Chip Turner из Red Hat, предоставляет большинство возможностей, необходимых для работы с RPM из Perl.

Для работы должны быть установлены пакеты perl-RPM2 и сам интерпретатор Perl.

Модуль RPM2 содержит методы для работы с двумя типами объектов RPM: rpm-файлами и инсталлированными пакетами.

Далее - Открытие rpm-файла
Назад - Программирование RPM на Perl
Содержание


17.2.1 Открытие rpm-файла

Процедура open_package открывает файл пакета и возвращает объект хэдера (RPM2::Header). Базовый синтаксис следующий:

my $header = RPM2->open_package( $filename );

Например:

my $header = RPM2->open_package("jikes-1.14-1-glibc-2.2.i386.rpm");

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

Далее - Получение значений полей хэдера из файла пакета
Назад - Получение и использование RPM-модулей Perl
Содержание


17.2.2 Получение значений полей хэдера из файла пакета

Каждый rpm-пакет содержит информацию, хранящуюся в определенных полях (тегах) хэдера пакета. Например, имя пакета содержится в поле NAME, а длинное описание в поле DESCRIPTION.

Процедура tag возвращает значение данного тега (поля). Например, для получения имени пакета используйте значение поля NAME:

use RPM2;

my $header = RPM2->open_package("jikes-1.14-1-glibc-2.2.i386.rpm" );

print $header->tag("NAME"), "\n";

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

#!/usr/bin/perl

#

# Lists summary from an RPM package file

# Usage:

# rpmsum.pl package_name.rpm

#

use strict;

use RPM2;

my $header = RPM2->open_package( $ARGV[0] );

print $header->tag("NAME"), ": ", $header->tag("SUMMARY"), "\n";

При запуске скрипта необходимо передать ему имя файла пакета в качестве параметра. Например:

$ ./rpmsum.pl jikes-1.14-1-glibc-2.2.i386.rpm

jikes: java source to bytecode compiler

Далее - Удобные методы
Назад - Открытие файла пакета
Содержание


17.2.3 Удобные методы

Модуль RPM2 включает методы для обработки ВСЕХ полей хэдера. Таким образом, вместо tag("NAME") можно употребить name() и также для всех прочих тегов. Например:

print $header->name(), ": ", $header->summary(), "\n";

Далее - Вывод имени и версии
Назад - Получение значений полей хэдера из файла пакета
Содержание


17.2.4 Вывод имени и версии

Модуль RPM2 предоставляет удобную процедуру для получения значений полей NAME, VERSION, RELEASE, и EPOCH, часто это сочетание заменяют аббревиатурой NVRE. Процедура, as_nvre, возвращает одиночную строку с этими значениями в стандартном формате, разделенными знаком минус.

Тег EPOCH обычно имеет пустое значение. Если значение имеется, оно будет на первом месте в строке вывода, и, далее, после двоеточия, имя, релиз и версия. Например:

5:redhat-config-httpd-1.0.1-13

Эту процедуру можно вызывать для любого объекта хэдера или любого объекта пакета для получения полного имени. Например:

print $header->as_nvre(), "\n";

Далее - Проверка, является ли файл пакета пакетом с исходными кодами
Назад - Удобные методы
Содержание


17.2.5 Проверка, является ли файл пакета пакетом с исходными кодами

Другая удобная процедура проанализирует, является ли пакет пакетом с исходными кодами, или бинарным. Процедура is_source_package возвращает true если проверяется пакет с исходниками, и false в противном случае.

Следующий скрипт, rpmpkg.pl, показывает, как использовать as_nvre и is_source_package в одном флаконе:

#!/usr/bin/perl

#

# Queries RPM package file and prints

# out name and whether this is a source pkg.

# Usage:

# rpmpkg.pl package_name

#

use strict;

use RPM2;

my $header = RPM2->open_package( $ARGV[0] );

if ( $header->is_source_package() ) {

print "Source package ", $header->as_nvre(), "\n";

} else {

print $header->as_nvre(), "\n";

}

Далее - Открытие БД RPM
Назад - Вывод имени и версии
Содержание


3.1 Утилита rpm

Все, что необходимо для управления пакетами, это утилита rpm.
Такие операции, как установка или удаление пакета могут быть выполнены быстро и эффективно.
Навыки использования утилиты вырабатываются быстро и могут быть задействованы уже через несколько минут после начала чтения этого раздела.

Далее - Установка и обновление пакетов
Назад - Команды RPM
Содержание


17.3.1 Открытие БД RPM

Помимо доступа к информации внутри файла rpm-пакета, RPM2 содержит также и процедуры для работы с БД RPM.

Для открытия БД используется процедура to open_rpm_db для объекта RPM2:

my $rpm_db = RPM2->open_rpm_db();

Также можно задать каталог, где размещена (например, альтернативная) БД RPM:

my $rpm_db = RPM2->open_rpm_db( "-path" => "/var/lib/rpm" );

Единожды получив объект БД RPM, можно неоднократно вызывать процедуры запросов для поиска пакетов по различным критериям в стиле команды rpm q.

Далее - Поиск пакетов
Назад - Проверка, является ли файл пакета пакетом с исходными кодами
Содержание


17.3.2 Поиск пакетов

Процедура find_by_name находит пакет или пакеты по имени. Она возвращает список Perl из найденных записей. Например, если установлена более чем одна версия пакета, find_by_name должна вернуть итератор для обхода списка, полученного с помощью шаблона имени.

Подход с применением итераторов обычно более эффективен.

Далее - Обход списка пакетов
Назад - Открытие БД RPM
Содержание


17.3.3 Обход списка пакетов

Итераторы весьма важны в пакете RPM2. Они предоставляют эффективный интерфейс к большим (в потенциале) наборам пакетов, а также итераторы более близки к реализации нижележащих функций в C API. Они просты для использования. Вызов процедуры next переводит нас к следующему в наборе пакету.

Например:

my $pkg_iter = $rpm_db->find_by_name_iter( "kernel" );

while (my $pkg = $pkg_iter->next() ) {

# Do something ...

}

Следующий листинг содержит скрипт (rpmname.pl), который работает подобно команде rpm q без прочих опций командной строки.

#!/usr/bin/perl

#

# Queries RPM database for given package.

# Usage:

# rpmname.pl package_name

#

use strict;

use RPM2;

my $rpm_db = RPM2->open_rpm_db( "-path" => "/var/lib/rpm" );

my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );

while (my $pkg = $pkg_iter->next() ) {

print $pkg->tag("NAME"), "-", $pkg->tag("VERSION"), "\n";

}

$rpm_db->close_rpm_db();

При запуске скрипта ему необходимо передать имя пакета в качестве параметра. Например:

$ ./rpmname.pl kernel

kernel-2.4.18

Далее - Дополнительные функции поиска
Назад - Поиск пакетов
Содержание


17.3.4 Дополнительные функции поиска

Процедура find_by_name_iter ищет пакет по имени. Модуль RPM2 также поддерживает ряд функций для повышения информативности запросов. Описание функций приводится в таблице ниже.

Функция

Использование

find_all()

Возвращает список всех пакетов из БД RPM

find_all_iter()

Возвращает итератор для обхода всех пакетов в БД RPM

find_by_file($filename)

Возвращает список пакетов, каждый из которых содержит данный файл

find_by_file_iter($filename)

Возвращает итератор для обхода пакетов, каждый из которых содержит данный файл

find_by_name($package_name)

Возвращает список пакетов, имена которых соответствуют шаблону имени

find_by_name_iter($package_name)

Возвращает итератор для обхода пакетов, имена которых соответствуют шаблону имени

find_by_provides($capability)

Возвращает список пакетов, предоставляющих заданную возможность

find_by_provides_iter($capability)

Возвращает итератор для обхода пакетов, предоставляющих заданную возможность

find_by_requires($capability)

Возвращает список пакетов, имеющих данную зависимость

find_by_requires_iter($capability)

Возвращает итератор для обхода пакетов, имеющих данную зависимость

Для демонстрации возможностей этих функций предлагается следующий скрипт (rpmprovides.pl), результат работы которого можно сравнить с результатом работы команды rpm с соответствующими ключами. Скрипт ищет пакеты, предоставляющие определенную возможность и пакеты, которые зависят от нее.

#!/usr/bin/perl

#

# Queries RPM database for given package,

# listing what it provides and what other

# packages require the capability.

#

# Usage:

# rpmprovides.pl package_name

#

use strict;

use RPM2;

my $rpm_db = RPM2->open_rpm_db();

my $pkg_iter = $rpm_db->find_by_provides_iter( $ARGV[0] );

print "Provides: ", $ARGV[0], "\n";

while (my $pkg = $pkg_iter->next() ) {

print "\t", $pkg->as_nvre(), "\n";

}

# Now, what packages require this capability.

my $pkg_iter2 = $rpm_db->find_by_requires_iter( $ARGV[0] );

print "Requires: ", $ARGV[0], "\n";

while (my $pkg2 = $pkg_iter2->next() ) {

print "\t", $pkg2->as_nvre(), "\n";

}

$rpm_db->close_rpm_db();

При запуске скрипта с именем зависимости в качестве параметра, получим следующий вывод:

$ ./rpmprovides.pl httpd

Provides: httpd

httpd-2.0.40-8

Requires: httpd

mod_perl-1.99_05-3

5:redhat-config-httpd-1.0.1-13

mod_python-3.0.0-10

1:mod_ssl-2.0.40-8

Для проверки работы скрипта выполним команду rpm -q для сравнения полученных списков:

$ rpm -q --whatprovides httpd

httpd-2.0.40-8

$ rpm -q --whatrequires httpd

mod_perl-1.99_05-3

redhat-config-httpd-1.0.1-13

mod_python-3.0.0-10

mod_ssl-2.0.40-8

В обоих случаях увидим одинаковые списки пакетов.

Процедура find_by_provides_iter возвращает имя пакета, например, bash. Нет возможности передать имя файла, такое как /bin/bash, для получения имени пакета, предоставляющего этот файл.

Далее - Получение информации о пакетах
Назад - Обход списка пакетов
Содержание


17.3.5 Получение информации о пакетах

Процедуры tag, as_nvre и is_source_package, работающие с объектом хэдера, полученным из файла (как было показано ранее), также умеют работать и с записями, полученными из БД RPM.

Скрипт, приведенный ниже (rpminfo.pl), распечатывает описательную информацию о заданном пакете.

#!/usr/bin/perl

#

# Queries RPM database for given package and prints info.

# Usage:

# rpminfo.pl package_name

#

use strict;

use RPM2;

my $rpm_db = RPM2->open_rpm_db( "-path" => "/var/lib/rpm" );

my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );

while (my $pkg = $pkg_iter->next() ) {

printInfo( $pkg );

}

$rpm_db->close_rpm_db();

# Prints info on one package.

sub printInfo {

my($pkg) = shift;

print $pkg->as_nvre(), ", ", $pkg->tag("ARCH"), ", ",

$pkg->tag("OS"), ", ", $pkg->tag("PLATFORM"), "\n";

print $pkg->tag("SUMMARY"), "\n";

print "Group: ", $pkg->tag("GROUP"), "\n";

print $pkg->tag("DESCRIPTION"), "\n";

print "Vendor: ", $pkg->tag("VENDOR"), ", ", $pkg->tag("URL"), "\n";

print "Size: ", $pkg->tag("SIZE"), "\n";

}

Запуская скрипт, увидим вывод, подобный следующему:

$ ./rpminfo.pl XFree86

XFree86-4.2.0-72, i386, linux, i386-redhat-linux-gnu
The basic fonts, programs and docs for an X workstation.

Group: User Interface/X

XFree86 is an open source implementation of the X Window System. It provides the basic low level functionality which full fledged
graphical user interfaces (GUIs) such as GNOME and KDE are designed upon.

Vendor: Red Hat, Inc., http://www.xfree86.org

Size: 30552239

17.3.5.1 Вывод даты установки
Дата установки - это поле числового типа, представляющее количество секунд, прошедших со времени начала эпохи UNIX (1 января 1970 года) до момента установки пакета. Для придания этому значению (тег INSTALLTIME) человекочитаемого смысла используется функция Perl localtime. Скрипт rpmdate.pl показывает реализацию ее использования:

#!/usr/bin/perl

#

# Queries RPM database for given package,

# prints out name, vendor, and date installed.

# Usage:

# rpmdate.pl package_name

#

use strict;

use RPM2;

my $rpm_db = RPM2->open_rpm_db();

my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );

while (my $pkg = $pkg_iter->next() ) {

printDate( $pkg );

}

$rpm_db->close_rpm_db();

# Prints installation data for one package.

sub printDate {

my($pkg) = shift;

my $date = localtime( $pkg->tag("INSTALLTIME") );

printf("%-20s %-17s %s\n", $pkg->as_nvre(), $pkg->tag("VENDOR"), $date);

}

Функция printf в этом скрипте умеет нечто, чего команда rpm делать не умеет. Даже используя опцию --queryformat, мы не можем сгруппировать значения нескольких полей в одну строку, задавая формат вывода, с Perl это возможно. Просто ассоциируйте несколько значений в строку, используя имена полей или такие процедуры, как as_nvre.

Передав имя пакета скрипту в качестве параметра, увидим дату установки пакета:

$ ./rpmdate.pl kernel

kernel-2.4.18-14 Red Hat, Inc. Sat Oct 5 12:29:58 2002

17.3.5.2 Обработка полей, представляющих собой массивы строк
Не только формат даты может вызвать сложности. Ряд тегов (полей хэдера) представляют собой массивы строк. Это означает, что необходимо предусмотреть, каким образом эти массивы будут выводится в консолидированном виде.

Для помощи в обработке таких ситуаций процедура, показанная ниже, получает на вход массив строк, возвращая одну строку с заданным разделителем между частями строки:

sub arrayToString {

my($sep) = shift;

my(@array) = @_;

my($str);

$str = $array[0];

for ( $i = 1; $i < $#array; $i++ )

{

$str = $str . $sep . $array[$i];

}

return $str;

}

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

*BASENAMES

*CHANGELOGNAME

*CHANGELOGTEXT

*DIRNAMES

*FILEGROUPNAME

*FILELANGS

*FILELINKTOS

*FILEMD5S

*FILEUSERNAME

*OLDFILENAMES

*PROVIDENAME

*PROVIDEVERSION

*REQUIRENAME

*REQUIREVERSION

17.3.5.3 Получение списка файлов в пакете
Процедура files предоставляет список файлов, содержащихся в данном пакете. Нижеследующий листинг показывает, как с помощью скрипта rpmfiles.pl получить доступ к такому списку:

#!/usr/bin/perl

#

# Queries RPM database for given package,

# prints out the files in the package.

# Usage:

# rpmfiles.pl package_name

#

use strict;

use RPM2;

my $rpm_db = RPM2->open_rpm_db();

my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );

while (my $pkg = $pkg_iter->next() ) {

printFiles( $pkg );

}

$rpm_db->close_rpm_db();

# Prints installation data for one package.

sub printFiles {

my($pkg) = shift;

my $files = arrayToString("\n", $pkg->files() );

print "Files:\n", $files, "\n";

}

sub arrayToString {

my($sep) = shift;

my(@array) = @_;

my($str);

$str = $array[0];

for ( my $i = 1; $i < $#array; $i++ )

{

$str = $str . $sep . $array[$i];

}

return $str;

}

Запустив скрипт, увидим следующее:

$ ./rpmfiles.pl jikes

Files:

/usr/bin/jikes

/usr/doc/jikes-1.17/license.htm

Далее - Сравнение версий
Назад - Дополнительные функции поиска
Содержание


17.3.6 Сравнение версий

Модуль RPM2 использует оператор сравнения, <=>, для сравнения версий одноименных пакетов. Следующий скрипт (rpmver.pl) показывает, как сравнить все локальные файлы rpm-пакета с определенным именем с новейшей установленной версией этого пакета (если он установлен).

#!/usr/bin/perl -w

#

# Compare versions of all *.rpm files against the

# latest packages installed (if installed)

#

# Usage:

# rpmver.pl

# This script looks for all *.rpm files.

#

use strict;

use RPM2;

my $rpm_db = RPM2->open_rpm_db();

for my $filename (<*.rpm>) {

my $h = RPM2->open_package( $filename );

# Ensure we compare against the newest

# package of the given name.

my ($installed) =
sort { $b <=> $a } $rpm_db->find_by_name($h->name);

if (not $installed) {

printf "Package %s not installed.\n", $h->as_nvre;

} else {

my ($result) = ($h <=> $installed);

if ($result < 0) {

printf "Installed package %s newer than file %s\n",

$installed->as_nvre,

$h->as_nvre;

} else {

printf "File %s newer than installed package %s\n",

$h->as_nvre,

$installed->as_nvre;

}

}

}

Сортировка { $a <=> $b } перед вызовом find_by_name сортирует все пакеты с заданным именем по версии, поэтому сравнение происходит с новейшей версией установленного пакета. ($h <=> $installed) сравнивает информацию хэдера файла на диске с информацией об установленном пакете из БД.

При запуске скрипта вывод будет зависеть от локальных rpm-файлов, имеющихся в каталоге на диске:

$ perl rpmver.pl

Package acroread-4.0-0 not installed.

Package canvas-7.0b2.0-1 not installed.

Installed package jikes-1.18-1 newer than file jikes-1.14-1

Installed package SDL-1.2.4-5 newer than file SDL-0.9.9-4

Package ted-2.8-1 not installed.

Далее - Закрытие БД RPM
Назад - Получение информации о пакетах
Содержание


17.3.7 Закрытие БД

После завершения работы с БД вызовите close_rpm_db как показано ниже:

$rpm_db->close_rpm_db();

В принципе этот вызов не является обязательным, поскольку модуль RPM2 закроет БД, когда объект, в данном случае $rpm_db, выйдет из области видимости.

Далее - Раздел 18. Использование RPM в не-Red Hat Линуксах
Назад - Получение информации о пакетах
Содержание


18.1 О проблемах установки rpm-пакетов в не-Red Hat Линуксах

Когда мы имеем дело с установкой пакетов в не-Red Hat Линуксах, основные проблемы сосредотачиваются в следующих областях:

* Различия в версиях самой системы RPM

* Различное разделение ПО по пакетам

* Зависимости

* Отличающиеся пути размещения файлов

Следующие главы освещают эти темы.

Прим. перев. : Многие блоки информации в этом разделе сильно устарели. Главы переводятся "as is" без корректуры, с целью сохранения основных идей и подходов к решению проблем.

Далее - Версии системы RPM
Назад - Закрытие БД
Содержание


18.1.1 Версии системы RPM

Red Hat Linux 8.0 поставляется с RPM версии 4.1. Другие дистрибутивы могут поставлятся с иными версиями RPM. Поэтому, дабы не оставаться в неведении, первой командой перед работой с rpm в не-Red Hat дистрибутиве может быть rpm --version:

$ rpm --version

RPM version 4.1

Зная версию, мы можем предвосхищать возникновение проблем при установке пакетов. Например, RPM 4.0 и выше включает информацию о зависимостях в пакет автоматически. Если ваш дистрибутив имеет, например, версию RPM 3.х, придется отключить некоторые проверки при установке. Например, проверку зависимостей можно отключить с помощью --nodeps. В этом случае потребуется ручной контроль за удовлетворением зависимостей.

С другой стороны, если пакеты собирались под RPM 3.x и есть желание установить их в RPM 4.x систему, потребуется отключить проверку подписей с помощью --nosignature.

Далее - Разделение ПО по пакетам
Назад - О проблемах установки пакетов в не-Red Hat Линуксах
Содержание


18.1.2 Разделение ПО по пакетам

Не существует стандарта, придерживаясь которого разработчики разделяли бы большие проекты на пакеты в различных дистрибутивах Линукс. Это означает, что зависимости между пакетами будут отличаться.

Если возникли зависимости в отношении пакета, включающие множество других пакетов, проблема должна быть локализована, потому что пакеты, от которых возникли зависимости могут не существовать в определенном дистрибутиве или могут быть вовсе не нужны.

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

В этом случае единственное решение - использовать --nodeps. Устанавливать нужные зависимости или ссылки на нужные локации приходится вручную.

Кроме того, использование --nodeps может привести к коллапсу БД RPM. Поэтому оно оправдано, если зависимости действительно могут быть удовлетворены, например, из пакетов, имена которых отличаются от ожидаемых.

Далее - Зависимости
Назад - Версии системы RPM
Содержание


3.2. Установка и обновление пакетов

Для установки ПО в систему необходимо иметь нечто для установки. В нашем случае это rpm-пакет, то есть файл с расширением .rpm. Например, следующий файл содержит готовый для установки пакет ПО:

jikes-1.16-1.i386.rpm

Этот пакет несет в себе приложение jikes - компилятор Java. По имени файла, как уже отмечалось, можно определить версию ПО и номер сборки.

Другие пакеты содержат исходный код для сборки приложений или библиотек. Например, этот файл - пакет с исходниками:

jikes-1.16-1.i386.src.rpm

Нижеследующие главы описывают различные опции и способы применения rpm в ситуациях установки и обновления пакетов.

Далее - Режим установки
Назад - Утилита rpm
Содержание


18.1.3 Зависимости

Один из мощнейших источников проблем - зависимости. Здесь случаи могут варьироваться от простейшего случая установки необходимого пакета, до сложных случаев различия в версиях разделяемых библиотек или модулей Perl.

Рекомендации можно свести к следующим: используйте репозитории вендора вашего дистрибутива, используйте автоматизированные средства, вроде yum или yast для удовлетворения зависимостей пакета.

Если зависимость возникла от системной библиотеки, например, библиотеки C определенной версии, проще пересобрать пакет из исходников, чтобы получить пакет, оптимизированный на использование данной версии.

Более серьезные случаи возникают, когда пакет зависит от прикладной разделяемой библиотеки, например, смена API в библиотеке может привести приложение к неработоспособному состоянию. Установите пакет-собственник прикладной библиотеки нужной версии и вновь пересоберите пакет из исходников.

Ряд пакетов являются devel-пакетами. Они зависят от базового пакета. Например, rpm-devel зависит от базового пакета rpm. rpm-python зависит как от python, так и от rpm базовых пакетов определенной версии. Подход в разделении пакетов на базовый и devel-пакеты применяется в Red Hat, но другие вендоры не обязаны ему следовать. Исследуйте документацию для ознакомления с подходами вендора вашего дистрибутива.

Многие пакеты зависят от интерпретаторов языков сценариев (скриптовых языков), например, Perl. Подчас зависимость возникает из-за скрипта, использованного в пакете или из-за триггера, в котором задействованы какие-то скрипты. Проблемы могут возникнуть из-за расположения интерпретаторов на файловой системе. Например, Perl может быть установлен в /usr/bin/perl или в /usr/local/bin/perl. Кроме того, пакет может зависеть от определенного модуля Perl.

Пути к файлам также могут быть источниками проблем. Файл может находится по другому пути или принадлежать другому пакету. В этом случае следует найти пакет, которому принадлежит файл и убедиться, что пакет установлен.

Поисковые системы по пакетам, например, rpmseek.com также умеют обнаруживать пакеты, содержащие определенный файл.

Далее - Пути установки
Назад - Разделение ПО по пакетам
Содержание


18.1.4 Пути установки

Вендоры Линукс могут устанавливать ПО где угодно. Например, многие дистрибьюторы устанавливают значительное количество пакетов в /opt вместо /usr. Следование межфирменным соглашениям о стандартизации путей в будущем может помочь ограничению потока проблем с этой стороны.

В качестве способа переопределения путей можно предложить использовать опцию --badreloc. Но у этого подхода есть естественное ограничение - можно переопределить пути к файлам, но не содержимое файлов. Если внутри файлов имеются определенные ожидания, по каким путям находятся необходимые компоненты, ПО будет неработоспособным, если ожидания не оправдываются.

Единственным реальным путем является путь редактирования жестко заданных путей в скриптах пакетов. В случае же, когда жестко заданные пути внесены в бинарные файлы, без исправления исходного кода не обойтись.

Далее - Если ничего не помогает, пересоберите пакет из исходников
Назад - Зависимости
Содержание


18.1.5 Когда ничего не помогает, пересоберите пакет из исходников

Если проделано множество манипуляций, а пакет все равно не устанавливается, имеется последнее радикальное средство - установить src.rpm-пакет и пересобрать его, отредактировав spec-файл.

Например, в конце секции %install обычно выполняется группа скриптов brp (Build Root Policy). Эти скрипты выполняют такие задачи, как упаковка файлов помощи man. brp-скрипты Mandriva используют компрессор bzip2, скрипты Red Hat - gzip. В этом случае пересборка и установка пакета при переносе из одной системы в другую - наилучший ход.

Далее - Решение проблем сборки пакетов
Назад - Пути установки
Содержание


18.2 Решение проблем сборки пакетов

Учитывая все вышеперечисленные различия дистрибутивов, каким образом можно собирать пакеты на других Линуксах? Используя некоторые известные подходы следует таким образом настроить окружение сборки rpm, чтобы настройки покрывали большую часть порождающих проблемы моментов.

При сборке пакетов вам встретятся почти все те же проблемы, что и при их установке, то есть отличия в делении ПО на пакеты, путях, соответственно, зависимости. Существует также ряд проблем, встречающихся только при сборке.

Далее - Создание пакетов, специфичных для конкретного дистрибутива
Назад - Когда ничего не помогает, соберите пакет из исходников
Содержание


18.2.1 Создание пакетов, специфичных для конкретного дистрибутива

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

Это составляет довольно значительный объем работы. Если это возможно, поместите все различия в макросы и используйте единственный spec-файл для всех сборок, чтобы уменьшить количество непроизводительного труда. Иногда, однако, сложность spec-файла при этом превышает некоторые разумные пределы, в этом случае проще создать разные spec-файлы, по одному на каждый поддерживаемый дистрибутив.

Один из путей, облегчающих создание вендор-зависимых пакетов - рассмотреть пакет, содержащий специфичную для дистрибутива конфигурацию RPM. Например, в Red Hat Linux конфигурация RPM определяется пакетом redhat-rpm-config.

Получив список файлов этого пакета, увидим, в каких файлах Red Hat определяет специфичные для Red Hat Linux макросы.

$ rpm -ql redhat-rpm-config

/usr/lib/rpm/redhat

/usr/lib/rpm/redhat/brp-compress

/usr/lib/rpm/redhat/brp-redhat

/usr/lib/rpm/redhat/brp-sparc64-linux

/usr/lib/rpm/redhat/brp-strip

/usr/lib/rpm/redhat/brp-strip-comment-note

/usr/lib/rpm/redhat/brp-strip-shared

/usr/lib/rpm/redhat/find-lang.sh

/usr/lib/rpm/redhat/find-provides

/usr/lib/rpm/redhat/find-requires

/usr/lib/rpm/redhat/macros

/usr/lib/rpm/redhat/perl.prov

/usr/lib/rpm/redhat/perl.req

/usr/lib/rpm/redhat/rpmrc

Эти файлы, например, /usr/lib/rpm/redhat/macros, демонстрируют отличия настроек Red Hat Linux от других дистрибутивов. Вооружившись знаниями о специфических настройках, разработчик с меньшими затратами сможет создавать портируемые rpm-пакеты.

Далее - Работа с автоматической генерацией зависимостей
Назад - Решение проблем сборки пакетов
Содержание


18.2.2 Работа с автоматической генерацией зависимостей

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

Для отключения генерации зависимостей следует поместить специальную директиву в spec-файл:

Autoreq: 0

Если эта директива присутствует, необходимо ручное вмешательство в редактирование поля Requires: для определения всех зависимостей. Такое решение не всегда оптимально, возможно лучшим выбором будет переопределение макросов %{__find_requires} и %{__find_provides} для отфильтрования некоторых неактуальных зависимостей.

Эти два макроса разворачиваются в shell-скрипты, которые выполняют автоматические проверки зависимостей:

$ rpm --eval "%__find_provides"

/usr/lib/rpm/find-provides

rpm --eval "%__find_requires"

/usr/lib/rpm/find-requires

Вы можете переписать эти скрипты с тем, чтобы исключить зависимости, создающие проблемы для вашего пакета.

Далее - Работа с различающимися макросами
Назад - Создание пакетов, специфичных для конкретного дистрибутива
Содержание


18.2.3 Работа с различающимися макросами

Различные производители Линукс определяют отличающиеся макросы RPM. Это может означать не только другие значения макросов, но также и другие их имена. Из-за этого наилучшей практикой является определение собственного набора макросов при сборке пакетов.

В максимальной степени, насколько это возможно, рекомендуется зависеть от своих макросов, но не от макросов стороннего производителя. Можно задать свои макросы в стиле вендор-зависимых определений в spec-файле. Также можно воспользоваться примерами главы "Построение окружения и макросов" из этого раздела.

Далее - Создание пакетов с переопределяемыми путями
Назад - Работа с автоматической генерацией зависимостей
Содержание


18.2.4 Создание пакетов с переопределимыми путями

Следует ставить целью делать свои пакеты пакетами с переопределимыми путями, чтобы пользователи могли устанавливать их в любые каталоги. Это облегчит решение проблем с выбором каталогов для установки дополнительного ПО в других дистрибутивах.

Можно использовать макрос %{_bindir} в spec-файле. Он поможет созданию пакетов для различных дистрибутивов, сохраняя правильные пути.

Кроме того, можно задать макросы, определяющие пути к зависимостям. Далее с помощью опции --define утилиты rpmbuild установить условия, которые и определят значения макросов (а следовательно и пути).

Далее - Построение окружения сборки RPM
Назад - Работа с различающимися макросами
Содержание


18.2.5 Построение окружения сборки RPM

Если дело начато с идеи сборки пакета для нескольких версий Linux, можно установить такое окружение сборки, которое поможет четко разделить вендор-зависимые характеристики.

Ключевые темы в данном подходе:

* Определение вендора

* Использование макросов для задания процесса сборки

* Обработка различных зависимостей

18.2.5.1 Определение вендора
Для получения чистой среды сборки необходима возможность определения вендора, и, в зависимости от этого, нужных установок при сборке. Для облегчения решения этой задачи большинство вендоров помещают в определенное место файловой системы файл или устанавливают специальный пакет, который содержит имя производителя. Это имя может быть получено в процессе сборки.

Соглашение для файлов следующее:

/etc/vendor-release

Например:

$ more /etc/redhat-release

Red Hat Linux release 8.0 (Psyche)

Для пакетов соглашение касается имен пакетов:

$ rpm -q redhat-release

redhat-release-8.0-8

Также можно использовать простое определение макроса для имени вендора и затем опцию --define для rpmbuild. Например:

# rpmbuild ba --define 'linuxVendor suse'

С такой опцией используется макрос %linuxVendor.

Альтернативный подход - автоматическое определение вендора скриптами сборки. Ручное определение работает, однако требует введения информации от пересборщика пакета.

18.2.5.2 Построение окружения сборки и макросов
Будучи единожды установленным, значение макроса "вендор" позволяет задать другие макросы, учитывающие различия дистрибутивов, которые влияют на ваши приложения.

Для учета платформы используют главным образом условные определения, заключенные между %if и %endif. Кроме того, часто бывает полезным использование опций --with, --without и --target утилиты rpmbuild, позволяющие контролировать особенности сборки путем передачи условий в скрипты и макросы, определенные в spec-файле.

Макрос %if позволяет задать условия. Например:

%if %{old_5x} && %{old_6x}

%{error: You cannot build for .5x and .6x at the same time}

%quit

%endif

%if %{old_5x}

%define b5x 1

%undefine b6x

%endif

%if %{old_6x}

%define b6x 1

%undefine b5x

%endif

Также %if можно использовать для настройки таких полей, как
Requires: (показано в нижеследующем примере):

%if %{build6x}

Requires: util-linux, pam >= 0.66-5

%else

Requires: util-linux, pam >= 0.75-37, /etc/pam.d/system-auth

%endif

Опция командной строки --with задает значение специального макроса _with_. Например, следующая команда вносит установки в макросы spec-файла:

Также %if можно использовать для настройки таких полей, как
Requires: (показано в нижеследующем примере):

$ rpmbuild bc --with ssh filename.spec

В этом примере значение макроса _with_ssh будет установлено в значение --with-ssh. Этот формат задан специально для конфигурирования в стиле GNU (формат опции скрипта configure). Такой подход широко используется для условной, платформеннозависимой сборки.

Подобно опции --with, опция командной строки --without определяет значение специального макроса with _without_. Он определяет области кода, которые не будут использованы.

Часто комбинируют --with и --without для повышения гибкости этого шаблона. Кроме того, ветвление можно образовать с помощью проверки значения. Например:

./configure %{?_with_ssh}

Если макрос _with_ssh определен, команда будет такой:

./configure --with-ssh

Если макрос не определен, тогда такой:

./configure

Опция командной строки --target в свою очередь определяет макросы %_target, %_target_arch и %_target_os. Например:

$ rpmbuild -bc --target ppc-ibm-aix /usr/src/redhat/SPECS/jikes.spec

18.2.5.3 Пакеты совместимости (compatibility packages) и ассоциативные пакеты (glue packages)
Все дистрибутивы Linux имеют отличия. Только макросы не в состоянии покрыть все эти отличия для полной унификации сборки и получаемых пакетов. Тем не менее проблемы должны быть решены и многие из них решаются с помощью пакетов совместимости и ассоциативных пакетов.

Пакет совместимости предоставляет старый, унаследованный API для новой системы, которая больше не поддерживает старый API. В соответствии с соглашением пакеты совместимости для основного пакета именуются compat-имя_пакета.

Например:

$ rpm -q --qf "%{description}" compat-libstdc++

The compat-libstdc++ package contains compatibility Standard C++

Использование compat- пакетов позволяет создавать программы, использующие подход наименьшего общего знаменателя и программировать для старых, но наиболее общих API. Если некоторые дистрибутивы исключают пакеты со старыми API, compat- пакеты могут предоставить эти API.

Подобно compat- пакетам, ассоциативные или glue- пакеты предоставляют зависимости, которые присутствуют в одних дистрибутивах и отсутствуют в других. Они помогают "приклеить" ваш пакет к конкретному дистрибутиву, в котором недостает нужных зависимостей.

Основная цель пакетов совместимости и ассоциативных пакетов - в как можно большей степени оставить исходный пакет приложения в неприкосновенности, чтобы он был как можно ближе к версии вендора, выпустившего пакет. compat- и glue- подходы позволяют обеспечить работоспособность исходного приложения в других системах.

Таким образом, приложения, разработанные для Linux демонстрируют высокую степень адаптивности к разным дистрибутивам, кроме того, огромный пул ПО работоспособен (и имеются соответствующие бинарные пакеты) на различных процессорных архитектурах, таких как SPARC, MIPS, ARM.

Далее - Работа с не-rpmbased дистрибутивами
Назад - Создание пакетов с переопределимыми путями
Содержание


18.3. Работа с не-rpmbased дистрибутивами и утилита alien

Наиболее значимый дистрибутив, не являющийся rpmbased - это Debian GNU/Linux и его многочисленные клоны. С точки зрения разнообразия подходов важен также Slackware Linux. Для конвертации пакетов из одного формата в другой используется утилита alien.

18.3.1 Обработка не rpm пакетов с помощью alien
Alien - это пакет, поддерживающий конвертацию форматов между rpm и так называемыми alien-пакетами, такими как deb (Debian GNU/Linux), slp (Stampede Linux), и tgz (Slackware Linux).

Alien можно использовать в rpmbased дистрибутиве для конвертации rpm в другие форматы, или для конвертации, например, deb-пакетов в rpm.

Далее - Стандартизация RPM
Назад - Построение окружения сборки RPM
Содержание


3.2.1 Режим установки

Для установки пакета достаточно выполнить команду в режиме установки, например:

rpm -i jikes-1.16-1.i386.rpm

Однако, администраторы в основном предпочитают режим -U (--upgrade), так как это позволяет не задумываться о том, установлен ли такой пакет. Если пакет установлен, будет произведено его обновление, если не установлен - установка:

rpm -Uhv jikes-1.16-1.i386.rpm

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

warning: pyxf86config-0.3.1-2.i386.rpm: Header V3 DSA

signature: NOKEY, key ID 897da07a

В данном случае предупреждение говорит нам о том, что пакет подписан, но ключ не найден.

3.2.1.1 Установлен ли пакет?
Для быстрой проверки факта установки конкретного пакета используется простая форма запроса:

rpm -q jikes

Утилита вернет информацию о том, что пакет установлен. Короткое имя пакета указывает на соответствующий rpm-файл. Для получения информации rpm обращается к БД RPM. Если же пакет не установлен, вернется примерно следующее:

package jikes is not installed

3.2.1.2 Получение расширенной информации в процессе выполнения операций

Для получения большого количества диагностических сообщений можно использовать ключи -vv:

# rpm -Uhvv jikes-1.16-1.i386.rpm

D: ============== jikes-1.16-1.i386.rpm

D: Expected size: 702988 = lead(96)+sigs(100)+pad(4)+data(702788)

D: Actual size: 702988

D: jikes-1.16-1.i386.rpm: MD5 digest: OK
(2dba32192eca23eb480d1d02a9b6c022)

D: added binary package [0]

D: found 0 source and 1 binary packages

D: opening db environment /var/lib/rpm/Packages joinenv

D: opening db index /var/lib/rpm/Packages rdonly mode=0x0

D: locked db index /var/lib/rpm/Packages

D: ========== +++ jikes-1.16-1

D: opening db index /var/lib/rpm/Depends create mode=0x0

D: Requires: rpmlib(PayloadFilesHavePrefix) <= 4.0-1 YES (rpmlib provides)

D: opening db index /var/lib/rpm/Providename rdonly mode=0x0

D: opening db index /var/lib/rpm/Pubkeys rdonly mode=0x0

D: read h# 9 Header V3 DSA signature: NOKEY, key ID 897da07a

D: Requires: ld-linux.so.2 YES (db provides)

D: read h# 9 Header V3 DSA signature: NOKEY, key ID 897da07a

D: Requires: libc.so.6 YES (db provides)

D: read h# 9 Header V3 DSA signature: NOKEY, key ID 897da07a

D: Requires: libm.so.6 YES (db provides)

D: read h# 633 Header V3 DSA signature: NOKEY, key ID 897da07a

D: Requires: libstdc++-libc6.2-2.so.3 YES (db provides)

D: read h# 9 Header V3 DSA signature: NOKEY, key ID 897da07a

D: Requires: libc.so.6(GLIBC_2.0) YES (db provides)

D: read h# 9 Header V3 DSA signature: NOKEY, key ID 897da07a

D: Requires: libc.so.6(GLIBC_2.1) YES (db provides)

D: read h# 9 Header V3 DSA signature: NOKEY, key ID 897da07a

D: Requires: libc.so.6(GLIBC_2.1.3) YES (db provides)

D: Requires: rpmlib(CompressedFileNames) <= 3.0.4-1 YES (rpmlib provides)

D: closed db index /var/lib/rpm/Pubkeys

D: closed db index /var/lib/rpm/Depends

D: closed db index /var/lib/rpm/Providename

D: closed db index /var/lib/rpm/Packages

D: closed db environment /var/lib/rpm/Packages

D: ========== recording tsort relations

D: ========== tsorting packages (order, #predecessors, #succesors, tree, depth)D: 0 0 0 0 0 +jikes-1.16-1

D: installing binary packages

D: opening db environment /var/lib/rpm/Packages joinenv

D: opening db index /var/lib/rpm/Packages create mode=0x42

D: getting list of mounted filesystems

D: sanity checking 1 elments

D: opening db index /var/lib/rpm/Name create mode=0x42

D: read h# 707 Header sanity check: OK

D: computing 3 file fingerprints

Preparing... D: computing file dispositions

D: opening db index /var/lib/rpm/Basenames create mode=0x42

########################################### [100%]

package jikes-1.16-1 is already installed

D: closed db index /var/lib/rpm/Basenames

D: closed db index /var/lib/rpm/Name

D: closed db index /var/lib/rpm/Packages

D: closed db environment /var/lib/rpm/Packages

Одна из редко используемых опций для получения обратной связи - опция --percent. Этот ключ заставляет rpm выводить на отдельных строках прогресс выполнения операции в процентах:

# rpm -U --percent jikes-1.16-1.i386.rpm

%% 0.000000

%% 2.661902

%% 5.318614

%% 10.632039

%% 15.945465

%% 18.602177

%% 23.915603

%% 29.229028

%% 34.542453

%% 39.855879

%% 45.169304

%% 50.482729

%% 53.139442

%% 55.796154

%% 61.109580

%% 66.423005

%% 71.736430

%% 74.393143

%% 79.706568

%% 82.363281

%% 87.676706

%% 90.333419

%% 95.646844

%% 98.303557

%% 99.422736

%% 99.910411

%% 99.994892

%% 100.000000

Удобно забрать такой поток со стандартного вывода и использовать в другой программе, например для формирования прогресс-бара операции в графическом окне. Естественно, следует более или менее скептично относиться к десятичной разрядности данной формы вывода.

3.2.1.3 Процесс инсталляции в деталях
Для установки ПО из rpm-пакетов можно воспользоваться формой команды:

# rpm -U

или

# rpm -i

Производя установку пакета, rpm проходит следующие шаги:

- проверка пакета и файлов, входящих в него;
- выполнение пре-инсталляционных скриптов;
- распаковка файлов и копирование их в нужные локации;
- выполнение пост-инсталляционных скриптов;
- обновление базы данных RPM.

При проверке пакета rpm анализирует зависимости. Если функционирование программ и библиотек пакета зависит от других программ или библиотек, а они в системе отсутствуют, утилита завершит работу с выводом ошибки.
В дополнение к проверке зависимостей анализируются также конфликтные ситуации. Конфликт - это ситуация, когда требуется установить определенные файлы из пакета, а в системе имеются одноименные файлы более новых версий. Это может означать, что администратор желает установить пакет более старой версии, чем уже установленный.

После этих проверок (если они успешны) rpm выполняет пре-инсталляционные скрипты. Когда подготовительные работы закончены, начинается копирование файлов в систему.

Некоторые программные продукты требуют настройки после установки. Эта настройка часто производится с помощью пост-инсталляционных скриптов.

После завершения работы скриптов rpm обновляет БД RPM. Эта стадия важна для последующего отслеживания эволюций пакета.

3.2.1.4 Не хотите ли тест-драйв?

Опция --test позволяет администратору запустить rpm в тестовом режиме. При этом производится вся необходимая диагностика, но реальных операций по копированию (или удалению) файлов не происходит.

# rpm -U --test jikes-1.16-1.i386.rpm

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

package jikes-1.16-1 is already installed

Если целостность пакета нарушена, установка прервется с сообщением об ошибке:

chap4.txt: not an rpm package (or package manifest):

Это сообщение было получено при попытке применить rpm к файлу, который не является rpm-пакетом.
Опция --test также позволяет получить список зависимостей, которые необходимо удовлетворить.

Зависимости пакетов могут быстро превратиться в кошмар администратора. Нужно поставить пакет, который зависит от другого пакета, который зависит от пяти пакетов... и так далее.
В простых случаях опция --test сильно облегчит задачу. Например, желательно установить пакет eruby-devel. Проверим зависимости:

# rpm -U --test eruby-devel-0.9.8-2.i386.rpm

Диагноз:

error: Failed dependencies:

eruby-libs = 0.9.8 is needed by eruby-devel-0.9.8-2

Данное сообщение содержит не только имя, но и версию пакета. Проверим его зависимости?

# rpm -U --test eruby-libs-0.9.8-2.i386.rpm

error: Failed dependencies:

ruby-libs >= 1.6.4 is needed by eruby-libs-0.9.8-2

libruby.so.1.6 is needed by eruby-libs-0.9.8-2

Этот короткий пример демонстрирует тот факт, что иногда имеет смысл протестировать возможность установки пакета.

3.2.1.5 Установка или обновление более одного пакета за раз

Все примеры выше по тексту использовались для иллюстрации работы rpm в отношении одного пакета. Однако утилита позволяет установить и список пакетов. Основной синтаксис следующий:

# rpm -U package1.rpm package2.rpm .. package100.rpm

Опция --noorder требует не нарушать порядок установки пакетов из списка. По умолчанию rpm будет стремиться выстроить собственную последовательность для наилучшего удовлетворения взаимных зависимостей пакетов из списка. Обычно использование этой опции не является необходимостью.

3.2.1.6 Установка в директорию, отличную от заданной в пакете

Опции --prefix и --relocate служат для задания расположения файлов пакета в директории, не предусмотренной структурой директорий пакета. Однако, не все пакеты допускают подобную вольность. Синтаксис команды следующий:

# rpm -U --prefix /new/directory package.rpm

или

# rpm -i --relocate /old/directory=/new/directory package.rpm

Опция --root позволяет установить пакет в каталог, который сам пакет будет считать каталогом /. Такой прием обычно используется для создания тестовых системных окружений.

Опция --dpath говорит rpm, что БД RPM находится в обычном месте расположения, /var/lib/rpm. Это необходимо, если используется виртуальная root-директория, а информация о пакетах используется из основной системы. Совместное использование опций --root и --dpath может породить проблемы зависимостей. Например, виртуальная -root-директория должна иметь все стандартные библиотеки С и С++, установленные в нее.

# rpm -U --root /tmp --dbpath /var/lib/rpm jikes-1.16-1.i386.rpm

error: Failed dependencies:

ld-linux.so.2 is needed by jikes-1.16-1

libc.so.6 is needed by jikes-1.16-1

libm.so.6 is needed by jikes-1.16-1

libstdc++-libc6.2-2.so.3 is needed by jikes-1.16-1

libc.so.6(GLIBC_2.0) is needed by jikes-1.16-1

libc.so.6(GLIBC_2.1) is needed by jikes-1.16-1

libc.so.6(GLIBC_2.1.3) is needed by jikes-1.16-1

Для указания rpm возможности переопределения путей для всех файлов пакета используется опция --badreloc. В обычном случае переопределяются только пути для файлов, отмеченных как "relocatable".

3.2.1.7 Форсированная установка

Ряд опций rpm используется для решения проблем установки, в частности, для обхода механизмов самой утилиты.

Опция --replacepkgs позволяет заменить (переустановить) пакет, который, возможно, уже установлен.

Опция --replacefiles предлагает rpm заменить файлы с совпадающими именами, но принадлежащие другому пакету.

С помощью опции --justdb можно обновить БД RPM, как будто бы новые файлы были установлены, но сами файлы не устанавливать.

Опция --nosuggest позволяет блокировать некоторые предположения rpm, сделанные в отношении состояния пакета, которые в другом случае могли бы привести к ошибкам неудовлетворенных зависимостей.

Опция --excludepath позволяет исключить из дерева файлов и каталогов пакета некоторые пути. Это позволит не устанавливать файлы, путь к которым совпадает с образцом.Например:

# rpm -U --excludepath /usr/lib eruby-devel-0.9.8-2.i386.rpm

Эта команда установит все файлы пакета, кроме тех, в путевом имени которых есть /usr/lib.

Опция --allfiles заставит обновить все файлы пакета, независимо от того, имеются подобные файлы на жестком диске системы, или нет.

Опция --oldpackage поможет установить старую версию пакета поверх уже установленной более новой. Такая потребность может возникнуть, если новая версия имеет ошибки, или обновление версии какой-либо библиотеки приведет к неработоспособности зависящих от нее программ.

Опция --force является результатом совместного действия опций --replacepkgs, --replacefiles и --oldpackage.

Опция --nodeps заставляет rpm пропустить тест зависимостей и установить пакет в любом случае.

Не следует применять все эти опции кроме случаев, когда вы точно знаете, что делаете.

Одной из полезных возможностей является опция --aid. Если пакеты доступны (например, установка производится из директории, содержащей коллекцию пакетов), данный флаг заставит rpm добавить в список установки все зависимости всех пакетов, которые требуется установить. Если зависимости выдаются в виде имен файлов, а не пакетов, и в этом случае --aid сработает.

3.2.1.8 Пропуск скриптов

Одной из стадий процесса установки является выполнение пре- или пост- инсталляционных скриптов. Эти скрипты выполняются в определенное время установки при каждом запуске команды на установку для данного пакета, кроме случаев, когда администратор это явно запретил.

Опция --noscripts отменяет запуск всех скриптов, заданных файлом спецификации.
При необходимости степень контроля за выполнением скриптов можно увеличить. Опции --nopost и --nopre соответственно запрещают только постинсталляционные действия или только преинсталляционные операции.
Также --nopreun отменяет действия перед удалением пакета, --nopostun - действия после удаления.

В общем случае администратору нет никакой необходимости отменять работу скриптов.

Помимо скриптов rpm использует еще один интересный механизм, так называемые триггеры (обсуждаются в разделе 11). В процессе установки вы можете распорядиться отменить все триггеры, или определенные триггеры.

Опции:
--notriggers - отменяет все триггеры;
--notriggerin - отменяет все триггеры процесса инсталляции;
--notriggerun - отменяет все триггеры процесса удаления;
--notriggerpostun - отменяет все триггеры, работающие после удаления.

3.2.1.9 Счастье игнорирования

Rpm поддерживает некоторые опции, позволяющие игнорировать некоторые обстоятельства, которые в другом случае были бы учтены.

Например, весьма опасная опция --ignorearch позволяет установить в систему пакет чуждой архитектуры. Как правило, ничего хорошего это не сулит. Пакет для PowerPC, установленный на i386 систему не будет работать, в худшем случае будет опасен для системы.

Опция --ignoreos задает игнорирование операционной системы. В большинстве ситуаций это также не плодотворная идея. Но вдруг вам требуется запустить пакет, собранный для другого Линукса?

--ignoresize заставит rpm отказаться от проверки наличия достаточного свободного места на жестком диске.

--nodigest поможет пропустить проверку целостности пакета, а --nosignature - проверку подписи.

3.2.1.10 Документация? Какая документация?

Опция --excludedocs позволяет пропустить установку всех файлов пакета, которые помечены как документация. Может быть для какой-нибудь специальной установки вам надо сэкономить место на жестком диске? В противном случае, зачем использовать эту опцию?

Имеется также странноватая опция --includedocs, при ее наличии документация устанавливается. Поскольку это поведение по умолчанию, необходимость наличия данной опции сомнительна. Может, авторами двигали соображения фундаментальной симметрии Вселенной?

Далее - Режим обновления (upgrade)
Назад - Установка и обновление пакетов
Содержание


18.4 Стандартизация RPM

18.4.1 Стандарт иерархии файловой системы
FHS, Filesystem Hierarchy Standard определяет назначение всех каталогов верхних уровней, таких, как /var или /usr/bin для любой Linux-системы. Этот стандарт совместно с LSB, Linux Standard Base, продвигает различные дистрибутивы Linux к возможно большему сходству.

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

Информация по LSB: www.linuxbase.org

Информация по FHS: www.pathname.com/fhs/

18.4.2 Адаптация RPM
Система RPM была адаптирована для большого количества дистрибутивов. Кроме того, усилия по стандартизации пакетов и иерархии файловых систем делают различные дистрибутивы все менее отличающимися друг от друга. В будущем это облегчит создание кроссплатформенных пакетов.

Далее - Раздел 19. Использование RPM в других операционных системах
Назад - Работа с не-rpmbased дистрибутивами
Содержание


19.1 Запуск RPM на других операционных системах

Система RPM, являющаяся основой главным образом утилит rpm и rpmbuild, портирована на некоторые сторонние системы. Эти системы имеют свои собственные механизмы пакетного менеджмента. Вы можете предпочесть путь, по которому действует и развивается RPM или, может быть, захотите стандартизировать пакетный менеджмент среди всех платформ, которыми вы управляете. Есть, однако, ряд проблем в этом направлении. Например, патчи и апдейты, использующиеся в сторонней системе, приходят в формате пакетов этой системы, не в rpm.

В таком случае вам придется всегда иметь ввиду то обстоятельство, что в данном системном окружении присутствует два механизма пакетного менеджмента - нативный и RPM. Это обстоятельство, однако, не останавливает значительное количество специалистов, портировавших RPM на свои системы.

Среди преимуществ подхода - тот факт, что механизмы пакетного менеджмента как раз являются одним из главных отличий разных Линуксов и Юниксов друг от друга. Используя один сквозной механизм управления ПО можно добиться значительной экономии времени за счет стандартизации и многократного использования отточенных навыков. Большим плюсом может стать процесс обновления различных систем в одном стиле.

Другой хороший повод для использования RPM заключается в гораздо более развитой функциональности RPM по сравнению со многими системами пакетного менеджмента. Следуя философии RPM, каждый пакет обновляется и верифицируется независимо. Каждый пакет имеет зависимости и предоставляет возможности другим пакетам. RPM позволяет автоматизировать установку и обновление, сравнивать версии и подписи. Все это ведет к развитию более безопасных и производительных систем.

Первый шаг к использованию RPM в не-Linux системе - получить RPM для этой системы.

Далее - Получение RPM для целевой системы
Назад - Стандартизация RPM
Содержание


19.1.1 Получение RPM для целевой системы

В бОльшей части случаев получение RPM для целевой системы - сравнительно несложный шаг, поскольку RPM портирован на значительное число платформ, как показано в таблице ниже.

Платформа

Замечания

AIX

AmigaOS

В составе GeekGadgets

BeOS

В составе GeekGadgets

FreeBSD

HP-UX

10.20+, 9.04

IRIX

Linux

Множество процессорных платформ, включая Alpha, Intel, Motorola 68000, SGI MIPS, PowerPC и SPARC

LynxOS

MachTen

MacOS X

Mint

NCS System V

NetBSD

OS/2

OSF/1

3.2+

SCO OpenServer

5.0.2+

Sinix

Solaris

Solaris для SPARC 2.4 и 8+ Solaris для Intel

SunOS 4.1.3

Windows

Из-под Cygwin

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

Не пытайтесь найти rpm-пакеты системы RPM для этих платформ, так как их нечем будет установить. Бинарные сборки для сторонних систем обычно поставляются в формате пакетных менеджеров этих систем, как правило в компрессированных тарболлах.

Если пакеты доступны для нужной системы, скачайте их и следуйте инструкциям по установке, которые могут отличаться на разных платформах. Например, RPM для Solaris требует библиотеки libiconv и пакетов Solaris SUNWzlib и SUNWbzip. Эти компоненты должны быть установлены до установки RPM.

Каждая операционная система будет иметь подобные рекомендации. Windows потребует более сложных действий, так как сильно отличается от Unix-подобных систем.

Далее - Запуск RPM под Windows
Назад - Запуск RPM на других операционных системах
Содержание


19.1.2 Запуск RPM под Windows

Версия RPM для Windows требует установки cygwin, пакет, происходящий от Cygnus - порта коллекции Unix-утилит для Windows. Загрузить cygwin можно с его сайта: www.cygwin.com .

После установки cygwin скачайте и установите RPM для Windows.

Если RPM благополучно установлен, можно переходить к настройке, в частности, к разворачиванию системного окружения RPM.

Далее - Разворачивание RPM на других операционных системах
Назад - Получение RPM для целевой системы
Содержание


19.2 Разворачивание RPM на других операционных системах

Если нет возможности найти порт для целевой системы, можно портировать RPM самостоятельно. Поскольку множество платформ поддерживает POSIX системные вызовы, эта задача в большом количестве случаев не является сверхсложной.

Пусть вас не пугает полный размер пакета RPM. Практически вся система RPM спроектирована и реализована таким образом, что подразумевается возможность запуска и исполнения ее на множестве платформ, например, доступ к файлам абстрагирован в специальных процедурах, легко поддающихся портированию. Скажем, RPM портирована на такие ОС, как AmigaOS и BeOS, а это не Unix-подобные системы.

Далее - Скачивание кода
Назад - Запуск RPM под Windows
Содержание


19.2.1 Скачивание кода

Для сборки и разворачивания RPM на другой операционной системе нужно скачать исходный код с основного сайта поддержки RPM:
ftp://ftp.rpm.org/pub/rpm/dist/ .

Не требуется скачивать src.rpm пакет, так как RPM пока не существует на вашей системе. Обычно исходный код доступен также в виде тарболла соответствующей версии.

Далее - Извлечение ПО
Назад - Разворачивание RPM на других операционных системах
Содержание


19.2.2 Извлечение ПО

Если целевая система не имеет утилит для работы с .tar.gz файлами, следует найти путь для распаковки архива. Например, приложения типа WinZip поддерживают распаковку .tar.gz. Вероятно, ваша система имеет подобные приложения. Другой путь - портировать программы gzip и tar на целевую платформу.

Альтернативный подход - распаковать архив в Linux-системе, затем передать файлы в систему, на которой планируется сборка.

С момента доступности файлов исходного кода можно начинать портирование. Первый шаг прост - читаем документацию.

Далее - Информация в файле INSTALL
Назад - Скачивание кода
Содержание


19.2.3 Информация в файле INSTALL

В корневом каталоге с исходным кодом имеется два важных файла: README и INSTALL. Многие будут удивлены количеством случаев, в которых людям приходилось говорить это. Прочитайте их оба!

INSTALL содержит информацию главным образом о деталях установки на новую систему. Здесь описываются потребные библиотеки, подробности сборки RPM и подготовительные мероприятия для установки собранного ПО.

Однако, наиболее трудными аспектами портирования системы RPM были и остаются: работа с БД, сжатие и вызовы для работы с цифровыми подписями и подобными объектами шифрования.

Далее - Библиотеки, необходимые RPM
Назад - Извлечение ПО
Содержание


19.2.4 Библиотеки, необходимые RPM

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

Библиотека

Назначение

Berkeley DB

Движок БД RPM

bzip2

Сжатие

gettext

Интернационализация сообщений

gpg

Для работы с цифровыми подписями

gzip

Сжатие

popt

Разбор опций командной строки

zlib

Сжатие

Файл INSTALL может содержать информацию об источниках, откуда следует получить эти компоненты. Возможно выяснится, что каждая библиотека имеет свой собственный набор зависимостей. Если нет готовых для вашей системы компонентов, придется портировать все дерево: сами библиотеки и все их зависимости.

Далее - Инструменты для сборки RPM
Назад - Информация в файле INSTALL
Содержание


19.2.5 Инструменты для сборки RPM

Кроме необходимых библиотек, сборка RPM потребует и наличия ряда GNU утилит для сборки. Список приводится в таблице ниже:

Инструмент

Использование

Autoconf

Утилиты для построения конфигурирующих скриптов

Automake

Используется с autoconf

GNU make

Инструмент для контролирования процесса сборки

Libtool

Используется скриптом autogen.sh

Кроме того, наилучшим образом RPM собирается посредством C компилятора GNU - GCC.

Исходный код утилит GNU доступен на официальном сайте: www.gnu.org .

Далее - Сборка RPM
Назад - Библиотеки, необходимые RPM
Содержание


3.2.2 Режим обновления (upgrade)

Опция -U работает и в случае установки, и в случае обновления пакета. Когда проявляют себя потребности шагнуть в сторону от просто инстралляции, утилита rpm начинает проявлять свою недюжинную силу. Команда rpm -U весьма мощна и производит при установке/обновлении ряд комплексных нетривиальных операций, о которых администратору можно не задумываться, так как он использует единственный ключ.

Например, следующая последовательность команд показывает процесс обновления приложения синхронизации данных с Palm PDA:

# rpm -q jpilot

jpilot-0.97-1

# rpm -U jpilot-0.99.2-8.i386.rpm

# rpm -q jpilot

jpilot-0.99.2-8

Обратите внимание, старая версия пакета больше не существует в системе, так как команда rpm -U удалила старый пакет.

3.2.2.1 Опции обновления

ля обновления пакетов в командной строке можно указать более, чем один пакет. Кроме того, опции установки можно указывать и при обновлении.
Здесь есть особенности, например, опция --noscripts сработает только в отношении нового пакета, но, если не было задано иное, при установке прежнего пакета скрипты отработали.

При обновлении можно задать опцию --repackage. Она определит следующие события: утилита выявит все файлы, которые будут удалены при обновлении и создаст из них rpm-пакет. Кроме того, производится архивирование старого пакета, что позволяет откатить состояние системы назад, если новый пакет неработоспособен.

Синтаксис с использованием --repackage:

# rpm -U --repackage jpilot-0.99.2-8.i386.rpm

В соответствии с соглашением об именовании для большинства пакетов справедливо следующее: имена пакетов (старых и обновленных) совпадают с точностью до версии и номера сборки. Но некоторые производители нарушают данное соглашение. Например, Java programming developer's kit (JDK) для версии 1.3 использовал имя jdk-1.3.1_01.i386.rpm, для версии 1.4 - имя j2sdk-1_4_0_01-fcs-linux-i386.rpm. Администратору приходится держать в голове подобные различия.

3.2.2.2 Умные обновления

В процессе обновления пакетов rpm выступает во всем своем блеске. Утилита не только обновляет пакет одной командой, но и использует некоторые встроенные возможности для выполнения расширенных операций.

При обновлении rpm проходит все файлы пакета, формируя для каждого файла дайджест MD5. Эти контрольные значения хранятся для трех версий файла: версии файла из старого пакета, версии файла из нового пакета и версии файла, который находится на диске. rpm хранит эти три версии для работы с такими специальными случаями, как файлы конфигурации. Такой подход позволяет сохранить конфигурации настроенных сервисов и при их обновлении. Раздел 10 описывает, каким образом можно пометить файлы, как файлы конфигурации.

Если файл на диске идентичен файлу в новом пакете, rpm просто перезаписывает его поверх файла на диске. Если это файлы конфигурации и файл на диске не отличается от файла в новом пакете, rpm оставляет старый файл. Но если файл на диске отличается от оригинальной версии файла, и файл на диске отличается от своей новой версии, rpm перезапишет файл новой версии поверх, что будет гарантировать работоспособность конфигурации с новой версией пакета. Модифицированные файлы конфигурации будут сохранены в их локациях в виде архивных копий с расширением .rpmsave. Если же в пакете использована опция %config(noreplace) для конкретного файла, новый файл записывается рядом с расширением .rpmnew.

Далее - Обновление в режиме freshen
Назад - Режим установки
Содержание


19.2.6 Сборка RPM

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

RPM включает в себя несколько подсистем, таких как popt для разбора опций командных строк. Каждая из этих подсистем нуждается в конфигурировании. БОльшая часть этого конфигурирования может быть выполнена скриптом конфигурации, который в свою очередь генерируется скриптом autogen.sh и утилитами autoconf/automake.

Скрипт autogen.sh - это shell-скрипт, который делает ряд проверок на предмет соответствия конкретным версиям нужных библиотек и инструментов. После проверки зависимостей стартовый скрипт вызывает сепаратные скрипты autogen.sh в каталогах beecrypt, libelf, popt и zlib. После выполнения всех процедур autogen.sh вызывает скрипт configure.

Чтобы отключить вызов configure используется опция командной строки --noconfigure.

Если используются версии инструментов, отличные от ожидаемых, потребуется редактирование скрипта autogen.sh. Кроме того, целевая система может содержать нужные библиотеки, расположенные по другим путям, поэтому адаптация скрипта под свою систему в целом является хорошей практикой.

Одним значимым ожиданием, на основе которого построен autogen.sh, есть ожидание того, что целевая платформа - это Unix-подобная система. Если это не так, следует понять, каким образом построить сценарии Makefile вручную. Ручная работа с Makefile может потребовать множества неуспешных попыток сборки. Устраняйте ошибки одну за другой и запускайте процесс вновь вплоть до успеха.

Если autogen.sh-подход срабатывает, для создания системно-специфичных Makefile-ов, компилирования RPM и установки потребуется стандартный набор команд:

$ ./configure

$ make

$ make install

Скрипт configure забирает на вход файлы Makefile.in и, используя их как шаблоны-заготовки, создает файлы Makefile, адаптированные для целевой системы. (Система automake стартует с файлов Makefile.am, создает файлы Makefile.in и в результате получает Makefile, адаптированные для целевой системы). Если все эти пути ведут к неустранимым ошибкам, можно скопировать Makefile.in в Makefile и затем редактировать Makefile до полной работоспособности на своей системе.

Если же никакой из подходов не срабатывает, можно попробовать вручную скопировать исполнимые файлы и скрипты из бинарных rpm-пакетов для соответствующей процессорной архитектуры по нужным путям.

Далее - Решение проблем
Назад - Инструменты сборки RPM
Содержание


19.2.7 Решение проблем

В случаях неудачных попыток компилирования или установки RPM ключевым подходом является точная локализация проблемы. Если источник ошибки обнаружен, ее можно устранить и двигаться дальше.

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

$ ./configure any_options_set_here

$ make

$ make install

Возможно при этом понадобится изменить некоторые секции Makefile вручную (в каждом подкаталоге дерева с исходным кодом имеется свой Makefile).

Если изменение опций сборки или редактирование Makefile не дают нужного эффекта, есть возможность отредактировать Makefile.am для добавления необходимых установок. Например, может потребоваться задать дополнительные пути к библиотекам или некоторые опции компилятора.

При обнаружении проблемы помните, что вы не одиноки на пути портирования RPM. Проверьте списки рассылок по тематике портирования RPM и коллекции часто встречающихся вопросов.

Архив списков рассылки и подписка находятся здесь: www.rpm.org/mailing_list/ .

Далее - Установка и настройка RPM
Назад - Сборка RPM
Содержание


19.3.1 Разворачивание БД RPM

Итак, RPM теперь портирован на целевую платформу и установлен. Первым шагом в работе с RPM является инициализация БД RPM, включающая два шага:

* Инициализация пустой базы

* Наполнение базы информацией о пакетах, в особенности в контексте зависимостей

19.3.1.1 Инициализация пустой БД RPM
Пустая база создается с помощью опции --initdb:

# mkdir /var/lib/rpm

# rpm --initdb

Первая команда создает каталог для хранения БД (путь по умолчанию). Если будет использоваться иной путь, необходимо передать его в параметрах, как показано ниже:

# rpm --dbpath /location/of/your/rpm/database --initdb

Кроме того, можно использовать опцию v для повышения информативности вывода, что сильно помогает при возникновении ошибок.

Для указания альтернативной корневой директории используется опция --root. Использование корня файловой системы, отличного от общесистемного, оправдано, когда производится экспериментальная работа с пакетами, создание образов файловых систем ОС внутри действующей системы и в других подобных случаях.

Для указания набора rc файлов, отличного от умолчального, используется опция --rcfile, пользовательского набора макросов - опция --macros.

Наполнение пустой БД информацией о пакетах в большинстве случаев сводится к установке новых пакетов и происходит автоматически средствами RPM.

19.3.1.2 Обработка зависимостей пакетов, установленных без участия системы RPM
Всякий раз, когда устанавливается новый пакет, информация о нем попадает в БД RPM. Это хорошо работает, если все зависимости вновь устанавливаемого пакета уже установлены.

В rpmbased операционных системах, таких как Red Hat Linux, все пакеты за исключением некоторого количества стартовых механизмов, устанавливаются через RPM. Это означает, что практически вся система отражена в БД, RPM "знает" обо всех установленных пакетах и может правильно обрабатывать зависимости. Таким образом, ошибки при обработке зависимостей означают, что нужные пакеты не установлены.

В операционных системах, которые не базируются на RPM, таких как Solaris или IRIX, большинство пакетов установлены помимо системы RPM, поскольку эти операционные системы имеют собственные службы пакетного менеджмента. Поэтому, если rpm-пакеты, которые имеется в виду установить, зависят от ПО, поставляющегося как-то иначе, чем в rpm-пакетах, такие случаи можно считать удачными. Например, утилита rpm для Windows зависит от cygwin, а cygwin имеет собственный инсталлятор setup.exe и не зависит от наличия или отсутствия RPM.

Следовательно, для правильной обработки зависимостей необходимо наполнить БД RPM такой информацией, которая отражает текущее состояние системы. Основной путь здесь - установка виртуального пакета.

19.3.1.3 Установка виртуального пакета
Проблему ПО, которое существовало до разворачивания RPM можно решить построением виртуального пакета, который содержит список уже установленных библиотек и приложений. После установки такого пакета, rpm будет иметь информацию о предустановленных компонентах, хотя они не были установлены из rpm-пакетов. Это необходимо проделать в отношении всех предоставляемых системой возможностей и системных библиотек, попавших в ОС помимо контроля RPM.

Для создания виртуального пакета используется скрипт vpkg-provides.sh из каталога скриптов. Этот скрипт обходит каталоги в поисках разделяемых библиотек и интерпретаторов. Затем формируется список, помещаемый в spec-файл. Список содержит все найденные ресурсы (но это список файлов а не пакетов). Для наполнения БД RPM информацией о предоставляемых системой возможностях, на основе этого spec-файла собирается пакет, который устанавливается уже посредством утилиты rpm.

Виртуальный пакет не устанавливает в систему никаких файлов, поскольку они уже установлены, в то же время владельцем файлов с точки зрения БД теперь является этот пакет. Обработка зависимостей для вновь устанавливаемых пакетов теперь будет производиться правильно.

Скрипт vpkg-provides.sh принимает три основных опции: --spec_header, --ignore_dirs и --no_verify.

Опция --spec_header передает имя spec-файла, который будет использоваться в качестве шаблона для вновь создаваемого spec-файла. Например:

# sh vpkg-provides.sh --spec_header /path/to/spec/file

Шаблон нужен для генерации полного spec-файла. Шаблон должен содержать как минимум поля Summary, Name, Version и Release.

Опция --ignore_dirs говорит скрипту, какие каталоги необходимо пропустить. Для формирования списка пропускаемых каталогов передается шаблоны поиска egrep. Шаблоны разделяются символом вертикальной черты. Если egrep в системе недоступен, следует отредактировать скрипт vpkg-provides.sh, внеся в нужном месте список каталогов для игнорирования вручную.

Опция --no_verify позволяет пропустить шаг создания скрипта для проверки контрольных сумм всех найденных файлов.

Кроме главных опций имеются дополнительные:

Опция --shlib_dirs указывает на каталоги с разделяемыми библиотеками, список составляется в одну строку в двойных кавычках с двоеточием в качестве разделителя:

# sh vpkg-provides.sh --spec_header /path/to/spec/file \

--shlib_dirs "/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb:/usr/bsd"

Опция --interp_dirs говорит, в каких каталогах искать интерпретаторы, например, sh, bash, perl, awk. В свою очередь опция --interps используется для перечисления этих интерпретаторов. Обе эти опции ожидают для ввода строку с двоеточиями между параметрами.

Опция --find_provides указывает на расположение скрипта find-provides (по умолчанию /usr/lib/rpm/find-provides).

Скрипт vpkg-provides.sh находит каталоги с разделяемыми библиотеками и интерпретаторами в различных операционных системах. Как правило, бывает необходимо отредактировать соответствующую секцию в скрипте.

Если вы работаете с не-Unix системой, или при запуске скрипта возникают ошибки, можно редактировать скрипт в целях удаления проблемных команд. Также на основе vpkg-provides.sh можно создать новый сценарий на языке, поддерживаемом целевой системой. Некоторые системы могут не поддерживать не только системные команды, которые вызываются из скрипта, но и сам язык shell. vpkg-provides.sh проделывает значительное количество действий, направленных только на то, чтобы скрипт был максимально универсальным. Эта работа может быть сокращена путем прямого указания каталогов, команд и тому подобных параметров. Кроме того, можно вообще не использовать vpkg-provides.sh, а собрать виртуальный пакет вручную.

После завершения всех действий скрипт выдает spec-файл, в котором содержится и переданный ему шаблон, и список строк, каждая из которых содержит зависимость для будущих пакетов. Кроме того выводится несколько пустых определений для заполнения секций prep, build, install и clean.

Пример выполнения vpkg-provides.sh:

$ sh ./vpkg-provides.sh --spec_header my_header.spec --find_provides ./find-provides --no_verify

Provides: /bin/sh

Provides: /bin/csh

Provides: /bin/ksh

Provides: /bin/perl

Provides: /bin/awk

Provides: /bin/nawk

Provides: /bin/oawk

Provides: /usr/bin/sh

Provides: /usr/bin/csh

Provides: /usr/bin/ksh

Provides: /usr/bin/perl

Provides: /usr/bin/awk

Provides: /usr/bin/nawk

Provides: /usr/bin/oawk

Provides: /sbin/sh

Provides: /usr/dt/bin/dtksh

Provides: /usr/xpg4/bin/sh

Provides: /usr/xpg4/bin/awk

%prep

# nothing to do

%build

# nothing to do

%install

# nothing to do

%clean

# nothing to do

%files

# no files in a virtual package

Также добавляется описание пакета, содержащее информацию о том, как пакет был собран.

Далее с помощью созданного spec-файла собирается виртуальный rpm-пакет.

19.3.1.4 Создание виртуального пакета вручную
Проблемы автоматизированной генерации spec-файла для виртуального пакета могут возникнуть и на Unix-подобных системах, так как vpkg-provides.sh ожидает, что ряд утилит Unix и GNU будут доступны.

Если же замена команд и прямое указание нужных параметров не дает эффекта, следует написать spec-файл вручную. Добавьте Provides: для каждой библиотеки и интерпретатора в шаблон spec-файла, например:

Provides: libgen.so

Скопируйте пустые секции prep, build, install, и clean как показано в примерах, запустите rpmbuild для сборки пакета и установите его.

Далее - Настройка окружения RPM
Назад - Решение проблем
Содержание


19.3.2 Создание окружения RPM

Окружение RPM состоит из множества настроек и макроопределений. Запустите rpm --showrc для просмотра текущих значений этих настроек и макросов:

$ rpm showrc

ARCHITECTURE AND OS:

build arch : i386

compatible build archs: i686 i586 i486 i386 noarch

build os : Linux

compatible build os's : Linux

install arch : i686

install os : Linux

compatible archs : i686 i586 i486 i386 noarch

compatible os's : Linux

RPMRC VALUES:

macrofiles : /usr/lib/rpm/macros:/usr/lib/rpm/i686-linux/macros:/etc/

rpm/macros.specspo:/etc/rpm/macros.db1:/etc/rpm/macros.cdb:/etc/rpm/macros:/etc/

rpm/i686-linux/macros:~/.rpmmacros

optflags : -O2 -march=i686

Вывод сокращен ради экономии места. Как можно видеть, имеется множество установок, которые должны быть определены в обязательном порядке. На вашей системе аналогичные установки и макроопределения также должны быть заданы, но уже со значениями, которые будут правильными в локальном смысле, то есть в конкретной среде.

Файлы rpmrc.in и macros.in служат шаблонами по умолчанию; они используются для создания соответственно rc и macro. Эти файлы модифицируются скриптом configure для включения значений, специфичных для локальной операционной среды. Можно отредактировать эти файлы для нужд вашей системы перед установкой RPM. В случае необходимости редактирования сделайте это между вызовом команд make и make install.

Файл INSTALL также описывает некоторые изменения, которые вы возможно захотите произвести в отношении макросов.

Далее - Создание rpm-пакетов для не-Linux систем
Назад - Настройка БД RPM
Содержание


19.4 Создание rpm-пакетов для не-Linux систем

Установив и настроив систему RPM вы получаете возможность собирать пакеты для своей системы с помощью rpmbuild.

Не рекомендуется создавать пакеты, находясь в учетной записи root, так как из-за ошибок с spec-файле rpmbuild и скрипты могут разрушить файловую систему среды сборки.

Перед началом сборки можно подстроить свое окружение сборки для более полного отражения свойств вашей системы. Вы также можете обнаружить, что нативная сборка пакетов на вашей системе вовсе не проста и сосредоточиться на кросс-сборке пакетов. При этом rpmbuild будет работать на инструментальной машине и не потребуется запускать ее в целевой системе.

Далее - Настройка среды сборки
Назад - Создание окружения RPM
Содержание


19.4.1 Настройка окружения сборки

В терминологии RPM сборочная среда состоит из дерева каталогов, где происходит сборка, а также установок в rc и macro, которые содержат все переменные, необходимые rpmbased системе. Настроив сборочную среду, вы должны быть уверены, что установки rc и macro точно отражают системное окружение вашей не-Linux системы.

Команда rpm --showrc выведет список установок среды. Используйте ее для проверки значений.

Возможно потребуется изменить некоторые установки, например корень дерева сборки. По умолчанию эта установка выглядит примерно следующим образом:

_topdir %{_usrsrc}/redhat

В большинстве случаев _topdir указывает на каталог /usr/src/redhat. Ваша система может даже не иметь каталога /usr/src. Также вы можете не захотеть собирать rpm в каталоге redhat.

Если после всех настроек пакеты не собираются или дело идет с большим трудом, сосредоточтесь на кросс-сборке.

Далее - Кросс-сборка пакетов
Назад - Создание rpm-пакетов для не-Linux систем
Содержание


19.4.2 Кросс-сборка пакетов

Вы можете обнаружить, что сборка пакетов для целевой платформы на самой этой платформе весьма трудна. Возможно, более простым путем будет сборка на другой платформе, как правило под Linux. Этот процесс называется кросс-сборкой, поскольку вы должны собрать пакеты в системе, которая специальным образом подготовлена к сборке пакетов для другой системы.

Ключевые моменты при кросс-сборке таковы:

* Вы должны собирать бинарные пакеты с помощью правильного кросс-компилятора, предназначенного для целевой платформы.

* Вы должны установить правильную платформу в spec-файлах пакетов, которые вы собираете.

* Возможно вам придется обработать зависимости вручную и отключить автоматическую их генерацию.

Разворачивание среды кросс-сборки часто становится более массивной задачей, чем ожидается. Если есть возможность собирать пакеты на целевой платформе, сделайте это. Кросс-сборка в основном должна использоваться в случаях, когда нативная сборка невозможна. Например, множество наладонных компьютеров не имеют достаточно памяти и быстродействия процессора, чтобы осуществлять на них промышленную сборку компонентов.

Для сборки бинарников, предназначенных к запуску на иных платформах, необходим кросс-компилятор, который запускается на инструментальной платформе и собирает бинарные модули для целевой. Основное применение кросс-компиляторов - сборка программ для встроенных систем и маленьких компьютеров.

Linux компилятор gcc может работать в качестве кросс-компилятора. Для этого должны быть установлены дополнительные компоненты, соответствующие инструментальной и целевой платформам. Для более подробного изучения вопроса ознакомьтесь с документацией на сайте GNU: www.gnu.org .

Кроме компиляции для целевой платформы вы должны озаботиться тем, чтобы пакеты были отмечены как пакеты именно для нужной архитектуры. В противном случае утилита rpm будет работать с ошибками при установке пакетов.

Передать целевую архитектуру при сборке можно с помощью опции утилиты rpmbuild:

rpmbuild bi --target arm-sharp-linux

Подобная команда задает целевую процессорную архитектуру - ARM производства Sharp и операционную систему - Linux.

Также необходимо отключить или поправить процесс автоматической генерации зависимостей. Какие-то зависимости, основанные на целевой системе, могут быть не найдены, или найдены в иных локациях или форматах при сборке на инструментальной машине.

Далее - Раздел 20. Изменение поведения RPM
Назад - Настройка окружения сборки
Содержание


20.1 Настройка поведения с помощью RPM-макросов

Начиная с версии 3.0, RPM-макросы обеспечивают механизм настройки, замещающий установки из файлов rpmrc.

Макрос RPM задает единичную настройку для системы RPM. Макрос может быть определен как статическая переменная, например, путь установки RPM. Макрос может быть определен через другие макросы. Кроме того, макрос может быть определен с параметрами.

Следующий пример определяет два макроса в файле макросов:

%_usr /usr

%_usrsrc %{_usr}/src

В данном случае макрос %_usr задает каталог /usr. Макрос %_usrsrc задает каталог /usr/src через определение в другом макросе.

Далее - Определение макросов
Назад - Кросс-сборка пакетов
Содержание


20.1.1 Определение макросов

RPM допускает определение макросов в нескольких местах, включая spec-файл (возможно, наиболее общий случай использования), специальные файлы макросов, командную строку.

Во всех случаях синтаксис применения будет похожим.

20.1.1.1 Определение макроса в spec-файле
В spec-файле есть несколько мест, пригодных для задания макросов. Для этого используется директива %define и следующий синтаксис:

%define name(options) body

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

Опция

Содержит

%0

Имя макроса

%1

Первый аргумент после флагов, разобранных getopt

%2-%9

Дополнительные аргументы

%*

Все аргументы кроме флагов, которые должны быть разобраны

%#

Число агрументов

В целом эти опции сходны с таковыми в shell-скриптах.

В дополнение к возможности использовать эти опции можно использовать синтаксис %{-a}. Это выражение хранит -a, если опция -a передавалась. Синтаксис %{-a*} указывает на значение, следующее за -a.

Также можно придать макросу значение, которое возвращается shell-командой. Для этого используется такое выражение:

%(shell_command)

20.1.1.2 Определение макроса в файле инициализации макросов
Внутри файлов инициализации макросов используется следующий синтаксис:

%macro_name value

Макрос, предназначенный для управления системой RPM, начинается с нижнего подчеркивания. Такие макросы не экспортируются в хэдеры пакетов.

Встроенный макрос %expand каким-либо образом расширяет значение. Например, для расширения значения может использоваться shell-команда. В следующем примере задается домашний каталог пользователя для макроса %home:

%home %{expand:%%(cd; pwd)}

Возможно, прямое задание макроса %home в пользовательском файле инициализации макросов $HOME/.rpmmacros будет более простым ходом.

20.1.1.3 Определение макроса в командной строке
Утилита rpm позволяет задать макрос из командной строки:

$ rpm --define 'macro_name value'

Не предваряйте макрос символом процентов, если задаете его с помощью --define.

Раскрыть значение макроса можно командой с опцией --eval:

$ rpm --eval %_usrsrc

/usr/src

Далее - Пользовательские макросы
Назад - Настройка поведения через RPM-макросы
Содержание


20.1.2 Пользовательские макросы

Пользователь может задать свои собственные макроопределения с использованием изученных синтаксисов. Эти макросы будут считываться при каждом запуске rpm или rpmbuild.

Для задания своих макросов следует отредактировать один из файлов макроопределений.

Файл

Назначение

/usr/lib/rpm/macros

Официальные макросы RPM

/etc/rpm/macros

Системно-зависимые макросы

$HOME/.rpmmacros

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

Следует помнить, что пользовательские макросы, заданные в файле /usr/lib/rpm/macros будут утеряны, если установить пакеты rpm новой версии поверх старой.

Далее - Конфигурирование RPM
Назад - Определение макросов
Содержание


3.2.3 Обновление в режиме freshen

Операция freshen означает обновление пакета в одном узком случае - если уже установлен такой пакет более старой версии. Однако, эта операция во многом сходна с операцией upgrade, за исключением той ситуации, когда upgrade может установить пакет в первый раз.

Синтаксис:

# rpm -F jpilot-0.99.2-8.i386.rpm

Далее - Установка через сеть
Назад - Режим обновления (upgrade)
Содержание


20.2 Конфигурирование RPM

RPM содержит сотни установок, зависящих от системной архитектуры, системного окружения, версии RPM. Старый стиль конфигурирования, в основном опирающийся на rpmrc-файлы постепенно замещается более эффективным стилем, опирающимся на макросы.

Нам по прежнему доступны настройки rpmrc-файлов, но в большинстве случаев достаточно вместо этого определить пользовательские макросы.

Далее - Просмотр текущих установок
Назад - Пользовательские макросы
Содержание


20.2.1 Просмотр текущих установок

Для просмотра текущих установок используется опция --showrc утилиты rpm:

$ rpm showrc

ARCHITECTURE AND OS:

build arch : i386

compatible build archs: i686 i586 i486 i386 noarch

build os : Linux

compatible build os's : Linux

install arch : i686

install os : Linux

compatible archs : i686 i586 i486 i386 noarch

compatible os's : Linux

RPMRC VALUES:

macrofiles : /usr/lib/rpm/macros:/usr/lib/rpm/i686-linux/macros:/etc/

rpm/macros.specspo:/etc/rpm/macros.db1:/etc/rpm/macros.cdb:/etc/rpm/macros:/etc/

rpm/i686-linux/macros:~/.rpmmacros

optflags : -O2 -march=i686

Эта команда показывает текущую архитектуру, информационный список параметров операционной системы и список установок из rpmrc-файлов (вывод сокращен ради экономии места).

Далее - Расположение rpmrc-файлов
Назад - Конфигурирование RPM
Содержание


20.2.2 Расположение rpmrc-файлов

Опция --showrc указывает утилите rpm читать установки из всех rpmrc-файлов в различных локациях. По умолчанию это файлы
/usr/lib/rpm/rpmrc, /etc/rpm/rpmrc и .rpmrc в вашем домашнем каталоге.

Эти файлы читаются в указанном порядке; если в нескольких файлах имеется один и тот же ключ, его значение будет переопределяться значением из файла, который считывается позже.

Назначение файлов показано в таблице ниже:

Файл

Содержит

/usr/lib/rpm/rpmrc

Стандартные установки RPM

/etc/rpm/rpmrc

Конфигурация, зависящая от системы

$HOME/.rpmrc

Конфигурация, зависящая от пользователя

Переопределить список этих файлов можно вызовом rpm или rpmbuild с опцией --rcfile. С этой опцией утилиты будут ожидать на вход список в виде строки, в которой имена файлов разделены точкой с запятой, в нужном порядке. Например, если вы работаете на архитектуре i686, можно создать файл, который будет содержать следующую установку:

optflags: i686 -g

Эта установка взята только для примера, так как отключает оптимизацию.

Если теперь назвать файл .rpmnew и поместить его в домашний каталог, можно сконфигурировать альтернативный стек установок с помощью опции --rcfile. Затем выведем полученные установки с помощью --eval:

$ rpm --rcfile $HOME/.rpmnew --eval "%{optflags}"

-g

Когда используется опция --rcfile, только первый файл из списка должен существовать. Остальные файлы применяются опционально, если существуют. Файл /usr/lib/rpm/rpmrc применяется всегда.

Далее - Изменение установок
Назад - Просмотр текущих установок
Содержание


20.2.3 Изменение установок

Для изменения установок RPM можно редактировать системный или пользовательский rc файл. Формат rpmrc файлов исключительно прост, хотя есть несколько исключений. Базовый формат уже неоднократно обсуждался:

setting: value

В более сложных случаях, например, при указании системной архитектуры, синтаксис может быть таким:

setting: uname: value

В данном примере поле uname замещается значением, которое вернул системный вызов uname(2), например, i686.

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

20.2.3.1 Установка флагов оптимизации
Одно из исключений синтаксиса - установки флагов оптимизации, которые контролируют опции компилятора. Формат флагов:

setting: arch value

Двоеточие после архитектуры не используется. Например:

optflags: i686 -O2 -march=i686

optflags: alphaev5 -O2 -mieee -mcpu=ev5

В данном примере устанавливаются флаги -O2 -march=i686 для архитектуры i686 и -O2 -mieee -mcpu=ev5 для архитектуры alphaev5.

20.2.3.2 Установка архитектур
Установка значений поля arch_canon задает соответствие между названиями архитектур и внутренним представлением в виде числовых маркеров. Нижеследующий пример показывает, как установить соответствия между архитектурами Intel и SPARC и внутренним представлением:

arch_canon: athlon: athlon 1

arch_canon: i686: i686 1

arch_canon: i586: i586 1

arch_canon: i486: i486 1

arch_canon: i386: i386 1

arch_canon: sparc: sparc 3

arch_canon: sun4: sparc 3

arch_canon: sun4m: sparc 3

arch_canon: sun4c: sparc 3

arch_canon: sun4d: sparc 3

arch_canon: sparcv9: sparcv9 3

Поле arch_compat позволяет построить таблицу совместимых архитектур. Формат:

arch_compat: arch: compatible_with

Такая строка определяет данную архитектуру, как совместимую с другой архитектурой. Например:

arch_compat: athlon: i686

С помощью этого синтаксиса можно построить примерно такую таблицу совместимости архитектур:

arch_compat: i686: i586

arch_compat: i586: i486

arch_compat: i486: i386

arch_compat: i386: noarch

Установка os_canon определяет таблицу соответствия названий операционных систем и внутренних числовых идентификаторов. Базовый синтаксис:

os_canon: arch: name value

arch - это результат, возвращенный системным вызовом uname(2). name предоставляется через имя операционной системы, как оно определено в RPM, value - это внутренний числовой идентификатор, например:

os_canon: Linux: Linux 1

os_canon: HP-UX: hpux10 6

Установка buildarchtranslate определяет установку операционной системы для использования ее как системы сборки. Это значение транслирует то, что получено от системного вызова uname(2) в значение, которое ислользует опция arch_canon. Например:

buildarchtranslate: athlon: i386

buildarchtranslate: i686: i386

buildarchtranslate: i586: i386

buildarchtranslate: i486: i386

buildarchtranslate: i386: i386

buildarchtranslate: sun4c: sparc

buildarchtranslate: sun4d: sparc

buildarchtranslate: sun4m: sparc

buildarchtranslate: sparcv9: sparc

buildarchtranslate: sun4u: sparc64

Далее - Добавление псевдонимов popt
Назад - Расположение rpmrc-файлов
Содержание


20.3 Добавление псевдонимов popt

Popt - подсистема RPM, мощная библиотека для обработки сложных сочетаний опций командной строки. Вы можете настроить RPM таким образом, что определенные вами псевдонимы popt позволят задать нужную реакцию утилит rpm и rpmbuild. Псевдоним (алиас) popt - это опция командной строки, которая разворачивается в другие опции.

Эта техника используется для того, чтобы простой опцией можно было вызвать более сложный набор других опций. Большая часть алиасов служит для упрощения формата сложных запросов.

Например, следующая строка определяет опции --requires и R для утилиты rpm:

rpm alias --requires --qf \

"[%{REQUIRENAME} %{REQUIREFLAGS:depflags}
%{REQUIREVERSION}\n]" \

--POPTdesc=$"list capabilities required by package(s)"

rpm alias -R --requires

Данный синтаксис специфичен для RPM v. 4.1.

Далее - Определение псевдонимов
Назад - Изменение установок
Содержание


20.3.1 Определение псевдонимов

Определение алиасов - весьма простая процедура. Базовый синтаксис:

command_name alias option expansion

Для создания алиаса команды rpm вместо command_name подставляется rpm. Затем следует сам псевдоним и далее - опция. Для длинного и короткого формата опций псевдонимы задаются по отдельности. expansion, то есть во что разворачивается алиас, определяются в терминах уже определенных параметров командной строки.

В нижеследующем примере определяется сложный псевдоним для вывода информации о пакете:

rpm alias --info --qf 'Name : %-27{NAME}
Relocations:%|PREFIXES?{[%{PREFIXES} ]}:{(not relocateable)}|\n\

Version : %-27{VERSION} Vendor: %{VENDOR}\n\

Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}\n\

Install date: %|INSTALLTIME?{%-27{INSTALLTIME:date}}:{(not installed) }|
Build Host: %{BUILDHOST}\n\

Group : %-27{GROUP} Source RPM: %{SOURCERPM}\n\

Size : %-27{SIZE}%|LICENSE?{ License: %{LICENSE}}|\n\

Signature : %|DSAHEADER?{%{DSAHEADER:pgpsig}}:
{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:
{%|SIGGPG?{%{SIGGPG:pgpsig}}:
{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\n\

%|PACKAGER?{Packager : %{PACKAGER}\n}|\

%|URL?{URL : %{URL}\n}|\

Summary : %{SUMMARY}\n\

Description :\n%{DESCRIPTION}\n' \

--POPTdesc=$"list descriptive information from package(s)"

Поскольку алиасы popt фактически разворачиваются в Linux-команды, в них можно использовать конвейеры и другие традиционные подходы shell-скриптинга.

Для просмотра примеров задания алиасов загляните в файл /usr/lib/rpm/rpmpopt. Это наиболее полный набор возможных способов задания псевдонимов.

Кроме показанного подхода можно задавать алиасы, которые устанавливают макросы, как в показанном ниже примере. В данном случае устанавливается путь к БД RPM:

rpm alias --dbpath --define '_dbpath !#:+'

В данном примере конструкция !#:+ определена для задания поведения, как при редактировании истории shell-команд. С точки зрения popt это означает "забрать следующий параметр командной строки и поместить его в команду, в которую разворачивается псевдоним".

Для поддержки ключей --help и --usage можно определить опции
--POPTdesc и --POPTargs для алиасов, как показано в предыдущих примерах. Эти опции также поддерживают интернационализацию.

Из всего вышесказанного ясно, что в целом установка псевдонима popt весьма близка по смыслу к записям в таблице опций, которая используется в C RPM API.

Далее - Пользовательские псевдонимы
Назад - Добавление псевдонимов popt
Содержание


20.3.2 Пользовательские псевдонимы

Подобно макросам RPM, алиасы popt определяются в ряде файлов (общий системы RPM, системнозависимый, пользовательский). Официальные псевдонимы RPM определены в файле /usr/lib/rpm/rpmpopt. Редактировать этот файл не имеет смысла, так как правильное функционирование RPM сильно зависит от его содержимого.

Системнозависимые псевдонимы хранятся в файле /etc/popt. Свои наработки псевдонимов сохраняйте в файле $HOME/.popt . Они будут действительны в рамках ваших сессий.

Этот набор файлов влияет на все приложения, которые используют библиотеку popt.

Например, вы можете определить алиас для команды rpm -qa, который будет работать быстрее, чем обыкновенный запрос информации о всех пакетах, путем отключения проверки подписи пакета. Добавьте в ваш файл $HOME/.popt следующую строку:

rpm alias --qall -qa --nodigest --nosignature

При наличии такой строки вы можете осуществлять запрос информации об установленных пакетах в форме:

rpm --qall

Это будет работать на 30-50% быстрее, чем команда rpm -qa.

Далее - Раздел 21. Справочник по командам RPM
Назад - Определение псевдонимов
Содержание


21.1.1 Команда rpm в режиме запросов

Утилита rpm - рабочая лошадка системы RPM. Эта и несколько последующих глав описывают опции работы rpm в различных режимах.

В таблице ниже даны опции режима запросов. Они следуют за ключом -q или --query .

Опция

Использование

-a, --all

Запрос информации обо всех пакетах, установленных в системе

-c, --configfiles

Вывод списка конфигурационных файлов

--changelog

Вывод журнала изменений

--conflicts

Вывод списка возможностей, с которыми конфликтует пакет

-d, --docfiles

Вывод списка файлов документации

--dump

Вывод расширенной информации

-f, --file filename

Запрос пакета, владеющего файлом filename

--filesbypapkg

Вывод списка файлов каждого отмеченного пакета

--fileid md5_id

Запрос пакета, имеющего значение дайджеста MD5, равного md5_id

-g, --group group_name

Запрос пакетов данной группы

--hdrid sha1_header_id

Запрос пакета с заданным идентификатором хэдера в формате SHA1

-i, --info

Вывод информации о пакете, включая описание

--last

Задать порядок вывода списка пакетов таким образом, чтобы пакеты, установленные последними, выводились первыми в списке

--obsoletes

Вывод списка возможностей, которые данный пакет делает устаревшими

-p, --package rpm_file

Запрос заданного файла/файлов rpm-пакетов

--pkgid md5_id

Запрос пакета, имеющего заданный идентификатор MD5

--provides

Вывод списка возможностей, предоставляемых данным пакетом

--querybynumber number

Запрос записи из БД RPM по ее номеру

--qf, --queryformat format

Вывод запрошенной информации в заданном формате

--redhatprovides capability

Поиск пакета, предоставляющего заданные возможности, в базе данных пакетов Red Hat (rpmdb-redhat)

--redhatrequires capability

Поиск пакета, нуждающегося в заданных зависимостях, в базе данных пакетов Red Hat (rpmdb-redhat)

-R, --requires

Вывод списка пакетов и возможностей, от которых зависит заданный пакет

--specfile specfile

Запрос заданного spec-файла

-s, --state

Вывод статуса заданных файлов

--scripts

Вывод скриптов пакета

--tid transaction_id

Вывод пакета или пакетов с заданным идентификатором транзакции

--triggeredby package

Вывод пакетов, от которых зависят триггеры данного пакета

--triggers, --triggerscripts

Вывод скриптов триггеров

--whatrequires capability

Вывод списка пакетов, которые требуют данную возможность

--whatprovides capability

Вывод списка пакетов, которые предоставляют данную возможность

Далее - Режимы обновления и установки (upgrade, freshen, install)
Назад - Пользовательские псевдонимы
Содержание


21.1.2 Команда rpm в режимах установки и обновления (upgrade, freshen, install)

Ниже представлены опции, которые следуют за ключами -U, -i, --freshen .

Опция

Использование

--aid

Добавить в список установки пакеты, которые предлагаются по зависимостям

--allfiles

Установить все файлы, даже если некоторые из них должны быть пропущены

--badreloc

Переопределить пути файлов, даже если пакет не является пакетом с переопределимыми путями

--excludedocs

Пропустить файлы документации

--excludepath path

Пропустить файлы, путевые имена которых включают заданный образец

--force

Короткая форма для совместного применения опций --replacepkgs и --replacefiles

-h, --hash

Выводить символы решетки для оценки прогресса операций (50 символов = 100% выполнения)

--ignorearch

Игнорировать соответствие процессорной архитектуре, указанной в пакете

--ignoreos

Игнорировать соответствие операционной системе, указанной в пакете

--ignoresize

Пропустить проверку достаточности дискового пространства

--includedocs

Установить файлы документации, включенные по умолчанию

--justdb

Обновить информацию в БД RPM, но не обновлять сами файлы

--nodeps

Пропустить проверку зависимостей

--nodigest

Пропустить проверку дайджестов пакета и хэдера

--nomd5

Пропустить проверку контрольной суммы MD5 пакета

--noorder

Не переопределять порядка списка пакетов, которые должны быть установлены по зависимостям

--nopost

Не выполнять скриптов после установки пакета

--nopostun

Не выполнять скриптов после удаления пакета

--nopre

Не выполнять скриптов перед установкой пакета

--nopreun

Не выполнять скриптов перед удалением пакета

--nosuggest

Не предлагать пакетов для недостающих зависимостей

--noscripts

Не выполнять скриптов

--nosignature

Пропустить верификацию пакета и подписи

--notriggers

Не выполнять никакие триггеры

--notriggerin

Не выполнять триггеры установки

--notriggerpostun

Не выполнять триггеры после удаления

--notriggerun

Не выполнять триггеры перед удалением

--oldpackage

Допустить режим обновления на более старую версию пакета

--percent

Выводить прогресс в процентах выполнения

--prefix directory

Переопределить пакет на каталог directory, если пакет с переопределимыми путями

--relocate old=new

Переопределить пути, начинающиеся на old, заменив паттерн на new, если пакет с переопределимыми путями

--repackage

Создать пакет из удаляемых файлов (впоследствии файлы можно будет восстановить путем установки этого пакета)

--replacefiles

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

--replacepkgs

Установить пакеты, даже если они уже установлены

--test

Не выполнять реальных действий (в данном случае и удаления), только протестировать работу команды и вывести сообщения о возможных ошибках

Далее - Команда rpm в режиме удаления
Назад - Команда rpm в режиме запросов
Содержание


21.1.3 Команда rpm в режиме удаления

Ниже представлены опции, которые следуют за ключами -e или --erase .

Опция

Использование

--allmatches

Удалить все версии пакета. В обычном случае при наличии нескольких версий будет выводиться сообщение об ошибке с требованием указать конкретную версию

--nodeps

Не выполнять проверку зависимостей

--noscripts

Не выполнять скрипты

--nopostun

Не выполнять скрипты после удаления

--nopreun

Не выполнять скрипты перед удалением

--notriggers

Не выполнять триггеры

--notriggerpostun

Не выполнять триггеры после удаления

--notriggerun

Не выполнять триггеры перед удалением

--repackage

Создать пакет из удаляемых файлов

--test

Проверить последствия выполнения команды, не выполняя реальных действий

Далее - Команда rpm в режиме подписи
Назад - Команда rpm в режимах установки и обновления
Содержание


3.2.5 Установка через сеть

Все предыдущие примеры основывались на предположении, что имеется локальный rpm-пакет, к которому можно указать путь или выполнить команду в его каталоге. Но не более сложно установить пакет, имеющий копию где-то в сети. Для сетевой установки поддерживаются протоколы FTP и HTTP. Удаленный репозиторий пакетов должен быть доверенным, так как есть опасность скачать измененный злоумышленником пакет с фальшивого сервера.

3.2.5.1 Установка через FTP

Все изменения в команде для установки через FTP - это включение имени пакета в виде URL в качестве аргумента. Базовый синтаксис:

# rpm -i ftp://unclejoe@www-126.ibm.com/pub/jikes/jikes-1.16-1.i386.rpm

unclejoe, в данном случае - имя пользователя на сервере FTP. Пример, естественно, выдуманный и не содержит реального имени пользователя.

Команда, отданная в таком виде, вызовет приглашение на ввод пароля пользователя FTP. Можно задать имя пользователя и пароль в одной строке, разделяя их двоеточием:

# rpm -i ftp://unclejoe:workers@www-126.ibm.com/pub/jikes/jikes-1.16-1.i386.rpm

В данном случае пароль - workers.

3.2.5.2 Установка через HTTP

Ситуация, идентичная FTP:

# rpm i http://ftp.redhat.com/pub/contrib/noarch/SRPMS/Squeak-sources-3-1.src.rp...

Далее - Установка пакетов с исходным кодом
Назад - Режим обновления (freshen)
Содержание


21.1.4 Команда rpm в режиме подписи

Ниже представлены опции, использующиеся после ключей K, --checksig .

Опция --import используется сама по себе.

Опция

Использование

--addsign

Подписать пакет, то же, что и --resign

--import public_key

Добавить указанный публичный ключ в БД RPM

--nodigest

Пропустить проверку дайджестов пакета и хэдера

--nosignature

Пропустить проверку подписей пакета и хэдера

--resign

Подписать пакет

Далее - Команда rpm в режиме верификации
Назад - Команда rpm в режиме удаления
Содержание


21.1.5 Команда rpm в режиме верификации

Команда rpm может проверять пакеты. Это означает возможность сравнения всех установленных файлов с информацией о них в БД RPM. В результате обнаруживаются отличия или недостающие файлы.

Ниже представлены опции, следующие за ключами V или --verify.

Опция

Использование

-a, --all

Проверить все пакеты

-f, --file filename

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

-g, --group group_name

Проверить пакеты указанной группы

--nodeps

Не проверять зависимости

--nodigest

Пропустить проверку дайджестов пакета и хэдера

--nofiles

Не проверять файлы пакета

--nogroup

Не проверять группу владельца

--nolinkto

Не проверять атрибуты ссылки

--nomd5

Не проверять контрольные суммы MD5

--nomtime

Не проверять атрибут mtime

--nomode

Не проверять права

--nordev

Не проверять атрибут rdev

--noscripts

Не запускать скрипты верификации

--nosignature

Пропустить проверку подписей пакета и хэдера

--nosize

Не проверять размер файла

--nouser

Не проверять собственника файла

-p, --package rpm_file

Проверить rpm-файл указанного пакета

--specfile specfile

Проверить указанный spec-файл

--whatrequires capability

Проверить пакеты, зависящие от заданной возможности

--whatprovides capability

Проверить пакеты, предоставляющие заданную возможность

Далее - Команда rpm в режиме работы с БД RPM
Назад - Команда rpm в режиме подписи
Содержание


21.1.6 Команда rpm в режиме работы с БД RPM

С помощью опций режима работы с БД RPM можно создать новую пустую БД или перестроить существующую в случае сбоев.

Опция

Использование

--initdb

Инициализировать новую БД

--rebuilddb

Пересоздать все нарушенные структуры с помощью файла Packages

Далее - Разные опции
Назад - Команда rpm в режиме верификации
Содержание


21.1.7 Разные опции

Эти опции могут использоваться в любом режиме работы утилиты rpm, с любыми первичными ключами. Три опции, --querytags, --version и --showrc используются сами по себе.

Опция

Использование

-?, --help

Вывести помощь popt по всем опциям

--dbpath path_to_rpm_db

Использовать указанный каталог для БД RPM вместо каталога по умолчанию

-D, --define 'macro value'

Определить указанный макрос для хранения указанного значения

-E, --eval expression

Вывести значение указанного выражения

--ftpport port

Использовать указанный порт для доступа по FTP

--ftpproxy host

Использовать указанное имя хоста в качестве FTP-прокси

--httpport port

Использовать указанный порт для доступа по HTTP

--httpproxy host

Использовать указанное имя хоста в качестве HTTP-прокси

--macros file:file:file

Прочитать список разделенных двоеточиями файлов и использовать эти файлы для определения макросов. Только первый файл из списка обязан существовать

--pipe command

Перенаправить вывод команды rpm на ввод другой команды. То же, что и | в shell

--querytags

Вывести имена тегов и завершиться

--quiet

Тихое поведение. Выводятся только сообщения об ошибках

--rcfile file:file:file

Прочитать список разделенных двоеточиями файлов и использовать эти файлы для хранения установок RPM. Только первый файл из списка обязан существовать

--root directory

Использовать указанный каталог в качестве корня вместо /.

--showrc

Вывести rpmrc-файлы и файлы с определениями макросов и завершиться

-v, --verbose

Более многословный вывод

-vv

Еще более многословный вывод, включая отладочную информацию

--version

Вывести версию RPM и завершиться

Далее - Утилита rpmbuild. Сборка посредством указания spec-файла
Назад - Команда rpm в режиме работы с БД RPM
Содержание


21.2.1 Утилита rpmbuild. Сборка посредством указания spec-файла

Команда rpmbuild собирает пакет. Многие опции дублируются. Опции, которые начинаются с -b заведуют сборкой из spec-файла, опции, начинающиеся с -t - сборкой из tar-архивов.

В таблице ниже разбираются опции для сборки из spec-файла.

Опция

Использование

-ba

Собрать бинарный пакет и пакет с исходным кодом

-bb

Собрать бинарный пакет

-bc

Скомпилировать программу, но не собирать полный пакет. Выполнить секцию %build и остановиться

-bp

Подготовить пакет к сборке. Выполнить секцию %prep и остановиться

-bi

Выполнить процедуры до конца секции %install и остановиться

-bl

Проверить список файлов пакета

-bs

Собрать только пакет с исходным кодом

Все эти опции требуют наличия имени spec-файла в конце командной строки.

Далее - Утилита rpmbuild. Сборка из tar-архива
Назад - Разные опции
Содержание


21.2.2 Утилита rpmbuild. Сборка из tar-архива

Таблица в этой главе посвящена опциям сборки из компрессированных tar-архивов.

Опция

Использование

-ta

Собрать бинарный пакет и пакет с исходным кодом

-tb

Собрать бинарный пакет

-tc

Собрать ПО, но не собирать пакет. Выполнить секцию %build и остановиться

-tp

Выполнить секцию %prep и остановиться

-ti

Выполнить до конца секции %install и остановиться

-tl

Проверить список файлов пакета

-ts

Собрать только пакет с исходным кодом

Далее - Пересборка пакетов из пакетов с исходным кодом
Назад - Утилита rpmbuild. Сборка посредством указания spec-файла
Содержание


21.2.3 Пересборка пакетов из пакетов с исходным кодом

Для пересборки пакета из src.rpm используются опции пересборки и перекомпиляции:

Опция

Использование

--rebuild

Пересобрать бинарный пакет из src.rpm-пакета

--recompile

Перекомпилировать бинарный пакет из src.rpm-пакета

Обе этих опции требуют указания имени src.rpm-файла в конце командной строки.

Далее - Изменение хода сборки
Назад - Утилита rpmbuild. Сборка пакета из компрессированного tar-архива
Содержание


21.2.4 Изменение хода сборки

С помощью нижеследующих опций вы можете более тонко настроить процесс сборки пакета.

Опция

Использование

-?, --help

Вывести всю информацию popt об опциях командной строки

--buildroot directory

Переопределить каталог сборки по умолчанию в пользу каталога directory

--clean

Удалить дерево сборки после сборки

-D, --define 'macro value'

Определить макрос со значением value

--dbpath path_to_rpm_db

Использовать указанный путь в качестве пути к БД RPM вместо пути по умолчанию

-E, --eval expression

Развернуть значение данного выражения

--macros file:file:file

Считать список файлов для использования их в качестве файлов макроопределений. Только первый файл из списка должен существовать

--nobuild

Ничего не собирать в реальности. Опция служит для проверки spec-файла

--pipe command

Перенаправить вывод команды на ввод команды command

--quiet

Тихое поведение. Выдаются только сообщения об ошибках

--rcfile file:file:file

Считать список файлов для использования их в качестве rc-файлов, хранящих установки RPM. Только первый файл в списке обязан существовать

--rmsource

Удалить исходники после сборки

--rmspec

Удалить spec-файл после сборки

--root directory

Использовать указанный каталог в качестве корня файловой системы вместо каталога /

--short-circuit

В сочетании с опциями -bc или -bi используется для прямого перехода к данной стадии сборки и выполнения этой стадии (чтобы пропустить стадию компиляции, если ошибка сборки пакета - это ошибка RPM, а не компилятора)

--showrc

Вывести установки из rpmrc и macro-файлов

--sign

Подписать пакет сигнатурой GPG

--target platform

Собрать пакет для данной платформы. Не сработает, если нет кросс-компилятора для этой платформы.

-v, --verbose

Более многословный вывод

-vv

Еще более многословный вывод

--version

Вывести версию RPM

Далее - Раздел 22. Синтаксис spec-файла
Назад - Пересборка пакетов из пакетов с исходным кодом
Содержание


22.1 Поля, содержащие информацию о пакете

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

Тэги name-epoch-version-release (имя-эпоха-версия-релиз) используются для однозначной идентификации пакета, поэтому в обязательном порядке присутствуют в spec-файле, хотя тэг Epoch может быть пропущен:

Name: name

# Epoch: 1

Version: version_number

Release: package_release_number

Опциональное поле Epoch вводит еще один уровень для выстраивания порядковых номеров версий и заменяет утратившее значение поле Serial.

Ряд полей позволяют определить, кто собрал пакет и под какими условиями он выпущен:

Vendor: name_of_vendor

URL: URL_to_package_home

Copyright: package_copyright_message

Distribution: Linux_or_product_distribution

Packager: John Q. Smith

Group: group_for_categorizing_package

Используйте поле Group для облегчения потребителям категоризации пакета.

Поле Icon позволяет задать изображение ярлыка рабочего стола для этого пакета:

Icon: filename.xpm

Summary - однострочное описание пакета. Вам также необходимо включить в spec-файл многострочное описание в поле %description:

%description

Tcsh is an enhanced but completely compatible version of csh, the C
shell. Tcsh is a command language interpreter which can be used both as an interactive login shell and as a shell script command processor.
Tcsh includes a command line editor, programmable word completion, spelling correction, a history mechanism, job control and a C language like syntax.

В секции %description пустые строки означают новый абзац. Строки, начинающиеся с пробела, не форматируются.

Далее - Комментарии
Назад - Изменение порядка сборки
Содержание


22.1.1 Комментарии

Для документирования spec-файла применяются комментарии. Все строки, начинающиеся на #, содержат комментарии. RPM игнорирует комментарии.

В основном комментарии используются разработчиками для обоснования выбора способа действия, так как рано или поздно приходится просматривать spec-файл вновь, также его будут смотреть другие люди.

Избегайте появления символа % в комментариях, так как он может быть воспринят, как идентификатор начала макроса.

Далее - Параметры сборки
Назад - Поля, содержащие информацию о пакете
Содержание


3.2.6 Установка пакетов с исходным кодом

Пакеты с исходным кодом содержат код и сценарии для сборки приложений и библиотек. Кроме того, в пакете могут содержаться патчи к исходному коду, управляющие скрипты, файлы ресурсов приложений, документация. Обычно одному пакету с исходниками соответствует один бинарный пакет, хотя это и не всегда так.

Программное обеспечение, для которого доступен исходный код, обычно называется программным обеспечением с открытым кодом (Open Source Software). Установочные образы операционных систем Linux и репозитории пакетов в основном укомплектованы таким ПО.

Важные плюсы доступа к исходному коду:

- вендор может прекратить поддержку пакета, тогда те, кому необходимо использовать и развивать это ПО, могут занять его место;
- легко устранять ошибки безопасности, исправляя код;
- легко расширять функциональность ПО.

Приложения Linux доступны под различными открытыми лицензиями.

Команды для установки src.rpm ничем не отличаются от команд для бинарных пакетов. При установке пакета с исходниками в систему в самом простом случае копируется архив с деревом файлов и каталогов, содержащих исходный код и сценарии сборки, и файл спецификации.

# rpm i foo-0.1-1.src.rpm

Далее - Удаление пакетов
Назад - Установка пакетов по сети
Содержание


22.1.2 Параметры сборки

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

Специальное поле noarch указывает на пакет, не зависящий от процессорной архитектуры. Такой пакет может содержать документацию или скрипты на Perl или Python.

Поле BuildPreReq содержит предусловия сборки. Например:

BuildPreReq: ncurses-devel

Поле Buildroot называет временный каталог, в котором будет происходить сборка. Например:

Buildroot: %{_tmppath}/%{name}-root

Далее - Поля, содержащие информацию о зависимостях
Назад - Комментарии
Содержание


22.1.3 Поля, содержащие информацию о зависимостях

Тэги зависимостей определяют все зависимости пакета.

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

Provides: capability_name

Также можно задать конкретную версию, или указать, что ваш пакет требует более старшую/младшую версию, чем определенная. Например:

Requires: capability_name >= version_number

Requires: capability_name <= version_number

Requires: capability_name > version_number

Requires: capability_name < version_number

Requires: capability_name == version_number

Requires: capability_name = version_number

Символы = и == в контексте зависимостей идентичны. Оба задают требование равенства версии определенному числу.

В тэгах зависимостей можно определять множественные значения, разделенные запятыми:

Requires: python >= 1.3, perl

Дополнительные модули таких интерпретаторов, как Perl, допускают в полях зависимостей следующий синтаксис:

Provides: perl(MIME-Base64)

В строке примера пакет предоставляет возможность модуля Perl MIME-Base64.

Может быть задана более чем одна возможность.

Значения полей зависимостей Provides, Requires, Obsoletes и Conflicts работают также, как имена зависимостей и номера версий.

Далее - Файлы с исходным кодом
Назад - Параметры сборки
Содержание


22.1.4 Файлы с исходным кодом

Тэги Source: и Patch: идентифицируют файлы с исходным кодом, которые будут использованы для построения бинарного пакета. Patch: указывает на любые патчи, которые должны быть применены к исходникам. Если файлов с начальным исходным кодом или патчей больше одного, применяются числовые модификаторы, причем первый тэг Source будет Source0:, а первый тэг Patch - Patch1: . Например:

Source0: ftp://ftp.uk.linux.org/pub/linux/telnet-%{telnet_version}.tar.gz

Source2: telnet-client.tar.gz

Source3: telnet-xinetd

Source4: telnet.wmconfig

Patch1: telnet-client-cvs.patch

Patch5: telnetd-0.17.diff

Patch6: telnet-0.17-env.patch

Patch7: telnet-0.17-issue.patch

Patch8: telnet-0.17-sa-01-49.patch

Patch9: telnet-0.17-env-5x.patch

Patch10: telnet-0.17-pek.patch

Далее - Макросы
Назад - Поля, содержащие информацию о зависимостях
Содержание


22.2.1 Макросы определения переменных

Для помощи в контролировании процесса сборки пакета, макросы могут быть определены непосредственно в spec-файле.

Директива %define позволяет определить новый макрос. Наиболее часто встречающаяся форма - определить основные макросы в начале файла и затем использовать их на протяжении всего сценария сборки.

Например:

%define bindir /bin

Это позволяет задать установки в одном месте, и, если их придется изменить, также изменить все в одном месте.

Этот синтаксис используется для всех статических определений, например номеров версий:

%define major 2

%define minor 2

%define patchlevel 7

Version: %{major}.%{minor}.%{patchlevel}

Список более специфичных макросов для использования в spec-файле приводится в таблице ниже.

Макрос

Использование

%dump

Вывести значения макросов

%{echo:message}

Вывести сообщение в stderr

%{error:message}

Вывести сообщение в stderr и вернуть BADSPEC

%{expand:expression}

Подобно eval раскрывает выражение

%{F:file_exp}

Разрешить file_exp в имя файла

%global name value

Определить глобальный макрос

%{P:patch_exp}

Разрешить patch_exp в имя патча

%{S:source_exp}

Разрешить source_exp в имя файла с исходниками

%trace

Переключить вывод отладочной информации

%{uncompress:filename}

Проверить, является ли файл сжатым. Если да, то подвергнуть декомпрессии и включить в данный контекст. Если нет, вызывать cat для включения содержимого файла в данный контекст.

%undefine macro

Очистить заданный макрос

%{warn:message}

Вывести сообщение в stderr

Далее - Макросы условий
Назад - Файлы с исходным кодом
Содержание


22.2.2 Макросы условий

Для проверки, существует ли заданный макрос, используется специальный синтаксис. Например:

%{?macro_to_test: expression}

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

%{!?macro_to_test: expression}

В данном примере если macro_to_test не существует, тогда разворачивается выражение.

Для ветвления процесса используется макрос %if. Например:

%if %{old_5x}

%define b5x 1

%undefine b6x

%endif

%else позволяет специфицировать действия, которые необходимо проделать, если тест был неуспешный. Например:

%if %{old_5x}

%define b5x 1

%undefine b6x

%else

%define b6x 1

%undefine b5x

%endif

Здесь также может быть использован восклицательный знак для инверсии условия.

if ! %{old_5x}

%define b5x 1

%undefine b6x

%endif

Для комбинации нескольких тестов используется && :

%if %{old_5x} && %{old_6x}

%{error: You cannot build for .5x and .6x at the same time}

%quit

%endif

Далее - Встроенные макросы
Назад - Макросы определения переменных
Содержание


22.2.3 Встроенные макросы

Следующие макросы встроены в RPM и могут помочь разместить файлы в правильных локациях:

%_prefix /usr

%_exec_prefix %{_prefix}

%_bindir %{_exec_prefix}/bin

%_sbindir %{_exec_prefix}/sbin

%_libexecdir %{_exec_prefix}/libexec

%_datadir %{_prefix}/share

%_sysconfdir %{_prefix}/etc

%_sharedstatedir %{_prefix}/com

%_localstatedir %{_prefix}/var

%_libdir %{_exec_prefix}/lib

%_includedir %{_prefix}/include

%_oldincludedir /usr/include

%_infodir %{_prefix}/info

%_mandir %{_prefix}/man

Далее - Подготовка к сборке
Назад - Макросы условий
Содержание


22.3.1 Подготовка к сборке

Секция подготовки к сборке отвечает за начальную стадию сборки. Обычно содержит макрос %setup :

%prep

%setup -q

Далее - Сборка
Назад - Встроенные макросы
Содержание


22.3.2 Сборка

Секция сборки описывает подробности сборки приложения или библиотеки. В большинстве случаев последовательность инструкций содержится в Makefile, который обычно генерируется на стадии %prep.

Типичное содержимое секции таково:

%build

%configure

make

Далее - Установка
Назад - Подготовка к сборке
Содержание


22.3.3 Установка

После сборки работают команды из секции %install. Обычно здесь располагаются инструкции по очистке каталога сборки и команда или макрос make install:

%install
rm -rf %{buildroot}
%makeinstall

Далее - Очистка
Назад - Сборка
Содержание


22.3.4 Очистка

Обычно в секции очистки вызывается make clean, но может содержатся и просто команда на удаление каталога сборки:

%clean

rm -rf %{buildroot}

Далее - Скрипты стадий установки и удаления
Назад - Установка
Содержание


3.3 Удаление пакетов

Команда rpm хороша не только для установки ПО. Правильное удаление пакетов настолько же частая операция, нуждающаяся в автоматизации.

Для удаления пакетов используется опция -e. Основной синтаксис следующий:

# rpm e xcopilot

Используется имя файла без версии и постфиксов. Если установлено несколько версий одноименного пакета, а такое бывает, потребуется указать кандидата на удаление точнее:

# rpm e jikes-1.16-1

Для выполнения этих и других подобных действий необходимы права суперпользователя.

Команда удаления, так же как и команды установки, поддерживает опцию --test. Если от пакета зависит большое число установленного ПО, можно проверить, какие приложения и библиотеки утратят свою работоспособность:

# rpm e --test syslinux

error: Failed dependencies:

syslinux is needed by (installed) mkbootdisk-1.4.8-1

3.3.1 Был ли удален пакет?

Используя режим запросов, можно проверить, был ли пакет уже установлен. Но также можно проверить, был ли пакет удален. Например:

# rpm -q jikes

jikes-1.16-1

# rpm -e jikes-1.16-1

# rpm -q jikes

package jikes is not installed

3.3.2 Удаление списка пакетов одной командой

Можно удалить группу пакетов, сформировав список в командной строке:

rpm -e aspell-en-ca-0.33.7.1-16 aspell-en-gb-0.33.7.1-16


3.3.3 Опции, применимые для команд удаления

Опция --allmatches заставит rpm удалить все пакеты, имена которых содержат шаблон, заданный администратором в командной строке. Если более, чем один пакет соответствует шаблону, а опция не указана, работа будет завершена с сообщением об ошибке удаления.

Опция --nodeps позволяет удалить пакет даже в том случае, если в системе все еще есть зависящие от него пакеты. Использование этой и ей подобных опций может разрушить систему.

Опция --repackage позволит собрать удаляемые пакеты в rpm-пакет, который появится в директории для таких пакетов. По умолчанию это /var/spool/repackage. Пакет, построенный с помощью опции --repackage не является полноценным пакетом и его нельзя установить.

Подобно режиму установки для удаления можно использовать опции --noscripts и --notriggers. Помимо --noscripts также можно применить --nopreun и --nopostun. Соответственно, --nopreun отменяет выполнение скриптов перед удалением пакета, а --nopostun - скриптов, которые должны были отработать после удаления. Также сходным образом применяется опция --notriggers, или раздельно --notriggerun или --notriggerpostun.

Далее - Другие опции rpm
Назад - Установка пакетов с исходным кодом
Содержание


22.3.5 Скрипты стадий установки и удаления

Пакеты могут содержать скрипты, содержащие команды, которые должны быть выполнены после установки/удаления пакета или до его установки/удаления. Для каждого случая имеется специальная секция:

- для скриптов перед установкой: %pre;
- для скриптов после установки: %post;
- для скриптов перед удалением: %preun;
- для скриптов после удаления: %postun.

Например:

%post

/sbin/chkconfig --add ypbind

%preun

if [ "$1" = 0 ] ; then

/sbin/service ypbind stop > /dev/null 2>&1

/sbin/chkconfig --del ypbind

fi

exit 0

%postun

if [ "$1" -ge 1 ]; then

/sbin/service ypbind condrestart > /dev/null 2>&1

fi

exit 0

Далее - Файлы
Назад - Очистка
Содержание


22.4 Файлы

Секция %files содержит список файлов для установки. Например:

%files

%defattr(-,root,root)

/usr/X11R6/bin/xtoolwait

/usr/X11R6/man/man1/xtoolwait.*

Файлы документации и конфигурационные могут быть отмечены маркерами %doc и %config соответственно. Например:

%files

%defattr(-,root,root)

/sbin/ypbind

%{_mandir}/*/*

%config /etc/rc.d/init.d/*

%config /etc/yp.conf

%dir /var/yp

%dir /var/yp/binding

%doc README NEWS

Далее - Создание пакетов с переопределимыми путями
Назад - Скрипты стадий установки и удаления
Содержание


22.4.1 Создание пакетов с переопределимыми путями

Создать пакет с переопределимыми путями позволяет директива Prefix. Например:

Prefix: /usr

Prefix: /etc

Далее каждый файл в секции %files должен начинаться с одного из предоставленных префиксов. Такая конструкция пакета позволяет администратору установить файлы пакета по другим путям, используя возможности команды rpm:

# rpm --relocate /etc=/usr/etc file_name.rpm

Далее - Журнал изменений
Назад - Файлы
Содержание


22.5 Журнал изменений

Журнал изменений (Change Log) находится в конце spec-файла. Он содержит сообщения о каждом значительном изменении. Например:

%changelog
* Fri Jun 21 2002 Bob Marley
- automated rebuild
* Tue May 08 2001 Peter Tosh 1.3-1
- updated to 1.3

Далее - Раздел 23. Эволюция функциональности RPM
Назад - Создание пакетов с переопределимыми путями
Содержание


23 Эволюция функциональности RPM

Несмотря на то, что разные реализации RPM максимально совместимы между собой от версии к версии, сборщик пакетов должен иметь в виду, что RPM - развивающаяся система и разработчики добавляют функционал в каждую новую версию (кроме того, имеются форки сторонних разработчиков - прим. перев.). Когда собирается пакет, автор сборки должен принимать во внимание потенциальную аудиторию пользователей пакета. Какие версии RPM используют наши потребители? Среди этих версий необходимо выбрать "наименьший общий знаменатель" набора свойств системы, то есть использовать наиболее старую версию RPM. В качестве справочной информации, можно использовать сведения, приведенные в данной главе, касающиеся особенностей разных версий. Это руководство опирается на версию 4.1, главные же изменения в системе происходили в версиях RPM 2.5, 3.0.5, 4.0.4 и 4.1.
RPM 2.5 практически не используется, собирать под ней имеет смысл только в том случае, если пакет должен устанавливаться абсолютно из под всех версий системы.
RPM 3.0.5 - это финальный релиз серии 3.х. Этот релиз поставлялся с Red Hat 6.2. Он все еще используется некоторыми вендорами, например, Cobalt Linux.
RPM 4.0.4 использовался с выпусками Red Hat линейки 7.х, версия 4.1 - начиная с Red Hat 8.0.
RPM 2.5 поддерживает все основные функции, а также расширенные функции, такие как триггеры, интернационализация Summary:, Description:, и Group: в хэдере. Также эта версия была первой, в которой использовался формат файла RPM 3.
В RPM 2.5.3 добавлена поддержка тэга Epoch в хэдере пакета.
В RPM 2.5.4 добавлены типы %license и %readme для указания на файлы лицензии и README.
В RPM 2.5.6 включена поддержка директивы Epoch: в spec-файле. Она заменила Serial:, используя сходное поведение.
В RPM 2.5.7 была придана сила ранее введенному стандарту, касающемуся символа "-", который не должен использоваться в полях Version или Release в spec-файле.
В RPM 2.90 введена поддержка подписей и проверка пакетов с помощью технологии GPG.
В RPM 2.91 начинается использование Provides:, директивы, указывающей на абсолютные пути предоставляемых файлов. До этой версии Provides: предоставляла только списки предоставляемых возможностей без указания путей к файлам.
В RPM 3.0.2 стало возможным указывать множественные Provides:, это позволило отказаться от необходимости указывать предоставляемые возможности и имена файлов в одной строке.
RPM 3.0.3 предоставила возможность анализа зависимостей версий. До 3.0.3 в spec-файле можно было указывать зависимость от возможности или пакета, но без конкретной версии.
В RPM 3.0.4 добавлена поддержка CompressedFileNames. До этой версии RPM упаковывала абсолютные имена файлов всех архивов внутрь пакета. Хэдеры пакетов содержали определения, подобные этим:

fileName #0: /usr/bin/ar

fileName #1: /usr/bin/as

fileName #2: /usr/bin/gasp

fileName #3: /usr/bin/gprof

С началом поддержки CompressedFileNames хэдеры содержат только базовые имена файлов. Теперь в хэдерах имеются определения, как показано в примере ниже, то есть для заданного каталога - номера файлов:

dirName #0: /usr/bin

baseName dirIndex

#0 ar 0

#1 as 0

#2 gasp 0

#3 gprof 0

Каждая запись о файле теперь содержит базовое имя файла внутри заданного каталога, а также индекс номеров, каждый из которых ссылается на запись каталога. Такая технология хранения имен позволяет экономить значительное количество памяти при обработке rpm-файлов во время инсталляции.
В RPM 3.0.5 вводится поддержка компрессора bzip2. С этого момента можно использовать как архивы .tar.gz, так и архивы .tar.bz2. Несмотря на поддержку bzip2 на практике она используется сравнительно редко, так как bzip2 обладает более высокой степенью сжатия, но работает значительно медленнее и потребляет больше памяти. Кроме того, в RPM 3.0.5 начал поддерживаться формат файла RPM 4.
RPM 4.0 содержит некоторые весьма значительные изменения системы. Совершен переход на использование формата файлов RPM 4. БД RPM - вместо Berkeley db 1.85 используется Berkeley db 3.1. Изменилось имя файла БД. Изменение имени файла БД с /var/lib/rpm/packages.rpm на /var/lib/rpm/Packages позволило сосуществовать старой и новой базам вместе, если это необходимо, упрощая переход со старых релизов RPM к новым. Также была введена возможность PayloadFilesHavePrefix, эта особенность позволяет изменять путевые имена устанавливаемых файлов. С введением PayloadFilesHavePrefix все файлы в cpio-архиве имеют корневой префикс, например, ./usr/bin/ar. В этой версии RPM добавлена проверка синтаксиса spec-файла. Начиная с rpm 4.0 отпала необходимость в символьных ссылках, содержащих BuildRoot. Это сразу ликвидировало целый класс ошибок при сборке пакета. Наконец, в этой версии системы автоматически генерируются Provides: , поэтому нет необходимости заполнять эти поля в spec-файле.
В RPM 4.0.2 введено использование дайджеста SHA-1 для верификации различных областей хэдера.
RPM 4.0.3 добавляет директиву spec-файла %dev(type,major,minor), которая позволяет создавать файлы устройств в статическом варианте. Кроме того, %configure теперь поддерживает --target и host, облегчающие кросс-сборку. Директива %files дополнена субдирективой %exclude, позволяющей задать исключения из списков и шаблоны исключений. Наконец, в 4.0.3 формат файла пакета по умолчанию возвращен к версии 3, хотя версия 4 также поддерживается.
RPM 4.0.4 предоставляет поддержку PartialHardlinkSets. Иногда пакеты создаются с несколькими экземплярами одного файла, которые представлены жесткими ссылками для экономии места. До этой версии RPM обрабатывал коллекции жестких ссылок в идеологии "все-или-ничего"; или создавались все жесткие ссылки, или ни одной. Такое поведение может привести к проблемам, если некоторые ссылки относятся к файлам, помеченным атрибутами %doc или %lang. В определенных ситуациях rpm могла не установить ни одного файла, помеченного как %doc . PartialHardlinkSet исправляет эту проблему, вводя возможность создания подмножества коллекции жестких ссылок. Из интересных новшеств в RPM 4.0.4 также следует отметить возможность автоматической генерации Requires: для модулей Perl. Кроме того, с RPM 4.0.4 поддерживаются транзакции.
RPM 4.1 предоставляет подписи DSA и RSA отдельно для хэдера, что позволяет верифицировать собственно хэдер.

Итак, принимая во внимание особенности функционала RPM, необходимого в пакетах, которые вы собираете, следует иметь в виду, что некоторые особенности добавляются автоматически при сборке в зависимости от версии RPM, другие же указаны вручную в spec-файле. Например, использование директивы Requires: с конкретными версиями зависимостей возможно только начиная с версии 3.0.3. Подобно этому, релизы RPM версии 4.0 или более поздние генерируют такие rpm-пакеты, с которыми можно манипулировать лишь системами RPM, поддерживающими функционал PayloadFilesHavePrefix. В первом случае вы выбираете производство пакетов для работы с RPM версии 3.0.3 или свежее, но не с версией 2.5, во втором случае вы собираете пакеты, которые будут правильно пониматься лишь RPM версии 4.0 или более поздними.
Таким образом, наиболее верной практикой будет сборка пакетов в наиболее старой версии RPM из всех тех, которые вы собираетесь поддерживать.

Далее - Раздел 24. Формат файла rpm-пакета
Назад - Журнал изменений
Содержание


24.1 Файл пакета

Пакеты RPM поставляются в формате "один пакет - один rpm-файл". Все пакеты имеют следующий базовый формат, состоящий из четырех секций:

* Начальный идентификатор
* Подпись
* Хэдер пакета
* Полезная нагрузка в виде архива файлов для инсталляции

Все значения кодированы в сетевом порядке байт для поддержания возможности портирования на любую процессорную архитектуру.

Далее - Начальный идентификатор
Назад - Эволюция функциональности RPM
Содержание


24.1.1 Начальный идентификатор

Начальный идентификатор (rpmlead) - маркер в начале файла, магическая последовательность, которая указывает на тот факт, что данный файл является rpm-пакетом. Он также содержит версию RPM и информацию об архитектуре.
Первая часть начального идентификатора - магическое число. Утилита file считывает несколько первых байтов и сравнивает их с базой данных магических чисел, обычно /usr/share/magic или /etc/magic в некоторых Unix-системах. Эта технология позволяет утилите быстро определить тип файла.
Далее маркер содержит версию RPM, прямо указывающую на формат файла rpm-пакета.
Также имеется некий флаг, определяющий содержимое - бинарный пакет или пакет с исходниками.
Флаг процессорной архитектуры позволяет определить, не собираетесь ли вы установить пакет на несовместимую архитектуру.

Далее - Подпись
Назад - Файл пакета
Содержание


24.1.2 Подпись

Подпись располагается за начальным идентификатором. Она позволяет идентифицировать пакет, а также проверить его целостность. Подпись работает путем сравнения результата математического преобразования хэдера и нагрузки с данными в своих служебных полях. Математическими процессами могут служить криптоалгоритмы, либо хэш-функции.

Далее - Хэдер
Назад - Начальный идентификатор
Содержание


24.1.3 Хэдер

Секция хэдера включает три части:

* Запись хэдера
* Одну или несколько структур индекса хэдера
* Данные для структур индексов

Запись хэдера идентифицирует секцию, как хэдер rpm-пакета. Она также содержит число структур индексов и размер данных для структур индексов. Каждая запись индекса использует структуру, которая содержит номер поля данных, то есть идентификаторы для полей лицензии, имени пакета, версии и так далее. Тип идентификатора указывает на тип записи. Индикатор смещения курсора указывает, с какого смещения начинается данное поле. Счетчик хранит количество полей данного типа, которые имеются в хэдере.

Таблица ниже содержит идентификаторы типов полей.

Константа

Значение

Размер в байтах

RPM_NULL_TYPE

0

Не имеет размера

RPM_CHAR_TYPE

1

1

RPM_INT8_TYPE

2

1

RPM_INT16_TYPE

3

2

RPM_INT32_TYPE

4

4

RPM_INT64_TYPE

5

Пока не поддерживается

RPM_STRING_TYPE

6

Переменное количество байт, терминируется значением NULL

RPM_BIN_TYPE

7

1

RPM_STRING_ARRAY_TYPE

8

Переменный, вектор из строк, терминированных значением NULL

RPM_I18NSTRING_TYPE

9

Переменный, вектор из строк, терминированных значением NULL

Целые значения выровнены по двум байтам (16-битные целые) или по 4 байтам (32-битные целые).

Далее - Поля хэдера
Назад - Подпись
Содержание


24.1.3.1 Поля хэдера

Таблица ниже содержит идентификаторы полей

Константа

Значение

Тип

Обязательна ли для применения

RPMTAG_NAME

1000

STRING

Да

RPMTAG_VERSION

1001

STRING

Да

RPMTAG_RELEASE

1002

STRING

Да

RPMTAG_SUMMARY

1004

I18NSTRING

Да

RPMTAG_DESCRIPTION

1005

I18NSTRING

Да

RPMTAG_BUILDTIME

1006

INT32

Опционально

RPMTAG_BUILDHOST

1007

STRING

Опционально

RPMTAG_SIZE

1009

INT32

Да

RPMTAG_LICENSE

1014

STRING

Да

RPMTAG_GROUP

1016

I18NSTRING

Да

RPMTAG_OS

1021

STRING

Да

RPMTAG_ARCH

1022

STRING

Да

RPMTAG_SOURCERPM

1044

STRING

Опционально

RPMTAG_FILEVERIFYFLAGS

1045

INT32

Опционально

RPMTAG_ARCHIVESIZE

1046

INT32

Опционально

RPMTAG_RPMVERSION

1064

STRING

Опционально

RPMTAG_CHANGELOGTIME

1080

INT32

Опционально

RPMTAG_CHANGELOGNAME

1081

STRING_ARRAY

Опционально

RPMTAG_CHANGELOGTEXT

1082

STRING_ARRAY

Опционально

RPMTAG_COOKIE

1094

STRING

Опционально

RPMTAG_OPTFLAGS

1122

STRING

Опционально

RPMTAG_PAYLOADFORMAT

1124

STRING

Да

RPMTAG_PAYLOADCOMPRESSOR

1125

STRING

Да

RPMTAG_PAYLOADFLAGS

1126

STRING

Да

RPMTAG_RHNPLATFORM

1131

STRING

Утратила значение

RPMTAG_PLATFORM

1132

STRING

Опционально

Большая часть этих полей имеет самокомментирующее название, некоторые поля имеют специальное назначение. RPMTAG_SIZE хранит размер всех обычных файлов нагрузки. RPMTAG_ARCHIVESIZE хранит несжатый размер всей нагрузки, включая необходимые заголовки cpio. RPMTAG_COOKIE хранит скрытую строку.
В соответствии со стандартом LSB RPMTAG_PAYLOADFORMAT должен быть всегда cpio. RPMTAG_PAYLOADCOMPRESSOR должен быть gzip. RPMTAG_PAYLOADFLAGS должен быть всегда 9. RPMTAG_OPTFLAGS хранит специальные флаги компилятора, которые использовались при сборке пакета. RPMTAG_PLATFORM и RPMTAG_RHNPLATFORM хранят пустые строки.

Далее - Скрытые поля хэдера
Назад - Хэдер
Содержание


3.4 Другие опции rpm

Такие опции, как -v (многословный вывод) работают в большинстве режимов rpm, так же как и ее антипод, опция --quiet, подавляющая многословие.

Опция --rcfile позволяет задать файлы конфигурации rpm, отличные от конфигурации по умолчанию. В rc-файлах содержатся такие определения, как системная архитектура, операционная система, положение БД RPM, помимо множества других установок. Если надо задать несколько файлов конфигурации, поступают так:

# rpm i --rcfile file1:file2:file3 foo-0.1-1.i386.rpm

По умолчанию в ОС Red Hat Linux используется следующая группа rc-файлов: /usr/lib/rpm/rpmrc, /usr/lib/rpm/redhat/rpmrc, /etc/rpmrc, ~/.rpmrc.
Для просмотра всех установок, заданных в rc-файлах используется опция --showrc.

Опция --version выводит версию системы RPM.

Опция --pipe - полезная возможность перенаправить вывод rpm в другую программу. Синтаксис использования:

# rpm i --pipe имя_команды_для_захвата_вывода foo-0.1-1.i386.rpm

Далее - Раздел 4. Использование базы данных RPM
Назад - Удаление пакетов
Содержание


24.1.3.2 Скрытые поля хэдера

Таблица ниже показывает поля хэдера, которые рассматриваются как приватные.

Константа

Значение

Тип

Обязательна ли для применения

RPMTAG_HEADERSIGNATURES

62

BIN

Опционально

RPMTAG_HEADERIMMUTABLE

63

BIN

Опционально

RPMTAG_HEADERI18NTABLE

100

STRING_ARRAY

Да

RPMTAG_HEADERSIGNATURES указывает, что здесь имеется контейнер для подписи. RPMTAG_HEADERIMMUTABLE показывает поле, которое используется для подсчета подписей. Эти данные должны быть защищены. RPMTAG_HEADERI18NTABLE хранит таблицу локалей, которые будут использоваться для отображения интернационализированного текста.

Далее - Поля подписи
Назад - Поля хэдера
Содержание


24.1.3.3 Поля подписи

Хотя секция подписи реализована в виде структуры хэдера, по сути она не является частью хэдера.

В таблице ниже приведены поля, специализирующиеся на хранении информации о подписях.

Константа

Значение

Тип

Обязательна ли для использования

SIGTAG_SIGSIZE

1000

INT32

Да

SIGTAG_PGP

1002

BIN

Опционально

SIGTAG_MD5

1004

BIN

Да

SIGTAG_GPG

1005

BIN

Опционально

SIGTAG_PAYLOADSIZE

1007

INT32

Опционально

SIGTAG_SHA1HEADER

1010

STRING

Опционально

SIGTAG_DSAHEADER

1011

BIN

Опционально

SIGTAG_RSAHEADER

1012

BIN

Опционально

Поле SIGTAG_SIGSIZE задает размер секций хэдера и нагрузки, поле SIGTAG_PAYLOADSIZE хранит размер несжатой нагрузки.
Для проверки целостности пакета поле SIGTAG_MD5 хранит 128-битную контрольную сумму MD5 хэдера и нагрузки. SIGTAG_SHA1HEADER хранит контрольную сумму SHA1 всей секции хэдера.
Для проверки подлинности пакета SIGTAG_PGP хранит Version 3 OpenPGP подпись по алгоритму RSA хэдера и нагрузки. SIGTAG_GPG хранит Version 3 OpenPGP подпись по алгоритму DSA хэдера и нагрузки. SIGTAG_DSAHEADER хранит подпись по алгоритму DSA только хэдера. Если поле SIGTAG_DSAHEADER включено, SIGTAG_GPG также должен присутствовать. SIGTAG_ RSAHEADER хранит подпись по алгоритму RSA только хэдера. Если поле SIGTAG_ RSAHEADER включено, SIGTAG_PGP также должен присутствовать.

Далее - Поля для установочной информации
Назад - Скрытые поля хэдера
Содержание


24.1.3.4 Поля для установочной информации

Стек специфично инсталляционных полей говорит rpm, как обрабатывать пре- и пост- инсталляционные скрипты.

Константа

Значение

Тип

Обязательна ли для использования

RPMTAG_PREINPROG

1085

STRING

Опционально

RPMTAG_POSTINPROG

1086

STRING

Опционально

RPMTAG_PREUNPROG

1087

STRING

Опционально

RPMTAG_POSTUNPROG

1088

STRING

Опционально

RPMTAG_PREINPROG хранит имя интерпретатора прединсталляционного скрипта. Подобно этому RPMTAG_POSTINPROG содержит имя интерпретатора для запуска постинсталляционного скрипта. Поля RPMTAG_PREUNPROG и RPMTAG_POSTUNPROG выполняют те же функции для скриптов времени удаления пакета.

Далее - Поля для информации о файлах
Назад - Поля подписи
Содержание


24.1.3.5 Поля информации о файлах

Поля информации о файлах помещаются в хэдер для удобного к ним доступа. Эти поля описывают файлы из нагрузки.

Константа

Значение

Тип

Обязательна ли для использования

RPMTAG_OLDFILENAMES

1027

STRING_ARRAY

Опционально

RPMTAG_FILESIZES

1028

INT32

Да

RPMTAG_FILEMODES

1030

INT16

Да

RPMTAG_FILERDEVS

1033

INT16

Да

RPMTAG_FILEMTIMES

1034

INT32

Да

RPMTAG_FILEMD5S

1035

STRING_ARRAY

Да

RPMTAG_FILELINKTOS

1036

STRING_ARRAY

Да

RPMTAG_FILEFLAGS

1037

INT32

Да

RPMTAG_FILEUSERNAME

1039

STRING_ARRAY

Да

RPMTAG_FILEGROUPNAME

1040

STRING_ARRAY

Да

RPMTAG_FILEDEVICES

1095

INT32

Да

RPMTAG_FILEINODES

1096

INT32

Да

RPMTAG_FILELANGS

1097

STRING_ARRAY

Да

RPMTAG_DIRINDEXES

1116

INT32

Опционально

RPMTAG_BASENAMES

1117

STRING_ARRAY

Опционально

RPMTAG_DIRNAMES

1118

STRING_ARRAY

Опционально

RPMTAG_OLDFILENAMES, в том случае, если RPMTAG_REQUIRENAME не указывает на rpmlib(CompressedFileNames), используется, если имеют место несжатые файлы.
RPMTAG_FILESIZES задает размер всех файлов в нагрузке, в то время как RPMTAG_FILEMODES специфицирует права доступа. RPMTAG_FILEMTIMES хранит время последней модификации каждого файла.
RPMTAG_BASENAMES хранит массив базовых имен файлов в нагрузке, а RPMTAG_DIRNAMES - имена каталогов для этих файлов. RPMTAG_DIRINDEXES содержит индексы для каталогов из
RPMTAG_DIRNAMES.
Каждый rpm-пакет должен иметь или RPMTAG_OLDFILENAMES или триплет RPMTAG_BASENAMES, RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES, но не то и другое вместе.

Далее - Поля зависимостей
Назад - Поля для установочной информации
Содержание


24.1.3.6 Поля зависимостей

Поля зависимостей предоставляют наиболее существенный функционал системы, обеспечивающий автоматическую проверку зависимостей пакетов друг от друга.

Константа

Значение

Тип

Обязательна ли для использования

RPMTAG_PROVIDENAME

1047

STRING_ARRAY

Да

RPMTAG_REQUIREFLAGS

1048

INT32

Да

RPMTAG_REQUIRENAME

1049

STRING_ARRAY

Да

RPMTAG_REQUIREVERSION

1050

STRING_ARRAY

Да

RPMTAG_CONFLICTFLAGS

1053

INT32

Опционально

RPMTAG_CONFLICTNAME

1054

STRING_ARRAY

Опционально

RPMTAG_CONFLICTVERSION

1055

STRING_ARRAY

Опционально

RPMTAG_OBSOLETENAME

1090

STRING_ARRAY

Опционально

RPMTAG_PROVIDEFLAGS

1112

INT32

Да

RPMTAG_PROVIDEVERSION

1113

STRING_ARRAY

Да

RPMTAG_OBSOLETEFLAGS

1114

INT32

Опционально

RPMTAG_OBSOLETEVERSION

1115

INT32

Опционально

Каждое из этих полей существует в рамках триплетов, которые форматируются сходным образом. RPMTAG_REQUIRENAME содержит массив необходимых зависимостей. RPMTAG_REQUIREVERSION содержит массив версий необходимых зависимостей. RPMTAG_REQUIREFLAGS сводит информацию из двух предыдущих полей вместе, указывая битовые флаги, означающие, имеет ли указанный номер версии более младшую версию, равную версию, более старшую версию, чем зависимость.

Флаги показаны в таблице ниже.

Флаг

Значение

RPMSENSE_LESS

0x02

RPMSENSE_GREATER

0x04

RPMSENSE_EQUAL

0x08

RPMSENSE_PREREQ

0x40

RPMSENSE_INTERP

0x100

RPMSENSE_SCRIPT_PRE

0x200

RPMSENSE_SCRIPT_POST

0x400

RPMSENSE_SCRIPT_PREUN

0x800

RPMSENSE_SCRIPT_POSTUN

0x1000

RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION и RPMTAG_PROVIDEFLAGS относятся к предоставляемым пакетом возможностям.
RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION и RPMTAG_CONFLICTFLAGS определяют конфликты.
RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION и RPMTAG_OBSOLETEFLAGS определяют возможности, отменяемые данным пакетом.
Кроме того, в пакете могут быть определены некоторые специальные требования в полях RPMTAG_REQUIRENAME и RPMTAG_REQUIREVERSION.

Эти случаи показаны в таблице ниже.

Имя

Версия

Определяет особенность

Lsb

1.3

Этот пакет следует формату Linux Standards Base для пакетов RPM.

rpmlib(VersionedDependencies)

3.0.3-1

Пакет содержит зависимости или предварительные требования, которые имеют версии, ассоциированные с данным пакетом.

rpmlib(PayloadFilesHavePrefix)

4.0-1

Имена файлов содержат префикс “.” , предшествующий именам.

rpmlib(CompressedFileNames)

3.0.4-1

Пакет использует RPMTAG_DIRINDEXES,
RPMTAG_DIRNAME и RPMTAG_BASENAMES для определения имен файлов.

/bin/sh

NA

Определяет командный интерпретатор для запуска инсталляционных скриптов.

Далее - Нагрузка
Назад - Поля информации о файлах
Содержание


24.1.4 Нагрузка

Секция нагрузки, или архива, содержит файлы, используемые в данном пакете. Это файлы, которые команда rpm устанавливает во время установки пакета. Для экономии места данные в секции архива сжаты компрессором gzip. Расжатые данные представляют собой архив в формате cpio. Извлечь cpio-архив из пакета можно командой rpm2cpio. Структура архива представляет собой записи архива, по одной на каждый файл. Таблица ниже описывает структуру записи.

Элемент

Содержит

Заголовок cpio

Информация о файле, например права доступа

Имя файла

Строка переменной длины, терминированная символом NULL

"Распорка"

От 0 до 3 байт, если необходимо, для выравнивания следующего элемента по 4-байтному формату

Данный файла

Содержимое файла

"Распорка"

от 0 до 3 байт, если необходимо, для выравнивания следующей записи cpio-архива, то есть информации о следующем файле, по 4-х байтному формату

Информация в заголовке cpio дублирует информацию из хэдера rpm-файла.

Далее - Раздел 25. Ресурсы по RPM
Назад - Поля зависимостей
Содержание


25.1.1 Сайт rpm.org

Главный сайт по тематике RPM - www.rpm.org. Этот сайт предоставляет официальные дистрибутивы программного обеспечения RPM, а также много документации по теме.

Таблица ниже содержит ряд полезных ссылок в структуре этого сайта.

Ссылка

Указывает на

http://www.rpm.org/wiki/Download

Ссылки для загрузки программного обеспечения RPM

http://rpm.org/releases/historical/

Исторические релизы

http://www.rpm.org/wiki/Contribute

Как присоединиться к проекту и оказать ему посильную помощь

http://www.rpm.org/wiki/News

Новости RPM

http://www.rpm.org/wiki/RelatedSoftware

Море ПО вокруг RPM

http://www.rpm.org/wiki/Docs/RpmOrgFAQ

Часто задаваемые вопросы по RPM

http://www.rpm.org/wiki/Docs#Books

Книги и различные руководства по RPM

Далее - Сайты для поиска пакетов rpm
Назад - Нагрузка
Содержание


25.1.2 Сайты для поиска пакетов rpm

Ряд сайтов предложит вам помощь в поисках готовых rpm-пакетов различных приложений и библиотек. На основных сайтах этой тематики есть возможность найти сборки для конкретного дистрибутива Linux.

Сайт

Содержит

http://rpmfind.net

Ссылки на огромное количество пакетов для различных Линуксов и поисковую машину

http://rpm.pbone.net

Специализированный поисковик RPM PBone, удобен для расширенного поиска пакетов

http://rpmseek.com

Сайт для поиска rpm и deb-пакетов. Позволяет выполнять поиск по именам файлов, содержащихся в искомом пакете

http://jpackage.org

Программное обеспечение Java в формате пакетов RPM

http://plf.zarb.org

Фронт освобождения Пингвина. Пакеты, которые нельзя включать в Mandriva Free по лицензионным соображениям.

Далее - Сайты, посвященные утилитам RPM
Назад - Сайт rpm.org
Содержание


25.1.3 Сайты, посвященные утилитам RPM

Для работы с RPM существует множество сторонних утилит. Следующие ресурсы описывают наиболее интересные из них:

Инструмент

Сайт

apt4rpm

http://apt4rpm.sourceforge.net/

AutoRPM

www.autorpm.org

AutoUpdate

www.mat.univie.ac.at/~gerald/ftp/autoupdate

kpackage

www.kde.org

MakeRPM.pl

www.perl.com/CPAN/modules/by-authors/id/JWIED

rpm2html

http://rpmfind.net/linux/rpm2html/

rpmfind

http://rpmfind.net

RUST

www.rusthq.com

urpmi

http://wiki.mandriva.com/en/Tools/urpmi


Назад - Сайты для поиска пакетов rpm
Содержание


4.2.2 Группы пакетов

Пакеты в дистрибутиве могут быть собраны в группы. Группа пакетов - это произвольное наименование собрания пакетов, объединенных каким-либо функциональным признаком. Команда rpm qi, рассмотренная выше, выдает среди прочей информации имя группы, в которую входит пакет, если она была указана при сборке. Пакет tcsh, в частности, относится к группе System Environment/Shells.

Опция -g, следующая за -q, говорит утилите rpm вывести весь список пакетов указанной группы. Также можно использовать длинный вариант опции: --group . Базовый синтаксис такой:

rpm qg group_name

Например:

# rpm -qg "System Environment/Shells"

bash-2.05b-5

sh-utils-2.0.12-3

ash-0.3.8-5

tcsh-6.12-2

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

Далее - Список файлов пакета
Назад - Описание пакета
Содержание


4.1 Запросы к БД RPM

В предыдущих главах обсуждались основные режимы работы rpm. Одна опция переключает утилиту в определенный режим и множество подчиненных опций позволяют задать поведение утилиты в выбранном режиме.

Режим запросов выбирается опцией -q, или длинный вариант: --query. Этот режим расширяется огромным числом модификаторов запросов, позволяющих получить любую информацию о пакетах в Linux-системе.

Далее - Запросы о пакетах
Назад - Другие опции rpm
Содержание


4.2.3 Список файлов пакета

Опция -l (минус эль) запрашивает список всех файлов пакета. Также можно использовать длинный вариант: --list. Синтаксис:

rpm ql package

Например, для запроса файлов в пакете tcsh команда и вывод будут следующими:

# rpm -ql tcsh

/bin/csh

/bin/tcsh

/usr/share/doc/tcsh-6.10

/usr/share/doc/tcsh-6.10/FAQ

/usr/share/doc/tcsh-6.10/Fixes

/usr/share/doc/tcsh-6.10/NewThings

/usr/share/doc/tcsh-6.10/complete.tcsh

/usr/share/doc/tcsh-6.10/eight-bit.txt

/usr/share/doc/tcsh-6.10/tcsh.html

/usr/share/doc/tcsh-6.10/tcsh.html/header.html

/usr/share/doc/tcsh-6.10/tcsh.html/index.php

/usr/share/doc/tcsh-6.10/tcsh.html/lists.html

/usr/share/doc/tcsh-6.10/tcsh.html/tcsh.man

/usr/share/doc/tcsh-6.10/tcsh.html/tcsh.man2html

/usr/share/doc/tcsh-6.10/tcsh.html/top.html

/usr/share/locale/de/LC_MESSAGES/tcsh

/usr/share/locale/el/LC_MESSAGES/tcsh

/usr/share/locale/es/LC_MESSAGES/tcsh

/usr/share/locale/fr/LC_MESSAGES/tcsh

/usr/share/locale/it/LC_MESSAGES/tcsh

/usr/share/locale/ja/LC_MESSAGES/tcsh

/usr/share/man/man1/tcsh.1.gz

В команду с таким сочетанием опций можно передать более чем одно имя пакета, но тогда будет невозможно понять, какой файл относится к какому пакету. Для разделения списков используется опция --filesbypkg.

Если указана опция --filesbypkg, в начале каждой строки с именем файла будет указано имя пакета. Например:

# rpm -q --filesbypkg file openssh-clients

file /usr/bin/file

file /usr/share/magic

file /usr/share/magic.mgc

file /usr/share/magic.mime

file /usr/share/man/man1/file.1.gz

file /usr/share/man/man5/magic.5.gz

openssh-clients /etc/ssh/ssh_config

openssh-clients /usr/bin/sftp

openssh-clients /usr/bin/slogin

openssh-clients /usr/bin/ssh

openssh-clients /usr/bin/ssh-add

openssh-clients /usr/bin/ssh-agent

openssh-clients /usr/bin/ssh-keyscan

openssh-clients /usr/share/man/man1/sftp.1.gz

openssh-clients /usr/share/man/man1/slogin.1.gz

openssh-clients /usr/share/man/man1/ssh-add.1.gz

openssh-clients /usr/share/man/man1/ssh-agent.1.gz

openssh-clients /usr/share/man/man1/ssh-keyscan.1.gz

openssh-clients /usr/share/man/man1/ssh.1.gz

Эта опция используется без флага -l .

Опция -v позволит повысить информативность вывода информации о файлах. Например:

# rpm -qlv tcsh

lrwxrwxrwx 1 root root 4 Jun 24 2001 /bin/csh -> tcsh

-rwxr-xr-x 1 root root 288604 Jun 24 2001 /bin/tcsh

drwxr-xr-x 2 root root 0 Jun 24 2001 /usr/share/doc/tcsh-6.10

-rw-r--r-- 1 root root 8306 Aug 25 2000 /usr/share/doc/tcsh-6.10/FAQ

-rw-r--r-- 1 root root 64761 Nov 19 2000 /usr/share/doc/tcsh-6.10/Fixes

-rw-r--r-- 1 root root 6518 Oct 2 1998 /usr/share/doc/tcsh-6.10/NewThings

-rw-r--r-- 1 root root 41328 Nov 19 2000 /usr/share/doc/tcsh-6.10/complete.tcsh

-rw-r--r-- 1 root root 4668 Jun 24 2001 /usr/share/doc/tcsh-6.10/eight-bit.txt

drwxr-xr-x 2 root root 0 Jun 24 2001 /usr/share/doc/tcsh-6.10/tcsh.html

-rw-r--r-- 1 root root 124 Jun 24 2001 /usr/share/doc/tcsh-6.10/tcsh.html/header.html

lrwxrwxrwx 1 root root 8 Jun 24 2001 /usr/share/doc/tcsh-6.10/tcsh.html/index.php -> top.html

-rw-r--r-- 1 root root 911 Jun 24 2001 /usr/share/doc/tcsh-6.10/tcsh.html/lists.html

-rw-r--r-- 1 root root 0 Jun 24 2001 /usr/share/doc/tcsh-6.10/tcsh.html/tcsh.man

-rw-r--r-- 1 root root 22542 Jun 24 2001 /usr/share/doc/tcsh-6.10/tcsh.html
tcsh.man2html

-rw-r--r-- 1 root root 693 Jun 24 2001 /usr/share/doc/tcsh-6.10/tcsh.html/top.html

-rw-r--r-- 1 root root 45861 Jun 24 2001 /usr/share/locale/de/LC_MESSAGES/tcsh

-rw-r--r-- 1 root root 47566 Jun 24 2001 /usr/share/locale/el/LC_MESSAGES/tcsh

-rw-r--r-- 1 root root 47413 Jun 24 2001 /usr/share/locale/es/LC_MESSAGES/tcsh

-rw-r--r-- 1 root root 47156 Jun 24 2001 /usr/share/locale/fr/LC_MESSAGES/tcsh

-rw-r--r-- 1 root root 48264 Jun 24 2001 /usr/share/locale/it/LC_MESSAGES/tcsh

-rw-r--r-- 1 root root 18682 Jun 24 2001 /usr/share/locale/ja/LC_MESSAGES/tcsh

-rw-r--r-- 1 root root 62399 Jun 24 2001 /usr/share/man/man1/tcsh.1.gz

Вывод подобен выводу команды ls -l.

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

Далее - Список конфигурационных файлов пакета
Назад - Группы пакетов
Содержание


4.2.4 Список конфигурационных файлов пакета

Опция -c заставит rpm выводить только информацию о конфигурационных файлах пакета. Вместо -c можно использовать длинный вариант: --configfiles . Базовый синтаксис такой:

# rpm -qc bash

/etc/skel/.bash_logout

/etc/skel/.bash_profile

/etc/skel/.bashrc

Эта команда выводит список файлов конфигурации пакета bash.

Некоторые пакеты не имеют конфигурационных файлов, в этих случаях мы увидим следующее:

# rpm -qc python

#

В этом случае утилита rpm не выводит ничего. В других случаях можно получить весьма обширные списки, как например при запросе для пакета sendmail:

# rpm -qc sendmail

/etc/aliases

/etc/mail/Makefile

/etc/mail/access

/etc/mail/domaintable

/etc/mail/helpfile

/etc/mail/local-host-names

/etc/mail/mailertable

/etc/mail/sendmail.mc

/etc/mail/statistics

/etc/mail/trusted-users

/etc/mail/virtusertable

/etc/rc.d/init.d/sendmail

/etc/sendmail.cf

/etc/sysconfig/sendmail

/usr/lib/sasl/Sendmail.conf

Как в случае сочетания опций -lv, так и в случае -cv получим многословный вывод:

#rpm -qcv bash

-rw-r--r-- 1 root root 24 Jul 9 2001 /etc/skel/.bash_logout

-rw-r--r-- 1 root root 191 Jul 9 2001 /etc/skel/.bash_profile

-rw-r--r-- 1 root root 124 Jul 9 2001 /etc/skel/.bashrc

Далее - Список файлов документации
Назад - Список файлов пакета
Содержание


4.2.5 Список файлов документации пакета

Подобно опции -c, опция -d заставляет команду rpm -q вывести список файлов документации заданного пакета. Синтаксис:

rpm qd package_name

Например:

# rpm -qd tcsh

/usr/share/doc/tcsh-6.10/FAQ

/usr/share/doc/tcsh-6.10/Fixes

/usr/share/doc/tcsh-6.10/NewThings

/usr/share/doc/tcsh-6.10/complete.tcsh

/usr/share/doc/tcsh-6.10/eight-bit.txt

/usr/share/doc/tcsh-6.10/tcsh.html/header.html

/usr/share/doc/tcsh-6.10/tcsh.html/index.php

/usr/share/doc/tcsh-6.10/tcsh.html/lists.html

/usr/share/doc/tcsh-6.10/tcsh.html/tcsh.man

/usr/share/doc/tcsh-6.10/tcsh.html/tcsh.man2html

/usr/share/doc/tcsh-6.10/tcsh.html/top.html

/usr/share/man/man1/tcsh.1.gz

Можно добавить -v для получения более подробной информации о файлах.

Длинный вариант опции: --docfiles .

Далее - Список статуса файлов пакета
Назад - Список файлов конфигурации
Содержание


4.2.6 Список статуса файлов пакета

Сочетание опций -q и -s позволяет вывести статус каждого файла пакета. Синтаксис:

rpm qs package_name

Например:

# rpm -qs tcsh

normal /bin/csh

normal /bin/tcsh

normal /usr/share/doc/tcsh-6.10

normal /usr/share/doc/tcsh-6.10/FAQ

normal /usr/share/doc/tcsh-6.10/Fixes

normal /usr/share/doc/tcsh-6.10/NewThings

normal /usr/share/doc/tcsh-6.10/complete.tcsh

normal /usr/share/doc/tcsh-6.10/eight-bit.txt

normal /usr/share/doc/tcsh-6.10/tcsh.html

normal /usr/share/doc/tcsh-6.10/tcsh.html/header.html

normal /usr/share/doc/tcsh-6.10/tcsh.html/index.php

normal /usr/share/doc/tcsh-6.10/tcsh.html/lists.html

normal /usr/share/doc/tcsh-6.10/tcsh.html/tcsh.man

normal /usr/share/doc/tcsh-6.10/tcsh.html/tcsh.man2html

normal /usr/share/doc/tcsh-6.10/tcsh.html/top.html

not installed /usr/share/locale/de/LC_MESSAGES/tcsh

not installed /usr/share/locale/el/LC_MESSAGES/tcsh

not installed /usr/share/locale/es/LC_MESSAGES/tcsh

not installed /usr/share/locale/fr/LC_MESSAGES/tcsh

not installed /usr/share/locale/it/LC_MESSAGES/tcsh

not installed /usr/share/locale/ja/LC_MESSAGES/tcsh

normal /usr/share/man/man1/tcsh.1.gz

Вместо -s можно использовать также длинный вариант: --state .

Опцию -s можно комбинировать с другими ключами, например с -d для вывода статуса только файлов документации.

В таблице ниже показана классификация статусов, которые различает RPM.

Статус

Значение

normal

Файл был установлен

not installed

Файл не был установлен

replaced

Файл был заменен

Некоторые файлы могут исключаться из установки, если используются опции вроде --excludedocs. Это приводит к появлению у файлов статуса, отличного от normal. Кроме того, статус изменяется, если файлы были изменены после установки.

Далее - Список скриптов
Назад - Список файлов документации пакета
Содержание


4.2.7 Список скриптов

Пакет rpm может иметь в своей структуре скрипты, которые выполняются перед установкой, после установки, перед удалением, после удаления. Причем могут встречатся случаи, когда присутствует какой-либо один вид сценариев, несколько видов или все.

Опция --scripts позволяет вывести скрипты, ассоциированные с заданным пакетом. Базовый синтаксис:

rpm -q --scripts package_name

Например:

# rpm -q --scripts tcsh

postinstall scriptlet (through /bin/sh):

if [ ! -f /etc/shells ]; then

echo "/bin/tcsh" >> /etc/shells

echo "/bin/csh" >> /etc/shells

else

grep '^/bin/tcsh$' /etc/shells > /dev/null || echo "/bin/tcsh" >> /etc/shells

grep '^/bin/csh$' /etc/shells > /dev/null || echo "/bin/csh" >> /etc/shells

fi

postuninstall scriptlet (through /bin/sh):

if [ ! -x /bin/tcsh ]; then

grep -v '^/bin/tcsh$' /etc/shells | grep -v '^/bin/csh$'> /etc/shells.rpm

mv /etc/shells.rpm /etc/shells

fi

PRODUCTION: NOTE THE fi on a line by itself at the end of this listing. Thanks, -Eric

Некоторые пакеты могут иметь весьма сложные скрипты, как показано ниже:

# rpm -q --scripts sendmail

preinstall scriptlet (through /bin/sh):

/usr/sbin/useradd -u 47 -d /var/spool/mqueue -r -s /dev/null mailnull >/dev/null
2>&1 || :

postinstall scriptlet (through /bin/sh):

#

# Convert old format to new

#

if [ -f /etc/mail/deny ] ; then

cat /etc/mail/deny | \

awk 'BEGIN{ print "# Entries from obsoleted /etc/mail/deny"} \
{print $1" REJECT"}' >> /etc/mail/access

cp /etc/mail/deny /etc/mail/deny.rpmorig

fi

for oldfile in relay_allow ip_allow name_allow ; do

if [ -f /etc/mail/$oldfile ] ; then

cat /etc/mail/$oldfile | \

awk "BEGIN { print \"# Entries from obsoleted /etc/mail/$oldfile
\" ;} \

{ print \$1\" RELAY\" }" >> /etc/mail/access

cp /etc/mail/$oldfile /etc/mail/$oldfile.rpmorig

fi

done

#

# Oops, these files moved

#

if [ -f /etc/sendmail.cw ] ; then

cat /etc/sendmail.cw | \

awk 'BEGIN { print "# Entries from obsoleted /etc/sendmail.cw" ;} \
{ print $1 }' >> /etc/mail/local-host-names

cp /etc/sendmail.cw /etc/sendmail.cw.rpmorig

fi

#

# Rebuild maps (next reboot will rebuild also)

#

{ /usr/bin/newaliases

for map in virtusertable access domaintable mailertable

do

if [ -f /etc/mail/${map} ] ; then

/usr/bin/makemap hash /etc/mail/${map} < /etc/mail/${map}

sleep 1

fi

done

} > /dev/null 2>&1

/sbin/chkconfig --add sendmail

preuninstall scriptlet (through /bin/sh):

if [ $1 = 0 ]; then

/etc/rc.d/init.d/sendmail stop >/dev/null 2>&1

/sbin/chkconfig --del sendmail

fi

postuninstall scriptlet (through /bin/sh):

if [ "$1" -ge "1" ]; then

/etc/rc.d/init.d/sendmail condrestart >/dev/null 2>&1

fi

exit 0

В этом примере основной скрипт - постинсталляционный. Он конвертирует старый формат данных в новый, если это возможно, что помогает пользователю легко перейти на новый релиз ПО.

Далее - Список изменений
Назад - Список статуса файлов пакета
Содержание


4.2.8 Список изменений

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

Например, некий сетевой сервис был обновлен в плане исправления ошибок безопасности. Наверное, в этом случае вы захотите его обновить. Другие изменения, в том числе и функциональные, могут никак не влиять на вашу работу. Тогда администраторы часто руководствуются формулой "не ломай то, что работает".

Базовый формат команды:

rpm q --changelog package_name

В примере ниже показано начало журнала изменений (последние изменения в начале журнала). Адреса электронной почты изменены:

* Fri Aug 23 2002 Bob Marley <bob@marley.com.>

- re-bzip the docs, something was corrupted

* Thu Aug 22 2002 Peter Tosh <peter@tosh.com> 2.05b-4

- Fix history substitution modifiers in UTF-8 (bug #70294, bug #71186).

- Fix ADVANCE_CHAR at end of string (bug #70819).

- docs: CWRU/POSIX.NOTES no longer exists, but ship POSIX.

* Wed Aug 07 2002 Jimmy Cliff <jimmy@cliff.com> 2.05b-3

- Fixed out of memory problem with readline.

* Tue Jul 23 2002 Jimmy Cliff <jimmy@cliff.com> 2.05b-2

- Added symlink for sh.1 in man1 section so that man sh works (#44039)

Далее - Комбинирование запросов
Назад - Список скриптов
Содержание


4.2.9 Комбинирование запросов

Утилита rpm обладает большой гибкостью в отношении комбинирования опций запросов. Просто запустите команду rpm -q и добавляйте по потребности ключи -s, -d, -c, -v . В этой главе рассматриваются различные комбинированные запросы, которые могут быть полезны в реальной работе с пакетами.

4.2.9.1 Вывод описания пакета и файлов документации
Для получения информации о пакете и сведениях, как он документирован, используйте команду rpm -qdi :

# rpm -qdi grep

Name : grep Relocations: /usr

Version : 2.5.1 Vendor: Red Hat, Inc.

Release : 4 Build Date: Sat 20 Jul 2002 01:08:48 AM CDT

Install date: Sat 05 Oct 2002 12:21:58 PM CDT Build

Host: stripples.devel.redhat.com

Group : Applications/Text Source RPM: grep-2.5.1-4.src.rpm

Size : 475770 License: GPL

Signature : DSA/SHA1, Tue 03 Sep 2002 04:17:47 PM CDT, Key ID
219180cddb42a60e

Packager : Red Hat, Inc.

<http://bugzilla.redhat.com/bugzilla>

Summary : The GNU versions of grep pattern matching utilities.

Description :
The GNU versions of commonly used grep utilities. Grep searches
through textual input for lines which contain a match to a specified
pattern and then prints the matching lines. GNU's grep utilities
include grep, egrep, and fgrep.
You should install grep on your system, because it is a very useful utility for searching text.



/usr/share/doc/grep-2.5.1/ABOUT-NLS

/usr/share/doc/grep-2.5.1/AUTHORS

/usr/share/doc/grep-2.5.1/ChangeLog

/usr/share/doc/grep-2.5.1/NEWS

/usr/share/doc/grep-2.5.1/README

/usr/share/doc/grep-2.5.1/THANKS

/usr/share/doc/grep-2.5.1/TODO

/usr/share/info/grep.info-1.gz

/usr/share/info/grep.info-2.gz

/usr/share/info/grep.info-3.gz

/usr/share/info/grep.info.gz

/usr/share/man/man1/egrep.1.gz

/usr/share/man/man1/fgrep.1.gz

/usr/share/man/man1/grep.1.gz

Бывают ситуации, когда отследить документацию на пакет довольно сложно. Некоторые пакеты не имеют справки, кроме страниц man, другие содержат документы в формате info, третьи HTML-страницы, четвертые вовсе не документированы. Простая команда из примера выше поможет локализовать ваш случай.

4.2.9.2 Вывод статуса конфигурационных файлов
Для вывода статуса конфигурационных файлов какой-либо команды, используйте rpm -qcsf или -qcs если речь идет о пакете:

# rpm -qcsf /bin/bash

normal /etc/skel/.bash_logout

normal /etc/skel/.bash_profile

normal /etc/skel/.bashrc

4.2.9.3 Вывод списка пакетов, установленных последними
Для вывода списка пакетов, установленных последними используется опция --last. Эта опция полезна, если в результате последних установок пакетов возникли какие-то ошибки. Если затруднительно вспомнить имена пакетов, можно перенаправить вывод указанной команды на команду head:

# rpm -qa --last | head

comps-8.0-0.20020910 Sat 05 Oct 2002 01:17:30 PM CDT

tkinter-2.2.1-17 Sat 05 Oct 2002 01:16:58 PM CDT

tix-8.2.0b1-74 Sat 05 Oct 2002 01:16:52 PM CDT

tclx-8.3-74 Sat 05 Oct 2002 01:16:44 PM CDT

python-tools-2.2.1-17 Sat 05 Oct 2002 01:16:41 PM CDT

mx-2.0.3-6 Sat 05 Oct 2002 01:16:34 PM CDT

libxslt-python-1.0.19-1 Sat 05 Oct 2002 01:16:31 PM CDT

librpm404-devel-4.0.4-8x.27 Sat 05 Oct 2002 01:16:27 PM CDT

itcl-3.2-74 Sat 05 Oct 2002 01:16:12 PM CDT

gnumeric-1.0.9-2 Sat 05 Oct 2002 01:15:46 PM CDT

В данном примере выводится информация о последних десяти пакетах, установленных в систему. Освежив память, можно указать команде head выводить сведения о больше чем десяти пакетах, или наоборот, о меньшем количестве пакетов.

Далее - Создание пользовательских запросов
Назад - Список изменений
Содержание


4.2.10 Создание пользовательских запросов

Опция --qf (не путать с сочетанием первичных ключей -qf) или --queryformat в длинном варианте позволяет создавать запросы собственных конструкций любой сложности, хотя этот путь сравнительно более сложен, чем использование атомарных опций. Для создания запроса опции --qf необходимо передать форматную строку, синтаксис которой сходен с C-функцией printf. Базовый синтаксис формата запроса:

%{tag_name}

Можно комбинировать имена полей (тегов) для вывода более чем одного значения поля для указанного пакета. Также можно добавлять опции форматирования в соответствии с соглашениями C.

Например, для вывода имен всех пакетов используется команда, подобная указанной ниже:

# rpm -qa --qf "%{NAME}"
redhat-menusglibccracklibgdbmgmplibacllibjpeglincpcreshadow-
utilslibtermcapfreetypeinfofileutilspsmiscntpmountcracklib-dictskrb5-libscyrus-saslusermodeXftlibpnglibxmllibbonobopythonpygtk2pyxf86configredhat-config-usersredhat-config-keyboardrpm404-pythongnome-vfs2libgnomeuiashbind-utilscyrus-
sasl-plaindos2unixethtoolfingergroffautofskbdconfiglesslibtool-
libslockdevmailcapMAKEDEVmouseconfignetpbmntsysvORBitpartedppppsutilsrdaterhnlibrp
mrshsetuptoolstatserialtarlilopciutilstimeconfigunzipkernel-pcmcia-
csanacronXFree86

В этой команде использовался наиболее простой формат и запрашивались только имена пакетов. Для форматирования вывода необходимо добавить символ новой строки после каждого имени в конце форматной строки:

# rpm -qa --qf "%{NAME}\n"

redhat-menus

glibc

cracklib

gdbm

gmp

libacl

libjpeg

linc

pcre

shadow-utils

libtermcap

freetype

info

fileutils

psmisc

ntp

mount

cracklib-dicts

krb5-libs

cyrus-sasl

usermode

Xft

Для экономии места почти весь вывод опущен. Данная команда выводит то же, что и команда rpm -qa, поэтому взята лишь для примера, как конструируются пользовательские запросы.

В примере ниже показывается, как для каждого запрашиваемого пакета вывести имя и платформу (показано только несколько строк вывода, на каждое поле выделяется 20 символов):

# rpm -qa --qf "%-20{NAME} %-20{PLATFORM}\n"

redhat-menus noarch-redhat-linux-gnu

glibc i686-redhat-linux-gnu

cracklib i386-redhat-linux

gdbm i386-redhat-linux-gnu

gmp i386-redhat-linux-gnu

libacl i386-redhat-linux-gnu

libjpeg i386-redhat-linux

linc i386-redhat-linux-gnu

pcre i386-redhat-linux

shadow-utils i386-redhat-linux-gnu

libtermcap i386-redhat-linux

freetype i386-redhat-linux-gnu

info i386-redhat-linux-gnu

fileutils i386-redhat-linux-gnu

psmisc i386-redhat-linux

ntp i386-redhat-linux-gnu

mount i386-redhat-linux-gnu

cracklib-dicts i386-redhat-linux

krb5-libs i386-redhat-linux-gnu

cyrus-sasl i386-redhat-linux-gnu

usermode i386-redhat-linux-gnu

Xft i386-redhat-linux-gnu

4.2.10.1 Работа с полями формата запроса
Для построения запроса с помощью опции --queryformat необходимо знать, какие имена полей нам доступны в принципе. Для вывода списка имен доступных тегов используется опция --querytags. В примере ниже показано только несколько строк вывода:

# rpm --querytags

NAME

VERSION

RELEASE

SUMMARY

DESCRIPTION

BUILDTIME

Каждый из этих тегов имеет также вариант с префиксом, например, RPMTAG_NAME. Вы можете использовать имена полей как с префиксом, так и без оного.

$ rpm -q --qf "%{RPMTAG_NAME}\n" sendmail

sendmail

Эта команда использует опцию -q для запроса одного пакета вместо -qa (для запроса всех пакетов).

4.2.10.2 Запрос информации о пакете
Множество тегов отвечают за информацию о пакете, которая хранится в хэдере пакета. Таблица ниже содержит список таких полей.

Поле

Содержит

NAME

Имя пакета

VERSION

Номер версии

RELEASE

Номер релиза

SUMMARY

Однострочный коментарий содержимого пакета

DESCRIPTION

Текст описания пакета (многострочный)

BUILDTIME

Время создания пакета

BUILDHOST

Хост, на котором собран пакет

SIZE

Размер всех обычных файлов в нагрузке

LICENSE

Лицензия, под которой выпущен пакет

GROUP

Группа или категория пакета

OS

Операционная система, под которой пакет собирался

ARCH

Процессорная архитектура, например i386

SOURCERPM

Пакет с исходным кодом из которого собирался бинарный пакет

CHANGELOGTIME

Массив времен изменений журнала

CHANGELOGNAME

Массив имен записей журнала

CHANGELOGTEXT

Массив содержимого записей журнала

PREIN

Скрипт перед установкой

POSTIN

Скрипт после установки

PREUN

Скрипт перед удалением

POSTUN

Скрипт после удаления

PLATFORM

Платформа

Все поля, за исключением CHANGELOGTIME, CHANGELOGTEXT и CHANGELOGNAME, это поля, имеющие одно значение. Запросы многозначных полей осуществляются с помощью форматирования массивов.

4.2.10.3 Форматирование массивов
Некоторые записи хэдера представляют собой массивы, то есть содержат более чем одно значение. Для задания запроса каждой записи в массиве используются квадратные скобки. Например:

$ rpm -q --queryformat "[%-50{FILENAMES} %{FILESIZES}\n]" sendmail
/etc/aliases 1295

/etc/aliases.db 12288

/etc/mail 4096

/etc/mail/Makefile 748

/etc/mail/access 331

/etc/mail/access.db 12288

/etc/mail/domaintable 0

/etc/mail/domaintable.db 12288

/etc/mail/helpfile 5588

/etc/mail/local-host-names 64

Этот пример выводит файлы и размеры файлов пакета sendmail (вывод сокращен для экономии места).

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

$ rpm -q --queryformat "[%-15{=NAME} %-50{FILENAMES}\n]" sendmail jikes

sendmail /usr/lib/sendmail

sendmail /usr/sbin/mailstats

sendmail /usr/sbin/makemap

sendmail /usr/sbin/praliases

sendmail /usr/sbin/sendmail.sendmail

sendmail /usr/sbin/smrsh

sendmail /usr/share/man/man1/mailq.sendmail.1.gz

sendmail /usr/share/man/man1/newaliases.sendmail.1.gz

sendmail /usr/share/man/man5/aliases.sendmail.5.gz

sendmail /usr/share/man/man8/mailstats.8.gz

sendmail /usr/share/man/man8/makemap.8.gz

sendmail /usr/share/man/man8/praliases.8.gz

sendmail /usr/share/man/man8/rmail.8.gz

sendmail /usr/share/man/man8/sendmail.8.gz

sendmail /usr/share/man/man8/smrsh.8.gz

sendmail /var/spool/clientmqueue

sendmail /var/spool/mqueue

jikes /usr/bin/jikes

jikes /usr/doc/jikes-1.18/license.htm

jikes /usr/man/man1/jikes.1.gz

В этом примере за именем пакета следуют имена файлов пакета.

4.2.10.4 Специальные форматы
Некоторые поля содержат специальную информацию в бинарном виде, которую не имеет смысла выводить в том виде, в каком она есть. Для обработки подобных случаев используется такой синтаксис:

%{tag:special_format}

Например, для вывода INSTALLTIME применяется %{INSTALLTIME:date}, спецификация для вывода значения времени в формате date. Например:

$ rpm -q --qf "%{NAME}-%{VERSION}-%{RELEASE} %{INSTALLTIME:date}\n" jikes

jikes-1.18-1 Fri 06 Dec 2002 09:19:30 PM CST

Этот пример выводит Имя-Версию-Релиз вместе с датой установки.

Большая часть тегов в хэдере является опциональной. Можно выводить их значения, но если тег не задан, команда не выведет ничего. Для обработки этого случая можно использовать условный оператор, базирующийся на синтаксисе C:

%|tag?{print_if_present}:{print_if_absent}|

Если использовать обычный синтаксис %{tag}, этот условный синтаксис будет очень быстро усложняться. Следует разделять элементы. Например:

$ rpm -q --qf "%{NAME} %|EPOCH?{%{EPOCH}}:{(no Epoch)}|\n" perl
perl 1

Если пакет имеет не пустое поле EPOCH, мы увидим вывод как в примере. Большая часть пакетов не имеет этого поля. В случае, когда EPOCH не определено, мы увидим пустой вывод perl (no Epoch).

4.2.10.5 Запрос зависимостей пакета
Ряд тегов отвечает за информацию о зависимостях пакета. Каждый из этих тегов существует в рамках триплетов, которые форматируются сходным образом. Например, для возможностей, которые требует пакет, имеются поля REQUIRENAME, REQUIREVERSION и REQUIREFLAGS.
REQUIRENAME хранит имя требуемой возможности, REQUIREVERSION - массив подходящих версий, REQUIREFLAGS соединяет значения двух предыдущих полей на основании битовых флагов, которые задают статус зависимости в терминах "имеющаяся версия больше нужной", "имеющаяся версия равна нужной", "имеющаяся версия меньше нужной".

В таблице ниже перечислены теги зависимостей.

Поле

Содержит

CONFLICTFLAGS

Массив флагов для возможностей, с которыми пакет конфликтует

CONFLICTNAME

Массив имен возможностей, с которыми пакет конфликтует

CONFLICTVERSION

Массив номеров версий возможностей, с которыми пакет конфликтует

REQUIREFLAGS

Массив флагов возможностей, в которых пакет нуждается

REQUIRENAME

Массив имен возможностей, в которых пакет нуждается

REQUIREVERSION

Массив номеров версий возможностей, в котрых пакет нуждается

OBSOLETENAME

Массив имен возможностей, которые пакет делает неактуальными

OBSOLETEFLAGS

Массив флагов возможностей, которые пакет делает неактуальными

OBSOLETEVERSION

Массив номеров версий возможностей, которые пакет делает неактуальными

PROVIDENAME

Массив имен возможностей, которые пакет предоставляет

PROVIDEFLAGS

Массив флагов возможностей, которые пакет предоставляет

PROVIDEVERSION

Массив номеров версий возможностей, которые пакет предоставляет

Каждый из этих тегов - массив. Специальная опция форматирования флагов depflags представляет бинарные флаги в удобочитаемом формате. Например, следующая команда выводит зависимости пакета:

$ rpm -q --qf \
"[%{REQUIRENAME} %{REQUIREFLAGS:depflags} %{REQUIREVERSION}\n]" sendmail

rpmlib(VersionedDependencies) <= 3.0.3-1

chkconfig >= 1.3

/usr/sbin/useradd

/bin/mktemp

fileutils

gawk

sed

sh-utils

procmail

bash >= 2.0

/bin/sh

rpmlib(PayloadFilesHavePrefix) <= 4.0-1

rpmlib(CompressedFileNames) <= 3.0.4-1

Для тех зависимостей, которые имеют конкретную версию, эта команда выведет номер версии, предшествуемый оператором сравнения. Обратите внимание, что многие зависимости не имеют специфических требований по версии.

Кроме обычных зависимостей пакеты также могут зависеть от специфической версии RPM, поскольку зависят от какой-либо специфической возможности, например, rpmlib, предоставляющей CompressedFileNames.

4.2.10.6 Запрос информации о файлах
Поля данных о файлах содержат информацию, касающуюся файлов нагрузки, то есть тех файлов, которые будут установлены в систему. Это массивы, содержащие по одному значению на файл.

Поле

Содержит

OLDFILENAMES

Массив полных имен файлов, использовавшихся в старых версиях пакета

FILESIZES

Массив размеров файлов

FILEMODES

Массив прав доступа на каждый файл

FILERDEVS

Массив значений rdev на каждый файл

FILEMTIMES

Массив времени последнего изменения каждого файла

FILEMD5S

Даджест MD5 для каждого файла

FILELINKTOS

Массив информации о ссылках для каждого файла

FILEFLAGS

Массив флагов для каждого файла

FILEUSERNAME

Массив имен владельцев каждого файла

FILEGROUPNAME

Массив имен групп владельцев каждого файла

FILEDEVICES

Массив устройств каждого файла

FILEINODES

Массив индексных дескрипторов каждого файла

FILELANGS

Массив флагов языка каждого файла

DIRINDEXES

Массив индексов каталогов каждого файла (ассоциируют DIRNAMES и BASENBAMES)

BASENAMES

Массив базовых имен

DIRNAMES

Массив каталогов, которые ассоциируются с BASENAMES

OLDFILENAMES, в том случае, если REQUIRENAME не указывает на rpmlib(CompressedFileNames), используется, если имеют место несжатые файлы.
FILESIZES задает размер всех файлов в нагрузке, в то время как FILEMODES специфицирует права доступа. FILEMTIMES хранит время последней модификации каждого файла.
BASENAMES хранит массив базовых имен файлов в нагрузке, а DIRNAMES - имена каталогов для этих файлов. DIRINDEXES содержит индексы для каталогов из DIRNAMES.
Каждый rpm-пакет должен иметь или OLDFILENAMES или триплет BASENAMES, DIRNAMES, DIRINDEXES, но не то и другое вместе.

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

Поле

Содержит

ARCHIVESIZE

Размер несжатой секции нагрузки

COOKIE

Скрытая строка специального назначения

RPMVERSION

Версия RPM, с помощью которой пакет был собран

OPTFLAGS

Флаги оптимизации компилятора при сборке пакета

PAYLOADFORMAT

Must be cpio for LSB-compliant packages

PAYLOADCOMPRESSOR

Для совместимости с LSB всегда имеет значение gzip

PAYLOADFLAGS

Для совметсимости с LSB должно иметь значение 9

RHNPLATFORM

Скрытая строка специального назначения

FILEVERIFYFLAGS

Битовая маска, указывающая, какие тесты должны проводится для проверки файлов после установки

С помощью этих тегов можно, например, запросить, с помощью каких версий RPM создавались пакеты:

$ rpm -qp --qf "%{name} - rpm %{rpmversion}\n" *.rpm

acroread - rpm 2.5.5

canvas - rpm 3.0.3

jikes - rpm 4.0.2

SDL - rpm 2.5.1

ted - rpm 2.5.5

-p указывает на файлы rpm-пакетов в текущем каталоге, а не на установленные пакеты.

Далее - Прочие запросы
Назад - Комбинирование запросов
Содержание


4.2.11 Прочие запросы

Если все, что вы увидели в предыдущих примерах, еще далеко от требуемой полноты картины, существует ряд расширенных запросов. Эти ключи используются в основном разработчиками Red Hat.

Опция

Означает

--dump

Выдать дамп расширенной информации о файлах

--fileid md5_id

Запрос пакета с заданным значением дайджеста MD5

--hdrid sha1_header_id

Запрос пакета с заданным идентификатором хэдера в формате SHA1

--last

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

--pkgid md5_id

Запрос пакета с заданным идентификатором пакета в формате MD5 ID

--querybynumber number

Запрос записи БД с заданным номером

--tid transaction_id

Запрос пакета (пакетов) с заданным идентификатором транзакции

Далее - Получение информации из файла rpm-пакета
Назад - Создание пользовательских запросов
Содержание


4.3 Получение информации из файла rpm-пакета

Кроме возможностей, которые предоставляет обращение к БД RPM для получения информации об установленных пакетах, утилита rpm может извлекать сведения непосредственно из файла rpm-пакета. Эта возможность полезна, например, в случаях, когда нужно определить, стоит ли устанавливать данный пакет, или нет. Также она помогает, когда имя пакета ничего не говорит о его функциональности (kudzu, anaconda или dia).

Опция -p говорит утилите rpm извлечь информацию из файла rpm-пакета. Базовый синтаксис:

rpm qp option_query_options filename.rpm

где filename.rpm - достижимое имя, в общем случае полный путь к файлу. В качестве длинного варианта опции используется --package. Кроме того, такой команде можно передать более чем одно имя файла.

Все команды, использовавшиеся в примерах предыдущих глав, также будут работать для файлов rpm-пакетов. Например, для вывода списка конфигурационных файлов следует скомбинировать опции -q, -p и -c :

# rpm -qpc telnet-server-0.17-23.i386.rpm

/etc/xinetd.d/telnet

Для вывода списка файлов пакета используйте сочетание -q, -p и -l :

# rpm -qpl telnet-server-0.17-23.i386.rpm

/etc/xinetd.d/telnet

/usr/sbin/in.telnetd

/usr/share/man/man5/issue.net.5.gz

/usr/share/man/man8/in.telnetd.8.gz

/usr/share/man/man8/telnetd.8.gz

К файлам rpm-пакетов можно получить доступ по сети. Запросы к удаленным файлам подчиняются тем же правилам, что и другие команды. Например:

rpm -qp ftp://username:password@hostname:port/path/to/rpm/file

rpm -qp ftp://username@hostname:port/path/to/rpm/file

rpm -qp ftp://hostname:port/path/to/rpm/file

rpm -qp http://hostname:port/path/to/rpm/file

Если система расположена за прокси-сервером, используются опции, показанные в таблице ниже:

Опция

Означает

--ftpproxy proxy_hostname

Именует прокси-систему для трафика FTP

--ftpport proxy_port_number

Указывает порт на FTP прокси-сервере

--httpproxy proxy_hostname

Именует прокси-систему для трафика HTTP

--httpport proxy_port_number

Указывает порт на HTTP прокси-сервере

Далее - Верификация установленных пакетов
Назад - Прочие запросы
Содержание


4.1.1 Запросы о пакетах

Основной формат запроса приведен в примере:

$ rpm -q telnet-0.17

telnet-0.17-20

Если запрашиваемый пакет установлен, вернется имя пакета с версией и номером сборки. Если пакет не установлен, вернется сообщение:

$ rpm -q telnet-0.17

package telnet-0.17 is not installed

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

Также в командной строке запроса может присутствовать не одно имя пакета, а несколько, введенные через пробелы.

4.1.2 Запросить всё

Чтобы получить информацию обо всех пакетах, достаточно ввести:

$ rpm -qa

или лучше:

$ rpm -qa | less

Далее - Как повысить информативность запроса
Назад - Запросы к БД RPM
Содержание


4.4 Верификация установленных пакетов

Кроме запросов к установленным пакетам RPM позволяет оценить целостность системы и каждого пакета в отдельности с помощью режима верификации. Режим включается опцией -V или ее длинным аналогом --verify . Базовый синтаксис:

rpm -V verify_options package_name

Например:

#rpm -V telnet

#

Если все в порядке, не выводится никаких сообщений, так как режим rpm -V выводит только сообщения об ошибках. Например, если установленный в систему пакет telnet имеет некоторые поврежденные файлы, режим верификации даст об этом знать например таким образом:

# rpm -V telnet-server

missing c /etc/xinetd.d/telnet

missing /usr/sbin/in.telnetd

missing d /usr/share/man/man5/issue.net.5.gz

В данном примере -c и -d относятся к файлам конфигурации и файлам документации соответственно.

Кроме состояния пакетов rpm -V умеет также находить нарушенные зависимости.

Далее - Верификация системы в целом
Назад - Получение информации из файла rpm-пакета
Содержание


4.4.1 Верификация системы в целом

Для проверки всей системы используется опция -a . Например:

# rpm -Va

SM5....T c /usr/share/info/dir

.......T c /etc/krb5.conf

.......T /usr/share/pixmaps/gnome-default-dlg.png

.......T /usr/share/pixmaps/gnome-error.png

.......T /usr/share/pixmaps/gnome-info.png

.......T /usr/share/pixmaps/gnome-question.png

.......T /usr/share/pixmaps/gnome-warning.png

S.5....T c /etc/sysconfig/pcmcia

.....U.. /dev/winradio0

Каждая строка вывода указывает на проблему с указанным файлом. Символы S, 5, T и тому подобные говорят о характере проблемы. Буквенные коды ошибок приводятся в таблице ниже.

Кодовый символ

Означает

S

Изменился размер файла

M

Изменились атрибуты доступа файла

5

Изменилась контрольная сумма MD5 файла

D

Старший и младший номер файла устройства изменились

L

Ошибка ссылки

U

Изменился владелец файла

G

Изменилась группа файла

T

Время создания или время последней модификации файла изменились

Далее - Настройка проверок
Назад - Верификация установленных пакетов
Содержание


4.4.2 Настройка проверок

Ряд опций режима верификации используется для отключения некоторых проверок или для задания только нужных проверок. Таблица ниже описывает эти опции.

Опция

Использование

--nodeps

Не проверять зависимости

--nodigest

Не проверять дайджесты пакета и хэдера

--nofiles

Не проверять атрибуты файлов

--noscripts

Не проверять скрипты

--nosignature

Не проверять подписи пакета и хэдера

--nolinkto

Не проверять атрибуты файлов-ссылок

--nomd5

Не проверять дайджесты MD5 файлов

--nosize

Не проверять размеры файлов

--nouser

Не проверять владельцев файлов

--nogroup

Не проверять группы файлов

--nomtime

Не проверять время последней модификации файлов

--nomode

Не проверять права доступа

--nordev

Не проверять атрибуты rdev

-a

Проверить все пакеты

-g group

Проверить все пакеты в заданной группе

-p file

Проверить файл rpm-пакета

Далее - Работа с БД RPM
Назад - Верификация системы в целом
Содержание


4.5 Работа с БД RPM

Как правило база данных установленных пакетов хранится в /var/lib/rpm. Файлы в этом каталоге - это файлы СУБД Berkeley DB, в чем можно убедится с помощью команды file:

# file /var/lib/rpm/*

/var/lib/rpm/Basenames: Berkeley DB (Hash, version 7, native byte-order)

/var/lib/rpm/Conflictname: Berkeley DB (Hash, version 7, native byte-order)

/var/lib/rpm/__db.001: data

/var/lib/rpm/__db.002: X11 SNF font data, LSB first

/var/lib/rpm/__db.003: X11 SNF font data, LSB first

/var/lib/rpm/Dirnames: Berkeley DB (Btree, version 8, native byte-order)

/var/lib/rpm/Filemd5s: Berkeley DB (Btree, version 8, native byte-order)

/var/lib/rpm/Group: Berkeley DB (Hash, version 7, native byte-order)

/var/lib/rpm/Installtid: Berkeley DB (Btree, version 8, native byte-order)

/var/lib/rpm/Name: Berkeley DB (Hash, version 7, native byte-order)

/var/lib/rpm/Packages: Berkeley DB (Hash, version 7, native byte-order)

/var/lib/rpm/Providename: Berkeley DB (Hash, version 7, native byte-order)

/var/lib/rpm/Provideversion: Berkeley DB (Btree, version 8, native byte-order)

/var/lib/rpm/Requirename: Berkeley DB (Hash, version 7, native byte-order)

/var/lib/rpm/Requireversion: Berkeley DB (Btree, version 8, native byte-order)

/var/lib/rpm/Sha1header: Berkeley DB (Btree, version 8, native byte-order)

/var/lib/rpm/Sigmd5: Berkeley DB (Btree, version 8, native byte-order)

/var/lib/rpm/Triggername: Berkeley DB (Hash, version 7, native byte-order)

Каждый файл является базой данных в формате Berkeley DB за исключением файлов __db. Строки типа "/var/lib/rpm/__db.002: X11 SNF font data, LSB first" следует отнести к ограниченности функционала команды file, так как файлы __db.00x конечно не являются файлами шрифтов.

По сути дела БД RPM - это набор баз данных Berkeley DB, каждая для своего типа запроса. Поскольку эти файлы представляют собой хэш-таблицы в формате имя-значение, они работают очень быстро при поиске по имени записи, хотя и не слишком быстро при полном переборе записей.

Если что-то идет не так с БД RPM, следует в первую очередь попытаться перестроить или переинициализировать ее, для чего существует специальные режимы rpm. Однако изначально полезно иметь резервную копию БД.

Далее - Создание резервной копии БД RPM
Назад - Настройка проверок
Содержание


4.5.1 Создание резервной копии БД RPM

Для создания резервной копии БД RPM следует создать копию каталога /var/lib/rpm, например с помощью следующих команд:

# cd /var/lib

# tar cvfz rpmdb.tgz ./rpm

Сжатый архив подкаталога rpm каталога /var/lib позволит позднее восстановить содержимое при необходимости.

Далее - Перестройка БД RPM
Назад - Работа с БД RPM
Содержание


4.5.2 Перестройка БД RPM

Если каким-либо образом целостность БД нарушится, вы можете ее перестроить с помощью опции --rebuilddb утилиты rpm:

#rpm --rebuilddb

Эта команда пересоздаст нужные файлы БД из текстового файла-описателя установленных пакетов - Packages. Если БД RPM в порядке, команда перестройки БД не будет выполнять все операции, только удалит неиспользуемые записи, экономя место на диске.

Для проверки работы команды перестройки базы можно предложить следующую последовательность операций: запрос всех пакетов с помощью rpm -qa, создание резервной копии БД, запуск rpm --rebuilddb, новое выполнение rpm -qa, сравнение списков, полученных в первый и второй раз.

Еще одна возможность - использование команд db_dump и db_load для резервирования и восстановления файла Packages. Последовательность резервирования и восстановления Packages поможет устранить ошибки в таблицах, если таковые имелись. Перед выполнением этих операций также рекомендуется создать резервную копию БД.

Далее - Создание новой БД RPM
Назад - Создание резервной копии БД RPM
Содержание


4.5.3 Создание новой БД RPM

Если все вышеописанные меры по исправлению БД RPM не срабатывают, используйте опцию --initdb, которая создает новую пустую БД. Как правило, эта мера нехороша в силу того, что новая пустая БД не содержит информации об уже установленных пакетах, что приводит к массе проблем. Базовый синтаксис:

rpm --initdb

Команда в такой форме не должна угрожать целостности существующей БД RPM. Если дела зашли столь далеко, что БД не может быть перестроена, возможно наилучшим решением будет установка новой операционной системы с нуля.

Кроме проблемных случаев, создание пустой БД используется для тестирования установки пакетов в отдельный каталог. Тогда можно создать БД по альтернативному пути, используя опцию --dbpath. Например:

#mkdir /tmp/rpm

#rpm --initdb --dbpath /tmp/rpm

Эти команды создают временный каталог и БД RPM в нем. После выполнения команд можно проверить наличие необходимых файлов:

# ls -l /tmp/rpm
total 288
-rw-r--r-- 1 root root 8192 Oct 10 20:29 __db.001

-rw-r--r-- 1 root root 1310720 Oct 10 20:29 __db.002

-rw-r--r-- 1 root root 360448 Oct 10 20:29 __db.003

-rw-r--r-- 1 root root 12288 Oct 10 20:29 Packages

Наличие этого списка указывает на успешное создание пустой БД RPM.

Далее - Раздел 5. Зависимости пакетов
Назад - Перестройка БД RPM
Содержание


5.1 Введение в концепцию зависимостей

Зависимости проявляют себя, когда один пакет зависит от другого. Может показаться, что мы получим легко управляемую систему, если ни один пакет не будет зависеть от другого, однако в этом случае мы столкнулись бы с рядом проблем и не в последнюю очередь с проблемой переполнения жестких дисков.

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

Например, многие программы используют низкоуровневые сетевые примитивы. Допустим, произошло устранение критической ошибки в системной библиотеке. Поскольку реализация базовых функций изменена централизовано, нет нужды переписывать и пересобирать многочисленные сетевые приложения. В этом случае зависимость от одной библиотеки будет нам на руку.

Кроме того, использование разделяемых библиотек и, следовательно, многократно используемого кода уменьшает количество сопровождаемого кода приложений и повышает их качество. Понятие "расшаривание кода" существует в компьютерном лексиконе с 1960-х годов.

Хотя только некоторые пакеты зависят напрямую от системных библиотек, многие программы зависят от программ, входящих в другие пакеты. Например, редактор Emacs зависит от скриптового языка Perl, в особенности от интерпретатора perl. Приложения систем управления базами данных как правило зависят от серверов баз данных. Можно привести и другие примеры.

RPM отслеживает зависимости ПО, сохраняя целостность системы. Например, RPM не даст удалить пакет, если от него зависят сторонние приложения, так как это может сделать систему неработоспособной.

Далее - Возможности
Назад - Создание новой БД RPM
Содержание


5.1.1 Возможности

В терминологии RPM каждый пакет предоставляет некоторые возможности. "Возможность" представлена текстовой строкой, которая задана в секции Provides хэдера пакета. В большинстве случаев возможность - это имя файла или имя другого пакета. Но технологически это может быть любая текстовая строка.

Другие пакеты могут зависеть от определенной возможности. Каждый пакет содержит в себе информацию как о предоставляемых возможностях, так и о возможностях, от которых он зависит (секция Requires).

Когда вы устанавливаете пакет, информация о возможностях помещается в БД RPM. Когда вы удаляете пакет, утилита rpm проверяет БД. Если пакет для удаления должен быть удален вместе с некоторыми возможностями, от которых зависят другие пакеты, утилита сгенерирует ошибку и завершит работу. Например:

# rpm -e setup

error: Failed dependencies:

setup is needed by (installed) basesystem-8.0-1

setup >= 2.0.3 is needed by (installed) initscripts-6.95-1

setup >= 2.5.4-1 is needed by (installed) filesystem-2.1.6-5

setup is needed by (installed) xinetd-2.3.7-2

setup is needed by (installed) dump-0.4b28-4

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

# rpm -q setup

setup-2.5.20-1

Этот пример показывает, что пакет setup не был удален из-за ошибок операции.

Многие возможности, от которых зависят другие пакеты - это системные библиотеки, особенно разделяемые библиотеки. Разделяемые библиотеки, файлы которых имеют обычно расширение .so (от shared object), предоставляют эффективный механизм экономии памяти и разделения кода. Поскольку множество программ зависит от разделяемых библиотек, система RPM умеет автоматически обрабатывать эти зависимости.

Для исследования вопроса об используемых программой библиотеках, применяется команда ldd. Например:

$ ldd /bin/grep

libc.so.6 => /lib/i686/libc.so.6 (0x42000000)

/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Другие зависимости могут содержать специфические требования к номерам версий.

Далее - Зависимости версий
Назад - Введение в концепцию зависимостей
Содержание


5.1.2 Зависимости версий

Приложение может зависеть от возможности, предоставляемой другим пакетом. Кроме того, приложение может зависеть от возможности, предоставляемой другим пакетом только какой-либо конкретной версии. Например, некоторые модули-дополнения веб-сервера Apache зависят от версии самого Apache и модули для версии 1.3 не пригодны для версии 2.0.

Множество зависимостей от других пакетов требуют определенного уровня совместимости, поэтому как правило зависимости от версий формулируются как требование версии такой-то или выше.

Далее - Конфликты
Назад - Возможности
Содержание


4.1.3 Как повысить информативность запроса

4.1.3.1 Перенаправление вывода на grep

Команда grep предоставляет мощные инструменты фильтрации текстового потока для Linux (Unix) систем. Сочетание rpm -qa и grep представляет собой настоящую поисковую машину. Например, задание шаблона "py" в качестве аргумента grep приведет к такому выводу:

# rpm -qa | grep py

python-2.2.1-17

pygtk2-1.99.12-7

pyxf86config-0.3.1-2

rpm404-python-4.0.4-8x.27

python-devel-2.2.1-17

gnome-python2-gtkhtml2-1.99.11-8

orbit-python-1.99.0-4

gnome-python2-canvas-1.99.11-8

gnome-python2-bonobo-1.99.11-8

gnome-python2-1.99.11-8

pyOpenSSL-0.5.0.91-1

rpm-python-4.1-1.06

pygtk2-devel-1.99.12-7

kdesdk-kspy-3.0.3-2

mod_python-3.0.0-10

gnome-python2-gconf-1.99.11-8

libxslt-python-1.0.19-1

python-tools-2.2.1-17

libxml2-python-2.4.23-1

pygtk2-libglade-1.99.12-7

python-optik-1.3-2

kfloppy-3.0.3-3

Опции grep, а также регулярные выражения, которые можно использовать в grep, досупны в справке man.

Наиболее интересные примеры.

Для поиска пакета, имя которого начинается с определенного буквосочетания, введите:

# rpm -qa | grep ^py

где py - начальные буквы имен пакетов.

Для исключения пакетов с заданным буквосочетанием в имени, введите:

# rpm -qa | grep -v blabla

В команде grep опция -v означает не многословный вывод, а инверсию шаблона, то есть "выведи мне все, что не соответствует шаблону".

4.1.3.2 Запросы с помощью метасимволов

Помимо возможности перенаправить вывод, rpm имеет некоторые встроенные механизмы, помогающие детализировать запрос к списку пакетов. Например, можно использовать метасимволы для создания шаблонов имен:

# rpm -qa "send*"

sendmail-cf-8.11.6-3

sendmail-8.11.6-3

Кавычки вокруг шаблона send* экранируют специальный символ * от интерпретации его определенным образом механизмами Linux shell. Эта команда ищет все пакеты, имена которых начинаются с send. Подобно grep, такая форма команд может инвертировать шаблон с помощью символа !:

# rpm -qa "!send*"

Данная вариация будет искать пакеты, имена которых не начинаются с send.

Помимо grep часто используются и другие команды, например wc -l можно использовать для подсчета количества найденных пакетов.

Далее - Какому пакету принадлежит файл?
Назад - Запросы о пакетах
Содержание


5.1.3 Конфликты

Некоторые пакеты могут предоставлять возможности, которые интерферируют с таковыми из других пакетов. Такая ситуация называется конфликтом и обрабатывается силовым методом. Попытка установки конфликтующего пакета приведет к ошибке. Например, пакет httpd, содержащий веб-сервер Apache, конфликтует с пакетом thttpd. Оба этих пакета предоставляют системе предпочитаемый веб-сервер.

Конфликт можно обойти с помощью опций форсирования установки, но с точки зрения функционала это как правило приводит к ошибкам стадии выполнения.

Далее - Неактуальные возможности
Назад - Зависимости версий
Содержание


5.1.4 Неактуальные возможности

Система RPM умеет обрабатывать еще один вид зависимостей, так называемые неактуальные возможности (obsoletes). Возможности могут стать неактуальными, если пакет предоставляет такую возможность, перекрывая сходную возможность другого пакета. Например, применение новой версии интерпретатора Perl делает бессмысленным применение старой версии. В большинстве случаев, однако, неактуальные возможности возникают вследствии переименования пакета. Например, пакет веб-сервера Apache с какого-то момента стал именоваться httpd. Его возможности делают неактуальными возможности, предоставляемые старым пакетом - apache.

Таким образом, в целом RPM обрабатывает такие виды зависимостей:

* Потребности (Requires). Отслеживаются возможности, в которых пакет нуждается
* Возможности (Provides). Отслеживаются возможности, которые пакет предоставляет
* Конфликты (Conflicts). Описывают возможности, которые будучи установленными, конфликтуют с возможностями пакета
* Неактуальные возможности (Obsoletes). Описывают возможности, которые пакет делает неактуальными в других пакетах

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

Далее - Проверка зависимостей вида Requires
Назад - Конфликты
Содержание


5.2.1 Проверка зависимостей вида Requires

Первый и наиболее важный шаг на пути увязывания зависимостей - это определение потребностей пакета. Если все возможности, в которых нуждается пакет (requires), а это не только библиотеки, нужные упакованному в пакет ПО, но и потребности скриптов, триггеров и тому подобных инструментов, удовлетворены, пакет может быть безопасно установлен.

Опция --requires в команде rpm -q поможет определить потребности заданного пакета. Базовый синтаксис:

rpm q query_options --requires packages

Например:

$ rpm -qp --requires sendmail-8.12.5-7.i386.rpm

/usr/sbin/alternatives

rpmlib(VersionedDependencies) <= 3.0.3-1

chkconfig >= 1.3

/usr/sbin/useradd

/bin/mktemp

fileutils

gawk

sed

sh-utils

procmail

bash >= 2.0

/bin/sh

rpmlib(PayloadFilesHavePrefix) <= 4.0-1

rpmlib(CompressedFileNames) <= 3.0.4-1

/bin/bash

libcrypto.so.2

libcrypt.so.1

libc.so.6

libc.so.6(GLIBC_2.0)

libc.so.6(GLIBC_2.1)

libc.so.6(GLIBC_2.1.3)

libc.so.6(GLIBC_2.2)

libdb-4.0.so

libgdbm.so.2

libhesiod.so.0

liblber.so.2

libldap.so.2

libnsl.so.1

libnsl.so.1(GLIBC_2.0)

libresolv.so.2

libresolv.so.2(GLIBC_2.0)

libresolv.so.2(GLIBC_2.2)

libsasl.so.7

libssl.so.2

В этом примере тестируется не установленный пакет, а файл rpm-пакета sendmail, на предмет требований, которые пакет предъявляет к наличию в системе тех или иных средств. Данный пакет зависит от большого количества сторонних библиотек, пакетов и исполняемых файлов. Кроме того, есть требование к определенной версии системы RPM (зависимость от rpmlib).

Для проверки степени удовлетворения зависимостей можно использовать опцию --test перед установкой пакета. Под этой опцией RPM лишь проверяет возможность установки и диагностирует возможные ошибки, но не выполняет реальных действий.

Короткий вариант опции: -R.

Кроме бинарных пакетов, зависимости в смысле требований могут иметь и пакеты с исходным кодом, так как для сборки ПО часто требуются различные средства. Например, нижеследующая команда показывает потребности пакета с исходным кодом (они будут проверятся при установке пакета в систему):

$ rpm -qp --requires telnet-0.17-23.src.rpm

ncurses-devel

Некоторые пакеты требуют определенных версий других пакетов, например:

pm -qp --requires xcdroast-0.98a9-18.src.rpm

imlib-devel >= 1.9.13-9

gtk+-devel >= 1.2.10

desktop-file-utils >= 0.2.92

rpmlib(CompressedFileNames) <= 3.0.4-1

Из этого примера видно, что пакет xcdroast для сборки своего ПО требует imlib-devel версии 1.9.13-9 или выше, gtk+-devel версии 1.2.10 или выше, и desktop-file-utils версии 0.2.92 или выше. Это более строгое требование, чем зависимость от определенного пакета вообще, независимо от версии. Этот старый пакет требует также, чтобы наличествовала версия RPM
3.0.4-1 или ниже.

Некоторые пакеты требуют определенной версии rpmlib. Например, пакет setup содержит специальные системные конфигурационные файлы, которые зависят от определенного функционала RPM:

$ rpm -q --requires setup

rpmlib(PayloadFilesHavePrefix) <= 4.0-1

rpmlib(CompressedFileNames) <= 3.0.4-1

Как видно из примера, данный пакет зависит от собственных возможностей RPM, в частности важно, каким образом формируются списки файлов в нагрузке и как именно они компрессируются.

Далее - Проверка зависимостей вида Provides
Назад - Неактуальные возможности
Содержание


5.2.2 Проверка зависимостей вида Provides

Пакеты требуют каких-то возможностей и сами предоставляют возможности для других пакетов. Для вывода списка предоставляемых возможностей используется опция --provides. Эти возможности могут задаваться произвольным именем (файла), быть разделяемой библиотекой или собственным именем пакета. Базовый синтаксис:

rpm q query_options --provides packages

Например, пакет tcsh предоставляет две возможности (под определенным номером версии), как показано ниже:

$ rpm -q --provides tcsh

csh = 6.12

tcsh = 6.12-2

Другие пакеты могут содержать намного более длинные списки, включая разделяемые библиотеки. Например, пакет httpd:

$ rpm -q --provides httpd

webserver

httpd-mmn = 20020628

libapr.so.0

libaprutil.so.0

mod_access.so

mod_actions.so

mod_alias.so

mod_asis.so

mod_auth_anon.so

mod_auth_dbm.so

mod_auth_digest.so

mod_auth.so

mod_autoindex.so

mod_cern_meta.so

mod_cgi.so

mod_dav_fs.so

mod_dav.so

mod_deflate.so

mod_dir.so

mod_env.so

mod_expires.so

mod_headers.so

mod_imap.so

mod_include.so

mod_info.so

mod_log_config.so

mod_mime_magic.so

mod_mime.so

mod_negotiation.so

mod_proxy_connect.so

mod_proxy_ftp.so

mod_proxy_http.so

mod_proxy.so

mod_rewrite.so

mod_setenvif.so

mod_speling.so

mod_status.so

mod_suexec.so

mod_unique_id.so

mod_userdir.so

mod_usertrack.so

mod_vhost_alias.so

httpd = 2.0.40-8

Далее - Проверка на конфликты
Назад - Проверка зависимостей вида Requires
Содержание


5.2.3 Проверка на конфликты

Используйте опцию --conflicts для проверки наличия конфликтов с указанным пакетом. Базовый синтаксис:

rpm q query_options --conflicts packages

Например:

# rpm -q --conflicts httpd

thttpd

Вывод этой команды говорит нам о том, что пакет httpd (веб-сервер Apache) конфликтует с пакетом thttpd. Оба пакета предоставляют сходные возможности. Пакеты httpd и thttpd вследствии этого не могут быть установлены в систему одновременно. Эта информация содержится в пакете httpd, имеющем запись, указывающую на возможный конфликт. При этом конфликт не гарантируется. Возможно, что работоспособность пакетов, установленных вместе, не пострадает. Но производитель пакета httpd предупреждает о возможных проблемах, а пакет опубликовывает эту информацию для общего сведения.

Система RPM будет сообщать о конфликтах и выводить ошибку, если администратор попытается установить конфликтующие пакеты. Этот механизм дает создателям пакетов реальную возможность предупредить пользователей о возможных проблемах и передать ответственность за возможные ошибки времени выполнения администратору системы.

Опции форсирования установки позволяют обойти ошибки на страх и риск администратора.

Далее - Какой пакет требует данную возможность?
Назад - Проверка зависимостей вида Provides
Содержание


5.2.4 Какой пакет требует данную возможность?

Основным параметром при запросе зависимостей является имя пакета, однако имеется возможность делать запрос и по имени зависимости. Этот функционал позволяет определить, какой пакет требует данную возможность.

Опция --whatrequires позволяет найти пакеты, требующие данную возможность. Базовый синтаксис:

rpm q query_options --whatrequires capability

Некоторые пакеты не требуются никакому другому:

$ rpm -q --whatrequires tcsh

no package requires tcsh

В какой-то степени это удачное обстоятельство, так как подобные пакеты могут быть удалены из системы без каких-либо проблем.

Разделяемые библиотеки также могут являтся именем зависимости. Запрос должен быть таким:

$ rpm -q --whatrequires librpm-4.1.so

rpm-4.1-1.06

net-snmp-5.0.1-6

rpm-python-4.1-1.06

rpm-devel-4.1-1.06

rpm-build-4.1-1.06

Этот пример показывает, что библиотека ядра системы RPM используется группой пакетов, имеющих отношение к RPM (за исключением пакета net-snmp).

Возможность, указываемая в запросе, должна быть поименована точно. Например, результаты будут различны для bash и /bin/bash, так как в первом случае имеет место имя пакета, во втором - команда. Для первого имени получим список пакетов, требующи наличия пакета bash:

$ rpm -q --whatrequires bash

gpm-1.19.3-20

info-4.0b-3

initscripts-6.40-1

sendmail-8.11.6-3

sysklogd-1.4.1-4

vixie-cron-3.0.1-63

ypbind-1.8-1

ypserv-1.3.12-2

Если же запросить пакеты, которые требуют интерпретатора /bin/bash, получим следующий вывод:

$ rpm -q --whatrequires /bin/bash

apmd-3.0final-34

at-3.1.8-20

autofs-3.1.7-21

autofs-3.1.7-21

bash-2.05-8

bind-9.1.3-4

cipe-1.4.5-6

rontabs-1.10-1

dialog-0.9a-5

gpm-1.19.3-20

hotplug-2001_04_24-11

initscripts-6.40-1

ipchains-1.3.10-10

iproute-2.2.4-14

kudzu-0.99.23-1

logwatch-2.1.1-3

man-1.5i2-6

mkbootdisk-1.4.2-3

mkinitrd-3.2.6-1

mutt-1.2.5i-17

openssh-server-3.1p1-2

pine-4.44-1.72.0

rpm-build-4.0.3-1.03

rusers-server-0.17-12

sendmail-8.11.6-3

shapecfg-2.2.12-7

sharutils-4.2.1-8

sysklogd-1.4.1-4

tetex-1.0.7-30

ucd-snmp-4.2.1-7

vixie-cron-3.0.1-63

xinetd-2.3.3-1

ypbind-1.8-1

ypserv-1.3.12-2

Не существует короткой формы опции --whatrequires .

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

# rpm -q --whatrequires libcrypt.so.1 | sort

autofs-3.1.7-21

cvs-1.11.1p1-3

cyrus-sasl-1.5.24-23

cyrus-sasl-devel-1.5.24-23

cyrus-sasl-plain-1.5.24-23

fetchmail-5.9.0-1

ircii-4.4Z-7

krbafs-1.0.9-2

nss_ldap-172-2

openldap12-1.2.12-4

openldap-2.0.11-13

openldap-clients-2.0.11-13

pam-0.75-19

pam_krb5-1.46-1

passwd-0.64.1-7

perl-5.6.0-17

pine-4.44-1.72.0

pwdb-0.61.1-3

python-1.5.2-35

rsh-0.17-5

rsh-server-0.17-5

screen-3.9.9-3

sendmail-8.11.6-3

shadow-utils-20000902-4

sh-utils-2.0.11-5

SysVinit-2.78-19

tcsh-6.10-6

util-linux-2.11f-17

vim-enhanced-5.8-7

wu-ftpd-2.6.1-20

xinetd-2.3.3-1

ypserv-1.3.12-2

yp-tools-2.5-1

Поскольку некоторые пакеты требуют доступа к функциям шифрования/дешифрования, эта библиотека приобретает критическое значение для нормального функционирования операционной системы.

Для более удобного отслеживания зависимостей запросы можно комбинировать. Например:

$ rpm -q --provides sendmail

smtpdaemon

sendmail = 8.11.6-3

$ rpm -q --whatrequires smtpdaemon

fetchmail-5.9.0-1

mutt-1.2.5i-17

Первая команда выводит список возможностей, которые предоставляет пакет sendmail, включая шаблонную возможность smtpdaemon. Далее можно запросить список пакетов, нуждающихся в этих возможностях, как показано во второй команде. Это хорошая помощь в процессе анализа пакетов, которые зависят от других пакетов, которые зависят еще от каких-то пакетов.

Далее - Какой пакет предоставляет данную возможность?
Назад - Проверка на конфликты
Содержание


5.2.5 Какой пакет предоставляет данную возможность?

Для полноты картины можно запросить пакет, который предоставляет данную возможность. Эта информация поможет отследить зависимость назад по траектории вплоть до пакета-источника.

Опция --whatprovides для команды rpm -q позволяет получить имя пакета, предоставляющего данную возможность. Базовый синтаксис:

rpm q --whatprovides capability

Не существует короткой формы для этой опции.

Для запроса пакета, который предоставляет функционал webserver, используйте следующую команду:

$ rpm -q --whatprovides webserver

httpd-2.0.40-8

В данном случае возможность именована произвольной строкой. Данная зависимость является шаблонной. Функционал webserver может предоставлятся несколькими различными пакетами, но в системе такой пакет как правило один.

Опция --whatprovides поддерживает также поиск пакетов, предоставляющих возможность в виде отдельного файла. Например:

$ rpm -q --whatprovides /etc/skel/.bashrc

bash-2.05-8

Команда rpm -qf предоставляет более простой способ для поиска пакета - владельца файла. Например:

$ rpm -qf /etc/skel/.bashrc

bash-2.05-8

Поэтому, если вы ищете источник файла, используйте rpm -qf, если источник зависимости, --whatprovides.

Далее - Триггеры
Назад - Какой пакет требует данную возможность?
Содержание


5.3 Триггеры

Триггер - это скрипт, который запускается в момент установки или удаления пакета. Триггеры позволяют пакету, который зависит от других пакетов, правильно настроить его окружение в зависимости от того, какие версии этих пакетов установлены и обновлялись ли они.

Триггеры, определенные в пакете, можно вывести с помощью опции --triggers. Например:

$ rpm -q --triggers sendmail

triggerpostun script (through /bin/sh) -- sendmail < 8.10.0

/sbin/chkconfig --add sendmail

Из примера видно, что в пакете sendmail определен короткий скрипт-триггер.

С этим случаем контрастирует пакет anonftp, имеющий сказочно сложный набор триггеров, как показано ниже:

$ rpm -q --triggers anonftp

triggerin script (through /bin/sh) -- glibc

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

# Kill off old versions

rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl* /var/ftp/lib/lib
nss_files* &>/dev/null || :

# Copy parts of glibc, needed by various programs in bin.

LIBCVER=`basename $(ls --sort=time /lib/libc-*.so |head -n 1) .so |cut -f2- -d-`

copy /lib/ld-${LIBCVER}.so /var/ftp/lib

copy /lib/libc-${LIBCVER}.so /var/ftp/lib

copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib

copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib

md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.* 2>/dev/null
>/var/ftp/lib/libs.md5

chmod 0400 /var/ftp/lib/libs.md5

# Use ldconfig to build symlinks and whatnot.

[ ! -e /var/ftp/etc/ld.so.conf ] && touch /var/ftp/etc/ld.so.conf

/sbin/ldconfig -r /var/ftp

triggerin script (through /bin/sh) -- fileutils

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/ls /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

triggerin script (through /bin/sh) -- cpio

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/cpio /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

triggerin script (through /bin/sh) -- tar

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/tar /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

triggerin script (through /bin/sh) -- gzip

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/gzip /var/ftp/bin

ln -sf gzip /var/ftp/bin/zcat

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

triggerin script (through /bin/sh) -- libtermcap

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :

copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib

md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.* 2>/dev/null
>/var/ftp/lib/libs.md5

chmod 0400 /var/ftp/lib/libs.md5

# Use ldconfig to build symlinks and whatnot.

[ ! -e /var/ftp/etc/ld.so.conf ] && touch /var/ftp/etc/ld.so.conf

/sbin/ldconfig -r /var/ftp

triggerin script (through /bin/sh) -- ncompress

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /usr/bin/compress /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

triggerpostun script (through /bin/sh) -- anonftp 4.0

if [ "$2" != 1 ] ; then

# The user has multiple glibc packages installed. We can't read the

# user's mind, so don't do anything.

exit 0

fi

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

# Kill off old versions

rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl* /var/ftp/lib/lib
nss_files* &>/dev/null || :

# Copy parts of glibc, needed by various programs in bin.

LIBCVER=`basename /lib/libc-*.so .so | cut -f2- -d-`

copy /lib/ld-${LIBCVER}.so /var/ftp/lib

copy /lib/libc-${LIBCVER}.so /var/ftp/lib

copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib

copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib

copy /bin/ls /var/ftp/bin

copy /bin/cpio /var/ftp/bin

copy /bin/tar /var/ftp/bin

copy /bin/gzip /var/ftp/bin

ln -sf gzip /var/ftp/bin/zcat

copy /usr/bin/compress /var/ftp/bin

rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :

copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib

# Use ldconfig to build symlinks and whatnot.

[ ! -e /var/ftp/etc/ld.so.conf ] && touch /var/ftp/etc/ld.so.conf

/sbin/ldconfig -r /var/ftp

# Generate md5sums for verifyscript

md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.* 2>/dev/null
>/var/ftp/lib/libs.md5

chmod 0400 /var/ftp/lib/libs.md5

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

Анализ текста триггера показывает, что данный пакет и его окружение зависит от версии библиотеки glibc. Этот факт можно подтвердить с помощью опции --triggeredby, как показано ниже:

$ rpm -q --triggeredby glibc

anonftp-4.0-9

Пакет anonftp нуждается в уведомлениях об изменении пакета glibc. Если в glibc произошли изменения и администратор установил новую версию пакета, anonftp должен перестроить свое окружение правильным образом, поэтому при обновлении glibc будут вновь запущены триггеры пакета.
Таким образом, триггеры можно рассматривать как расширенную форму увязки зависимостей одних пакетов от других. В примере выше показано, что пакет anonftp столь сильно привязан к реализации glibc, что нуждается в перенастройке при каждом изменении пакета, от которого он зависит.

Далее - Раздел 6. Транзакции
Назад - Какой пакет предоставляет данную возможность?
Содержание


6.1 Введение в транзакции

Транзакции - это путь отделения группы операций от других операций. При этом такая группа становится новой целостной сущностью. Эта новая сущность строится таким образом, что все операции можно отменить (как правило такое действие называют откатом). Если откат произведен, система возвращается в прежнее состояние. Ключевая проблема в том, что в группе операций все операции должны пройти без ошибок, или же вы должны иметь возможность откатить все операции группы назад. Если из группы операций какая-то одна завершится с ошибками, система приходит в неконсистентное состояние. Транзакции позволяют этого избежать.

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

Начиная с RPM версии 4.0.4 транзакции и откаты стали рабочей частью любого инструмента администрирования пакетов. Утилита rpm формирует транзакции всегда в случаях установки, удаления или обновления группы пакетов.

Далее - Когда транзакции необходимы
Назад - Триггеры
Содержание


6.1.1 Когда транзакции необходимы

Когда бы вы не устанавливали или удаляли пакеты, RPM формирует транзакцию и присваивает ей уникальный идентификатор - transaction ID. Далее совершаются операции над пакетами, которые имеют одинаковый ID транзакции. Также доступна операция отката действия над пакетом или группой пакетов. Откат обновлений (в отличие от установки и удаления) доступен только с версии RPM 4.1.

RPM сохраняет снимок хэдера каждого пакета, который устанавливается или удаляется. Эти снимки могут использоваться, когда нужно что-то вернуть в прежнее состояние. Для обращения к снимкам система применяет поиск по ID транзакции.

Основное преимущество транзакций заключается в том, что утилита rpm автоматически формирует транзакции в любых административных действиях и не выполняет операции, если возникают ошибки. Возможность формировать транзакции для каждого вызова rpm блокирует множество возможностей возникновения ошибок.

Используйте возможности транзакций, если необходимо правильно и без ошибок установить группу пакетов.

Далее - Возврат транзакции
Назад - Введение в транзакции
Содержание


4.1.4 Какому пакету принадлежит файл?

Одной из наиболее общих задач управления пакетами является задача отслеживания принадлежности отдельных файлов.

Опция -qf позволяет использовать rpm для поиска информации о принадлежности указанного файла конкретному пакету. Основной синтаксис:

# rpm -qf путевое_имя_файла

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

# which grep

/bin/grep

В данном примере определяется положение утилиты grep. Теперь можно определить принадлежность grep конкретному пакету.

# rpm -qf /bin/grep

grep-2.4.2-7

Осталось объединить команды в одну средствами Linux:

# rpm -qf `which grep`

grep-2.4.2-7

Если используется bash shell, имеется возможность использовать свойства этой оболочки:

# rpm -qf $(which grep)

grep-2.4.2-7

Если файл не принадлежит пакету (а это пользовательские файлы, документы etc.), будет выведено сообщение:

# rpm -qf mail

file mail is not owned by any package

Одна из причин, почему команда rpm -qf довольно часто используется, это отсутствие связи между именами команд и именами пакетов, в которые они входят. Например:

# rpm -qf `which ssh`

openssh-clients-3.1p1-2

Далее - Описание пакета
Назад - Как повысить информативность запроса
Содержание


6.1.2 Возврат транзакции

Возврат транзакции вызывает две операции: откат действий и переустановку пакетов для восстановления прежнего статуса системы. В простейшем случае rpm самостоятельно отработает все необходимые шаги.

Эта поддержка автоматизированной обработки транзакций - большая помощь системным администраторам, но применима, только если вы впервые установили, удалили или обновили пакеты. Если же система была изменена, а проблемы обнаружились позже, можно использовать опцию --rollback для возврата системы в прежнее состояние, например после обновления группы пакетов.

Далее - Транзакции с командой rpm
Назад - Когда транзакции необходимы
Содержание


6.2 Транзакции с командой rpm

Все, что нужно сделать для формирования транзакции - это передать в качестве аргумента более чем одно имя пакета в командную строку rpm. Например, для формирования транзакции для установки трех пакетов, используйте команду, подобную следующей:

rpm -ihv package1.rpm package2.rpm package3.rpm

Если в отношении какого-либо пакета из списка произойдут ошибки, rpm не будет устанавливать ни один пакет. Принцип - или все пакеты должны быть установлены, или ни одного.

Этот путь весьма пригоден в сложных случаях, например, если есть большая группа пакетов, выполняющих одну задачу. Скажем, имеется интегрированная среда разработки (IDE) с разными отладчиками, компиляторами и инструментами разработки. Если устанавливать такую группу в рамках транзакции, вы будете уверены, что все необходимое установлено.

В качестве примера установим пакет gnorpm, предоставляющий графический фронтенд для утилиты rpm и пакет rpmrebuild, который позволяет собрать пакет из файлов уже установленного пакета. Установим эти пакеты в рамках транзакции:

# rpm -ihv gnorpm-0.9-1.i386.rpm rpmrebuild-1.0-0.noarch.rpm

Preparing...
########################################### [100%]

package gnorpm-0.9-1 is already installed

Пакет rpmrebuild может быть установлен, но поскольку пакет gnorpm уже установлен и выдана ошибка, то вся транзакция отменена. Ни один пакет не будет установлен. Для проверки того, что пакеты не были установлены, то есть концепция транзакций работает, как описано, используйте rpm q:

# rpm -q rpmrebuild

package rpmrebuild is not installed

Этот пример показывает, что rpmrebuild не был установлен, хотя может быть установлен изолированно, не в рамках транзакции.

Утилита rpm действует сходным образом и при удалении и при обновлении пакетов. При удалении можно увидеть подобное сообщение об ошибке, если какой-либо пакет не может быть удален:

# rpm -e setup jikes-1.17

error: Failed dependencies:

setup is needed by (installed) basesystem-8.0-1

setup >= 2.0.3 is needed by (installed) initscripts-6.95-1

setup >= 2.5.4-1 is needed by (installed) filesystem-2.1.6-5

setup is needed by (installed) xinetd-2.3.7-2

setup is needed by (installed) dump-0.4b28-4

Пакет setup не может быть удален, так как от него зависят другие пакеты. Можно проверить, что пакет jikes не был удален, не смотря на то, что он не ограничен зависимостями и может быть удален в одиночку:

# rpm -q jikes

jikes-1.17-1

Далее - Идентификаторы транзакций
Назад - Возврат транзакции
Содержание


6.2.1 Идентификаторы транзакций

Утилита rpm сопоставляет каждому установленному пакету идентификатор транзакции. Идентификатор транзакции - это временная метка в формате времени Unix (количество секунд, прошедших с начала эпохи Unix, с 1 января 1970 года). Получив ID транзакции, можно проделывать с пакетами, помеченными данным ID, некоторые операции.

То обстоятельство, что ID транзакции - это временная метка в формате Unix, может изменится в будущем.

Все пакеты, установленные в рамках одной команды, имеют одинаковый ID транзакции. Это означает, что с использованием ID можно совершать операции над данной группой пакетов. Однако у этой особенности есть и оборотная сторона. Все пакеты, установленные в момент инсталляции системы, имеют одинаковый ID. В силу этого обстоятельства вы не можете оперировать этими пакетами селективно, а только всеми вместе.

6.2.1.1 Просмотр идентификаторов транзакций
Для нахождения идентификатора транзакции конкретного пакета используется команда, подобная следующей:

$ rpm -q --qf "%-20{NAME} %-20{INSTALLTID}\n" jikes

jikes 1035589778

Эта команда использует специальный формат запроса для вывода временной метки (идентификатора транзакции, TID). Этот идентификатор также является ID для удаления (REMOVETID). Его тоже можно запросить:

$ rpm -qa --qf "%-20{NAME} %-20{REMOVETID}\n" termcap

termcap (none)

Такой вывод бывает, если пакет не удалялся.

6.2.1.2 Пакеты, ассоциированные с данным ID транзакции
Имея ID транзакции, можно использовать опцию --tid для запроса пакетов, ассоциированных с данным TID. Пример команды:

$ rpm -q --tid 1035589778

jikes-1.17-1

Этот пример использует TID, полученный способом, который описывался в предыдущей главе. Если одномоментно устанавливалась группа пакетов, мы увидим в выводе такой команды список всех пакетов с данным TID.

Например, подобный список можно получить для пакетов, установленных во время инсталляции или обновления системы. Получим TID, вводя в качестве параметра имя пакета, который точно устанавливается во время инсталляции:

$ rpm -q --qf "%-20{NAME} %-20{INSTALLTID}\n" setup

setup 1033838323

Далее, используем этот TID для вывода списка всех пакетов, установленных во время инсталляции системы:

$ rpm -q --tid 1033838323 | more

redhat-menus-0.26-1

glibc-2.2.93-5

cracklib-2.7-18

gdbm-1.8.0-18

gmp-4.1-4

libacl-2.0.11-2

libjpeg-6b-21

linc-0.5.2-2

pcre-3.9-5

shadow-utils-20000902-12

libtermcap-2.0.8-31

freetype-2.1.2-7

info-4.2-5

fileutils-4.1.9-11

psmisc-20.2-6

ntp-4.1.1a-9

mount-2.11r-10

cracklib-dicts-2.7-18

krb5-libs-1.2.5-6

cyrus-sasl-2.1.7-2

usermode-1.63-1

Xft-2.0-1

С помощью просмотрщика more список можно будет пролистывать. При запуске примера не забудьте заменить TID реальным значением для вашей системы.

В этом примере показана незначительная часть вывода.

Далее - Откат транзакций
Назад - Транзакции с командой rpm
Содержание


6.2.2 Откат транзакций

Опция --rollback позволяет откатить пакет обновлений, опираясь на время применения транзакции. Используйте команду из примера:

# rpm U --rollback "3 months ago"

Команда rpm -U --rollback весьма ограничена в своей функциональности. Опция --rollback действует только в отношении обновлений. Нельзя откатить первую установку пакета. Это ограничение связано с необходимостью защиты пакетов, установленных во время инсталляции системы. Опция пригодна в ситуациях, когда вы хотите возвратить систему в прежнее состояние после неудачного обновления. Если от момента обновления до момента желаемого отката производилось обновление самой системы RPM, могут возникнуть непредсказуемые последствия, если некоторые вновь установленные пакеты зависят от обновленных. Кроме того, несмотря на применимость только в узком круге ситуаций, команда rpm -U --rollback не всегда может диагностировать статус и вывести сообщения, когда необходимые условия отката не выполнены. rpm может просто не сделать ничего или удалить пакеты, которые для этого не назначены.

Перед применением опции --rollback создайте резервную копию БД RPM.

Вместо применения --rollback можно рекомендовать следующий подход: запросите пакеты, установленные последними. Получив список, вы можете удалить пакеты, от которых желаете избавиться или переустановить пакеты, которые нужно исправить. В некоторых случаях такой подход наиболее безопасен и дает ясное представление о действиях, которые вы должны предпринять в отношении возврата статуса системы.

Далее - Сохранение старых пакетов
Назад - Идентификаторы транзакций
Содержание


6.3 Сохранение старых пакетов

При установке, удалении или обновлении пакетов можно использовать опцию --repackage для сохранения старых версий файлов пакетов, которые вы обновляете или самих пакетов при удалении. Пакеты, создаваемые под опцией --repackage не являются настоящими пакетами rpm. Для создания настоящих пакетов можно использовать утилиту rpmbuild.

Впоследствии можно будет переустановить старые файлы, если были созданы настоящие пакеты. Эта возможность полезна в том случае, если обновления пакетов принесли с собой новые ошибки функционала.

По умолчанию rpm с опцией --repackage помещает старый пакет в каталог /var/spool/repackage. Другие применяющиеся каталоги - /var/spool/up2date или /var/tmp. Конкретный каталог зависит от конфигурации RPM, заданной для обработки данной опции.

Для примера. Вы имеете пакет jikes, который нужно обновить. Но есть опасения, что новая версия не будет работать правильно. Первым делом проверьте установленную версию:

# rpm -q jikes

jikes-1.14-1

Вывод команды показывает, что установлена версия 1.14. Вы можете обновить пакет до версии 1.17, сохраняя старый пакет:

# rpm -Uhv --repackage jikes-1.17-glibc2.2-1.i386.rpm
Preparing... ########################################

[100%]

Repackaging...

1:jikes
########################################

[100%]

Upgrading...

1:jikes
########################################

[100%]

Эта команда обновит пакет и сохранит копию старого пакета в каталоге /var/spool/repackage. Проверим последнее обстоятельство:

$ ls -l /var/spool/repackage/

total 692

-rw-r--r-- 1 root root 703037 Oct 25 18:49 jikes-1.14-1.i386.rpm

Увидим пакет со старым номером версии. Это не то же самое, что прежний установленный пакет, его содержимое не полно. Перепакованные пакеты содержат снимок файлов пакета, которые были на тот момент на жестком диске, но не на момент установки пакета. Кроме того, rpm --repackage не может правильным образом подписать пакет, как был подписан оригинальный.

Для создания снимков любого установленного пакета можно также использовать свободную утилиту rpmrebuild. Написанная Eric Gerbier, она позволяет создать rpm-пакет из любого установленного, и, возможно, удаленного или обновленного пакета. Загрузите rpmrebuild отсюда: http://rpmrebuild.sourceforge.net/ .

Далее - Раздел 7. Программное обеспечение для управления RPM
Назад - Откат транзакций
Содержание


7.1 Нахождение программного обеспечения в формате rpm-пакетов

RPM предоставляет мощный инструмент управления программным обеспечением, так как позволяет установить сложные программные комплексы одной командой в конфигурации, готовой к использованию. Также просто можно удалить пакет или группу пакетов. Однако, программное обеспечение должно быть при этом упаковано в rpm-пакеты. Собрать нужное ПО в пакет в общем несложно, но можно сэкономить значительное количество времени, если затратите некоторые усилия для поиска нужного ПО уже в формате rpm.

Начав искать rpm-пакеты в Интернет, вы обнаружите тысячи пакетов. Многие из них собраны для конкретного дистрибутива, например, для SUSE, Mandriva или PCLinuxOS. Во многих случаях целевой дистрибутив не имеет значения, пакет все равно будет работоспособен, однако все же лучшим выбором будет пакет для вашего Линукса или пересборка с исправлением spec-файла из .src.rpm в вашей среде.

Хотя в данной книге все примеры ориентированы на Red Hat Linux, они будут работать и во всех остальных rpm-based дистрибутивах, если прямо не указано иное.

Наиболее эффективным средством поиска пакетов являются специальные сайты и специальные утилиты поиска.

Далее - rpmfind и rpm2html
Назад - Сохранение старых пакетов
Содержание


7.1.1 rpmfind и rpm2html

7.1.1.1 rpmfind
Одним из популярных средств поиска пакетов является утилита rpmfind, написанная Daniel Veillard. Этот инструмент предоставляет командный интерфейс к средствам поиска пакетов по имени или описанию и вывода (опционально - загрузки пакета) информации о пакетах, соответствующих шаблону поиска. Также предоставляется информация о зависимостях пакета с возможностью автоматизированной загрузки этих зависимостей.

Во время поиска пакетов утилита обращается к локальной БД RPM и к удаленным базам, например, к базе на rpmfind.net.

Обычно rpmfind используют для поиска пакета по имени, но также можно искать пакет по ключевым словам, содержащимся в описании. Например, мне нужно найти новый почтовый клиент. Мне известно, что весьма функциональный клиент - Ximian Evolution. Для поиска Evolution нужно ввести нечто вроде:

$ rpmfind evolution

Resource evolution already installed

Перед поиском в Интернет rpmfind вначале проверит локальную систему. В данном примере пакет evolution уже установлен в системе, поэтому дальнейший поиск не требуется.

Другой пример. Найдем еще один популярный Unix-клиент для почты, exmh:

$ rpmfind exmh

Installing exmh will require 7301 KBytes

### To Transfer:

 ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//nmh-1.0.4-9.i386.rpm

 ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//exmh-2.4-2.noarch.rpm

Do you want to download these files to /tmp [Y/n/a/i] ? : a

transferring

 ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//nmh-1.0.4-9.i386.rpm

saving to /tmp/nmh-1.0.4-9.i386.rpm

transferring

 ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//exmh-2.4-2.noarch.rpm

saving to /tmp/exmh-2.4-2.noarch.rpm

rpm -U /tmp/nmh-1.0.4-9.i386.rpm /tmp/exmh-2.4-2.noarch.rpm

Здесь rpmfind ищет в локальной системе exmh, но поскольку пакет не установлен, утилита проверяет базы на  http://rpmfind.net, и далее делает две вещи: находит пакет, и находит зависимость пакета - nmh. После повторной проверки и установления факта, что nmh также отсутствует в локальной системе, утилита спрашивает, следует ли выкачать также зависимости, причем вариантов ответа четыре:
* y/yes для закачки файла;
* n/no для отказа от закачки файла;
* a для закачки всего необходимого;
* i для установки всех закачанных пакетов.

Найти и получить пакеты может любой пользователь, установить - только root.

Поскольку в примере выбран ответ "a", утилита скачает все необходимые пакеты в каталог /tmp и сделает попытку обновить пакеты, запуская следующую команду:

rpm -U /tmp/nmh-1.0.4-9.i386.rpm /tmp/exmh-2.4-2.noarch.rpm

В данном случае команда вернет ошибку, так как rpmfind выполняется не от имени root.

Если имя пакета неизвестно, можно выполнить поиск по ключевым словам. Опция --apropos заставляет rpmfind проверять все поля описаний в базе данных на предмет поиска совпадений с шаблоном. Например, нужно отыскать все пакеты, предоставляющие функционал почтовых клиентов. Тогда поможет следующее:

$ rpmfind --apropos "mail client"

Searching the RPM catalog for mail client ...

1:

 ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//netscape-communicator-4.78-2.i386.rpm

netscape-communicator : A Web browser, news reader and e-mail client.
2:

 ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//sylpheed-0.5.0-3.i386.rpm

sylpheed : A GTK+ based, lightweight, and fast email client.

.............................................................................................

364:  ftp://ftp.pld.org.pl/PLD-1.0/dists/ra/PLD/SRPMS/SRPMS/sylpheed-0.7.4-1.src.rpm

sylpheed : GTK+ based fast e-mail client

Большая часть вывода опущена из соображений экономии места. Команда нашла 364 пакета, имеющих отношение к почтовым клиентам. В данном случае утилита запросила базы данных узла  http://rpmfind.net и вернула расположение всех пакетов, в описательных полях которых встретился образец "mail client". Из всех 364 найденных пакетов некоторые не являются почтовыми клиентами, другие не подойдут для Red Hat Linux.

Следует со вниманием отнестись к сообщениям rpmfind, так как в базах данных  http://rpmfind.net проиндексированы все пакеты для всех дистрибутивов для всех процессорных архитектур, бинарные и с исходным кодом.

Для сокращения и повышения информативности вывода утилиты, существуют специальные опции, позволяющие тоньше настроить запрос. Основные опции показаны в таблице ниже.

Опция

Результат применения

-v

Повышает многословность вывода. Можно использовать варианты -vv и -vvv

-s server

Подключиться к заданному серверу с базой данных rpmfind

--sources package

Искать пакеты с исходниками

--apropos key word(s)

Вместо имени пакета применять ключевое слово для поиска в описательных полях хэдеров

--dist dist

Ограничить поиск пакетами для заданного дистрибутива

--latest package

Найти наиболее свежую версию пакета

--upgrade package

Найти зависимости наиболее свежих версий

7.1.1.2 rpm2html
Специальные базы данных rpmfind создаются утилитой rpm2html. Если необходимо, rpm2html может создать локальное зеркало баз данных rpmfind.net или же проиндексирует все локально доступные вам пакеты для создания базы данных локального использования.

Утилита генерирует страницы HTML, содержащие описание пакетов. Очень простая по архитектуре, она весьма востребована в течение уже многих лет.

Вывод rpm2html - это одна HTML-страница на каждый пакет, созданная на основе информации, которую выводит команда rpm -qi. Кроме того, на страницу помещаются зависимости видов requires и provides. И, наконец, на генерируемой странице обязательно присутствует ссылка для скачивания.

Все пакеты с одинаковым именем собираются на странице Summary. Эта страница содержит список всех дистрибутивов, содержащих данный пакет.

Используемая вместе со своей базой данных, rpm2html предоставляет эффективную машину поиска rpm.

7.1.1.3 pdbv
Есть еще одна полезная программа - pdbv. Она создает стек HTML-страниц, объединенных перекрестными ссылками. Этот набор отражает состояние пакетов, установленных в вашу систему. Pdbv не выполняет поиск и не была спроектирована для работы с сайтами поиска rpm-пакетов и она еще проще, чем rpm2html. Ее задача - дать общую информацию по пакетам, зависимостям и файлам, входящим в пакеты. Работая сравнительно быстро, она создает мгновенный снимок состояния вашей системы.

Далее - Сайты, посвященные RPM, в Интернете
Назад - Нахождение программного обеспечения в формате rpm-пакетов
Содержание


7.2 Сайты, посвященные RPM, в Интернете


7.3.1 Yum

Yum - очень мощный пакетный менеджер. Он умеет автоматически разрешать зависимости, а это делает установку пакета со множеством зависимостей тривиальной операцией. Yum также умеет искать и удалять пакеты, а также запрашивать различные списки.

В таблице ниже приводятся основные опции команды yum.

Опция

Значение

-h, --help

Вывод короткой справки

-t, --tolerant

Включить режим игнорирования некритичных ошибок

-C

Работать из кеша, не обновляя его

-c config_file

После этого ключа указывается альтернативный конфиг-файл

-R minutes

Максимальное время ожидания в минутах

-d debug_level

Уровень отладочных сообщений

-e error_level

Уровень многословности сообщений об ошибках

-y

Автоматически отвечать "yes" на все возникающие вопросы

--version

Вывести версию yum

--installroot=path

Указать корневой каталог установки, отличный от каталога по умолчанию (корневой)

--enablerepo=repo

Сделать доступным один или несколько дополнительных репозиториев (поддерживаются шаблоны)

--disablerepo=repo

Сделать недоступными один или несколько репозиториев (поддерживаются шаблоны)

-x, exclude=package

Исключить пакет по имени или шаблону

--obsoletes

Включить обработку возможностей, которые устанавливаемый пакет делает неактуальными

--noplugins

Отключить плагины yum

--nogpgcheck

Отключить проверку подписи gpg

--disableplugin=plugin

Отключить конкретный плагин по его имени

Применение yum сравнительно несложно. Далее приводятся наиболее употребительные примеры.

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

$ yum search package_name

Вывод списка доступных пакетов
Yum будет проверять все доступные ему репозитории и выведет список пакетов с указанием для каждого, откуда он может загрузить его:

$ yum list available

Получение информации о пакете

$ yum info package_name

Установка пакета
Эта операция выполняется от имени пользователя root:

# yum install package_name

Вывод списка установленных пакетов

$ yum list extras

Удаление пакета
Эта операция выполняется от имени пользователя root. Вы можете удалить пакет и все его зависимости. Если какое-либо приложение использует зависимости удаляемого пакета, они будут оставлены в системе:

# yum remove package_name

Обновление всей системы
Можно обновить всю систему без какой-либо необходимости ручного вмешательства:

# yum update

Если нужно проверить наличие обновлений, тогда:

# yum check-update

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

# yum localinstall /path/to/the/rpm

Далее - Рекомендуемые плагины yum
Назад - Сайты, посвященные RPM, в Интернете
Содержание


7.3.2 Рекомендуемые плагины yum

yum-presto
Этот плагин ускоряет процессы обработки данных и загрузки пакетов с помощью информации о различиях между старым и новым пакетом на уровне файлов. Особенно помогает при установке большого количества обновлений. Установите плагин с помощью следующей команды:

# yum -y install yum-presto

Есть, однако, особенность использования yum-presto. Во время работы плагина должны быть доступны специальные репозитории presto. Отредактируйте /etc/yum.repos.d/fedora-updates-newkey.repo (для Fedora). Нужно изменить mirrorlist на:

mirrorlist=http://presto-mirrors.anmar.eu.org/mirrorlist?repo=updates-released-f$releasever.newkey&arch=$basearch

Далее - Графические фронт-энды программ управления пакетами
Назад - Yum
Содержание


4.2.1 Описание пакета

Опция -i в сочетании с командой запроса заставит rpm выдать информацию о пакете. Кроме -i можно использовать длинный вариант: --info. Базовый синтаксис:

rpm -qi package

Последовательность ключей важна. Если -i будет на первом месте, утилита перейдет в режим установки пакета. rpm -q переводит систему в режим запросов.

Пример запроса информации о пакете:

# rpm -qi tcsh-6.10-6

Name : tcsh Relocations: (not relocateable)

Version : 6.10 Vendor: Red Hat, Inc.

Release : 6 Build Date: Sun 24 Jun 2001 10:45:29
PM CDT

Install date: Fri 14 Dec 2001 10:45:39 AM CST Build

Host: porky.devel.redhat.com

Group : System Environment/Shells

Source RPM: tcsh-6.10-6.src.rpm

Size : 764000 License: distributable

Packager : Red Hat, Inc.

URL : http://www.primate.wisc.edu/software/csh-tcsh-book/

Summary : An enhanced version of csh, the C shell.

Description :
Tcsh is an enhanced but completely compatible version of csh, the C
shell. Tcsh is a command language interpreter which can be used both
as an interactive login shell and as a shell script command processor.
Tcsh includes a command line editor, programmable word completion,
spelling correction, a history mechanism, job control and a C language
like syntax.

Из вывода такой команды можно извлечь массу информации о пакете, например, кто его поставляет. Следует обратить внимание также на точное имя пакета с исходным кодом, из которого был собран исследуемый пакет.

Далее - Группы пакетов
Назад - Какому пакету принадлежит файл?
Содержание


7.3.3 Графические фронт-енды программ управления пакетами

7.3.3.1 Yumex
Extended yum - графическая оболочка yum для пользователей, которым не нравится командная строка. Для установки выполните команду (репозитории должны быть настроены):

# yum -y install yumex

Yumex имеет интуитивно понятный интерфейс и встроенную справку. Для пользователей, понимающих, как работает yum, сложностей с использованием yumex не бывает.

7.3.3.2 PackageKit
PackageKit позиционируется разработчиками как мета-инструмент, который должен работать не только в разных rpm-based дистрибутивах, но и в deb-based дистрибутивах. В настоящее время в современных дистрибутивах Fedora используется инкарнация программы KPackageKit (и в Gnome, и в KDE). Он имеет аскетичный интерфейс и немногословен в плане вывода диагностики. Например, если запрос пакетов невозможен вследствии недоступности сети или некоторых репозиториев, операция завершится с ошибкой. Сообщений типа "Вставьте дистрибутивный диск" или "Репозиторий недоступен" не будет. Пока этот инструмент особенной популярностью не пользуется, хотя в Fedora 10 является утилитой менеджмента пакетов по умолчанию (в графической среде).

Далее - Раздел 8. Создание rpm-пакетов: обзор
Назад - Рекомендуемые плагины yum
Содержание


12.1.1 Использование плагинов vim для облегчения редактирования spec-файлов

Легендарный в мире Unix редактор vi, разработанный Bill Joy в 1976 году, в настоящее время не является свободным программным обеспечением, поэтому в Linux системах применяется Open Source - реализация vi - текстовый процессор vim (http://www.vim.org). Он доступен на условиях GPL во всех Линуксах и бОльшей части Unix-систем, а также для Windows. Помимо реализации "в лоб" функциональности оригинального vi, vim также имеет множество особенностей, которые в vi отсутствуют. Одной из таких особенностей является умение подсвечивать синтаксис spec-файла. vim имеет расширяемый интерфейс, через который ему можно передавать информацию о типе обрабатываемого файла, что указывает на способ подсветки текущего синтаксиса. Имея поддержку какого-либо типа файлов, редактор может подсвечивать синтаксис этого типа различными способами. Это очень удобно при написании кода и скриптов, например, редактор сразу укажет на ошибку незакрытого цикла в shell-коде и другие подобные коллизии.

Изначально поддержка синтаксиса spec-файла в vim отсутствует. Необходимо подключить файл синтаксиса spec.vim. После подключения плагина редактор подсвечивает все ключевые структуры spec-файла, что значительно облегчает его редактирование. Большинство дистрибутивов Linux, в том числе и Red Hat Linux имеют этот плагин в составе дистрибутива. Если используется не Linux-система, потребуется загрузить плагин отдельно. Обычно пользовательские настройки vim сохраняются в каталогах вроде ~/etc/vim. Чтобы плагин заработал, его расположение следует указать в файле ~/.vimrc, добавив в него следующую секцию:

augroup syntax

au! BufNewFile,BufReadPost *.spec so ~/etc/vim/spec.vim

au BufNewFile,BufReadPost *.spec so ~/etc/vim/spec.vim

augroup END

Для настройки цветов подсветки потребуется отредактировать файл ~/etc/vim/spec.vim.

vim имеет сотни встроенных команд для форматирования текста. При необходимости можно добавить новые команды. Эти команды могут быть определены в плагинах FileType, таким образом набор доступных команд будет зависеть от типа редактируемого файла. Gustavo Niemeyer написал плагин pi_spec, содержащий различные команды для работы со spec-файлом. Например, этот плагин облегчает редактирование журнала изменений с помощью вызова специальных макросов путем нажатия сочетания клавиш. Кроме того, он умеет проверять, действительно ли растет номер версии от записи к записи.

Далее - Добавление функций редактирования с помощью emacs-плагина rpm-spec-mode
Назад - Импорт публичного ключа
Содержание


12.1.2 Добавление функций редактирования с помощью emacs-плагина rpm-spec-mode

Другим популярным в мире Unix редактором является emacs, написанный
Richard M. Stallman. В отличие от vi, emacs не входит во все системы по умолчанию, но доступен во всех дистрибутивах Linux в виде отдельных пакетов.

Подобно vim, emacs умеет подсвечивать различные синтаксисы и имеет интерфейс для подключения плагинов различных синтаксисов и дополнительных команд.

Для подключения плагина обработки spec-файлов следует указать такие инструкции в файле ~/.emacs (или ~/.xemacs, в зависимости от того, какую реализацию вы используете):

(autoload 'rpm-spec-mode "rpm-spec-mode.el" "RPM spec mode." t)

(setq auto-mode-alist (append '(("\\.spec" . rpm-spec-mode)) auto-mode-alist))

Файл режима rpm-spec-mode.el содержит указания на то, что должно подсвечиваться и какими цветами. Кроме того, файл режима содержит дополнительные функции обработки spec-файлов, например быстрые клавиши для навигации между секциями. Некоторые важные макрокоманды приведены в таблице ниже.

Команда

Выполняет

Ctrl+C Tab

Добавление нового тэга в spec-файл

Ctrl+C Ctrl+F F

Добавление нового файла в секцию %files

Ctrl+C Ctrl+F C

Добавление нового конфигурационного файла в секцию %files

Ctrl+C Ctrl+F D

Добавление нового файла документации в секцию %files

Ctrl+C Ctrl+F G

Добавление нового ghost-файла в секцию %files

Ctrl+C Ctrl+D D

Добавление нового каталога в сецию %files

Ctrl+C Ctrl+D O

Добавление нового каталога с документацией в секцию %files

Ctrl+C Ctrl+C U

Смена маски в поле %defattr секции %files

Ctrl+C Ctrl+C O

Смена владельца в поле %defattr секции %files

Ctrl+C Ctrl+C G

Смена группы в поле %defattr секции %files

(Субъективное мнение переводчика. Все эти дополнительные функции редакторов vim и emacs по эффективности применения не идут ни в какое сравнение с эффективностью редактора mcedit, который практически не требует времени на освоение)

Далее - Отладка spec-файла с помощью rpmlint
Назад - Использование плагинов vim для облегчения редактирования spec-файлов
Содержание


12.1.3 Отладка spec-файла с помощью rpmlint

После того, как spec-файл написан, на его основе может быть собран бинарный rpm-пакет, который в свою очередь может быть проверен на наличие наиболее общих ошибок. Эту проверку можно выполнить с помощью утилиты rpmlint. Имя rpmlint пришло из Unix, где популярна утилита lint. Она используется для "санитарной проверки" кода на C. Типичные ошибки разработчиков ищутся с помощью шаблонов этих ошибок. Идея rpmlint сходная - в процессе анализа бинарного rpm-пакета искать наиболее часто повторяющиеся ошибки пакетировщиков.

rpmlint имеет интерфейс подключения новых функций, однако и поставляется с довольно большим набором стандартных проверок. Стандартно проверяются следующие факты: .noarch.rpm не содержит бинарных файлов, никакие бинарные файлы не устанавливаются в каталог /etc, типы бинарных файлов соответствуют заявленной процессорной архитектуре, разделяемые библиотеки сконфигурированы корректно, все исполняемые файлы подверглись очистке от лишних символов (операция strip).

Кроме того, rpmlint выполняет ряд проверок на соответствие файлов пакета стандарту Filesystem Hierarchy Standard, стандарту Linux Standards Base и что все файлы и каталоги имеют правильные атрибуты доступа. Init-скрипты проверяются на соответствие базовой структуре init-скрипта и что %post и %preun правильно их конфигурируют. %post, %pre и %preun проверяются на указание на правильные интерпретаторы и на верность синтаксиса с точки зрения этих интерпретаторов. Также проверяется различными способами целостность пакета в целом.

Установленная утилита rpmlint может быть сконфигурирована путем редактирования файлов /etc/rpmlint/config или, в масштабе пользователя, $HOME/.rpmlintrc.

Пример запуска rpmlint для пакета с исходным кодом:

$ rpmlint tin-1.5.12-1.src.rpm

E: tin no-packager-tag

W: tin invalid-license distributable

W: tin no-url-tag

W: tin strange-permission tin-1.5.12.tar.bz2 0664

W: tin obsolete-tag Copyright

Как показывает вывод, в основном пакет выглядит как правильно сформированный. Права на файлы кода могут быть изменены на 0644 и поле Copyright заменено на License, после чего пакет станет полностью легитимным (с точки зрения rpmlint).

При запуске rpmlint для бинарного пакета увидим примерно следующее:

$ rpmlint tin-1.5.12-1.i386.rpm

W: tin invalid-vendor None

W: tin invalid-distribution None

E: tin no-packager-tag

W: tin invalid-license distributable

W: tin no-url-tag

Данный пакет выглядит правильным. Предупреждения об отсутствии необязательных полей можно игнорировать. Тип лицензии rpmlint неизвестен. Это можно изменить или также проигнорировать.

Многие вендоры Linux проверяют с помощью rpmlint дистрибутивы в целом. Подвергать такой проверке отдельные пакеты, особенно приходящие извне - это хороший подход.

Далее - Использование rpm2cpio для извлечения файлов из нагрузки пакетов
Назад - Добавление функций редактирования с помощью emacs-плагина rpm-spec-mode
Содержание


12.1.4 Использование rpm2cpio для извлечения файлов из нагрузки пакетов

В стандартной ситуации сборщик пакетов имеет дело с пакетами с исходным кодом и бинарными rpm-пакетами, которые содержат файлы программ или кода в виде, пригодном для использования конечным пользователем. Порой, однако, конечный пользователь может попасть в ситуацию, когда они со сборщиком пакетов находятся по разные стороны баррикады. Доступ к файлам, содержащимся в полезной нагрузке пакета всегда можно получить, установив его в систему, но если пользователю это не нужно? Странно устанавливать пакет ради доступа к spec-файлу или одному патчу. А если нужно использовать файлы на не-Linux системе, например, в Solaris?

К счастью относительно несложно извлечь файлы из rpm-пакета с помощью специальных средств (или двух нажатий клавиши в файловом менеджере Midnight Commander - прим. переводчика).

Структурно пакет представляет собой метаданные и cpio-архив, упакованные в один файл. Если убрать бинарный заголовок, можно получить полноценный cpio-архив формата cpio System V R4, которым впоследствии манипулировать с помощью команды cpio.

RPM поставляется с утилитой rpm2cpio, основной задачей которой является конвертация файла rpm-пакета в cpio-архив, который она выдает на стандартный вывод. Базовый синтаксис использования rpm2cpio:

$ rpm2cpio fluxbox-0.1.8-2.src.rpm > fluxbox-0.1.8-2.cpio

Эта команда создает cpio-архив из пакета. Им можно манипулировать с помощью cpio или перенаправить на вход различных конвейеров:

$ rpm2cpio fluxbox-0.1.8-2.src.rpm | cpio -i -d

656 blocks

Эта команда получает содержимое нагрузки пакета в виде файлов.

rpm2cpio входит в состав RPM и поэтому доступна во всех rpm-based Linux дистрибутивах. Однако, стандартная реализация утилиты написана на C, поэтому ее использование, например, в Solaris, подразумевает первоначально сборку бинарного модуля. Для кросс-платформенного применения существует две реализации rpm2cpio на скриптовых языках - Perl и bash. Bash скрипт будет работать не только в большинстве Unix-системах, но и в Windows под cygwin. Ниже приведен скрипт, который можно сохранить под именем rpm2cpio.sh, сделать исполнимым и поместить в стандартный каталог программ, например, /usr/bin, после чего можно манипулировать архивами, полученными из rpm-пакетов обычным образом:

#!/bin/sh

pkg=$1

if [ "$pkg" = "" -o ! -e "$pkg" ]; then

echo "no package supplied" 1>&2

exit 1

fi

leadsize=96

o=`expr $leadsize + 8`

set `od -j $o -N 8 -t u1 $pkg`

il=`expr 256 \* \( 256 \* \( 256 \* $2 + $3 \) + $4 \) + $5`

dl=`expr 256 \* \( 256 \* \( 256 \* $6 + $7 \) + $8 \) + $9`

# echo "sig il: $il dl: $dl"

sigsize=`expr 8 + 16 \* $il + $dl`

o=`expr $o + $sigsize + \( 8 - \( $sigsize \% 8 \) \) \% 8 + 8`

set `od -j $o -N 8 -t u1 $pkg`

il=`expr 256 \* \( 256 \* \( 256 \* $2 + $3 \) + $4 \) + $5`

dl=`expr 256 \* \( 256 \* \( 256 \* $6 + $7 \) + $8 \) + $9`

# echo "hdr il: $il dl: $dl"

hdrsize=`expr 8 + 16 \* $il + $dl`

o=`expr $o + $hdrsize`

dd if=$pkg ibs=$o skip=1 2>/dev/null | gunzip

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

$ rpm2cpio.sh fluxbox-0.1.8-2.src.rpm | cpio -i -d

656 blocks

В данном случае мы перенаправили вывод на cpio, распаковывая архив напрямую. Можно перенаправить вывод и в файл, если это требуется.

Perl-реализация rpm2cpio написана Roger Espel Llima. Этот скрипт должен работать во всех системах, имеющих современный интерпретатор Perl. Сохраните скрипт в файле rpm2cpio.pl, сделайте его исполнимым и поместите в каталог программ.

#!/usr/bin/perl

# Copyright (C) 1997,1998,1999, Roger Espel Llima

#

# Permission is hereby granted, free of charge, to any person obtaining a copy

# of this software and any associated documentation files (the "Software"), to

# deal in the Software without restriction, including without limitation the

# rights to use, copy, modify, merge, publish, distribute, sublicense,

# and/or sell copies of the Software, and to permit persons to whom the

# Software is furnished to do so, subject to the following conditions:

#

# The above copyright notice and this permission notice shall be included in

# all copies or substantial portions of the Software.

#

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

# SOFTWARE'S COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

# THE SOFTWARE

# (whew, that's done!)

# why does the world need another rpm2cpio? because the existing one

# won't build unless you have half a ton of things that aren't really

# required for it, since it uses the same library used to extract RPM's.

# in particular, it won't build on the HPsUX box i'm on.

# sw 2002-Mar-6 Don't slurp the whole file

# add a path if desired

$gzip = "gzip";

sub printhelp {

print <
rpm2cpio, perl version by orabidoo +sw

dumps the contents to stdout as a cpio archive

use: rpm2cpio [file.rpm] > file.cpio

Here's how to use cpio:

list of contents: cpio -t -i < /file/name

extract files: cpio -d -i < /file/name

HERE

exit 0;

}

if ($#ARGV == -1) {

printhelp if -t STDIN;

$f = "STDIN";

} elsif ($#ARGV == 0) {

open(F, "< $ARGV[0]") or die "Can't read file $ARGV[0]\n";

$f = 'F';

} else {

printhelp;

}

printhelp if -t STDOUT;

# gobble the file up

##undef $/;

##$|=1;

##$rpm = <$f>;

##close ($f);

read $f,$rpm,96;

($magic, $major, $minor, $crap) = unpack("NCC C90", $rpm);

die "Not an RPM\n" if $magic != 0xedabeedb;

die "Not a version 3 or 4 RPM\n" if $major != 3 && $major != 4;

##$rpm = substr($rpm, 96);

while (!eof($f)) {

$pos = tell($f);

read $f,$rpm,16;

$smagic = unpack("n", $rpm);

last if $smagic eq 0x1f8b;

# Turns out that every header except the start of the gzip one is

# padded to an 8 bytes boundary.

if ($pos & 0x7) {

$pos += 7;

$pos &= ~0x7;# Round to 8 byte boundary

seek $f, $pos, 0;

read $f,$rpm,16;

}

($magic, $crap, $sections, $bytes) = unpack("N4", $rpm);

die "Error: header not recognized\n" if $magic != 0x8eade801;

$pos += 16;# for header

$pos += 16 * $sections;

$pos += $bytes;

seek $f, $pos, 0;

}

if (eof($f)) {

die "bogus RPM\n";

}

open(ZCAT, "|gzip -cd") || die "can't pipe to gzip\n";

print STDERR "CPIO archive found!\n";

print ZCAT $rpm;

while (read($f, ($_=''), 16384) > 0) {

print ZCAT;

}

close ZCAT;

Применение rpm2spio.pl:

$ rpm2cpio.pl fluxbox-0.1.8-2.src.rpm | cpio -i -d

CPIO archive found!

656 blocks

В зависимости от используемой системы, какая-то из трех реализаций будет работоспособна (или все).

Далее - Раздел 13. Пакетостроение - генеральная линия партии или колхоз "Светлый путь"
Назад - Отладка spec-файла с помощью rpmlint
Содержание


1.1 Необходимость системы управления пакетами

Хотя Linux, понимаемый как ядро операционной системы, великолепен, одного ядра недостаточно для выполнения даже рутинных задач. Точное техническое определение понятия "операционная система" - по сей день предмет жарких дебатов. Однако фактически любой пользователь Linux помимо ядра использует массу приложений (начиная от стандартной библиотеки C и заканчивая такими пафосными в мире Unix приложениями, как редактор vi) для достижения своих повседневных целей, поэтому мы понимаем Linux расширительно, как дистрибутив ОС, как GNU/Linux.

Пользователи используют Linux и в качестве платформы для запуска веб-сервера Apache, и в качестве десктопа для запуска OpenOffice.org, и в качестве пускача для Lotus Notes/Domino и других коммерческих приложений. Но в целом - в качестве хоста для множества функциональных пакетов ПО. По сути дела, пользователи перестали различать Linux как ядро и Linux как все остальное, что приходит в составе дистрибутива. Некоторые дистрибутивы поставляются в составе десятков тысяч пакетов (много DVD-дисков). Эта ситуация просто требует эффективной системы пакетного менеджмента. Плюс ко всему, свободное программное обеспечение поставляется в основном в виде исходных кодов и может быть установлено в систему только после сборки бинарных модулей.

Множество пользователей не имеют достаточной квалификации для решения многих задач разработчика, например, кросс-сборки целой системы из исходного кода. И даже если кто-то решил приобрести квалификацию по ходу процесса, чем окупится время, затраченное на разворачивание и компиляцию системы с нуля, если конечная цель - запустить на своей машине Linux?

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

Самые первые дистрибутивы, такие как MCC и SLS представляли собой ни что иное, как снимки с рабочих винчестеров разработчиков. Пользователь не имел никаких инструментов контроля за тем, что будет установлено в его системе, если он скопирует себе такой снапшот. Что было на текущий момент, то инсталлятор устанавливал и пользователю. Поэтому наилучшим выбором было собирать свой дистрибутив самому. Разработчики, однако, быстро смекнули, что популярность дистрибутива зависит от возможности выбора в широком смысле слова, как во время инсталляции, так и после установки системы. Начался поиск оптимальных решений.

Например, Slackware делил все приложения на несколько функциональных категорий. Все пользователи получали базовую систему. Если нужно было что-то еще, пользователь мог выбрать категорию. Нужны сетевые приложения - устанавливались все сетевые приложения. Нужна графика - устанавливался X-сервер и все графические приложения. Эта концепция реализовывала принцип свободы выбора, но на очень примитивном уровне.

Следующий логический шаг в эволюции дистрибутивов - разработка инструментов детального контроля устанавливаемых приложений. Несколько вендоров дистрибутивов занялись независимой разработкой средств управления ПО на уровне приложений. Было ясно, что Slackware двигается в правильном направлении, но атомизация процесса должна базироваться на отдельном приложении, чтобы его можно было установить/удалить.

В 1993 году Rik Faith, Doug Hoffman и Kevin Martin начали публиковать первые бета-версии дистрибутива BOGUS. BOGUS был снабжен системой пакетного менеджмента (pms) и базировался на концепции возможности установки/удаления ПО на уровне приложений. Некоторое время спустя был представлен коммерческий дистрибутив Red Hat Commercial Linux (лето 1994 года). Первоначально Red Hat использовал Software Program Packages (RPP) в качестве системного инструмента управления пакетами. Подобно pms, RPP здорово облегчал задачу установки/удаления ПО.

Хорошие идеи приходят в голову хорошим людям одновременно, поэтому тем же летом 1994 года Ian Murdock основал дистрибутив Debian Gnu/Linux, который в свою очередь базировался на системе управления пакетами dpkg, разрабатываемой с начала 1993.

Далее - Цели разработки RPM
Содержание


1.2 Цели разработки RPM

Все ранние инструменты управления системными свойствами в конечном итоге имели одну цель. Они пытались предоставить возможности установки целого приложения с помощью одной команды, отслеживания файлов, которые должны быть установлены в систему и удаления этих файлов также с помощью одной команды. Поскольку этот подход предлагался в качестве преимущества, постольку он и был популярен. Все ранние системы, однако, имели как технические, так и практические недостатки. Некоторые работали только на 32-разрядной Intel-платформе, хотя наличие иных платформ и ядра для них требовали кроссплатформенных свойств от подобных приложений. Другие инструменты имели проблемы в процессах проверки подготовленных пакетов, что делало невозможной уверенность в правильности сборки пакетов и воспроизводимую сборку. Из-за этих нерешенных вопросов, после выхода первого релиза Red Hat Linux разработчики обратили пристальное внимание на собственную систему RPP и другие подобные системы, в частности на ПО BOGUS pms. Разработчики Red Hat Marc Ewing и Erik Troan принялись за написание того, что они назвали Red Hat Package Manager (RPM). Основываясь на подходах ранних систем управления, своих знаниях и сравнительном анализе, Red Hat имела в виду несколько ясных ориентиров при разработке RPM. Среди них были следующие функциональные требования:

* Легкость использования
* Ориентирование на понятие "пакет"
* Возможность обновления пакетов
* Отслеживание межпакетных зависимостей
* Возможность различных запросов
* Возможность верификации
* Поддержка различных процессорных архитектур
* Использование "чистых" исходников

В следующих главах показывается, как Red Hat удалось выполнить эти требования в проекте RPM.

Далее - Легкость использования
Назад - Необходимость системы пакетного менеджмента
Содержание


1.2.1 Легкость использования

Возможно, первичной целью разработки RPM была цель построения системы, легкой в использовании. Ручная инсталляция ПО была главным методом разворачивания программ на Unix-станциях в течение тридцати лет до этого и на протяжении этих лет подход всегда работал хорошо. Чтобы резоны предложения нового программного обеспечения были весомы, RPM должен был быть действительно значительно проще в использовании всех других инструментов. Поэтому большая часть задач должна была выполнятся с помощью одной команды. Например, установить пакет можно с помощью одной команды rpm -U software_package, в то время как ручной метод в стиле GNU требует как минимум нескольких шагов для выполнения той же задачи:

tar zxf software_package

cd software_package

./configure

make

su

make install

Также и удаление пакета с помощью RPM требует одной команды, в случае ручной установки удалить чисто все файлы - задача трудная, а подчас и невозможная (если почему-либо был удален Makefile, содержащий цель uninstall).

Далее - Ориентирование на понятие "пакет"
Назад - Цели разработки RPM
Содержание


1.2.2 Ориентирование на понятие "пакет"

Подобно своим предшественникам, RPM подразумевает действия с ПО на уровне пакетов. По сравнению с оперированием на уровне отдельных файлов (когда при разворачивании ПО на Unix-станции наиболее употребимыми командами были mv u cp) или на уровне подсистем в целом, RPM предоставляет возможность управления сотнями и тысячами отдельных пакетов. Каждый пакет - дискретный набор компонентов одного приложения или библиотеки (файлы приложения, документация, файлы конфигурации).

Путем фокусирования на понятии "пакет", RPM стал системой, сделавшей установку или удаление приложения экстремально простым действием.

Далее - Возможность обновления пакетов
Назад - Легкость использования
Содержание


1.2.3 Возможность обновления пакетов

В дополнение к своему пакетно-ориентированному подходу, RPM дизайн должен был обеспечивать возможность обновления пакетов. Если в систему установлен пакет, следует иметь инструмент, который позволит установить новую версию этого пакета, не нарушая целостности. При этом для приложения устанавливаются файлы новых верси, а старые файлы удаляются. В процессе обновления RPM должен предотвратить некоторые возможные действия по автоматизированной настройке приложения.

Например, веб-сервер Apache устанавливается в систему для обслуживания веб-доступа к документам и веб-сервисам. Конфигурация Apache хранится в текстовых файлах, в которых администраторы производят различные настройки поведения сервера. Если вы производите обновление пакета, RPM принимает меры предосторожности от возможного изменения файлов конфигурации. В сравнении с этим подходом ручная сборка и установка приложения заставляет администратора делать резервные копии конфигурации, возвращая их впоследствии на место, в противном случае он рискует потерять все сделанные ранее настройки.

Далее - Межпакетные зависимости
Назад - Ориентирование на понятие "пакет"
Содержание


8.1 Подготовка к сборке пакета

Задача сборки пакета начинается со сбора всех необходимых материалов. Завершающими этапами являются собственно сборка и тестирование пакета. Это звучит слишком просто и в этом смысле, как правило, не является отражением действительности.

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

Классификация подзадач при сборке пакета может выглядеть следующим образом:

1. Планирование того, что желательно собрать
2. Комплектование ПО для пакета
3. Накладывание при необходимости патчей на исходный код
4. Осуществление воспроизводимой сборки ПО
5. Планирование обновлений
6. Отслеживание зависимостей
7. Сборка пакета
8. Тестирование пакета

В последующих главах рассматриваются все эти подзадачи.

Далее - Планирование: что хотим собрать
Назад - Графические фронт-енды программ управления пакетами
Содержание


1.2.4 Межпакетные зависимости

Программное обеспечение, управляющее установленными в систему приложениями на уровне отдельного приложения или библиотеки имеет существенный недостаток в сравнении с подходом, согласно которому ОС управляет приложениями с точки зрения целой системы (подобно Microsoft Windows или OS/2), которые допускают обновление всей системы, но не отдельных приложений. Дело в том, что приложения часто имеют взаимные зависимости друг от друга - одно приложение может работать, только если установлено другое.

Например, для поддержки аутентификации пользователей почтовые агенты Postfix и Sendmail нуждаются в пакете Cyrus SASL, иными словами, зависят от него. Для систем, в которых управление ПО основано на системе в целом подобные зависимости не представляют большой проблемы. Все необходимые компоненты включены в систему изначально и обновление в системе происходит путем увязанного обновления всех компонентов.

Например, в Microsoft Windows 2000 веб-сервер IIS зависит от других приложений, вроде EventLog. Поскольку управление ПО происходит на системном уровне, эта зависимость гарантированно обеспечивается.

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

Далее - Возможность запросов
Назад - Возможность обновления пакетов
Содержание


1.2.5 Возможность запросов

Как часть своей реализации, RPM поддерживает базу данных установленных пакетов с информацией о функционале, зависимостях и времени установки пакетов.

Это сильно облегчает управление пакетами, так как с помощью одной команды можно запросить информацию обо всех установленных пакетах, определить, какому приложению принадлежит файл или откатить неудачное обновление.

Далее - Верификация пакетов
Назад - Межпакетные зависимости
Содержание


1.2.6 Верификация пакетов

RPM также обслуживает полный набор сведений о всех файлах, установленных в систему. Хранятся данные о правах на файл, которые должны быть, размер файла, который был установлен и так далее. Дизайн базы данных установленных пакетов обеспечивает легкость проверки этих сведений.

С течением времени в жизни системы могут происходить изменения, которые ведут к неработоспособности компонентов. Например, администратор выставил неверные права доступа к ключевым файлам, или произошло какое-либо экзотическое событие, изменился один символ, по правильному адресу в памяти записались неверные данные, один бит памяти вышел из ожидаемого значения и приложение пришло в неработоспособное состояние. Хотя RPM не может предотвратить подобные события, он может предупредить о наиболее общих ошибках. Если приложение не работает, можно запустить процедуру верификации с целью убедиться, что все файлы приложения сохранили целостность и правильные права доступа.

Далее - Поддержка различных архитектур
Назад - Возможность запросов
Содержание


1.2.7 Поддержка различных архитектур

БОльшая часть целей разработки RPM сфокусирована на системных администраторах и пользователях, которые часто устанавливают/удаляют/обновляют приложения и проверяют файлы установленных пакетов. Однако некоторая часть дизайна ориентирована на разработчиков, которые подготавливают ПО в виде пакетов, которые должны быть установлены в различные системы посредством RPM.

Одним из нативных ограничений ранних систем управления в Linux было ориентирование на одну архитектуру Intel 32-bit. С 1994 года началась работа по поддержке других архитектур. Первыми кандидатами на поддержку ядром были Digital Alpha и Motorola 68000. Эта задача породила проблему для вендоров дистрибутивов, таких как Red Hat и Debian, и для разработчиков приложений, которые собирали пакеты для Linux. Поскольку существовавшие методы пакетирования не предполагали производство пакетов для многих архитектур, сборщикам пакетов приходилось применять много ручного труда для того, чтобы предоставить пакет под альтернативную архитектуру.

Однако собранные пакеты не имели никаких индикаторов, указывающих на целевую архитектуру, что отнюдь не облегчало жизнь конечным пользователям.

В Red Hat было принято решение преодолеть это ограничение путем встраивания мультиплатформенной поддержки в саму конструкцию RPM. Это также предусматривало наличие индикаторов в собранном пакете, для какой архитектуры он собирался.

Далее - "Чистые" исходные коды
Назад - Верификация пакетов
Содержание


1.2.8 "Чистые" исходные коды

Система управления пакетами дистрибутива BOGUS - pms, использовала чистые исходные коды для подготовки пакетов. В Red Hat RPP и других подобных ранних проектах, сборщики пакетов должны были компилировать ПО вручную. Любые изменения оригинального исходного кода не документировались и должны были воспроизводится другими людьми в случае необходимости. Однако конечный пользователь желает знать, какие изменения были произведены, а такой возможности не было.

В системе RPM предусмотрено два типа пакетов - бинарные и пакеты с исходным кодом. Бинарные пакеты содержат собранное ПО, которое может быть установлено и использовано. Пакеты с исходным кодом содержат исходный код этого ПО с документацией о том, каким именно образом ПО должно собираться, чтобы получился тот самый бинарный пакет. Эта отличительная черта - возможно единственное, что действительно отличает RPM от, например, пакетных менеджеров коммерческих Unix (pkg). Пакеты с исходным кодом сильно облегчают работу сборщика пакетов, поскольку имеется возможность взять референсный пакет со старым кодом, изменить его и выпустить новую версию пакета с новыми возможностями, необходимыми пользователям. Все изменения оформляются патчами и процесс их применения к "чистым" исходникам документирован.

Далее - Терминология RPM
Назад - Пооддержка различных архитектур
Содержание


1.3 Терминология RPM

Ключевым моментом в работе с RPM является понимание концепции пакетов. RPM пакеты поставляются в виде компрессированных архивов, которые содержат не менее одного файла, а также инструкции по установки этих файлов, включая права доступа, которые должны быть применены к каждому файлу в процессе установки. Эти инструкции также могут содержать скрипты, которые запускаются перед или после установки (удаления) пакета.

Пакет в виде архива весьма удобен для применения, один файл, содержащий все необходимое для установки приложения, это очень практичный формат для передачи пакетов по сети или на других носителях, по сравнению с необходимостью передавать много файлов, если управление ПО происходит на уровне отдельных файлов.

Для облегчения установки и управления все пакеты имеют ясные имена. Полное имя делится на 4 части и выглядит так:

kernel-smp-2.4.18-3.athlon.rpm

kernel-smp-2.4.18-3.i586.rpm

kernel-smp-2.4.18-3.i686.rpm

kernel-source-2.4.18-3.i386.rpm

rootfiles-7.2-1.noarch.rpm

Части имен отделяются дефисами или точками. Структура имени такова: имя-версия-релиз.процессорная_архитектура.rpm .

Имя указывает на ПО, содержащееся в пакете. Например, kernel-smp содержит ядро Linux с поддержкой многопроцессорности. Иногда пакет представляет собой коллекцию файлов, необходимых системе. Например, пакет rootfiles - это не приложение или библиотека, а набор базовых файлов конфигурации системы, таких как /root/.bashrc, представляющих собой преконфигурированное окружение пользователя root.

Второе поле - это версия. Версия указывает на версию ПО, содержащегося в пакете. Например, kernel-smp-2.4.18 говорит о том, что в пакете содержится ядро версии 2.4.18.
Каждый пакет также имеет поле релиза. Изменение релиза может указывать как на изменения в самом пакете, так и на изменения в содержащемся ПО.

Финальным полем является поле процессорной архитектуры, например, i586 или athlon. Файлы с четвертым полем noarch содержат только скрипты или документацию, но не бинарные модули.

Таблица поддерживаемых процессорных архитектур приведена ниже.

Платформа

Идентификаторы

Intel 32-bit совместимые

i386, i486, i586, i686, athlon

Intel 64-bit совместимые

ia64

HP Alpha

alpha, alphaev5, alphaev56, alphapca56, alphaev6,
alphaev67

Sparc/Ultra Sparc (Sun)

sparc, sparcv9, sparc64

ARM

armv3l, armv4b, armv4l, armel

MIPS

mips, mipsel

Power PC

ppc, ppciseries, ppcpseries, ppc64

Motorola 68000

m68k, m68kmint

SGI MIPS

Sgi

IBM RS6000

rs6000

IBM S/390

i370, s390x, s390

Платформно-независимые пакеты

noarch

Расширение .rpm присутствует у всех пакетов RPM.

Имя установленного пакета с точки зрения RPM отличается от имени файла rpm-пакета. Пакеты, загружаемые из сети, устанавливаемые с какого-либо носителя всегда имеют формат имени name-version-release.architecture.rpm . Установленные пакеты, имена которых могут использоватся в качестве аргументов команды rpm, имеют формат name-version-release. Установленный пакет как правило имеет много файлов, не один rpm-файл. И все эти файлы будут принадлежать одному пакету. Поэтому kernel-smp-2.4.18-3.i586.rpm, установленный в систему, будет идентифицироваться как kernel-smp-2.4.18-3. Возможность обращения к пакету только по имени, без версии и релиза будет означать, что только одна версия-релиз установлена в систему. В противном случае, RPM будет требовать указания версии-релиза для различения разных пакетов.

Далее - Раздел 2. Обзор RPM
Назад - "Чистые" исходные коды
Содержание


8.1.1 Планирование: что хотим собрать

Первый шаг на многотрудном пути оформления ПО в виде rpm-пакета - определенно решить, что имеется в виду получить в итоге. Пакет с приложением? библиотекой? Коллекцию файлов конфигурации? Документацию? Если это приложение, будет ли оно изменено, будут ли накладываться патчи?

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

Многие проекты стартуют с имеющегося src.rpm-пакета, но также многие - с архива с исходным кодом. Имеющийся src.rpm-пакет значительно облегчит задачу достижения воспроизводимой пересборки. Также сильно упрощается задача установки исходного кода на другие машины, поскольку в простом случае src.rpm представляет собой запакованный исходный код и файл спецификации сборки, так называемый spec-файл.

Далее - Консолидация программного обеспечения
Назад - Подготовка к сборке пакета
Содержание


8.1.2 Консолидация программного обеспечения

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

В основном все сводится к трем вариантам:
- либо пакетируется собственное ПО;
- либо пакетируется ПО сторонних разработчиков;
- либо пакетируется некий проект, подвергшийся переработке, исправлению ошибок, улучшению функциональности, накладыванию патчей.

Во всех случаях не избежать процесса подбора компонентов. Основной философией RPM на этой стадии является подход "всегда начинаем с оригинальной версии". Иными словами, все изменения всегда оформляются в виде патчей.

Такой подход имеет следующие преимущества:
- ясно видно, какие изменения сделаны по отношению к оригинальным версиям; если что-то пошло не так, всегда можно вернуться к исходному состоянию; поскольку процесс сборки автоматизирован, легко можно утратить изменения, если использовать другие механизмы;
- всегда имеется воспроизводимый путь повторения чего-быто ни было, любых версий сборок, накладывания патчей и так далее.

Патч является атомарной единицей изменения, способом автоматизации всех модификаций исходного кода. Для получения патчей используют утилиту diff.

Далее - Воспроизводимая сборка ПО
Назад - Планирование - что хотим собрать
Содержание


8.1.3 Воспроизводимая сборка ПО

RPM может автоматизировать только успешные шаги, которые были осуществлены при сборке в процессе выполнения целей сборки, как они указаны в Makefile. Если проект не собрался при помощи make, rpm-пакет также не может быть собран. К сожалению, процессы конфигурирования сборки и последующей компиляции не всегда просты. Тем не менее, если проект успешно собран единожды, можно добиться воспроизводимой сборки. Для сборки используется ряд Linux-утилит. Конкретный набор утилит зависит от того, откуда произошел комплект ПО.

8.1.3.1 Распаковка ПО

Множество приложений и библиотек поставляются с сайтов производителей в виде компрессированных tar-архивов, часто называемых тарболами. Тарбол - это tar-архив, сжатый, как правило, утилитой gzip. Для распаковки используют последовательно команды:

$ gunzip filename.tgz

$ tar xf filename.tar

Можно обойтись и одной командой:

$ tar xvfz filename.tgz

Если для компрессии использовался компрессор bzip2, тогда вместо ключа z следует указать ключ j:

$ tar xvfj filename.tar.bz2

8.1.3.2 Читаем README

Чаще всего ПО поставляется с инструкциями по сборке, обычно содержащимися в файле README в корневом каталоге распакованного проекта. Текст в этом файле отвечает на большинство вопросов, могущих возникнуть в процессе конфигурирования и компиляции проекта.

8.1.3.3 Собираем программное обеспечение с помощью Linux-утилит сборки

Большинство проектов составлены в предположении, что из исходного кода будут собираться приложения или компилироваться библиотеки. Эти операции производятся как правило под управлением утилиты make. Make имеет конфигурационный файл, который называется Makefile. Он содержит правила сборки. Обычно Makefile находится в каждой корневой директории каждой части проекта.

Каждый Makefile содержит ряд так называемых целей, определяющих объекты, которые make может собрать. Каждая цель определяет набор команд, которые необходимо запустить для сборки цели. Некоторые комбинации целей в итоге своего выполнения дают искомый результат в виде приложений или библиотек. Make запускает цели, которые оператор укажет в командной строке, или которые определены по умолчанию в Makefile.

В простейшем случае для сборки проекта требуется сказать:

$ make

а для установки

# make install

Когда make указывается без задания цели, собирается цель по умолчанию, так называемая цель all. Обычно all собирает приложение или библиотеку. Цель install командует утилите make скопировать собранные файлы в систему. Еще одной общей целью является цель clean. Clean очищает директорию сборки от прежде собранных файлов.

Команды в Makefile могут быть специфичны для конкретной системы. Например, традиционной командой для сборки кода C является cc (сокращение от C compiler). Вместо этого ваш Linux может иметь gcc (GNU C Compiler). Опции компилятора также могут быть аппаратно и системно зависимыми. Другие необходимые команды могут располагаться в директориях, отличных от тех, которые предполагаются в Makefile.

Поскольку Makefile - ы системно зависимы, ряд утилит были разработаны для создания соответствующих Makefile - ов. При сборке должен быть взят файл для нужной платформы. Одна из таких "утилит" - ручной выбор из коллекции Makefile - ов. Например, получен проект, в котором имеются следующие файлы: Makefile.amiga, Makefile.solaris, и Makefile.linux. Для использования конкретного файла его надо скопировать в файл Makefille.

Утилиты для создания Makefile.

8.1.3.3.1. imake

Программа imake довольно часто используется для генерации приложений X Window system (в основном старых версий). Эта утилита использует входной файл по имени Imakefile. Он содержит инструкции по созданию платформно-зависимых Makefile - ов, что позволяет выполнять графические приложения на многих платформах. Если в проекте имеется Imakefile, последовательность действий будет следующая:

$ xmkmf

$ make

# make install

Команда xmkmf - это скрипт, запускающий, в общем ряду, и команду imake для создания Makefile. Если xmkmf выполнить невозможно, следует сказать:

make Makefile

Или, если имеется много директорий с исходным кодом, может сработать

make Makefiles

Большинство приложений Linux, особенно серверных и утилит командной строки, имеют в дереве проекта специальный скрипт, который на выходе дает платформно-зависимый Makefile. Если в корне проекта имеется скрипт configure, последовательность действий такая:

$ ./configure

$ make

# make install

Скрипт configure в свою очередь генерируется стеком утилит, включая automake и autoconf, использующих на входе файлы-заготовки configure.in и makefile.am. В большом количестве случаев скрипту configure передаются параметры сборки. Один из наиболее употребимых параметров --prefix, он указывает вершину дерева директорий, от которой откладываются все остальные пути при сборке и установке. Это позволяет задать нестандартный путь установки или временный/тестовый каталог сборки.

8.1.3.3.3. Построение модулей Perl

Perl - скриптовый язык, использующийся всеми Linux-системами, особенно любимый администраторами. Большинство модулей языка и программные комплексы на Perl собираются с помощью такой последовательности команд:

$ perl Makefile.PL

$ make

$ make test

# make install

Устраняя по мере выполнения команд сборки возникающие ошибки, можно добиться воспроизводимой сборки ПО, что на этом этапе и требуется.

Далее - Планирование обновлений
Назад - Консолидация ПО
Содержание


8.1.4 Планирование обновлений

Любое приложение (библиотека), которое желательно оформить в виде rpm-пакета рано или поздно потребует обновления. Когда время для этого пришло, потребуется собрать новый rpm. Этот новый пакет должен уметь обрабатывать не только команды установки, но и некоторые специфические операции обновления. Необходимо обдумать следующие вопросы:

- как устанавливать пакет с новыми версиями ПО, потребуются ли для корректной обработки задач установки инстолл-скрипты?

- как удалять предыдущие версии ПО? Если пакет имеет инстолл-скрипты, можно чисто удалить прежние версии с помощью скрипта. Так как RPM автоматически удаляет одноименные файлы прежних версий, с помощью скриптов можно отменить некоторые из этих действий.

С момента начала обновлений основные усилия производителя rpm направлены на поддержку ПО в актуальном состоянии.

Далее - Удовлетворение зависимостей
Назад - Воспроизводимая сборка ПО
Содержание


8.1.5 Удовлетворение зависимостей

Часто наиболее сложной задачей становится сборка ПО должным образом. Одна из потенциальных проблем - существование зависимостей ПО от других программ и библиотек. В процессе работы с make следует обращать внимание на сторонние библиотеки, которые требуются для сборки. Эти зависимости должны быть позднее включены в спецификацию пакета на стадии построения rpm. В общем случае, каждая зависимость удовлетворяется собственным rpm-пакетом, таким образом нужно будет озаботиться обеспечением доступности этих rpm-пакетов.

Когда достигнуты три цели: обеспечена воспроизводимая сборка, спланированы обновления, удовлетворены все зависимости, можно приступать к собственно сборке rpm-пакета.

Далее - Разворачивание структуры директорий
Назад - Планирование обновлений
Содержание


8.2.1 Разворачивание структуры директорий

RPM использует для сборки пакетов пять каталогов, они описаны в таблице.

Каталог

Использование

BUILD

Утилита rpmbuild использует этот каталог в качестве каталога сборки ПО.

RPMS

Утилита rpmbuild помещает в этот каталог собранные бинарные rpm-пакеты.

SOURCES

В этот каталог необходимо поместить тарболлы с исходным кодом проектов, запланированных на сборку.

SPECS

В этот каталог помещаются spec-файлы всех rpm-пакетов, которые запланированы на сборку.

SRPMS

Утилита rpmbuild помещает в этот каталог собранные src.rpm-пакеты с исходным кодом.

Обычно каталог RPMS содержит подкаталоги для разных платформ, например на Intel-машине это будет следующий список:

$ ls RPMS

athlon

i386

i486

i586

i686

noarch

В системе Red Hat Linux родительским каталогом для дерева каталогов сборки обычно бывает /usr/src/redhat.
Поскольку изначально RPM был спроектирован для построения дистрибутивов Linux в целом, этот путь может отличаться от указанного в других системах и его можно изменить редактированием rpmrc файлов.

Самый легкий способ - использовать уже имеющийся в системе путь к каталогам сборки. Для сборки под непривилегированным пользователем может потребоваться изменить права доступа к ним. Следует помнить, что ошибки сборки rpm-пакетов могут привести к серьезным проблемам в системе, если сборка производится от пользователя root.

Для того, чтобы приступить к сборке пакета осталось выполнить два действия:

- поместить исходный код в SOURCE;
- поместить spec-файл в SPECS.

Далее - Размещение исходного кода в дереве сборки
Назад - Удовлетворение зависимостей
Содержание


8.2.2 Размещение исходного кода в дереве сборки

Вообще говоря, можно поместить в SOURCES дерево каталогов с исходным кодом проекта. Но гораздо удобнее (и так и делается), особенно, если собирается много пакетов, поместить туда тарболл. Тогда в простом случае на каждый собираемый пакет будет приходится один файл с архивом. Раскрываться архив будет с помощью макросов RPM, тривиально с точки зрения пользователя. Это помогает держать исходный код разных проектов отдельно друг от друга, так как все они находятся в директории SOURCES.

Соглашение об именовании тарболлов с исходным кодом предлагает следующую форму имен: имя_пакета-версия.tar.gz. Поместив архив в SOURCES, оператор делает скрипты сборки, исходный код и все необходимое доступным для RPM.

Далее - Создание spec-файла
Назад - Разворачивание структуры директорий
Содержание


8.2.3 Создание spec-файла

Spec-файл, сокращение от "файл спецификации", определяет все действия утилиты rpmbuild, которые должны быть выполнены при построении приложения, так же как и все действия, необходимые при установке/удалении приложения. Каждый src.rpm-пакет имеет в своем составе spec-файл для последующей пересборки пакета.

Spec-файл - это текстовый файл. Соглашение об именовании предлагает называть spec-файл таким образом: имя_пакета.spec.

Текст внутри spec-файла имеет специальный синтаксис. Синтаксические определения имеют значения, задающие порядок сборки, номер версии, информацию о зависимостях и вообще всю информацию о пакете, которая может быть впоследствии запрошена из БД RPM.

8.2.3.1 Секция общей информации (introduction)

Секция общей информации содержит сведения о пакете, которые после его установки могут быть запрошены командой rpm -qi имя_пакета. Например:

Summary: java source to bytecode compiler

Summary(ru): Исходный код компилятора байт-кода java

%define version 1.17

Copyright: IBM Public License, http://ibm.com/developerworks/oss/license10.html

Group: Development/Languages

Name: jikes

Prefix: /usr

Provides: jikes

Release: 1

Source: jikes-%{version}.tar.gz

URL: http://ibm.com/developerworks/opensource/jikes

Version: %{version}

Buildroot: /tmp/jikesrpm

%description
The IBM Jikes compiler translates Java source files to bytecode.
It also supports incremental compilation and automatic
makefile generation, and is maintained by the Jikes Project:
http://ibm.com/developerworks/opensource/jikes/

%description -l ru
Компилятор Java производства IBM Jikes осуществляет
преобразование исходного кода Java в
байт-код. Он поддерживает инкрементную компиляцию и автоматическую генерацию Makefile. Мантейнер - Jikes Project: http://ibm.com/developerworks/opensource/jikes/

Из этого примера, в общем, понятно, как устроена секция общей информации. Этот пример не следует всем требованиям RPM. Например, тэг Copyright в настоящее время утратил значение и не используется, номер версии можно задать непосредственно, в примере задается через определение макроса.

Для отслеживания изменений требований от версии к версии rpm можно проанализировать spec-файлы пакетов современных сборок и сравнить их с прежними сборками.

8.2.3.2 Секция prep

Секция подготовки отвечает за команды, необходимые для начала сборки. Например, если в SOURCES положен тарболл проекта, его необходимо распаковать. В секции указываются для этого соответствующие макросы rpm:

%prep

%setup -q

Секция начинается со строки %prep. Этот пример использует макрос %setup, который умеет распаковывать компрессированные архивы. Как правило, это единственная строка в данной секции.

8.2.3.3 Секция build

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

%build

./configure CXXFLAGS=-O3 \
--prefix=$RPM_BUILD_ROOT/usr


make

В данном примере задействованы два параметра скрипта configure (флаги оптимизации компилятора и имя временного каталога сборки) и команда make (без параметра, то есть для цели all). Секция начинается строкой %build.

8.2.3.4 Секция install

Секция содержит команды установки файлов пакета в систему. Например:

%install

rm -rf $RPM_BUILD_ROOT

make install

На данной стадии очищаем каталог сборки и копируем файлы пакета в каталог, определенный опцией --prefix. Если не очистить каталог сборки, файлы от прежних сборок могут нарушить чистоту установки. Секция начинается строкой %install.

8.2.3.5 Секция clean

Команды в этой секции вычищают файлы, созданные на других стадиях:

%clean

rm -rf $RPM_BUILD_ROOT

Секция начинается строкой %clean.

8.2.3.6 Секция files

И, наконец, команды в секции files задают списки файлов и каталогов, которые с соответствующими атрибутами должны быть скопированы из дерева сборки в rpm-пакет и затем будут копироваться в целевую систему при установке этого пакета. Например:

%files

%defattr(-,root,root)

/usr/bin/jikes

%doc /usr/doc/jikes-%{version}/license.htm

%doc /usr/man/man1/jikes.1*

Секция начинается строкой %files. Макрос %doc отмечает файлы документации. Это позволяет составить документацию из подходящих файлов проекта.

После окончания редактирования spec-файла осталось поместить его в каталог SPECS под /usr/src/redhat, а тарболл с исходным кодом в SOURCES. Все готово для сборки rpm.

Далее - Сборка пакета с помощью утилиты rpmbuild
Назад - Размещение исходного кода в дереве сборки
Содержание


8.2.4 Сборка пакета с помощью утилиты rpmbuild

Базовый синтаксис использования утилиты rpmbuild:

rpmbuild -bСтадия_сборки имя_пакета.spec

Опция -b указывает на режим сборки. Второй ключ после -b говорит, до какой стадии осуществлять процесс. Возможные стадии процесса рассмотрены в таблице.

Опция

Значение

-ba

Собрать бинарный пакет и пакет с исходным кодом

-bb

Собрать бинарный пакет

-bc

Скомпилировать программу, но не собирать rpm-пакет, то есть выполнить до секции %build включительно

-bp

Выполнить подготовку и остановиться сразу после завершения стадии %prep

-bi

Выполнить сборку бинарного пакета и остановиться сразу после завершения стадии %install

-bl

Выполнить проверку списка файлов для пакета и вывести резюме ошибок, если корневой каталог сборки не содержит каких-то файлов из списка

-bs

Собрать только пакет с исходным кодом

Следующий пример показывает результат выполнения команды rpmbuild -bp jikes.spec, отданный из каталога /usr/src/redhat/SPECS :

$ rpmbuild -bp jikes.spec

Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.72435

+ umask 022

+ cd /usr/src/redhat/BUILD

+ LANG=C

+ export LANG

+ cd /usr/src/redhat/BUILD

+ rm -rf jikes-1.17

+ /usr/bin/gzip -dc /usr/src/redhat/SOURCES/jikes-1.17.tar.gz

+ tar -xf -

+ STATUS=0

+ '[' 0 -ne 0 ']'

+ cd jikes-1.17

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

+ /bin/chmod -Rf a+rX,g-w,o-w .

+ exit 0

После запуска команды на выполнение файлы с исходным кодом распаковываются в каталог /usr/src/redhat/BUILD, в подкаталог jikes-1.17. Подкаталоги используются, чтобы избежать смешивания файлов сборки различных проектов. Если зайти в каталог jikes-1.17, можно увидеть все необходимое для сборки проекта с помощью make.

Помимо стадий сборки, определяемых вторичными ключами, описанными в таблице, утилита rpmbuild принимает некоторые другие опции. Например, команда

rpmbuild --clean specfile.spec

очистит временный каталог установки файлов пакета и каталог сборки проекта:

$ rpmbuild --clean /usr/src/redhat/SPECS/jikes.spec

Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.21908

+ umask 022

+ cd /usr/src/redhat/BUILD

+ rm -rf jikes-1.17

+ exit 0

Далее - Верификация собранных пакетов
Назад - Создание spec-файла
Содержание


8.2.5 Верификация собранных пакетов

После сборки пакета для его проверки может быть использована процедура верификации. Кроме того, с помощью опции -bl можно проверить список файлов пакета. Например:

$ rpmbuild -bl /usr/src/redhat/SPECS/jikes.spec

Processing files: jikes-1.17-1

error: File not found: /tmp/jikesrpm/usr/bin/jikes

error: File not found:

/tmp/jikesrpm/usr/doc/jikes-1.17/license.htm

error: File not found by glob:

/tmp/jikesrpm/usr/man/man1/jikes.1*

Provides: jikes

RPM build errors:

File not found: /tmp/jikesrpm/usr/bin/jikes

File not found: /tmp/jikesrpm/usr/doc/jikes-1.17/license.htm

File not found by glob: /tmp/jikesrpm/usr/man/man1/jikes.1*

В этом примере показан вывод диагностики некоторого количества ошибок. Опция -bl проверяет список всех необходимых файлов пакета, расположенных в директории сборки. Из вывода ясно, что пакет не собрался правильно.

В ситуациях, подобных этой, существует два подхода: можно собирать пакет сначала, выполняя все операции, либо воспользоваться опцией --short-circuit для того, чтобы начать сборку с определенной стадии. Это поможет пропустить секции, в которых нет ошибок.

Для верификации полностью собранного пакета используют следующий синтаксис:

$ rpm -Vp /usr/src/redhat/RPMS/i386/jikes-1.17-1.i386.rpm

S.5....T /usr/bin/jikes

.......T d /usr/doc/jikes-1.17/license.htm

..5....T d /usr/man/man1/jikes.1.gz

В выводе команды верификации видно, что имеются различия в контрольных суммах MD5 и времени создания некоторых файлов, что может указывать, например, на тот факт, что оригинальный пакет был собран на другой системе с более старой версией дистрибутива Red Hat. В случае, если файлы пакета были изменены вручную после его установки, вывод ошибок будет похожий.

Далее - Раздел 9. Работа со spec-файлом
Назад - Сборка пакета с помощью утилиты rpmbuild
Содержание


9.1 Чтение spec-файла

Первый шаг на пути более глубокого изучения структуры и секций spec-файла - читать spec-файлы различных по сложности пакетов установленного Linux-дистрибутива. Беглый просмотр большого количества спецификаций сразу обнаруживает две вещи:

- специфический синтаксис spec-файла не так сложен, как может показаться на первый взгляд;
- многие другие разработчики уже решали (и решили) проблемы, которые необходимо решить в процессе сборки вашего пакета.

В этой книге используются примеры из реальной жизни, показывающие, как механизмы, заложенные в RPM, помогают разрешить встречающиеся сложности. Пакеты могут содержать серверные и клиентские компоненты, задачи по установке и запуску системных сервисов, работу с почтой и сетью. Во многих из этих пакетов все эти задачи выполнены. Для изучения подходов, применявшихся в других пакетах, эти src.rpm необходимо установить в систему.

По мере изучения spec-файлов можно увидеть встречающиеся паттерны, помогающие понять, как нужно задавать определения, имена, как использовать макросы и наиболее общие элементы в секции %build. В инстолл-скриптах заданы образцы решения таких задач, как, например, установка сетевых сервисов в Linux-системе.

Если разработчик владеет базовыми знаниями о создании и работе shell-скриптов, а также о сборке C-приложений с помощью Linux-утилит сборки, он обнаружит, что синтаксис и конструкция spec-файла сравнительно просты для понимания.

Далее - Начинаем создавать spec-файл
Назад - Верификация собранных пакетов
Содержание


9.2 Начинаем создавать spec-файл

Spec-файл - это текстовый файл, содержащий директивы RPM. Директивы задаются простым синтаксисом: имя поля, двоеточие, пробел, значение. Например:

Version: 1.15

Пример устанавливает версию пакета в значение 1.15. Имя поля регистронезависимо, поэтому version, Version и VERSION задают одну и ту же переменную.

Кроме задания различных значений можно определять макросы с использованием RPM-синтаксиса %define. Например:

%define major 2

Этот пример определяет макрос по имени major со значением 2. Однажды определив макрос, можно получать к нему доступ посредством инструкции %{имя_макроса} или, проще, %имя_макроса. Например:

source: %{name}-%{version}.tar.gz

Остальные возможности макроопределений обсуждаются ниже.

Главные секции spec-файла также маркируются разделителем %.

9.2.1 Комментарии

Всё, что начинается с #, является комментарием и игнорируется RPM. Комментарии - полезная вещь. Они помогают разработчику и всем, кто читает spec-файл после создания rpm, понять выбор той или иной синтаксической конструкции, особенно, если конструкция отличается от стандартной в подобном случае. Например, если используются нестандартные опции компилятора, будет полезно обосновать необходимость этого в комментарии. Такой комментарий будет полезен при портировании rpm под другую архитектуру.

Комментарии отменяют действие единичного знака %. Например:

# Added new commands to %prep

9.2.2 Сохранение spec-файла на диске

Созданный spec-файл должен быть сохранен в каталоге дерева разработки /usr/src/redhat/SPECS (с вариациями этого пути в не-Red Hat дистрибутивах).

Далее - Описание пакета
Назад - Чтение spec-файла
Содержание


9.3.1 Описание пакета

9.3.1.1 Имена пакетов

Наиболее важной частью информации о пакете является NVR, то есть Name-Version-Release (Имя-Версия-Релиз), так как эта информация критична для работы RPM и используется в механизмах сравнения версий и отслеживания изменений. Имя устанавливается с помощью директивы Name:

Name: myapp

Имя не должно содержать пробелов, табуляций и символов новой строки. Однако, допустимо использовать дефис.

Номер версии используется при сравнении версий. Алгоритм сравнения версий RPM сравнительно сложен, но может проявлять тупость в отношении номеров версий, не следующих соглашениям. Примеры хороших с точки зрения алгоритма номеров версий: 1.5, 2.3.1.1.4, 1.0. Пример определения:

Version: 1.1.2

В номере версии нельзя использовать дефис, так как дефисом отделяются имя, версия и релиз.

Релиз обычно начинается с 1 при стартовой сборке пакета и далее увеличивается на единицу при каждой следующей пересборке:

Release: 1

Всякий раз, когда вы изменили spec-файл или файлы пакета, увеличивайте номер релиза.

Если номера версии недостаточно для отделения одних групп версий от других, например, при смене плана разработки меняется система смены номеров версий, можно кроме версии задействовать понятие эпохи. Эпоха задается директивой Epoch: . Например:

Epoch: 3

Номера эпох задаются целым числом.

Директива Group: задает классификатор пакета. Для классификаторов лучше использовать имеющиеся группы пакетов, определенные в системе. Например:

Group: System Environment/Shells

Многие графические утилиты управления пакетами разделяют пакеты по признаку группы. Официальный список групп пакетов расположен здесь: /usr/share/doc/rpm-4.1/GROUPS, либо по сходному пути для других версий RPM.

Директива Distribution: используется вендорами Linux-дистрибутивов для указания, что данный пакет является частью определенного дистрибутива. Множество пакетов, порожденных сторонними разработчиками, не связанными с Linux вендорами, не имеют в spec-файле данной директивы.

Distribution: Red Hat Linux

Директива, именуемая Icon:, указывает на файл изображения из состава пакета. Формат изображения, которое будет идентифицировать пакет в графических средах, должен быть XPM или GIF.

9.3.1.2. Включение информации о компании

В юридических целях возможно потребуется включить в пакет информацию о производителе ПО и пакета. Если пакет создан независимым разработчиком, может быть необходимым добавить информацию для связи с разработчиком и получении более подробной информации.

Директива Vendor: определяет производителя пакета (компанию или организацию):

Vendor: The Really Cool Company

Директива URL: предоставляет информацию о нахождении сетевого ресурса ПО (или его производителя):

URL: http://mycompany.yow/products/coolstuff

Директива Packager: соодержит имя и электронный адрес сборщика пакета:

Packager: Bob Marley <marley@reggae.com>

Директивы License: и Copyright: предоставляют правовую информацию о пакете. В более старых версиях пакетов использовалось поле Copyright:, в настоящее время используется License:.

9.3.1.3 Описание пакета

Директива Summary: - это однострочное описание пакета. Данное поле заменило прежнюю директиву Description:. Кроме Summary: имеется еще многострочное описание, оно содержится не в директиве, а в специальной секции spec-файла, %description. Например:

%description

This is a really cool package. It contains the really cool

program that provides a maximum return on investment,

or ROI, for achieving your crucial business objectives

utilizing world-class high-caliber componentized software

implemented with world-class quality and performance

metrics.

Для задания национальных описаний используется синтаксис: для Summary:

Summary(ru): Реально крутой пакет

для %description

%description -l ru

Описание реально крутого

пакета

в многострочном формате.

В секции %description используется некоторое количество опций форматирования. Пустые линии интерпретируются как разделители абзацев. Строки, начинающиеся с пробелов или табуляций, интерпретируются как предварительно отформатированные абзацы и отображаются как есть, как правило, моноширинным шрифтом.

9.3.1.4 Задание процессорной архитектуры

Spec-файл может указывать на тот факт, что пакет работоспособен только в определенной среде исполнения, или же может при соответствующей сборке запускаться более чем на одной платформе.

Для этого имеется несколько возможностей. Например, директива ExcludeArch: задает платформы, для которых пакет не должен собираться:

ExcludeArch: sparc s390 s390x

В данном примере исключены для сборки архитектуры SPARC и мэйнфреймы s/390. В директиве можно использовать множественные определения, разделяя названия архитектур пробелами или запятыми.

Сходным образом действует ExclusiveArch: , с той разницей, что эта директива определяет список архитектур, в которых пакет будет работоспособен. Например:

ExclusiveArch: i386 ia64 alpha

Директивы Excludeos: и Exclusiveos: ограничивают список операционных систем, соответственно, Excludeos: исключает какие-то ОС из списка поддерживаемых, а Exclusiveos: задает закрытый список ОС, которые поддерживаются.

Exclusiveos: linux

Далее - Установка пути сборки
Назад - Начинаем создавать spec-файл
Содержание


9.3.2 Установка пути сборки

RPM различает два каталога, имеющих отношение к сборке: build и buildroot. Build - каталог, в котором происходит запуск скриптов конфигурации, компиляция ПО и прочие операции по сборке приложения или библиотеки, как если бы в этот каталог был распакован архив с исходным кодом вручную и выполнены команды ./configure и make. В обычном случае разработчику не приходится беспокоится об этом каталоге, так как при необходимости RPM его переопределит самостоятельно. С другой стороны, buildroot выступает в роли директории окончательной установки ПО. Имя buildroot учитывает тот факт, что обычно корневым каталогом установки является /, root-каталог. Install-секция spec-файла устанавливает ПО в buildroot так, как будто это корневой каталог целевой системы, в соответствующие подкаталоги. Это позволяет buildroot-каталогу хранить все пути установки, начиная с /.

Buildroot устанавливается с помощью определения Buildroot:, например:

Buildroot: %{_tmppath}/%{name}-%{version}-root

Этот пример определяет buidroot как подкаталог временного каталога, заданного макроопределением %_tmppath. Имя подкаталога складывается из имени пакета и его версии с добавлением -root. Если раскрыть все определения, то полный путь к buildroot будет выглядеть примерно так:

/tmp/ypbind-1.12-root

Когда buildroot определен, скрипты и команды из spec-файла получают возможность обращаться к нему через переменную окружения RPM_BUILD_ROOT. Обычно это происходит в секции Install.

Далее - Имена файлов архивов с исходным кодом
Назад - Описание пакета
Содержание


9.3.3 Имена файлов архивов с исходным кодом

Большинство пакетов имеют более одного источника исходного кода, к которым необходимо обращаться из spec-файла. Как правило, это tar.gz-архивы с файлами кода. Это могут быть архивы от вендора или загруженные с сайтов сторонних разработчиков. Определять источники кода следует с помощью полей Source, начиная счет с 0:

Source0: telnet-client.tar.gz

Source1: telnet-xinetd

Source2: telnet.wmconfig

В этом примере Source0: ссылается на tar.gz-архив. Утилита rpmbuild распакует его в каталог buildroot. Source1: и Source2: указывают на отдельные файлы с исходным кодом. Если существует только один файл с исходниками, можно пропустить 0:

Source: telnet-client.tar.gz

Также допустимо использовать ссылки на сетевые источники кода (FTP или HTTP):

Source0: ftp://somesite.yow/pub/linux/%{telnet_version}.tar.gz

RPM не загружает файлы по этим ссылкам, они нужны только для дальнейшего обращения к источнику кода. Код по-прежнему будет загружаться из каталога SOURCES по имени файла.

Довольно часто возникает необходимость исключить какие-то файлы исходного кода из src.rpm-пакета по соображениям проприетарности или чтобы сократить объем пакета. Для выполнения этой операции используется директива NoSource:

NoSource: 3

Данный пример означает, что из коллекции исходников, помещаемых в src.rpm будет исключен источник 3. Подобным же образом действует директива NoPatch, она позволяет не включать в пакет с исходным кодом патчи разработчика. Директивы NoSource: и NoPatch: принимают только один номер патча (файла исходного кода) за раз. Если необходимо исключить несколько источников, потребуется задать соответвствующее количество строк.

Если в spec-файле присутствуют директивы NoSource: или NoPatch:, вместо src.rpm будет собран пакет nosrc.rpm.

Далее - Имена патчей
Назад - Установка пути сборки
Содержание


9.3.4 Имена патчей

Патчи именуются подобно исходному коду:

Patch1: telnet-client-cvs.patch

Patch2: telnetd-0.17.diff

Patch3: telnet-0.17-env.patch

Patch4: telnet-0.17-issue.patch

Patch5: telnet-0.17-sa-01-49.patch

Patch6: telnet-0.17-env-5x.patch

Patch10: telnet-0.17-pek.patch

Следует обратить внимание, что номера патчей могут образовывать увеличивающуюся последовательность, но не обязаны следовать подряд, один за другим. Кроме того, можно добавлять патчи и вручную

Патчи могут быть отдельными файлами или патчами, компрессированными gzip.

Далее - Подготовка к сборке
Назад - Имена файлов архивов с исходным кодом
Содержание


9.4.1 Подготовка к сборке

Секция %prep задает команды, необходимые для подготовки к сборке ПО. В простейших случаях достаточно запуска макроса %setup, например:

%prep

%setup -q

Эта команда меняет рабочий каталог на каталог сборки, как правило /usr/src/redhat/BUILD, и в нем разворачивает указанный архив. Предполагается, что хотя бы один файл исходного кода при распаковке создаст необходимый подкаталог по имени пакета. Если в составе исходников нет ни одного tar.gz-архива, макрос создаст необходимый подкаталог, если указана опция -c.

Опция -q задает тихое поведение с минимальным выводом. Опция -T отключает автоматическую распаковку сжатых архивов. Можно вручную задать имя подкаталога сборки с помощью опции -n. По умолчанию %setup перед распаковкой удаляет уже имеющийся подкаталог с совпадающим именем, это поведение можно отключить с помощью опции -D.

Нижеследующая таблица резюмирует параметры командной строки макроса %setup.

Параметр

Значение

-a номер

Распаковать только Source с определенным номером, например -a 0 для первого архива Source0, после смены рабочего каталога на тот, куда происходит распаковка

-b номер

Распаковать только Source с определенным номером, например -b 0 для первого архива Source0, перед сменой рабочего каталога на тот, куда происходит распаковка

-c

Создать подкаталог перед распаковкой. Используется, когда процесс распаковки не подразумевает создание нужного подкаталога.

-D

Не удалять подкаталог перед распаковкой

-n name

Создать подкаталог с именем name

-q

Запустить макрос в тихом режиме с минимальным выводом ошибок

-T

Отключить автоматическую распаковку архива

Хотя наиболее распространенным форматом файлов архивов с исходным кодом является .tar.gz, %setup умеет также автоматически распаковывать tar, zip, gzip,bzip2, pack, compress и lzh.

Подобно маккросу %setup директива %patch применяет патчи к коду. Директива также применяется в секции %prep. В каждой строке, содержащей %patch, описывается только один патч. Соответственно, если применяются все патчи, количество строк с директивой будет равно количеству патчей.
%patch принимает некоторые опции командной строки. Опция -p с номером, например, -p0, указывает команде patch не удалять слеши из пути, а -p1 говорит о том, что требуется удалить один слеш и, соответственно, один уровень иерархии директорий перед применением патча.

Секция %prep с применением к коду двух патчей будет выглядеть примерно так:

%prep

%setup -q

%patch1

%patch2

Номера используются для различения патчей друг от друга, и указания, какой из них применяется. Например, %patch0 указывает на патч, описанный в директиве %Patch0: .
Необходимо использовать по одной директиве на каждый патч. Строка %patch указывает на %patch0.

Если необходимо применить какой-либо конкретный патч из набора, используют опцию -P, например:

%patch -P 2

Далее - Сборка ПО
Назад - Имена патчей
Содержание


9.4.2 Сборка ПО

Секция %prep готовит процесс сборки, который выполняется секцией %build. Секцию сборки необходимо заполнить всеми нужными для сборки командами. В простых случаях это будет примерно следующее:

%build

./configure

make

В данном случае выполняется две команды, ./configure для запуска скрипта конфигурации и make для сборки ПО. Вместо запуска скрипта ./configure часто используется макрос %configure. Скрипт ./configure как правило имеет множество опций, которые можно вывести по команде ./configure --help . Как правило, большая часть этих опций заведует установкой переменных окружения сборки. Макрос %configure может задать часть переменных по умолчанию. Если требуется посмотреть, как макрос разворачивается, следует выполнить команду rpm --eval '%configure' :

$ rpm --eval '%configure'

CFLAGS="${CFLAGS:--O2 -march=i386 -mcpu=i686}" ; export CFLAGS ;

CXXFLAGS="${CXXFLAGS:--O2 -march=i386 -mcpu=i686}" ; export CXXFLAGS ;

FFLAGS="${FFLAGS:--O2 -march=i386 -mcpu=i686}" ; export FFLAGS ;

[ -f configure.in ] && libtoolize --copy --force ;

./configure i386-redhat-linux \

--prefix=/usr \

--exec-prefix=/usr \

--bindir=/usr/bin \

--sbindir=/usr/sbin \

--sysconfdir=/etc \

--datadir=/usr/share \

--includedir=/usr/include \

--libdir=/usr/lib \

--libexecdir=/usr/libexec \

--localstatedir=/var \

--sharedstatedir=/usr/com \

--mandir=/usr/share/man \

--infodir=/usr/share/info

Важное значение имеет то обстоятельство, что команды в секции %build должны быть согласованы с конструкцией Makefile, и цели сборки должны указываться те, которые определены в Makefile. В данном случае указана команда make без параметров, которая по умолчанию использует цель all.

Не рекомендуется помещать слишком много логики в spec-файл, это затруднит тестирование приложения или библиотеки.

Если необходимо изменить каталог, куда будет устанавливаться ПО при установке пакета, указывают параметр --prefix. Например:

%build

./configure --prefix=$RPM_BUILD_ROOT/usr

make

В данном примере ПО будет устанавливаться в RPM_BUILD_ROOT и именно там rpmbuild будет искать файлы для упаковки их в пакет.

Далее - Инсталляция ПО
Назад - Подготовка к сборке
Содержание


9.4.3 Инсталляция ПО

Секция %install содержит команды, которые устанавливают ПО, собранное на стадии %build. Если Makefile содержит все необходимые инструкции по установке, достаточно определить команды в секции так:

%install

make install PREFIX=$RPM_BUILD_ROOT/usr

В большинстве случаев требуется задать еще какие-то параметры для правильной установки всех файлов в buildroot. Иногда вместо make install используют команду install, как в следующем примере:

%install

install -m755 myapp $RPM_BUILD_ROOT/usr/bin/myapp

Множество пакетов вместо make install используют макрос %makeinstall. Например:

%install

rm -rf $RPM_BUILD_ROOT

%makeinstall

Этот пример также содержит команду для очистки buildroot.

Для того, чтобы посмотреть, как разворачивается макрос %makeinstall, используется команда rpm --eval '%makeinstall' :

$ rpm --eval '%makeinstall'

make \

prefix=/usr \

exec_prefix=/usr \

bindir=/usr/bin \

sbindir=/usr/sbin \

sysconfdir=/etc \

datadir=/usr/share \

includedir=/usr/include \

libdir=/usr/lib \

libexecdir=/usr/libexec \

localstatedir=/var \

sharedstatedir=/usr/com \

mandir=/usr/share/man \

infodir=/usr/share/info \

install

Далее - Очистка после сборки
Назад - Сборка ПО
Содержание


9.4.4 Очистка после сборки

Секция %clean содержит команды, задача которых - очистка дерева сборки и каталога установки. Если используется buildroot, тогда секция выглядит примерно так:

%clean

rm -rf $RPM_BUILD_ROOT

Далее - Определение установочных скриптов
Назад - Инсталляция ПО
Содержание


9.4.5 Определение установочных скриптов

В дополнение к макросам и командам сборки-установки-очистки разработчик может определить в spec-файле собственные скрипты. RPM поддерживает выполнение скриптов перед установкой (задаются маркером %pre) и скриптов после установки (маркер %post). В том же стиле можно выполнять скрипты перед удалением пакета (%preun) и после удаления пакета (%postun).

После ввода строки с нужным маркером задаются команды shell в необходимой последовательности. В примере показаны скрипты из пакета ypbind:

%post

/sbin/chkconfig --add ypbind

%preun

if [ "$1" = 0 ] ; then

/sbin/service ypbind stop > /dev/null 2>&1

/sbin/chkconfig --del ypbind

fi

exit 0

%postun

if [ "$1" -ge 1 ]; then

/sbin/service ypbind condrestart > /dev/null 2>&1

fi

exit 0

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

Скрипты %pre также встречаются довольно часто, так как многие пакеты требуют перед своей установкой проведение определенной работы.

Настоятельно не рекомендуется в данном стиле определять интерактивные скрипты. Если пакеты устанавливаются списком автоматически, или используется графическая утилита, вывод будет потерян.

Команда rpm принимает один параметр для скриптов, показанный в примере как $1. Параметр содержит количество версий пакета, которые установлены в систему. Возможные значения параметра даны в таблице.

Действие

Значение параметра

Установка в первый раз

1

Обновление

2 или больше

Удаление последней версии пакета

0

В предыдущем примере скрипт получает значение через shell-переменную $1.

Далее - Заполнение списка файлов
Назад - Очистка после сборки
Содержание


9.5 Заполнение списка файлов

Секция %files содержит полный список файлов, которые будут установлены в систему при установке пакета. Список должен быть исчерпывающим, чтобы утилита точно знала, что именно пакет устанавливает. Существуют некоторые опции, позволяющие облегчить создание списка в больших проектах.

В стандартном (и простом) случае секция содержит список отделных файлов с их путями в целевой системе (а не относительно buildroot). Например:

%files

/usr/X11R6/bin/xtoolwait

/usr/X11R6/man/man1/xtoolwait.1

Из примера ясно, что пакет устанавливает два файла, приложение и справку man.

Далее - Использование шаблонов
Назад - Определение установочных скриптов
Содержание


9.5.1 Использование шаблонов

Кроме прямого перечисления файлов возможно использование шаблонов:

%files

/usr/X11R6/bin/xtoolwait

/usr/X11R6/man/man1/xtoolwait.*

Пример определяет, что все файлы из каталога /usr/X11R6/man/man1, которые начинаются с xtoolwait., должны быть включены в пакет.

Далее - Названия каталогов
Назад - Заполнение списка файлов
Содержание


9.5.2 Имена каталогов

Кроме использования шаблонов сильно облегчит задачу создания списка файлов возможность включать в список целые каталоги. Например:

%files

/usr/X11R6/bin/xtoolwait

/etc/xtoolwait

Этот пример задает каталог /etc/xtoolwait и все его файлы как часть пакета. Здесь следует проявлять определенную осторожность - нельзя включать в список системные каталоги, такие, как /usr/bin, так как в этом случае ваш пакет станет хозяином всего каталога /usr/bin. Возникнут проблемы, в том числе и при удалении пакета.

Для того, чтобы включить в пакет пустой каталог, используют инструкцию %dir:

%files

/usr/X11R6/bin/xtoolwait

%dir /etc/xtoolwait

Далее - Пометка файлов как файлов документации или конфигурационных
Назад - Использование шаблонов
Содержание


9.5.3 Пометка файлов как файлов документации или конфигурационных

RPM отслеживает файлы, которые специальным образом помечены, как файлы документации или файлы, содержащие данные конфигураций. Для пометки этих файлов существуют специальные директивы.

Директива %doc используется для пометки документации:

%files

/usr/X11R6/bin/xtoolwait

%doc /usr/X11R6/man/man1/xtoolwait.*

Если полные пути к файлам не включаются, RPM создаст специальный каталог для документации и поместит в него указанные файлы:

%doc README NEWS

Строка в этом примере помещает файлы README и NEWS во вновь создаваемый каталог, имя которого создается по имени пакета, в стандартном случае - под каталогом /usr/share/doc.

Директива %docdir именует каталог, содержащий документацию. Все файлы под этим каталогом автоматически помечаются как документация. Например:

%files

/usr/X11R6/bin/xtoolwait

%docdir /usr/X11R6/man/man1

/usr/X11R6/man/man1/xtoolwait.*

Подобно директиве %doc действует директива %config, помечая файлы конфигурации:

%files

/sbin/ypbind

%config /etc/rc.d/init.d/*

%config /etc/yp.conf

%doc README NEWS

Директива %config имеет специальную опцию, уместную, когда при переустановке пакета необходимо сохранить конфигурацию - %noreplace. Если используется %config(noreplace), файл пакета не будет перезаписывать существующий файл конфигурации, который был изменен. rpm, однако, при установке пакета запишет новый файл рядом с расширением .rpmnew.

В этом же стиле директива %config(missingok) означает, что файл на диске не обязан существовать. Эта конструкция обычно используется для файлов или симлинков, которые создаются в процессе выполнения %post скриптов, но должны быть удалены, если пакет удаляется.

Другой специальный модификатор, %ghost, указывает rpm, что файл не должен становиться частью пакета. Это относится к файлам, которые создаст вновь установленное приложение в начале своей работы. Например, разработчик может захотеть быть уверенным, что файлы журналов программы имеют соответствующие атрибуты.

Далее - Определение атрибутов файлов
Назад - Имена каталогов
Содержание


9.5.4 Определение атрибутов файлов

Когда пакет установлен, вы можете контролировать атрибуты файлов, так же как и файлов, которые будут включаться в пакет. Эта возможность весьма полезна, так как файлы пакетов, установленных в систему пользователем root вовсе не обязаны принадлежать этому пользователю.

Директива %attr позволяет задавать права на определенный файл. Формат следующий:

%attr(mode, user, group) filename

например:

%attr(0644, root, root) /etc/yp.conf

Этот пример устанавливает права доступа в 644, пользователь и группа - root. Если нет необходимости задавать значение параметра, используется дефис. При этом права будут такими, какие имел файл при сборке. Например:

%attr(-, root, -) /etc/yp.conf

Директивы можно комбинировать в одной строке:

%config %attr(-, root, -) /etc/yp.conf

В качестве разделителей кроме запятых можно также использовать пробелы:

%attr(0700 root root) %dir /var/tux

Для установки атрибутов по умолчанию всех файлов пакета существует директива %defattr :

%files

%defattr(-,root,root)

/usr/X11R6/bin/xtoolwait

/usr/X11R6/man/man1/xtoolwait.*

Эта инструкция позволяет скрыть большой объем работы, требующийся для установки всех атрибутов для каждого файла индивидуально. Именно поэтому %deffatr содержат практически все spec-файлы.

Также есть возможность отметить определенные файлы, как файлы конкретного языка. Это делается с помощью директивы %lang:

%files

%defattr(-,root,root)

%doc FAQ Fixes NewThings complete.tcsh eight-bit.txt tcsh.html

%{_bindir}/tcsh

%{_bindir}/csh

%{_mandir}/*/*

%lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*

%lang(el) %{_datadir}/locale/el/LC_MESSAGES/tcsh*

%lang(en) %{_datadir}/locale/en/LC_MESSAGES/tcsh*

%lang(es) %{_datadir}/locale/es/LC_MESSAGES/tcsh*

%lang(et) %{_datadir}/locale/et/LC_MESSAGES/tcsh*

%lang(fi) %{_datadir}/locale/fi/LC_MESSAGES/tcsh*

%lang(fr) %{_datadir}/locale/fr/LC_MESSAGES/tcsh*

%lang(it) %{_datadir}/locale/it/LC_MESSAGES/tcsh*

%lang(ja) %{_datadir}/locale/ja/LC_MESSAGES/tcsh*

%lang(pl) %{_datadir}/locale/pl/LC_MESSAGES/tcsh*

%lang(ru) %{_datadir}/locale/ru/LC_MESSAGES/tcsh*

%lang(uk) %{_datadir}/locale/uk/LC_MESSAGES/tcsh*

Далее - Верификация секции %files
Назад - Пометка файлов как файлов документации или конфигурационных
Содержание


9.5.5 Верификация секции %files

Разработчик может определить, какие проверки будет производить rpm в отношении файлов пакета в режиме верификации. В таблице показаны тесты, которые можно включить или исключить с помощью директивы %verify:

Тест

Что делает

group

Проверка группы файла

maj

Проверка старшего номера файла устройства

md5

Проверка контрольной суммы MD5

min

Проверка младшего номера файла устройства

mode

Проверка прав доступа

mtime

Проверка времени последнего изменения файла

owner

Проверка владельца файла

size

Проверка размера файла

symlink

Проверка символической ссылки

Формат использования директивы следующий:

%verify(owner group size) /etc/yp.conf

Этот пример ограничивае список проверок проверкой владельца, группы и размера файла. Для исключения теста из списка проверки выполните следующее:

%verify(not owner) /etc/yp.conf

Данный пример исключает проверку владельца.

Далее - Автоматизированное создание списка файлов
Назад - Определение атрибутов файлов
Содержание


9.5.6 Автоматизированное создание списка файлов

Всегда есть стремление упростить создание списка файлов - чем меньше строк, тем меньше вероятность ошибки. Опция -f директивы %files позволяет прочитать список из текстового файла. Содержимое этого файла должно выглядеть, как выглядела бы секция %files при прямом указании списка внутри секции, содержащего описание одного файла на строку. Можно использовать различные инструкции, например %attr или %doc. Можно комбинировать обращение к файлу и прямое указание файлов в одной секции:

%files -f xconfig_files.txt

%defattr(-,root,root)

/usr/X11R6/bin/xtoolwait

/usr/X11R6/man/man1/xtoolwait.1

Этот пример читает список из файла и дополнительно включает два отдельных файла.

Файл списка будет работать лучше, если дополнительные записи для файлов не указываются. Процедуры внутри %build могут создавать различные файлы, имена которых базируются на макроопределениях. Кроме того, не всегда очевидны пути к файлам до окончания процедуры сборки.

Далее - Обработка ошибок для неупакованных файлов
Назад - Верификация секции %files
Содержание


9.5.7 Обработка ошибок для неупакованных файлов

Начиная с RPM 4.1, rpmbuild выходит из процедуры сборки пакета, если все файлы каталога $RPM_BUILD_ROOT не найдены в секции %files или в файле, заданном опцией -f. Это явление официально известно под именем "фашистская политика сборки". Такое поведение, однако, можно отключить.

В одном из настроечных файлов (глобальном или пользователя), .rpmmacros, следует найти макроопределение
%_unpackaged_files_terminate_build и посмотреть его значение. Если установлено в 1, установить в 0:

%define _unpackaged_files_terminate_build 0

Также можно отключить проверку наличия всей документации. Для этого надо найти макроопределение %define _missing_doc_files_terminate_build и установить его в 0:

%define _missing_doc_files_terminate_build 0

Тем не менее, жесткая политика сборки поможет отловить действительные ошибки.

Далее - Добавление записей в журнал изменений
Назад - Автоматизированное создание списка файлов
Содержание


9.6 Добавление записей в журнал изменений

В конце spec-файла располагается секция %changelog, содержащая записи о каждом значительном изменении пакета, будь то изменение spec-файла или программного обеспечения. Например, было обновлено ПО, загружаемое для сборки пакета. Необходимо добавить примерно следующее:

%changelog

* Fri Jun 21 2002 Bob Marley

- Downloaded version 1.4, applied patches

* Tue May 08 2001 Peter Tosh 1.3-1

- updated to 1.3

Таким образом, более свежие записи располагаются ближе к началу секции. Формат даты стандартизован, и, если нарушается, rpmbuild выйдет из процедуры сборки с сообщением об ошибке.

Далее - Встроенные макросы
Назад - Обработка ошибок для неупакованных файлов
Содержание


9.7.1 Встроенные макросы

RPM включает ряд встроенных макросов, в том числе определения для наиболее употребимых каталогов:

%_prefix /usr

%_exec_prefix %{_prefix}

%_bindir %{_exec_prefix}/bin

%_sbindir %{_exec_prefix}/sbin

%_libexecdir %{_exec_prefix}/libexec

%_datadir %{_prefix}/share

%_sysconfdir %{_prefix}/etc

%_sharedstatedir %{_prefix}/com

%_localstatedir %{_prefix}/var

%_libdir %{_exec_prefix}/lib

%_includedir %{_prefix}/include

%_oldincludedir /usr/include

%_infodir %{_prefix}/info

%_mandir %{_prefix}/man

Определения этого примера взяты из стандартного файла для макроопределений, /usr/lib/rpm/macros. В файле, специфичном для дистрибутивов Red Hat, /usr/lib/rpm/redhat/macros, содержится:

%_prefix /usr

%_sysconfdir /etc

%_localstatedir /var

%_infodir /usr/share/info

%_mandir /usr/share/man

%_initrddir %{_sysconfdir}/rc.d/init.d

%_defaultdocdir %{_usr}/share/doc

Далее - Макросы, специфичные для spec-файла
Назад - Добавление записей в журнал изменений
Содержание


9.7.2 Макросы, специфичные для spec-файла

Большинство предопределенных RPM-макросов содержат пути к каталогам или информацию по архитектуре. RPM также включает блок макросов, с помощью которых удобно отлаживать проблематичные spec-файлы и выполнять какие-либо стандартные действия из spec-файла. В таблице показаны отладочные и другие специальные макросы.

Макрос

Что делает

%dump

Выводит значение макроса

%{echo:message}

Выводит message на стандартный вывод ошибок

%{error:message}

Выводит message на стандартный вывод ошибок и возвращает BADSPEC

%{expand:expression}

Подобно eval раскрывает выражение

%{F:file_exp}

Раскрывает file_exp в имя файла

%global name value

Определяет глобальный макрос

%{P:patch_exp}

Раскрывает patch_exp в имя файла патча

%{S:source_exp}

Раскрывает source_exp в имя файла с исходным кодом

%trace

Включает вывод отладочной информации

%{uncompress:filename}

Проверяет, является ли файл filename сжатым. Если да, распаковывает и включает в заданный контекст. Если нет, вызывает cat для включения файла в заданный контекст.

%undefine macro

Аннулирует данный макрос

%{warn:message}

Выводит message на стандартный вывод ошибок

Чтобы увидеть текущий список макросов, нужно поместить %dump в начало spec-файла.

Далее - Определение нового макроса
Назад - Встроенные макросы
Содержание


9.7.3 Определение нового макроса

Разработчик может определить свои макросы для облегчения сопровождения пакета. Используется следующий синтаксис:

%define major 2

%define minor 2

%define patchlevel 7

Далее можно обращаться к макроопределениям в стиле %macro_name или %{macro_name}. Например:

Version: %{major}.%{minor}.%{patchlevel}

Также можно использовать результат выполнения shell-команд с помощью синтаксиса %(command):

%define today %(date)

Далее - Параметры макросов
Назад - Макросы, специфичные для spec-файла
Содержание


9.7.4 Параметры макросов

Большая часть макросов может выполнять простые текстовые подстановки. Также макросу можно передать параметры, и получить доступ к их значениям, подобно тому, как это происходит в shell.

Для передачи параметров обычное определение расширяется следующим образом:

%define macro_name(options) value

Любой текст в круглых скобках передается getopt(3) и выступает в качестве параметра для макроса. Кроме того, можно передать параметры макросу, если используется способ определения без фигурных скобок. Например:

%foo 1 2 3

Этот пример передает параметры 1, 2 и 3 макросу foo. Внутри макроса вы можете использовать shell-подобный синтаксис для доступа к параметрам через специальные макросы. В таблице показаны такие макросы.

Макрос

Содержит

%0

Имя макроса

%*

Все параметры

%#

Число параметров

%1

Первый параметр

%2

Второй параметр

%3

Третий параметр и так далее

%{-p}

Содержит -p, если параметр -p был передан макросу, в противном случае не содержит ничего

%{-p*}

Содержит значение, переданное с параметром -p, если параметр был передан макросу, в противном случае не содержит ничего

%{-p:text}

Содержит text, если параметр -p был передан макросу, в противном случае не содержит ничего

Специальные макросы из этой таблицы будут содержать свои значения только после того, как отработает процесс getopt(3). Эти макросы можно использовать в определениях своих макросов. Также можно вкладывать макросы один в другой, как показано в примере:

%define mypatch() patch %{-p:-p%{-p*}}

Этот макрос раскроется в команду patch в том случае, если параметр -p не будет передан макросу. Если параметр будет передан, например -p 1, тогда макрос раскроется в patch -p1 .
Этот тип синтаксиса используется в основном с командой patch.

Далее - Создание spec-файла в XML-формате
Назад - Определение нового макроса
Содержание


9.8 Создание spec-файла в XML-формате

RPM spec-файл - это текстовый файл, содержащий структурированную информацию. Использование XML для хранения такой информации - естественный шаг вперед. В качестве экспериментальной возможности поддерживается анализ spec-файла в формате XML. Утилита rpmxmlbuild соберет rpm-пакет, используя такой файл.

Пример XML spec-файла показан ниже:

<?xml version="1.0"?>

<spec distribution="RPM Test" vendor="rpm.org"
name="bash" version="2.05a" release="02test"
copyright="GPL"
url="http://www.gnu.org/software/bash/bash.html">

<source name="%{name}-%{version}.tar.bz2"
size="1434025" md5="c29b50db808003e39558a0f6354f4cad"
path="%{name}-%{version}">

</source>

<buildrequires>

<require name="bash" />

<require name="gcc" />

<require name="make" />

</buildrequires>

<!-- packages -->

<package group="System/Base" autoreqprov="no">

<requires>

<require name="glibc" />

</requires>

<summary>The Bash package contains the bash program.</summary>

<description>%{summary}
Bash is the Bourne-Again SHell, which is a widely used command interpreter on Unix systems. Bash is a program that reads from standard input, the keyboard. A user types something and the program will evaluate what he has typed and do something with it, like running a program.
</description>

<files list="%{name}.files.lst" />

</package>

<package name="bash-doc" group="Documentation/System/Base" autoreqprov="no">

<requires>

<require name="%{name}" />

</requires>

<summary>Documentation for the bash package.</summary>

<description>%{summary}</description>

<pre script="%{name}-doc.pre.sh" />

<files list="%{name}-doc.files.lst" />

</package>

<!-- scripts to create the package -->

<prep script="%{name}.prep.sh">

<setup />

<script>echo "Prep completed"</script>

</prep>

<build script="%{name}.build.sh" />

<install script="%{name}.install.sh" />

<clean script="%{name}.clean.sh" />

<!-- changelog -->

<changelog>

<changes date="Mon Aug 26 2002" version="2.05a-02test"
author="" author-email="">

<change>Added setup macro to extract files</change>

<change>Initial version ready for jbj</change>

</changes>

</changelog>

</spec>

Далее - Раздел 10. Расширенные возможности RPM
Назад - Параметры макросов
Содержание


10.1 Зависимости пакета

Зависимости - одна из важнейших сфер деятельности RPM. БД RPM отслеживает зависимости между пакетами, что значительно облегчает задачи администратора. Зависимости возникают в тех случаях, когда работоспособность ПО из одного пакета зависит от ПО, входящего в состав другого пакета. Основная задача RPM - проследить, чтобы зависимости не нарушались при установке, обновлении или удалении пакетов. Внутри этой простой парадигмы RPM различает четыре типа зависимостей:

- Requirements, случаи, когда пакету требуются возможности, предоставляемые другим пакетом;

- Provides, списки пакетов, которые требуют возможностей данного, а он их предоставляет;

- Conflicts, случаи, когда пакет конфликтует с возможностями, предоставляемыми другим пакетом;

- Obsoletes, случаи, когда возможности данного пакета делают устаревшими возможности другого пакета; обычно бывают, если при смене версии пакет меняет имя.

Списки всех этих типов зависимостей могут быть указаны в spec-файле, однако наиболее важной информацией о зависимостях является информация о зависимости пакета от других пакетов (requires).

Далее - Имена зависимостей
Назад - Создание spec-файла в XML-формате
Содержание


10.1.1 Имена зависимостей

Основной синтаксис именования зависимостей:

Requires: capability

где capability, как правило, имя другого пакета. В данном примере тип зависимости - Requires, то есть те возможности, которые нужны нашему пакету. Для всех других типов зависимостей строки будут выглядеть похоже:

Provides: capability

Obsoletes: capability

Conflicts: capability

Для добавления группы зависимостей их разделяют пробелом, или запятой и пробелом:

Requires: bash perl

10.1.1.1 Версии зависимостей

Часто бывает необходимо уточнить версию зависимости, например:

Conflicts: bash >= 2.0

Запись в строке говорит о том, что пакет будет конфликтовать с любым пакетом bash, чья версия 2.0 или выше.

В таблице приводятся различные случаи сравнения версий:

Тип сравнения

Что значит

package < version

Пакет со значением версии меньше, чем version

package > version

Пакет со значением версии больше, чем version

package >= version

Пакет со значением версии больше или равной version

package <= version

Пакет со значением версии меньше или равной version

package = version

Пакет со значением версии, в точности равной version

package

Пакет под именем package любой версии

При сравнении версий RPM поддерживает и расширенные номера, в стиле Эпоха: Версия-Релиз, например:

1:5.6.0-17

Очень часто для сравнения требуется только версия. Эпоха может помочь в случае сложных номеров версий, а релиз почти никогда не используется, за исключением случаев, когда зависимость привязана к конкретной сборке.

10.1.1.2 Создание виртуальных возможностей

Зависимости базируются на возможностях, в большинстве случаев возможность предоставляется пакетом. Но можно создать так называемые виртуальные возможности, которые представляют собой абстрактные имена. Например, пакет sendmail предоставляет функциональность smtp-сервера и в пакете этот факт представлен виртуальной возможностью, названной smtpdaemon. Например:

Provides: smtpdaemon

Данная возможность ссылается на функционал SMTP этого пакета. Допустим, ряд программ нуждается в отправке писем во время своей работы, причем все равно, через какой почтовый сервис. Тогда, указав в соответствующих пакетах виртуальную возможность smtpdaemon, разработчик сделает допустимым установку пакета с такими программами в систему, в которой есть какой-либо из smtp-сервисов (если укажет в Requires параметр smtpdaemon), причем неважно, какой именно.

10.1.1.3 Зависимости от скриптовых движков и модулей

Скриптовые языки, такие, как Perl или Tcl, поддерживают модули расширения (add-ons). Разрабатываемый пакет может зависеть от такого модуля. RPM использует специальный синтаксис с использованием круглых скобок для указания модуля интерпретируемого языка. Например:

Requires: perl(Carp) >= 3.2

Такая строка указывает на потребность пакета в модуле Carp языка Perl версии 3.2 или выше.

Далее - Установка предварительных требований
Назад - Зависимости
Содержание


10.1.2 Установка предварительных требований

Предварительные требования (prerequisites) - тип зависимости, очень похожий на потребности (requires) за одним исключением: prerequisites должны быть уже установлены в системе, чтобы пакет установился. Предварительные требования задаются строкой:

PreReq: capability

Работают и версии:

PreReq: capability >= version

В большинстве случаев prerequisites действуют также, как и requires. Фактически, директива PreReq: существует только для возможности выставления порядка зависимостей вручную. RPM гарантирует, что пакеты PreReq: будут установлены строго раньше целевого пакета.

В разделе 14 затрагивается тема борьбы с циклическими зависимостями с помощью этой директивы.

Далее - Зависимости сборки
Назад - Имена зависимостей
Содержание


10.1.3 Зависимости сборки

Однажды собранный, пакет уже несет в себе ряд зависимостей. Эти зависимости влияют так или иначе на любого пользователя, который желает установить пакет в систему. Однако, существуют и зависимости времени сборки пакета. Если они формализованы, в spec-файле появляется информация для сборщика и утилиты rpmbuild о средствах, необходимых для сборки данного пакета. В обычном случае зависимости установки и зависимости сборки - не одно и то же и это обстоятельство хорошо ложится на общее стремление вендоров дистрибутивов Linux отделять пакеты с исполняемым ПО от пакетов со средствами разработки.

RPM позволяет задать зависимости сборки с помощью следующего синтаксиса:

BuildRequires:

BuildConflicts:

BuildPreReq:

Указанные директивы ничем не отличаются от Requires:, Conflicts: и PreReq:, за исключением того обстоятельства, что это потребности исключительно времени сборки, а не времени установки и функционирования.

Далее - Автоматизация создания списка зависимостей
Назад - Установка предварительных требований
Содержание


10.1.4 Автоматизация создания списка зависимостей

Поскольку множество зависимостей относятся к разделяемым библиотекам, RPM будет стремиться сгенерировать зависимости Provides: для любого файла пакета, если он относится к .so-файлам. RPM также генерирует Requires: для каждого файла из секции %files, если он зависит от разделяемых библиотек. Для достижения этих целей RPM вызывает команду ldd, которая определяет, какие библиотеки требуются приложению.

Скрипты find-requires и find-provides в каталоге /usr/lib/rpm умеют определять зависимости программ на Perl, Python и Tcl, а также приложений Java.

Далее - Установка триггеров
Назад - Зависимости сборки
Содержание


10.2 Установка триггеров

Триггеры предоставляют возможность изменять поведение пакета в зависимости от статуса установки другого пакета. Триггер - это скрипт, который разработчик поместил в свой spec-файл для того, чтобы система RPM запустила его на выполнение, если статус другого указанного пакета изменился. Если пакет каким-либо образом зависит от другого, может возникнуть необходимость выполнить какие-либо действия в случае изменений в этом другом пакете.

Триггеры не являются заменой зависимостей. Они нужны для
специальных случаев. Например, если пакет содержит программное обеспечение почтового клиента, ему потребуется присутствие в системе агента передачи почты, MTA. Linux поддерживает множество MTA и в стандартном случае один из них установлен в системе. В большинстве ситуаций почтовому клиенту нет нужды беспокоится об MTA, до тех пор, пока он установлен. Скрипт %trigger отработает, если пакет, от которого есть зависимость, будет, например, обновлен или удален. Он не будет отрабатывать, если будет удален наш гипотетический пакет с почтовым клиентом.

Для написания скрипта триггера нужен список целевых пакетов, например:

%triggerin -- tcsh

команды скрипта

Условимся об именах: наш пакет - это пакет, зависящий от другого, в данном случае, tcsh. Это пакет, в котором мы определяем триггер. tcsh - целевой пакет, от него зависит "наш пакет". Пример выше показывает, что если tcsh будет установлен или обновлен, RPM запустит скрипт. Если "наш пакет" будет установлен или обновлен, а tcsh в это время будет установленным, RPM также запустит скрипт.

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

%triggerpostun -- vixie-cron < 3.0.1-56

/sbin/chkconfig --del crond

/sbin/chkconfig --add crond

Этот пример из пакета планировщика отложенных задач vixie-cron запускает пост-инсталляционный триггер для того же пакета, но более старой версии.

Триггеры запускаются в интерпретаторе /bin/sh, наиболее общем исполнителе shell-скриптов, конкретный вариант которого может зависеть от системы. Для определения другого интерпретатора можно воспользоваться опцией -p. Например, для запуска триггера на Perl:

%triggerpostun -p /usr/bin/perl -- vixie-cron < 3.0.1-56

system("/sbin/chkconfig --del crond");

system("/sbin/chkconfig --add crond");

Для субпакетов используется опция -n, чтобы указать скрипту на субпакет:

%triggerpostun -n subpackage_name -- vixie-cron < 3.0.1-56

/sbin/chkconfig --del crond

/sbin/chkconfig --add crond

Внутри триггера $1 - первый аргумент командной строки, содержит количество установок "нашего пакета", которые будут существовать после того, как все операции завершатся. Второй аргумент, $2, содержит количество установок целевого пакета, которые будут существовать, когда все операции завершатся. Если
$2 есть 0, целевой пакет будет удален.

Пример пакета, содержащего множество триггеров - anonftp. Этот сетевой пакет сильно привязан к конкретной версии glibc:

%triggerin -- glibc

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

# Kill off old versions

rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl* /var/ftp/lib/lib
nss_files* &>/dev/null || :

# Copy parts of glibc, needed by various programs in bin.

LIBCVER=`basename $(ls --sort=time /lib/libc-*.so |head -n 1) .so |cut -f2- -d-`

copy /lib/ld-${LIBCVER}.so /var/ftp/lib

copy /lib/libc-${LIBCVER}.so /var/ftp/lib

copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib

copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib

md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.* 2>/dev/null >/var

/ftp/lib/libs.md5

chmod 0400 /var/ftp/lib/libs.md5

# Use ldconfig to build symlinks and whatnot.

[ ! -e /var/ftp/etc/ld.so.conf ] && touch /var/ftp/etc/ld.so.conf

/sbin/ldconfig -r /var/ftp

%triggerin -- fileutils

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/ls /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

%triggerin -- cpio

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/cpio /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

%triggerin -- tar

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/tar /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

%triggerin -- gzip

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /bin/gzip /var/ftp/bin

ln -sf gzip /var/ftp/bin/zcat

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

%triggerin -- libtermcap

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :

copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib

md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
2>/dev/null >/var

/ftp/lib/libs.md5

chmod 0400 /var/ftp/lib/libs.md5

# Use ldconfig to build symlinks and whatnot.

[ ! -e /var/ftp/etc/ld.so.conf ] && touch /var/ftp/etc/ld.so.conf

/sbin/ldconfig -r /var/ftp

%triggerin -- ncompress

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

copy /usr/bin/compress /var/ftp/bin

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

%triggerpostun -- anonftp 4.0

if [ "$2" != 1 ] ; then

# The user has multiple glibc packages installed. We can't read the

# user's mind, so don't do anything.

exit 0

fi

copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2" 2>/dev/null |
| cp -df "$file" "$2"; }

# Kill off old versions

rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl* /var/ftp/lib/lib
nss_files* &>/dev/null || :

# Copy parts of glibc, needed by various programs in bin.

LIBCVER=`basename /lib/libc-*.so .so | cut -f2- -d-`

copy /lib/ld-${LIBCVER}.so /var/ftp/lib

copy /lib/libc-${LIBCVER}.so /var/ftp/lib

copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib

copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib

copy /bin/ls /var/ftp/bin

copy /bin/cpio /var/ftp/bin

copy /bin/tar /var/ftp/bin

copy /bin/gzip /var/ftp/bin

ln -sf gzip /var/ftp/bin/zcat

copy /usr/bin/compress /var/ftp/bin

rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :

copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib

# Use ldconfig to build symlinks and whatnot.

[ ! -e /var/ftp/etc/ld.so.conf ] && touch /var/ftp/etc/ld.so.conf

/sbin/ldconfig -r /var/ftp

# Generate md5sums for verifyscript

md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.* 2>/dev/null >/var

/ftp/lib/libs.md5

chmod 0400 /var/ftp/lib/libs.md5

md5sum `ls /var/ftp/bin/* |grep -v bin.md5` >/var/ftp/bin/bin.md5

chmod 0400 /var/ftp/bin/bin.md5

Далее - Написание проверочных скриптов
Назад - Автоматизация создания списка зависимостей
Содержание


10.3 Написание проверочных скриптов

RPM автоматически выполняет проверку пакета в режиме верификации, сравнивая для установленных файлов их размер и другие атрибуты с эталоном. Может возникнуть необходимость делать больше. Среди возможностей RPM разработчику доступны:

- контроль над проведением тестов, как уже обсуждалось ранее по тексту;
- написание собственных проверочных скриптов, выполняющих другие тесты, помимо встроенных.

Если необходимо выполнять какие-либо проверки в отношении собранного пакета, например, проверку, имеют ли некоторые переменные в конфигурационном файле определенные значения, следует определить директиву %verifyscript в spec-файле. Такие скрипты во всем подобны %pre или %post скриптам, за исключением того, что они выполняются в режиме верификации rpm:

%verifyscript

команды скрипта

Характерные команды для таких скриптов - проверка записей в файлах конфигурации или в инит-скриптах.

Далее - Создание субпакетов
Назад - Установка триггеров
Содержание


10.4 Создание субпакетов

Spec-файл может определять сборку более чем одного пакета. Этот тип дополнительных пакетов называется "субпакет" (subpackage). Субпакет имеет место для закрытия потребности в тех случаях, когда разработчик не хочет жестко ассоциировать один spec-файл с одним пакетом. Например, вы можете захотеть включить в один набор исходников пакет с исполняемым ПО и пакет с файлами разработки, или клиентское и серверное приложение. Разделение больших наборов документации на несколько субпакетов - также обычное дело.

В концепции субпакетов разработчику доступны:

- один spec-файл;
- один src.rpm;
- один набор команд сборки;
- несколько бинарных rpm.

В большинстве случаев субпакеты используют как средство разделения набора собранных файлов на несколько пакетов. Например, часто встречаются библиотеки разработки и заголовочные файлы, отделенные от главного пакета с приложением. Часто для этого требуется только использование нужной директивы и специальным образом организованная секция %files.

Для определения субпакета применяется директива %package:

%package sub_package_name

%package -n new_sub_package_name

По умолчанию имя субпакета строится следующим образом: имя исходного пакета - дефис - имя субпакета из директивы %package. Например:

%package server

Этот пример называет субпакет "server" и это реальный субпакет в пакете telnet. В данном случае бинарный пакет получит имя telnet-server.

Если есть причины (или нет желания) использовать стандартный синтаксис именования субпакета, доступна опция -n, с помощью которой можно задать полностью новое имя субпакета с использованием следующего:

%package -n new_sub_package_name

Система RPM не станет прибавлять префикс к полностью новому имени субпакета.

Далее - Предоставление информации о субпакетах
Назад - Написание проверочных скриптов
Содержание


10.4.1 Предоставление информации о субпакетах

При определении субпакета в spec-файле необходимо предоставить информацию о нем, по крайней мере заполнить поля Summary:, Group: и %description . Всё, что не было задано, будет взято из информации о родительском пакете (например, версия). Обязательные директивы помещаются после директивы %package:

%package server

Requires: xinetd

Group: System Environment/Daemons

Summary: The server program for the telnet remote login protocol.

Директива %description для субпакета требует имени субпакета с использованием следующего синтаксиса:

%description server

Telnet is a popular protocol for logging into remote systems over the Internet. The telnet-server package includes a telnet daemon that supports remote logins into the host machine. The telnet daemon is enabled by default. You may disable the telnet daemon by editing /etc/xinetd.d/telnet.

Если в директиве %package используется опция -n, тогда она же используется в директиве %description :

%description n my-telnet-server

Telnet is a popular protocol for logging into remote systems over the Internet. The telnet-server package includes a telnet daemon that supports remote logins into the host machine. The telnet daemon is enabled by default. You may disable the telnet daemon by editing /etc/xinetd.d/telnet.

Тот же образец действует для секции %files. Для каждого субпакета нужна своя секция %files. Например:

%files server

%defattr(-,root,root)

%{_sbindir}/in.telnetd

%{_mandir}/man5/issue.net.5*

%{_mandir}/man8/in.telnetd.8*

%{_mandir}/man8/telnetd.8*

И тот же самый подход в отношении опции -n : используется в %package - используется в %files :

%files -n my-telnet-server

%defattr(-,root,root)

%{_sbindir}/in.telnetd

%{_mandir}/man5/issue.net.5*

%{_mandir}/man8/in.telnetd.8*

%{_mandir}/man8/telnetd.8*

Далее - Скрипты в субпакетах
Назад - Создание субпакетов
Содержание


10.4.2 Скрипты в субпакетах

Также, как определяются для субпакетов секции %files и %description, можно определить install и uninstall скрипты. Формат определений схож с определениями %files и %description:

%pre subpackage

Например, следующий листинг определяет скрипты для пакета VNC:

%post server

if [ "$1" = 1 ]; then

/sbin/chkconfig --add vncserver

fi

%preun server

if [ "$1" = 0 ]; then

/sbin/service vncserver stop >/dev/null 2>&1

/sbin/chkconfig --del vncserver

fi

%postun server

if [ "$1" -ge "1" ]; then

/sbin/service vncserver condrestart >/dev/null 2>&1

fi

Далее - Сборка субпакетов
Назад - Предоставление информации о субпакетах
Содержание


10.4.3 Сборка субпакетов

Секция build в spec-файле может использоваться как для сборки основного пакета, так и для сборки субпакета.

Чтобы оптимизировать сборку субпакета используются некоторые специальные свойства макросов. В частности, весьма способствует процессу наличие множества опций макроса %setup. Например, макрос %setup позволяет производить селективную распаковку архивов с исходным кодом, в отличие от случая по умолчанию, когда распаковываются все архивы.

Следующий пример показывает, как %setup может задать специфические инструкции утилите rpmbuild для распаковки источников кода:

%setup D- T a 1

Опция -D в этом примере отключает автоматическое удаление каталога распаковки. Это означает, что содержимое каталога, образовавшееся от предыдущих операций распаковки, возможно для кода других субпакетов, останется неповрежденным. Опция -T отключает автоматическую распаковку источников кода, опция -a 1 указывает распаковать только первый Source.

При работе с субпакетами все эти опции могут понадобиться.

С другой стороны, в большом числе случаев понятие "субпакет" означает лишь упаковку некоторого количества собранных файлов в отдельный бинарный rpm-пакет. В этих случаях специальные опции %setup не нужны.

Далее - Создание пакетов с переопределяемыми путями
Назад - Скрипты в субпакетах
Содержание


10.5 Создание пакетов с переопределяемыми путями

Пакет с переопределяемыми путями позволяет пользователю задать свои пути установки файлов пакета. Например, если собирается пакет для дистрибутива Red Hat Linux, обычным каталогом исполняемых программ будет /usr/bin. Другие дистрибутивы могут иметь отличные от стандартного пути. Тогда пакет, устанавливающий файлы в стандартные каталоги будет неработоспособным, если в дистрибутиве принят, например, в качестве каталога для исполняемых программ какой-нибудь /opt/bin.

В пакете с переопределяемыми путями заложена возможность задать при установке корень каталогов, отличный от стандартного.

Для создания такого пакета нужно:

- определить директиву prefix для вершины каталогов;
- задать список файлов относительно prefix-директории.

Далее - Задание префикса
Назад - Сборка субпакетов
Содержание


10.5.1 Задание префикса

Директива Prefix: именует каталог верхнего уровня, который можно изменить на другой. Например:

Prefix: /usr

Этот пример показывает, что rpm для этого пакета теперь имеет информацию, благодаря которой при задании в командной строке во время установки какого-либо каталога, например /opt, /usr будет заменен на него.

Далее - Редактирование секции files
Назад - Создание пакетов с переопределяемыми путями
Содержание


10.5.2 Редактирование секции files

Если используется директива Prefix:, все файлы в секции %files должны быть позиционированы относительно заданного каталога. Например, для файлов пакета компилятора jikes:

Prefix: /usr

...

%files

%defattr(-,root,root)

/usr/bin/jikes

%doc /usr/doc/jikes-%{version}/license.htm

%doc /usr/man/man1/jikes.1*

В этом примере все файлы располагаются под каталогом /usr. Если имеется более чем один каталог верхнего уровня, например, /usr и /etc, следует использовать соответствующее количество директив Prefix: . Например:

Prefix: /usr

Prefix: /etc

Далее - Проблемы создания пакетов с переопределяемыми путями
Назад - Задание префикса
Содержание


10.5.3 Проблемы создания пакетов с переопределяемыми путями

Не все пакеты хороши в роли пакета с переопределяемыми путями. Некоторые пакеты содержат файлы, которые должны быть установлены в совершенно определенные каталоги и не подлежат никаким перемещениям. Некоторые программы настроены на поиск своих компонентов в жестко определенных каталогах и не могут быть перенесены куда-либо. Другие пакеты содержат символические ссылки, которые также нельзя перенести. Кроме того, пакет может содержать ПО, к которому обращаются программы других пакетов по известным путям. Переопределение путей для вышеописанных пакетов сделает неработоспособным любое ПО, которое ничего не знает о таком переносе.

Если ваш пакет относится к одному из перечисленных типов, попытка сделать его пакетом с переопределяемыми путями определенно является неудачной идеей.

Кроме того, если директива %doc используется с локальными именами файлов, следует помнить о том, что RPM создает в таких случаях пакетно-зависимые каталоги с документацией. Например:

%doc README NEWS

Наличие такой инструкции в исходном spec-файле может свести на нет попытки создать пакет с переопределяемыми путями до тех пор, пока имеется директива Prefix: /usr, так как обычный путь установки документации пакетов - /usr/share/doc .

Далее - Условная сборка
Назад - Редактирование секции files
Содержание


10.6 Условная сборка

Наряду с возможностью определять макросы внутри spec-файла, а также использовать макросы, определенные где-то еще, разработчик имеет возможность детализированного контроля через настройку самого процесса сборки. К инструментам такой настройки относятся специальные директивы, позволяющие выполнять определенные наборы команд только при наступлении определенных условий. Эти инструменты не только повышают функциональность самого spec-файла, но и облегчают решение таких задач, как сборка пакета для разных архитектур и разных версий Linux.

Для определения подобных конструкций необходимо создать управляющие модули с условиями. Кроме того, могут потребоваться макросы, которые эти условные модули будут использовать.

RPM поддерживает ряд директив, позволяющих разработчику структурировать spec-файл таким образом, что отдельные его части будут выполняться или не выполняться в зависимости от наличия или отсутствия определенных условий. Среди них: условные макросы, условные блоки и специальные директивы для задания системных архитектур.

Далее - Условные макросы
Назад - Проблемы создания пакетов с переопределяемыми путями
Содержание


10.6.1 Условные макросы

Используется специальный синтаксис для проверки, был ли определен данный макрос. Например:

%{?macro_to_test: expression}

Эта строка говорит RPM развернуть выражение expression, если макрос macro_to_test существует. Если макрос не существует, ничего не будет выведено. Проверку также можно осуществлять реверсивно. Если в проверке первый символ - знак !, выражение будет разворачиваться, если макрос НЕ существует:

%{!?macro_to_test: expression}

В данном примере выражение expression будет развернуто, если макрос macro_to_test не существует.

При необходимости выражение можно пропустить и проверять только наличие или отсутствие макроса. Если макрос существует, RPM использует значение макроса, если не существует, RPM не будет делать ничего. Например:

%build

./configure %{?_with_ldap}

make

В этом случае, если макрос _with_ldap существует, значение этого макроса будет подставлено в командную строку в скрипт ./configure в качестве параметра. Если макрос _with_ldap не существует, в скрипт не будет подставлено никаких параметров. Это весьма мощная возможность для процессов сборки или установки пакета.

Далее - Условные блоки
Назад - Условная сборка
Содержание


10.6.2 Условные блоки

Макрос %if делает доступными все инструкции вплоть до директивы %endif, если условие выполняется. Эта конструкция подобна сходным конструкциям в любом скриптовом языке. Например:

%if %{old_5x}

%define b5x 1

%undefine b6x

%endif

В этом примере, если макрос %old_5x задан и имеет значение, проверка возвратит true и все команды внутри блока будут выполнены.

%else позволяет задать действия, если тест не успешен. Например:

%if %{old_5x}

%define b5x 1

%undefine b6x

%else

%define b6x 1

%undefine b5x

%endif

В этом случае, если макрос %old_5x имеет значение, все команды до %else будут выполнены. Если %old_5x не задан, будут выполнены команды от %else до %endif.

И вновь, восклицательный знак используется для инверсии проверки:

%if ! %{old_5x}

%define b5x 1

%undefine b6x

%endif

Для вставки в конструкцию логического AND используется &&. Например:

%if %{old_5x} && %{old_6x}

%{error: You cannot build for .5x and .6x at the same time}

%quit

%endif

Далее - Архитектурно-зависимые условия
Назад - Условные макросы
Содержание


10.6.3 Архитектурно-зависимые условия

В дополнение к базовому функционалу директивы условий %if , разработчику доступны специальные инструкции, тестирующие процессорную архитектуру и операционную систему. Процесс сборки в этом случае построен зависимым образом от результатов этих тестов.

Директива %ifarch делает выполняемыми все команды до директивы %endif, если процессорная архитектура машины, на которой производится сборка, соответствует образцу. Например:

%ifarch sparc

%define b5x 1

%undefine b6x

%endif

Блок из примера будет выполнен только в том случае, если процессорная архитектура машины - SPARC.

Могут быть перечислены несколько архитектур, разделенных запятой или пробелом:

%ifarch sparc alpha

%define b5x 1

%undefine b6x

%endif

Также как в %if для покрытия всех случаев, когда проверка неуспешна, используется %else :

%ifarch sparc alpha

%define b5x 1

%undefine b6x

%else

%define b6x 1

%undefine b5x

%endif

В данном примере проверяется, является ли текущая архитектура архитектурой SPARC или Alpha. Если да, выполняется блок между %ifarch и %else, если нет - блок между %else и %endif.

Директиву %ifarch (то есть, выполняемые ею действия) можно инвертировать. Для этого используется директива %ifnarch. Нижеследующий пример позволяет убедиться, что текущая архитектура не i386 и не Alpha.

%ifnarch i386 alpha

%define b5x 1

%undefine b6x

%endif

Директива %ifos проверяет текущую операционную систему. Например:

%ifos linux

%define b5x 1

%undefine b6x

%endif

В данном примере, если операционная система не Linux, никакие команды блока не будут выполнены. Этот случай также подлежит инвертированию:

%ifnos irix

%define b5x 1

%undefine b6x

%endif

То есть, если операционная система НЕ Irix, то команды блока будут выполнены.

Далее - Раздел 11. Контролирование сборки с помощью утилиты rpmbuild
Назад - Условные блоки
Содержание


11.1.1 Настройка сборки

Для изменения поведения утилиты rpmbuild по умолчанию существует набор специальных опций, показанных в таблице ниже:

Опция

Что делает

--buildroot directory

Выбирает для сборки директорию directory, отличную от buildroot по умолчанию

--clean

Удаляет дерево сборки после сборки

--nobuild

Тестирует spec-файл не выполняя сборки

--rmsource

Удаляет исходники после сборки

--rmspec

Удаляет spec-файл после сборки

--short-circuit

В связке с опциями -bc или -bi переходит прямо к указанной стадии сборки и продолжает сборку пакета с этого места

--sign

Подписывает пакет сигнатурой GPG

--target platform

Сборка для указанной платформы. Может не сработать, если не используются команды сборки для альтернативных платформ, такие, как в случаях кросс-компиляции.

Далее - Тестирование сборки
Назад - Архитектурно-зависимые условия
Содержание


11.1.2 Тестирование сборки

Одна из наиболее часто используемых опций - опция --nobuild, говорящая утилите rpmbuild не собирать ничего. Она используется для проверки, может ли пакет с таким spec-файлом собраться в принципе. При использовании этой опции утилита запускает парсер spec-файла в поисках ошибок, но ничего не собирает.

Опция --buildroot позволяет разработчику задать свой корневой каталог сборки, эта опция перекрывает директиву BuildRoot, заданную в spec-файле. Это означает, что вы можете собирать ПО в другой директории в поисках ошибок. Это помогает не смешивать события с чем-либо из BuildRoot.

Далее - Отладка сборки
Назад - Настройка сборки
Содержание


11.1.3 Отладка сборки

Опция --short-circuit заставляет rpmbuild стартовать с определенного места сборки. Например, если ПО собирается без ошибок, но ошибки возникают на конечных стадиях сборки пакета, нет нужды перекомпилировать ПО, достаточно устранить ошибки, критичные для RPM. Это работает только в связке с опциями -bc, -bi , -tc и -ti .

Если возникали ошибки на стадии %build и они были устранены, --short-circuit также поможет сэкономить время.

В процессе обычной сборки разработчик должен выполнить все стадии, обнаружить ошибки, повторить сборку исправив ошибки , и так множество раз. Если ПО компилируется, например, часы, то этого можно избежать благодаря --short-circuit.

Разрабочики RPM не рекомендуют распространять пакеты, собранные под опцией --short-circuit. Она должна использоваться только для отладки.

Далее - Очистка
Назад - Тестирование сборки
Содержание


11.1.4 Очистка

Опция --clean включает режим очистки дерева сборки после завершения. Это позволяет быть уверенным, что следующая сборка начнется с известной ситуации, и на нее не повлияют прежде собранные файлы. Например:

$ rpmbuild --clean /usr/src/redhat/SPECS/jikes.spec

Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.98247

+ umask 022

+ cd /usr/src/redhat/BUILD

+ rm -rf jikes-1.17

+ exit 0

Опция --clean может использоваться самостоятельно, как в показанном выше примере, а может в связке с другими опциями, например, -bi для сборки и установки бинарного пакета. В этом случае дерево сборки будет удалено после того, как все команды сборки будут выполнены.

Подобным образом, опция --rmsource удаляет исходники после сборки. Эту опцию также можно использовать отдельно или в связке с -bi, тогда исходники будут удалены после выполнения всех необходимых команд.

Опция --rmspec используется также, как предыдущие опции. С ее помощью можно просто удалить spec-файл, или же удалить его после выполнения операций сборки. Используйте эту опцию с осторожностью, чтобы не удалить свой единственный spec-файл.

Далее - Сборка для других платформ
Назад - Отладка сборки
Содержание


11.1.5 Сборка для других платформ

Опция --target переключает rpmbuild на сборку для платформы, отличной от текущей. Необходимо задать идентификатор платформы:

rpmbuild -bi --target i486-redhat-linux

Базовый формат - процессор-вендор-операционная_система. Например, строка i686-redhat-linux задает сборку для процессора i686, операционной системы Red Hat Linux. Опция --target задает архитектуру на время сборки данного пакета. Это означает, что на низком уровне --target перекрывает значения некоторых макросов, таких как %_target, %_target_arch, и %_target_os . Однако, задания процессорной архитектуры недостаточно. Мы, на самом деле, не можем собрать исполняемый файл PowerPC на процессоре Intel без кросс-компилятора, то есть такого компилятора, который умеет собирать бинарные модули для целевой платформы на другой платформе.

Если попробовать собрать ПО, использующее конфигурирующие средства в стиле GNU для конфигурации сборки, платформа под --target будет игнорирована. Например, если пытаться собрать пакет jikes с целью сборки ppc-ibm-aix, мы увидим игнорирование цели, так как система
configure обнаружит, что сборка происходит на Linux и процессоре i686 :

$ rpmbuild -bc --target ppc-ibm-aix
/usr/src/redhat/SPECS/jikes.spec

Building target platforms: ppc-ibm-aix

Building for target ppc-ibm-aix

Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.94955

+ umask 022

+ cd /usr/src/redhat/BUILD

+ LANG=C

+ export LANG

+ cd /usr/src/redhat/BUILD

+ rm -rf jikes-1.17

+ /usr/bin/gzip -dc /usr/src/redhat/SOURCES/jikes-1.17.tar.gz

+ tar -xf -

+ STATUS=0

+ '[' 0 -ne 0 ']'

+ cd jikes-1.17

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

+ /bin/chmod -Rf a+rX,g-w,o-w .

+ exit 0

Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.15710

+ umask 022

+ cd /usr/src/redhat/BUILD

+ cd jikes-1.17

+ LANG=C

+ export LANG

+ ./configure CXXFLAGS=-O3 --prefix=/tmp/jikesrpm/usr

checking for a BSD-compatible install... /usr/bin/install -c

checking whether build environment is sane... yes

checking for gawk... gawk

checking whether make sets ${MAKE}... yes

checking whether to enable maintainer-specific portions of Makefiles... no

checking build system type... i686-pc-linux-gnu

checking host system type... i686-pc-linux-gnu

checking for g++... g++

Как можно видеть из сокращенного листинга, сборка начинается под заданную платформу, но скрипт configure быстро перезадает архитектуру под текущую платформу.

Далее - Опции для работы с tar-архивами
Назад - Очистка
Содержание


11.2.1 Опции rpmbuild для работы с tar-архивами

Множество возможностей утилиты rpmbuild требуют наличия spec-файла. Если приложение загружается, например, с сайта производителя, возможна ситуация, когда не вся необходимая для spec-файла информация доступна. Кроме того, создание spec-файла - операция весьма затратная по времени. Однако, производитель мог уже написать spec-файл и включить его в tar-архив исходников.

Существует специальный блок опций для работы со spec-файлами, включенными в tar-архив с исходниками. Тарбалл - это файл архива, опционально сжатый компрессором gzip (как правило). Для работы с ними rpmbuild использует опции -t, подобные опциям -bВторой_символ.

Базовый синтаксис:

rpmbuild -tВторой_символ compressed_tar_archive

где Второй_символ обозначает стадию сборки, как в -bBuildStage. Опция -t в основном подобна -b, за исключением того обстоятельства, что -t указывает утилите сборки искать spec-файл в tar-архиве. Таблица ниже описывает возможные варианты:

Опция

Что задает

-ta

Собирать все, бинарный rpm и пакет с исходными кодами

-tb

Собирать бинарный пакет

-tc

Остановиться после завершения секции %build

-tp

Остановиться после завершения секции %prep

-ti

Остановиться после завершения секции %install

-tl

Проверить список файлов для rpm

-ts

Собрать только src.rpm

Эти опции работают только с tar-архивами или компрессированными tar-архивами.

Далее - Ожидаемая структура архива
Назад - Сборка для других платформ
Содержание


11.2.2 Ожидаемая структура архива

Для сборки пакета в стиле, описанном в предыдущем пункте, архив должен иметь ожидаемую утилитой структуру, включая скрипт configure и Makefile с нужными целями. Критично наличие spec-файла в составе архива. Утилита вовсе не обязана знать, как собрать любую программу во вселенной, эта идея ведет нас к необходимости определенной стандартизации типов сборочного процесса и требований к его компонентам.

Если имеет место вывод, как в примере, очевидно нарушение ожидаемой структуры архива, например, отсутствует spec-файл:

$ rpmbuild -tc vixie-cron*tar.gz

error: Name field must be present in package: (main package)

error: Version field must be present in package: (main package)

error: Release field must be present in package: (main package)

error: Summary field must be present in package: (main package)

error: Group field must be present in package: (main package)

error: License field must be present in package: (main package)

Далее - Работа с rpm-пакетами, содержащими исходный код (src.rpm)
Назад - Опции rpmbuid для работы с tar-архивами
Содержание


11.3 Работа с rpm-пакетами, содержащими исходный код (src.rpm)

Основная рассматриваемая ситуация при работе с утилитой rpmbuild - сборка пакета при наличии архива с исходными текстами и spec-файла. Кроме этой ситуации во множестве случаев разработчику доступны возможности, заложенные в свойства src.rpm-пакета, независимо от того, хотите ли вы пересобрать его или просто загрузить.

Поскольку src.rpm - это rpm-пакет, с ним можно проделать те же операции, что и с бинарным rpm (установка, удаление, запрос служебной информации). Установив src.rpm в систему, вы увидите spec-файл и архив с исходным кодом в соответствующих каталогах дерева сборки под каталогом
/usr/src/redhat (специфичный для Red Hat Linux путь).

Инсталляция src.rpm не есть в точности та же операция, что и инсталляция бинарного пакета. Например, в этом случае RPM не будет обновлять базу данных пакетов. Кроме того, листинг файлов будет показывать относительные пути, но не полные.

После установки пакета с исходным кодом из него может быть собран бинарный пакет (пакеты) с помощью утилиты rpmbuild.

Далее - Пересборка бинарных пакетов из src.rpm
Назад - Ожидаемая структура архива
Содержание


11.3.1 Пересборка бинарных пакетов из src.rpm

Нет необходимости устанавливать пакет с исходными кодами в систему, чтобы пересобрать из него бинарный пакет. Вместо этого можно собрать пакет непосредственно, с помощью опции --rebuild .

Если команда выполняется из каталога, в котором находится src.rpm, базовый синтаксис такой:

rpmbuild --rebuild package.src.rpm

Эта команда собирает бинарный пакет с минимумом усилий. Например:

$ rpmbuild --rebuild unix2dos-2.2-17.src.rpm

Installing unix2dos-2.2-17.src.rpm

Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.15828

+ umask 022

+ cd /usr/src/redhat/BUILD

+ LANG=C

+ export LANG

+ cd /usr/src/redhat/BUILD

+ rm -rf unix2dos-2.2

+ /bin/mkdir -p unix2dos-2.2

+ cd unix2dos-2.2

+ /usr/bin/gzip -dc /usr/src/redhat/S

OURCES/unix2dos-2.2.src.tar.gz

+ tar -xf -

+ STATUS=0

+ '[' 0 -ne 0 ']'

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

+ /bin/chmod -Rf a+rX,g-w,o-w .

+ echo 'Patch #0 (unix2dos-mkstemp.patch):'

Patch #0 (unix2dos-mkstemp.patch):

+ patch -p1 -b --suffix .sec -s

+ echo 'Patch #1 (unix2dos-2.2-segfault.patch):'

Patch #1 (unix2dos-2.2-segfault.patch):

+ patch -p1 -b --suffix .segf -s

+ echo 'Patch #2 (unix2dos-2.2-manpage.patch):'

Patch #2 (unix2dos-2.2-manpage.patch):

+ patch -p1 -b --suffix .man -s

+ perl -pi -e 's,^#endif.*,#endif,g;s,^#else.*,#else,g'
unix2dos.c unix2dos.h

+ exit 0

Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.60650

+ umask 022

+ cd /usr/src/redhat/BUILD

+ cd unix2dos-2.2

+ LANG=C

+ export LANG

+ gcc -O2 -march=i386 -mcpu=i686 -ounix2dos unix2dos.c

+ exit 0

Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.35128

+ umask 022

+ cd /usr/src/redhat/BUILD

+ cd unix2dos-2.2

+ LANG=C

+ export LANG

+ rm -rf /var/tmp/unix2dos-root

+ mkdir -p /var/tmp/unix2dos-root/usr/bin /var/tmp/unix2dos-
root/usr/share/man/man1

+ install -m755 unix2dos /var/tmp/unix2dos-root/usr/bin

+ install -m444 unix2dos.1

/var/tmp/unix2dos-root/usr/share/man/man1

+ /usr/lib/rpm/redhat/brp-compress

+ /usr/lib/rpm/redhat/brp-strip

+ /usr/lib/rpm/redhat/brp-strip-comment-note

Processing files: unix2dos-2.2-17

Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.12033

+ umask 022

+ cd /usr/src/redhat/BUILD

+ cd unix2dos-2.2

+ DOCDIR=/var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2

+ export DOCDIR

+ rm -rf /var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2

+ /bin/mkdir -p

/var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2

+ cp -pr COPYRIGHT

/var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2

+ exit 0

Finding Provides: /usr/lib/rpm/find-provides

Finding Requires: /usr/lib/rpm/find-requires

PreReq: rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(CompressedFileNames)
<= 3.0.4-1

Requires(rpmlib): rpmlib(PayloadFilesHavePrefix) <= 4.0-1

rpmlib(CompressedFileNames) <= 3.0.4-1

Requires: libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1)

Checking for unpackaged file(s): /usr/lib/rpm/check-files
/var/tmp/unix2dos-root

Wrote: /usr/src/redhat/RPMS/i386/unix2dos-2.2-17.i386.rpm

Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.47653

+ umask 022

+ cd /usr/src/redhat/BUILD

+ cd unix2dos-2.2

+ rm -rf /var/tmp/unix2dos-root

+ exit 0

Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.47653

+ umask 022

+ cd /usr/src/redhat/BUILD

+ rm -rf unix2dos-2.2

+ exit 0

Действия, вызываемые rpmbuild с опцией --rebuild таковы: src.rpm устанавливается в систему, выполняется подготовка к сборке, компиляция и установка собранного бинарного пакета. Если по ходу не возникли ошибки, новый бинарный rpm будет найден в каталоге /usr/src/redhat/RPMS под соответствующей архитектурой.

После сборки и установки пакета происходит очистка директории сборки. Также в конце процесса удаляется установленный в систему src.rpm-пакет, то есть удаляется архив с исходными кодами и spec-файл.

Далее - Перекомпиляция бинарных пакетов из src.rpm
Назад - Работа с пакетами, содержащими исходный код (src.rpm)
Содержание


11.3.2 Перекомпиляция бинарных пакетов из src.rpm

Если разработчик хочет только перекомпилировать файлы в src.rpm-пакете, можно воспользоваться опцией --recompile . Например:

rpmbuild --recompile package.src.rpm

Выполняются те же процессы, что и при установке пакета с исходным кодом в систему и последующем выполнении команды rpmbuild -bc --clean package.spec .

Далее - Проверка установки программного обеспечения GPG
Назад - Пересборка бинарных пакетов из src.rpm
Содержание


11.4.1 Проверка установки программного обеспечения GPG

Для подписывания пакетов необходимо убедиться, что в системе доступна команда gpg. Используйте что-нибудь вроде:

$ rpm -qf `which gpg`

gnupg-1.0.7-6

Вывод команды показывает, что gpg доступна.

GPG или PGP? Документация использует GPG и PGP как синонимы, так, что кто-то может подумать, что это типографская опечатка. Однако, аббревиатура PGP используется для сокращения Pretty Good Privacy, системы ассиметричного шифрования Фила Циммермана. PGP поддерживает механизм электронной подписи. Электронная подпись помогает администратору быть уверенным, что он загрузил доверенное ПО именно нужного вендора, а не трояна или руткит с сайта злоумышленника. Эта проверка доступна с помощью публичного ключа вендора.

GPG означает GNU Privacy Guard, это свободное ПО, open-source реализация PGP, выполненная проектом GNU. GPG ставит своей целью полную совместимость со стандартом OpenPGP Internet standard, описанном в RFC 2440. GPG в силу своей доступности и открытости позволяет вендорам включать в свои дистрибутивы полноценную поддержку PGP. Таким образом, GPG предоставляет возможности PGP.

Далее - Конфигурирование подписи
Назад - Перекомпиляция бинарных пакетов из src.rpm
Содержание


11.4.2 Конфигурирование подписи

Для конфигурирования подписи в первую очередь необходимо создать новый ключ с помощью команды gpg, как показано ниже:

$ gpg --gen-key

gpg (GnuPG) 1.0.7; Copyright (C) 2002 Free Software Foundation, Inc.

This program comes with ABSOLUTELY NO WARRANTY.

This is free software, and you are welcome to redistribute it
under certain conditions. See the file COPYING for details.

gpg: Warning: using insecure memory!

gpg: please see http://www.gnupg.org/faq.html for more information

gpg: keyring `/home2/ericfj/.gnupg/secring.gpg' created

gpg: keyring `/home2/ericfj/.gnupg/pubring.gpg' created

Please select what kind of key you want:

(1) DSA and ElGamal (default)

(2) DSA (sign only)

(4) ElGamal (sign and encrypt)

(5) RSA (sign only)

Your selection? 1

DSA keypair will have 1024 bits.

About to generate a new ELG-E keypair.

minimum keysize is 768 bits

default keysize is 1024 bits

highest suggested keysize is 2048 bits

What keysize do you want? (1024)

Requested keysize is 1024 bits

Please specify how long the key should be valid.

0 = key does not expire

<n> = key expires in n days

<n>w = key expires in n weeks

<n>m = key expires in n months

<n>y = key expires in n years

Key is valid for? (0)

You need a User-ID to identify your key; the software
constructs the user id from Real Name, Comment and Email
Address in this form:

"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

Real name: Eric Foster-Johnson

Email address: please_no_spam@nospam.com

Comment: Example for Red Hat RPM Guide

You selected this USER-ID:

"Eric Foster-Johnson (Example for Red Hat RPM Guide) <eric@no_spam.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?

O

You need a Passphrase to protect your secret key.

Enter passphrase:

We need to generate a lot of random bytes. It is a good idea to
perform some other action (type on the keyboard, move the
mouse, utilize the disks) during the prime generation; this
gives the random number generator a better chance to gain
enough entropy.

+++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++
++++++

+++++++++++++++++++++++++++++++++++..+
++++..++++++++++>++++++++++........+++++


gpg: /home2/ericfj/.gnupg/trustdb.gpg: trustdb created public
and secret key created and signed.

key marked as ultimately trusted.

pub 1024D/01681C24 2002-11-05 Eric Foster-Johnson
(Example for Red Hat RPM Guide)
<please_no_spam@nospam.com>

Key fingerprint = 8C14 A2E9 47D1 301B 2153 7CDF BEE5
9C10 0268 1D24

sub 1024g/1A15D6C8 2002-11-05

Практически во всех пунктах можно согласиться со значениями по умолчанию. Ввести следует реальное имя, адрес и парольную фразу. Всякий раз, когда понадобиться подписать пакет, нужно будет вводить парольную фразу. После заведения ключа необходимо определить ряд макросов. Существует несколько мест, где это можно сделать, но использование файла .rpmmacros в домашнем каталоге - наиболее легкий путь. Отредактируйте файл, добавляя строки из примера:

%_signature gpg

%_gpg_path /home2/ericfj/.gnupg

%_gpg_name EricFJ (Eric Key) <erc@no_spam.com>

%_gpgbin /usr/bin/gpg

Замените значение %gpg_path на каталог .gnupg в домашнем каталоге или каталоге /root. Замените значение %_gpg_name на имя, которое было введено при генерации ключа.

Далее - Подписывание пакетов с помощью утилиты rpmbuild
Назад - Проверка установки программного обеспечения GPG
Содержание


11.4.3 Подписывание пакетов с помощью утилиты rpmbuild

Опция --sign задает операцию подписывания пакета, который собирается в рамках данной команды. При сборке пакета будет выведено приглашение для ввода парольной фразы, как показано в примере.

$ rpmbuild -bb --sign xtoolwait-1.2.spec

Enter pass phrase:

Pass phrase is good

Далее - Подписывание с помощью утилиты rpm
Назад - Конфигурирование подписи
Содержание


11.4.4 Подписывание с помощью утилиты rpm

Помимо опции --sign утилиты rpmbuild, уже собранный пакет можно подписать с помощью rpm. Опции --addsign и --resign генерируют новые подписи и вставляют их в готовый пакет:

rpm --addsign package.rpm

rpm --resign package.rpm

Опция --addsign добавляет в пакет другую подпись. RPM версии до 4.1 допускает подписывание несколькими ключами, что может быть источником проблем при автоматизированной верификации пакетов.

Опция --resign удаляет прежнюю подпись и вставляет новую.

Далее - Верификация подписей
Назад - Подписывание с помощью утилиты rpmbuild
Содержание


Тут могла бы быть ваша реклама!