пятница, 7 сентября 2018 г.

Модифицикация стороннего rpm-пакета

Шпаргалка


  1. Исходная версия модифицируемого пакета установлена.
  2. Кладём файлы (если требуется добавить файлы) в необходимые места на своей системе.
  3. Вызываем rpmrebuild -e <package-name> 
  4. В vi-редакторе модифицируем spec-файл и сохрняем (:wq)
  5. Забираем пересобранный пакет из ~/rpmbuild/RPMS/<arch>/<package>

История


Потребовалось собрать Qt5 SQL драйвер для Oracle Database в виде отдельного пакета для Oracle Linux 7. По аналогии с имеющимися в public репозитории аналогичными пакетами аналогичных драйверов для других баз данных. Для сборки были скачаны rpm-ки oracle-instantclient18.3 c оффициального сайта и требуемый драйвер был собран. Все эти рпм-ки были помещены в локальный репозиторий. Но при запуске

sudo yum  install qt5-qtbase-oci

yum ругался следующим образом:


[grin@grinol7 ~]$ sudo yum install qt5-qtbase-oci
Loaded plugins: langpacks, ulninfo
Resolving Dependencies
--> Running transaction check
---> Package qt5-qtbase-oci.x86_64 0:5.9.2-3el7 will be installed
--> Processing Dependency: libclntsh.so.18.1()(64bit) for package: qt5-qtbase-oci-5.9.2-3el7.x86_64
--> Finished Dependency Resolution
Error: Package: qt5-qtbase-oci-5.9.2-3el7.x86_64 (topaz)
           Requires: libclntsh.so.18.1()(64bit)
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest


Проверка показала, что требуемая библиотека находится (как сам файл так и Provides запись к нему) в пакете oracle-instantclient18.3-basic.

[grin@grinol7 tmp]$ rpm -ql oracle-instantclient18.3-basic
/usr/lib/oracle/18.3/client64/bin/adrci
/usr/lib/oracle/18.3/client64/bin/genezi
/usr/lib/oracle/18.3/client64/lib/libclntsh.so.18.1
/usr/lib/oracle/18.3/client64/lib/libclntshcore.so.18.1
/usr/lib/oracle/18.3/client64/lib/libipc1.so
/usr/lib/oracle/18.3/client64/lib/libmql1.so
/usr/lib/oracle/18.3/client64/lib/libnnz18.so
/usr/lib/oracle/18.3/client64/lib/libocci.so.18.1
/usr/lib/oracle/18.3/client64/lib/libociei.so
/usr/lib/oracle/18.3/client64/lib/libocijdbc18.so
/usr/lib/oracle/18.3/client64/lib/libons.so
/usr/lib/oracle/18.3/client64/lib/liboramysql18.so
/usr/lib/oracle/18.3/client64/lib/network/admin/README
/usr/lib/oracle/18.3/client64/lib/ojdbc8.jar
/usr/lib/oracle/18.3/client64/lib/xstreams.jar
/usr/share/oracle/18.3/client64/doc/BASIC_README
[grin@grinol7 tmp]$ rpm -q --provides oracle-instantclient18.3-basic

libclntsh.so.18.1
oracle-instantclient18.3-basic = 18.3.0.0.0-1
oracle-instantclient18.3-basic(x86-64) = 18.3.0.0.0-1


Но если вчитаться в лог об ошибке, то qt5-qtbase-oci требует не просто libclntsh.so.18.1, а libclntsh.so.18.1()(64bit). Также видно, что oracle-instantclient18.3 в качестве "provides" дважды указывает сам себя, причём второй раз дополнительно в скобках пишет архитектуру.

oracle-instantclient18.3-basic = 18.3.0.0.0-1
oracle-instantclient18.3-basic(x86-64) = 18.3.0.0.0-1


Следовательно нужно пересобрать oracle-instantclient18.3-basic, с добавленной в spec-file "Provides" записью для libclntsh.so.18.1()(64bit).

Помимо этого можно добавить файл конфигурации для ld (например в моём случае /etc/ld.so.conf.d/oracle-instantclient18.3.conf).

Редактировать (пересобирать новую rpm) будем через утилиту rpmrebuild.
Предварительно создадим файл в своей файловой системе /etc/ld.so.conf.d/oracle-instantclient18.3.conf, в который запишем путь к библиотекам oracle

/usr/lib/oracle/18.3/client64/lib

Напоминаю,  что в моём случае oracle-instantclient18.3-basic уже был установлен. Далее выполняем команду

rpmrebuild -e oracle-instantclient18.3-basic

После этого в терминале откроется vi редактор spec-файла для нового пакета.

В моём случае необходимо было добавить строку 

Provides:      libclntsh.so.18.1()(64bit)
 

и строку

%attr(0644, root, root) "/etc/ld.so.conf.d/oracle-instantclient-18.3.conf"

в соответствующие им места spec-файла.
После этого закрываем редактор с сохранением изменений (:wq).
Возвращаемся в терминал, где на запрос rmprebuild

Do you want to continue ? (y/N) 

отвечаем утвердительно.

В моём случае новый пакет  был собран в течении секунд 20-ти (т.е. не сразу - у кого-то быстрее, у кого-то дольше). Если ошибок не пишет - то значит всё ок, просто работает. В конце rpmbuild уведомляет что пакет создан и указывает где:

result: /home/grin/rpmbuild/RPMS/x86_64/oracle-instantclient18.3-basic-18.3.0.0.0-1.x86_64.rpm
Дальше я положил пакет  в свой локальный репозиторий (выполнил createrepo на сервере где расположен репозитори) и переустановил его

sudo yum clean expire-cache
sudo yum reinstall oracle-instantclient18.3-basic

После этого qt5-qtbase-oci успешно установился.

вторник, 30 января 2018 г.

Памятка: замена одного RPM пакета, другим в одной операции

Суть:
    Требуется использовать (в Red Hat based линуксах) команду yum shell
  • yum shell
  • remove <old_package>
  • install <new_package>
  • run
  • ....
  • exit

 Предистория
     Требовалось установить свою реализацию NTP-сервера/клиента вместо стандартного для Oracle Linux пакета ntp. В своём пакете (tssd) прописано, что он предоставляет функционал ntp (Provides: ntp внутри spec-файла). Помимо этого указано, что он конфликтует с ntp (что бы они сразу хором время не подводили). Итого: если попытаться установить сначала tssd - то получим конфликт, что сначала надо удалить ntp. Если сначала удалить ntp - то  зависимые от него системные пакеты тоже удалятся, а они могут быть важны и удалять их не стоит.

Пример выполнения
   Ниже приведён лог замены ntp на tssd.

[root@grinVMOL6x86 ~]# yum shell
Loaded plugins: security
Setting up Yum Shell
> remove ntp
Setting up Remove Process
> install tssd
Setting up Install Process
> run
--> Running transaction check
---> Package ntp.i686 0:4.2.6p5-12.0.1.el6_9.2 will be erased
---> Package tssd.i686 0:1.4-75 will be installed
--> Finished Dependency Resolution

================================================================
 Package Arch  Version                 Repository          Size
================================================================
Installing:
 tssd    i686  1.4-75                  topaz               118 k
Removing:
 ntp     i686  4.2.6p5-12.0.1.el6_9.2  @public_ol6_latest  1.6 M

Transaction Summary
================================================================
Install       1 Package(s)
Remove        1 Package(s)

Total download size: 118 k
Is this ok [y/N]: y
Downloading Packages:
tssd-1.4-75.i686.rpm                                                                                                                                                                                            | 118 kB     00:00     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : tssd-1.4-75.i686                              1/2 
tssd start/running, process 7303
  Erasing    : ntp-4.2.6p5-12.0.1.el6_9.2.i686               2/2 
  Verifying  : tssd-1.4-75.i686                              1/2 
  Verifying  : ntp-4.2.6p5-12.0.1.el6_9.2.i686               2/2 

Removed:
  ntp.i686 0:4.2.6p5-12.0.1.el6_9.2                                                                                                                                                                                                    

Installed:
  tssd.i686 0:1.4-75                                                                                                                                                                                                                   

Finished Transaction
> exit
Leaving Shell
[root@grinVMOL6x86 ~]#

среда, 17 января 2018 г.

Памятка: конвертация исходников CP-1251 в UTF-8 (Linux)

В долгоживущем проекте, который уже перенесли на линукс малая часть исходников была в кодировке CP-1251 (Windows 1251). А основная часть в кодировке UTF-8. Требовалось без затей перекодировать в UTF-8 указанную малую часть.

Выполнили следующим скриптом:

for incorrect_file in $(for file in $(find $(pwd) -type f | grep -E "*\.h$|*\.c$|*\.hpp$|*\.cpp$"); do file -i ${file}; done | grep charset=iso-8859-1 | awk 'BEGIN{FS=":"}{print $1}'); do echo ${incorrect_file}; iconv -f cp1251 -t utf-8 ${incorrect_file} -o ${incorrect_file}; done

Более читаемая форма:

files=$(find $(pwd) -type f | grep -E "*\.h$|*\.c$|*\.hpp$|*\.cpp$"); \
incorrect_files=$( for_ file in ${files}; do \
                                  file -i ${_file}; \
                              done | \
                              grep charset=iso-8859-1 | \
                              awk 'BEGIN{FS=":"}{print $1}'); \
for incorrect_file in ${incorrect_files} do \
    echo ${incorrect_file}; \
    iconv -f cp1251 -t utf-8 ${incorrect_file} -o ${incorrect_file}; \
done

Разбор:
  • find $(pwd) -type f - ищет рекурсивно все файлы вглубь относительно текущей директории
  • grep -E "\.h$|\.c$|\.hpp$|.\cpp$" - фильтр - выводит в stdout только файлы с раширениями: .h .c .hpp .cpp
  • file -i ${file} - выдаёт информацию о файле, включая его кодировку
  • grep charset=iso-8859-1 - фильтр - выводит в stdout только информацию по файлам, имеющим указанную кодировку. Суть в том, что для файла с фактической кодировкой CP1251 команда file  -i выводит информацию, что кодировка iso-8859-1.
  • awk 'BEGIN {FS=":"}{print $1}' из отфильтрованной строки команды file -i выводит только имя файла.
  • iconv -f cp1251 -t utf-8 ${incorrect_file} -o ${incorrect_file} - собственно перекодирует файл из кодировки CP1251 в UTF-8.

вторник, 26 декабря 2017 г.

Памятка: Скачивание rpm-пакета со всеми зависимостями

Периодически заказчику на объект, на котором не доступа к интернету (соотвественно и к паблик репозиториям), требуется поставить ПО (в виде RPM-пакета) вместе со всеми пакетами, от которых он зависит.

В Oracle Linux (6/7) это можно сделать через yum.

1. Создаём папку, куда будем скачивать пакеты:
     mkdir ~/tmp/rpms
2. Переходим в эту папку:
      cd ~/tmp/rpms
3. Скачиваем (через sudo или из-под рута):
    sudo yum install \
    --installroot=$(pwd) \
    --downloadonly \
    --downloaddir=$(pwd) <packet-name>
4. Удаляем папку var (может увеличить размер результата то гигабайта, вместо требуемых 122 МБ - был прицендент):
    rm -rf $(pwd)/var

Пример для скачивания  пакета net-snmp-utils

[grin@grintop]$ mkdir ~/tmp/rpms
[grin@grintop]$ cd ~/tmp/rpms
[grin@grintop]$ sudo yum install --installroot=$(pwd) --downloadonly --downloaddir=$(pwd) net-snmp-utils
[grin@grintop]$ rm -rf var

четверг, 14 декабря 2017 г.

Памятка: удаление подмодулей в Git

Взято отсюда: https://gist.github.com/kyleturner/1563153

1. В файле .gitmodules удаляем строки, относящиеся к удаляемому подмодулю
2. В файле .git/config удаляем строки, относящиеся к удаляемому подмодулю
3. Выполняем команду: git rm --cached <path_to_submodule>
4. Удаляем папку, куда примонтирован подмодуль.
5. Коммитим изменения.

вторник, 20 декабря 2016 г.

Шпаргалка по rpmbuild

Пересборка src.rpm:

    rpmbuild --rebuild xxx.src.rpm

Распковка src.rpm:

    rpm2cpio xxx.src.rpm | cpio --extract --make-directories --verbose

Частичная сборка:

    rpmbuild --short-circuit -b<id> --target $(uname -m) ~/rpmbuild/SPECS/xxx.spec

Где id - идентификатор секции в spec-файле:
%prep - p ( -bp )
%build - c ( -bc )
%install - i ( -bi )
%files - l ( -bl )

Полная сборка:

Выполняется после того, как последовательно прошлись по всем шагам:
    rpmbuild -ba --target $(uname -m) --clean ~/rpmbuild/SPECS/xxx.spec

Генерация gpg-ключа для подписывания пакетов:

gpg --gen-key

Добавление подписи к пакету: 

rpm --add-sign xxx.rpm

Автоматическое добавление подписи к пакету:

Сначала необходимо посмотреть список сгенерённых ключей:
$ gpg --fingerprint
/home/grin/.gnupg/pubring.gpg
-----------------------------
pub   2048R/8EF3B046 2015-01-26
      Key fingerprint = EBBC 7265 2A5E B117 E397  E63E FE30 9913 8EF3 B046
uid                  Rinat Gadelshin <rgadelsh@gmail.com>
sub   2048R/97A7AD93 2015-01-26

pub   2048R/52D7329A 2015-01-26
      Key fingerprint = 565C 5622 BD66 F17B DDB0  0378 CBF8 F0C1 52D7 329A
uid                  Rinat Gadelshin (grin) <rgadelsh@gmail.com>
sub   2048R/A394DD73 2015-01-26

Далее в файл ~/.rpmmacros необходимо добавить следующие строки:
%_signature gpg
%_gpg_name Rinat Gadelshin (grin) <rgadelsh@gmail.com>
 

По сути, мы прописываем строку uid, относящуюся к выбранному ключу (52D7329A из вывода команды gpg --fingerprint). Видно что для нашего ключа строка содержит комментарий (grin), а для другого ключа ( 8EF3B046 ) комментарий не содержится.


четверг, 10 ноября 2016 г.

Поиск библиотеки, содержащей определение функции

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

function="dbus_watch_set_data"; \
for library in $(ls /usr/lib/*.so); do \
    res=$(readelf -s ${library} 2> /dev/null | grep ${function} | grep -v 00000000); \
    if [ ! -z "$res" ]; then \
        echo "${library}: $res"; \
        break; \
    fi; \
done; \
if [ -z "$res" ]; then \
    echo "function '${function}' not found"; \
fi

Соответственно вместо dbus_watch_set_data нужно подставлять имя искомой функции.
Также можно вместо /usr/lib/ вставлять другие директории, например /usr/local/lib.

Пример удачного поика:
[grin@grinvbox-ol65-x86 ~]$ function="dbus_watch_set_data"; for library in $(ls /usr/lib/*.so); do res=$(readelf -s ${library} 2> /dev/null | grep ${function} | grep -v 00000000); if [ ! -z "$res" ]; then echo "${library}: $res"; break; fi; done; if [ -z "$res" ]; then echo "function '${function}' not found"; fi
/usr/lib/libdbus-1.so:    473: 0002bdd0   111 FUNC    GLOBAL DEFAULT   12 dbus_watch_set_data@@LIBDBUS_1_3
  1410: 0002bdd0   111 FUNC    GLOBAL DEFAULT   12 dbus_watch_set_data

Функция dbus_watch_set_data найдена (2 раза) в библиотеке /usr/lib/libdbus-1.so


Пример неудачного поиска:
[grin@grinvbox-ol65-x86 ~]$ function="dbusx_watch_set_data"; for library in $(ls /usr/lib/*.so); do res=$(readelf -s ${library} 2> /dev/null | grep ${function} | grep -v 00000000); if [ ! -z "$res" ]; then echo "${library}: $res"; break; fi; done; if [ -z "$res" ]; then echo "function '${function}' not found"; fi
function 'dbusx_watch_set_data' not found

Функция dbusx_watch_set_data не найдена (нет такой функции).


P.S. для более детального понимания, рекомендую man readelf.