RPM-repair

Материал из ALT Linux Wiki
Перейти к: навигация, поиск

rpmrepair: починка сторонних RPM путём перепаковки

При установке сторонних пакетов, собранных не для соответствующего репозитория Альт, могут возникать проблемы несовместимости со штатным менеджером пакетов rpm, могут быть допущены ошибки в скриптлетах пакета, могут быть неверно расставлены зависимости. Самый простой способ перепаковки предлагает утилита rpmrepair. Для её использования не требуются привилегии суперпользователя. В данном случае мы рассматриваем получение нового RPM не как процесс сборки из исходников. Бинарный результат у нас уже есть, с ним уже нельзя ничего сделать. Мы просто исправляем ошибки упаковки и рассматриваем RPM как архивный файл с метаданными, что позволит в дальнейшем при установке пакета отказаться от использования таких опций RPM, как --nodeps, --noscripts, --ignorearch.

Симптом[править]

# rpm -ivh 1C_Enterprise83-ws-nls-8.3.17-1549.x86_64.rpm
...
rpmlib(FileDigests) <= 4.6.0-1 нужен для 1C_Enterprise83-ws-nls-8.3.17-1549

Установка[править]

$ su-
# apt-get update
# apt-get install rpmrepair

Если в нужный репозиторий пакет ещё не попал, существует альтернативный способ установки:

$ su-
# apt-repo test 255700

Зависимости у rpmrepair минимальны -- rpm-build, rsync и fakeroot. Перечисленные пакеты нужны только на момент перепаковки, для работы перепакованных пакетов они не требуются.

Ответственный упаковщик[править]

Упаковщиком созданных пакетов (PACKAGER) по умолчанию будет тот, кто упаковал исходный пакет. Если данное поле не указано, им будет системный упаковщик по умолчанию -- берётся из файла ~/.rpmmacros или из командной строки (--packager). Если и это не будет указано, ответственным за перепакованный пакет по умолчанию ставится автор rpmrepair.

Получение справки[править]

$ rpmrepair --help
Usage: rpmrepair [<options>...] [--] [<package.rpm>...]

Options:
  -a, --noarch    Use noarch data packaging method.
  -n, --nodeps    Drop all dependencies in created RPM.
  -p, --packager  Set default PACKAGER name and e-mail.
  -r, --repair    Try to repair packaging errors.
  -s, --scripts   Add scriptlets from source RPM.
  -t, --notemp    Do not change TMPDIR at startup.
  -N, --noclean   Do not cleanup work files at exit.
  -v, --version   Show this program version and exit.
  -h, --help      Show this help message and exit.

Example:
  rpmrepair -p "John Doe <agent007@example.org>"

  Will be repacked all RPM's in the current directory,
  results will be saved to the 'repacked' sub-directory.
  All pre/post/preun/postun scripts will be dropped.

User manual:
  https://www.altlinux.org/RPM-repair (ru)

Please, report bugs to https://bugzilla.altlinux.org/

Принцип действия[править]

Программа распаковывает исходный RPM через rpm2cpio и cpio, упаковывает в архив .tar, извлекает метаданные пакета и создаёт SPEC, на его основе через rpm -bb собирается новый RPM-пакет. При этом отрываются зависимости на rpmlib(...), а если дополнительно указать параметр --nodeps, то из исходных пакетов вообще никакие зависимости не будут перенесены в перепакованные визави. В качестве аргумента можно указать один или несколько RPM, каждый перепаковывается независимо. Если не указать ни одного пакета, будет предпринята попытка перепаковать все RPM-пакеты в текущем каталоге. Только при успешном завершении в текущем каталоге создаётся подкаталог repacked, в который помещается результат работы. По умолчанию временные файлы удаляются, независимо от результата, но опция --noclean позволяет их оставить в отладочных целях.

Предупреждения[править]

До начала работы из текущего каталога будет удалён подкаталог repacked. Также будет удалён каталог ~/RPM со всем содержимым. Сохраняйте свои RPM'ки заблаговременно! Следует иметь ввиду: вендор исходного RPM-пакета не отвечает за получившийся перепакованный результат, поэтому ему следует адресовать рекламации только по исходному пакету. За перепакованный результат вообще никто не может отвечать, вы перепаковываете только на свой страх и риск.

Временный каталог[править]

Поскольку в дистрибутивах Альт TMPDIR обычно настроен на TMPFS (временные файлы создаются в оперативной памяти), а объём перепаковываемых RPM'ов может оказаться довольно большим, по умолчанию программа изменяет текущий TMPDIR на ~/tmp и вся работа выполняется в домашнем каталоге пользователя. Данное поведение можно изменить опцией --notemp. В этом случае перепаковка будет выполняться на TMPFS. В любом случае надо иметь ввиду, что при выполнении rpm -bb раздел, на котором выполняется перепаковка, должен быть смонтирован с опцией exec. В некоторых дистрибутивах Альт по умолчанию разделы /tmp и /home монтируются с noexec, следовательно до начала перепаковки их нужно перемонтировать:

$ su-
# mount -o remount,exec /home
# mount -o remount,exec /tmp

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

Степень починки[править]

rpmrepair --nodeps без дополнительных манипуляций практически гарантированно создаст RPM, который можно будет установить в систему. Конечно не факт, что упакованное ПО при этом заработает. Если же рабочий RPM получается с использованием rpmrepair --repair --scripts без дополнительных манипуляций, это намного лучше. Ключ --repair включает все стандартные очень жёсткие проверки альтовой сборочницы, включается максимальный поиск зависимостей и провайдсов, отделяются отладочные символы. Пробуйте разные варианты с индивидуальной RPM'кой, если не хотите вдаваться в детали.

Целевая архитектура[править]

Независимо от указанной в названии файла пакета архитектуры, упаковка нового RPM-пакета выполняется для текущей архитектуры. Если исходный RPM-пакет на самом деле содержит только архитектурно-независимые файлы, есть возможность упаковать его в пакет *.noarch.rpm, просто добавив ключ --noarch при запуске rpmrepair.

Исправление зависимостей[править]

Независимо от наличия или отсутствия ключа --nodeps, можно добавить свой "кусок спека" при перепаковке. Для этого достаточно сложить рядом с RPM-пакетом файл ИМЯ-ПАКЕТА.deps. Здесь и далее "ИМЯ-ПАКЕТА" можно получить командой:

$ rpm -qp --qf "%{NAME}\n" <package.rpm>

В файле ИМЯ-ПАКЕТА.deps можно указывать такие поля, как Requires:, Obsoletes:, Conflicts: и Provides:. Провайдсы из исходных RPM не переносятся никогда, так что по умолчанию пакет будет провайдить только сам себя. Чтобы выяснить, что требует и что провайдит исходный пакет, а затем исправить это, выполните пару команд:

$ rpm -qp --requires <package.rpm> |sed -E ',^,Requires: ,g' > ИМЯ-ПАКЕТА.deps
$ rpm -qp --provides <package.rpm> |sed -E ',^,Provides: ,g' >> ИМЯ-ПАКЕТА.deps

Перенос и исправление скриптов[править]

В сторонних и проприетарных RPM'ках могут находиться скрипты, зачастую вредные или с ошибками. Никто не проверял их на совместимость с ОС Альт, поэтому такие скрипты по умолчанию не переносятся в перепакованные RPM'ки. Нужно самостоятельно извлечь их, посмотреть, что они делают, и, если требуется, создать на их основе правильные скрипты для пред/пост-установки/удаления. Находясь в каталоге с исходным RPM сделать это можно командой:

$ rpm -qp --scripts <package.rpm> > ИМЯ-ПАКЕТА.scripts

Отредактированный файл ИМЯ-ПАКЕТА.scripts сам затянется в перепакованный RPM при запуске rpmrepair. Удалять и изменять строки типа "postinstall scriplet (through ...):" на соответствующие "%pre"/"%post"/итд... необязательно. Ключом --scripts можно включить автоматическое перекладывание скриптлетов из исходных RPM "как есть", при этом отредактированным вариантам всё равно отдаётся предпочтение.

Другие особенности[править]

Данный способ перепаковки не предусматривает "чистого" удаления, т.к. по умолчанию каталоги не принадлежат к какому-либо пакету. Следовательно, при удалении таких пакетов придётся "хвосты" (пустые каталоги) удалять вручную. Избавить от такой необходимости пользователей перепакованного RPM можно лишь добавив информацию о принадлежности каталогов конкретному пакету. Установить принадлежность для единственного пакета достаточно легко, для целой пачки пакетов -- задача непростая, но тоже решаемая. Просто перечислите все каталоги, относящиеся к пакету, в файле с именем ИМЯ-ПАКЕТА.dirs и сложите его рядом. rpmrepair сам затянет это в создаваемый RPM. При этом надо иметь ввиду, что конкретный каталог не может принадлежать двум пакетам одновременно.

Пример использования[править]

Возьмём за основу поломанную сборку сервера 1C v8.3.17.1549 -- приведённые ниже строки можно вставить в скрипт или скопировать на выполнение прямо в консоль.

cd ~/
tar -xf rpm64_8_3_17_1549.tar.gz
cat >1C_Enterprise83-common.dirs <<EOF
/opt/1C
/opt/1C/v8.3
/opt/1C/v8.3/x86_64
/opt/1C/v8.3/x86_64/licenses
/opt/1C/v8.3/x86_64/licenses/3rd_party
/opt/1C/v8.3/x86_64/dmf
/opt/1C/v8.3/x86_64/dmf/lib
EOF
echo "/opt/1C/v8.3/x86_64/ExtDst" >1C_Enterprise83-server.dirs
for rpm in 1C_Enterprise83*.rpm; do
	name="$(rpm -qp --qf "%{NAME}" "$rpm")"
	rpm -qp --requires "$rpm" |grep -E ^1C_ |sed -E 's,^,Requires: ,g' >"$name.deps"
	[ -s "$name.deps" ] || rm -f "$name.deps"
done
rpmrepair --nodeps --scripts

Перепаковка займёт порядка 4.5 минут. В подкаталоге repacked окажется семь RPM-файлов на 360Мб. Теперь установим перепакованные пакеты:

$ su-
# rpm -ivh /home/user/repacked/*.rpm

Обратите внимание на особенности удаления -- common удаляется в последнюю очередь:

# rpm -e $(rpm -qa |grep -E ^1C_ |grep -v 1C_Enterprise83-common-8.3.17-1549)
Stopping 1C:Enterprise 8.3 server: Warning: server not running!
OK
# rpm -e 1C_Enterprise83-common-8.3.17-1549
# l /opt/1C/
ls: невозможно получить доступ к /opt/1C/: Нет такого файла или каталога

То есть, дезинсталляция выполняется "без хвостов".

Получение полуфабриката[править]

Ключ --noclean предписывает не удалять промежуточные результаты работы. Таким образом над распакованным каталогом и созданным спеком можно провести дополнительную работу, не предусмотренную данной программой (например, удалить лишние файлы, пропатчить эльфы, итд...), после чего упаковать каталог в тарбол и запустить rpm -bb вручную.

Отладка и отправка сообщений об ошибках[править]

Для отправки в Bugzilla сообщения об ошибке следует запустить на одиночном RPM-пакете, перепаковка которого выполняется с ошибками, команду:

$ /bin/bash -eux /usr/bin/rpmrepair --noclean [другие_опции] <package.rpm> 2>&1 |tee ИМЯ-ПАКЕТА.log

Получившийся отчёт вместе с соответствующими файлами *.deps, *.dirs, *.scripts из текущего каталога и всеми файлами из временного каталога (кроме подкаталога make-tar) приложить к сообщению об ошибке.


Enjoy! -;)