Product SiteDocumentation Site

Глава 2. Пакетная разработка на Альт с помощью Hasher

2.1. Hasher by ALT Linux Team
2.1.1. Настройка hasher
2.1.2. Первый запуск
2.1.3. Создание нулевого пакета
2.1.4. Создание примитивного пакета
Итогом в рамках разработки под Linux является пакет. Пакетом называются ресурсы, необходимые для установки и интеграции в систему некоторого компонента (архив файлов, до- и послеустановочные сценарии, информация о пакете и его сопровождающем), объединённые в одном файле. Основной материал курса направлен на изучение парадигм и технологий локальной разработки. Лабораторные работы будут объединять полученные знания в рамках сборки пакетов программ. В линейке дистрибутивов Альт используется формат пакетов RPM. Различают .rpm-пакеты, непосредственно предназначенные для установки компонентов в систему, и .src.rpm-пакеты, содержащие все необходимые для сборки .rpm-пакета данные — исходные тексты и сценарии сборки.

2.1. Hasher by ALT Linux Team

В рамках разработки на Альт Платформе используется специальный инструмент Hasher. Это средство безопасной и воспроизводимой сборки пакетов в «чистой» и контролируемой среде. Hasher создает изолированное пространство (файловая система, процессы, отсутствие доступа к сети по умолчанию и т. п.), устанавливает туда базовую систему и все сборочные зависимости, после чего запускает сборку пакета. Главная особенность hasher — возможность запуска в нем непроверенного и потенциально небезопасного кода без какого-либо воздействия на внешнюю систему. В сборочном окружении hasher нет суперпользователя (его заменяет системный пользователь с обычными правами и библиотека fakeroot), все процессы запускаются либо с его правами, либо с правами второго системного пользователя, и ни один из этих процессов не имеет доступа к ресурсам внешней системы. Однако для сборки пакетов предоставляется некоторая информация извне (например, объём памяти и количество ядер процессора) и некоторые свойства ОС (например, работа с псевдотерминалами, поддержка сети и т. п.). Скорость работы приложений в hasher не снижается, но каждый раз среда разворачивается заново, чтобы исключить влияние предыдущей сборки на последующую.
Некоторые следствия данной парадигмы работы hasher:
  • все необходимые для сборки зависимости должны быть установлены заранее, либо взяты из .src.rpm-пакета;
  • сборка не зависит от конфигурации компьютера пользователя, собирающего пакет (установленное, система и их версии), и может быть повторена на другом компьютере;
  • изолированность среды сборки позволяет с легкостью собирать на одном компьютере пакеты для разных дистрибутивов и веток репозитория — для этого достаточно лишь направить hasher на различные репозитории для каждого сборочного окружения.

2.1.1. Настройка hasher

Ещё одной особенностью hasher является независимость от прав суперпользователя. Все действия внутри системы выполняются в изолированном блоке файловой системы, а действия, требующие прав суперпользователя, журналируются и выполняются фиктивно в изолированном блоке.
Для работы hasher необходимо зарегистрировать пользователя, который будет выполнять сборки, чтобы на его основе создать специальных внутренних пользователей для работы.
Регистрация выполняется суперпользователем с помощью команды hasher-useradd:
[root@VM ~]# id user
uid=1000(user) gid=1000(user) группы=1000(user),10(wheel),100(users),36(vmusers)

[root@VM ~]# hasher-useradd user
useradd: Warning: missing or non-executable shell '/dev/null'
useradd: Warning: missing or non-executable shell '/dev/null'
Добавление пользователя user в группу user_a
Добавление пользователя user в группу user_b
Добавление пользователя user в группу hashman
hasher-useradd: enabling hasher-privd
Внимание: Отправляется запрос 'systemctl enable hasher-privd.service'.
Synchronizing state of hasher-privd.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable hasher-privd hasher-useradd: starting hasher-privd

[root@VM ~]# id user
uid=1000(user) gid=1000(user) группы=1000(user),10(wheel),100(users),997(hashman),1001(user_a),1002(user_b),36(vmusers)
[root@VM ~]#
При регистрации создаются два дополнительных пользователя. B-пользователь отвечает за непосредственно сборку пакета, A-пользователь выполняет роль суперпользователя в рамках системы сборки (при помощи fakeroot).

2.1.2. Первый запуск

Все действия, связанные с работой hasher, контролируются множеством утилит семейства hsh.
Перед каждой сборкой нового пакета необходимо пересоздавать окружение, сделать это можно с помощью ключа --init. Также окружение автоматически пересоздаётся при открытии архива исходников пакета (.src.rpm-файлы). При первом создании окружения необходимо отдельно создать директорию для расположения изолированного блока файловой системы. По умолчанию инструмент ожидает директорию ~/hasher/, однако она может быть любой из разрешённых в файле /etc/hasher-priv/system (ключ prefix=), в таком случае необходимо одним из параметров передавать путь к расположению директории:
[user@VM ~]$ hsh --init
/usr/bin/hsh-sh-functions: строка 281: cd: /home/user/hasher: Нет такого файла или каталога
[user@VM ~]$ mkdir hasher
[user@VM ~]$ hsh -v --init │& tee log
Рассмотрим вывод при создании окружения и обсудим некоторые составные части hasher:
hsh: Executing wrapper: systemd-run  --user --scope --same-dir --property=Delegate=yes --send-sighup --collect
Running as unit: run-p8052-i8352.scope; invocation ID: 4eed2a0919cc4c27bb1bc0b063dc7735
hsh: changed working directory to `/home/papillon_jaune/hasher'
hsh: Locked working directory `/home/papillon_jaune/hasher'

<...>

Чтение списков пакетов...
Построение дерева зависимостей...
Selected version fakeroot#1.29-alt3:p11+348779.600.1.1@1716502783 for fakeroot>=0:0.7.3
Следующие дополнительные пакеты будут установлены:
 bash       getopt            libelf        libpopt             sh
 bash5      glibc-core        libgcc1       libreadline8        sh5
 bashrc     glibc-preinstall  libgcrypt20   librpm7             terminfo
 bzlib      grep              libgmp10      libselinux          zlib
 coreutils  libacl            libgpg-error  libsha1detectcoll1
 fakeroot   libattr           liblua5.3     libtinfo6
 findutils  libcap            liblzma       libzstd
 gawk       libdb4.7          libpcre2      sed
Следующие НОВЫЕ пакеты будут установлены:
 bash        gawk              libdb4.7      libpcre2            rpm
 bash5       getopt            libelf        libpopt             sed
 bashrc      glibc-core        libgcc1       libreadline8        setup
 bzlib       glibc-preinstall  libgcrypt20   librpm7             sh
 coreutils   grep              libgmp10      libselinux          sh5
 fakeroot    libacl            libgpg-error  libsha1detectcoll1  terminfo
 filesystem  libattr           liblua5.3     libtinfo6           zlib
 findutils   libcap            liblzma       libzstd
<...>
Завершено.

hsh-initroot: Calculated package file list.
hsh-initroot: Generated initial package file list.
Чтение списков пакетов...
Построение дерева зависимостей...
<...>
Следующие дополнительные пакеты будут установлены:
 alt-os-release                      libmount
 autoconf                            libmpc3
 autoconf-common                     libmpfr6
 autoconf_2.71                       libncursesw6
 automake                            libpam0
 automake-common                     libpasswdqc
 automake_1.16                       libpcre2
 bash                                libpopt
 bash5                               libproc2_1
 bashrc                              libreadline8
 binutils                            librpm
 bison                               librpm7
 bison-runtime                       librpmbuild
 branding-xalt-kworkstation-release  librpmbuild7
 bzip2                               libseccomp
 bzlib                               libselinux
 chkconfig                           libsframe1
 common-licenses                     libsha1detectcoll1
 control                             libshell
 coreutils                           libsmartcols
 cpio                                libstdc++6
 cpp                                 libtcb
 cpp13                               libtic6
 debugedit                           libtinfo6
 diffutils                           libtool
 elfutils                            libtool-common
 emacs-base                          libtool_2.4
 etcskel                             libtsan2
 file                                libubsan1
 filesystem                          libudev1
 findutils                           libunistring2
 gawk                                libuuid
 gcc                                 libvtv0
 gcc-common                          libxml2
 gcc13                               libzio
 getopt                              libzstd
 gettext                             m4
 gettext-tools                       make
 glib2                               nss_tcb
 glib2-locales                       pam
 glibc                               pam-config
 glibc-core                          pam-config-control
 glibc-devel                         pam0_mktemp
 glibc-gconv-modules                 pam0_passwdqc
 glibc-kernheaders                   pam0_tcb
 glibc-kernheaders-generic           pam0_userpass
 glibc-kernheaders-x86               passwdqc-control
 glibc-locales                       patch
 glibc-nss                           perl-CPAN-Meta-Requirements
 glibc-preinstall                    perl-base
 glibc-pthread                       perl-parent
 glibc-timezones                     perl-threads
 glibc-utils                         pkg-config
 gnu-config                          procps
 grep                                psmisc
 gzip                                rootfiles
 iconv                               rpm
 info-install                        rpm-build
 kernel-headers-common               rpm-build-file
 libacl                              rpm-build-perl
 libasan8                            rpm-macros-python
 libasm                              rpm-macros-python3
 libatomic1                          rpm-macros-systemd
 libattr                             rpmspec
 libaudit1                           sed
 libbeecrypt7                        service
 libblkid                            setarch
 libcap                              setup
 libcap-ng                           sh
 libcap-utils                        sh5
 libcrypt                            shadow-convert
 libcrypt-devel                      shadow-utils
 libctf-nobfd0                       sisyphus_check
 libdb4.7                            sysvinit-utils
 libdw                               tar
 libelf                              tcb-utils
 libffi8                             terminfo
 libgcc1                             termutils
 libgcrypt20                         tzdata
 libgmp10                            util-linux
 libgpg-error                        util-linux-control
 libgpm                              vim-minimal
 libhwasan0                          vitmp
 libitm1                             which
 liblsan0                            xml-common
 liblua5.3                           xz
 liblzma                             zlib
 libmagic                            zstd

 Следующие НОВЫЕ пакеты будут установлены:
  alt-os-release                      libmount
  autoconf                            libmpc3
  autoconf-common                     libmpfr6
  autoconf_2.71                       libncursesw6
  automake                            libpam0
  automake-common                     libpasswdqc
  automake_1.16                       libpcre2
  basesystem                          libpopt
  bash                                libproc2_1
  bash5                               libreadline8
  bashrc                              librpm
  binutils                            librpm7
  bison                               librpmbuild
  bison-runtime                       librpmbuild7
  branding-xalt-kworkstation-release  libseccomp
  bzip2                               libselinux
  bzlib                               libsframe1
  chkconfig                           libsha1detectcoll1
  common-licenses                     libshell
  control                             libsmartcols
  coreutils                           libstdc++6
  cpio                                libtcb
  cpp                                 libtic6
  cpp13                               libtinfo6
  debugedit                           libtool
  diffutils                           libtool-common
  elfutils                            libtool_2.4
  emacs-base                          libtsan2
  etcskel                             libubsan1
  file                                libudev1
  filesystem                          libunistring2
  findutils                           libuuid
  gawk                                libvtv0
  gcc                                 libxml2
  gcc-common                          libzio
  gcc13                               libzstd
  getopt                              m4
  gettext                             make
  gettext-tools                       nss_tcb
  glib2                               pam
  glib2-locales                       pam-config
  glibc                               pam-config-control
  glibc-core                          pam0_mktemp
  glibc-devel                         pam0_passwdqc
  glibc-gconv-modules                 pam0_tcb
  glibc-kernheaders                   pam0_userpass
  glibc-kernheaders-generic           passwdqc-control
  glibc-kernheaders-x86               patch
  glibc-locales                       perl-CPAN-Meta-Requirements
  glibc-nss                           perl-base
  glibc-preinstall                    perl-parent
  glibc-pthread                       perl-threads
  glibc-timezones                     pkg-config
  glibc-utils                         procps
  gnu-config                          psmisc
  grep                                rootfiles
  gzip                                rpm
  iconv                               rpm-build
  info-install                        rpm-build-file
  kernel-headers-common               rpm-build-perl
  libacl                              rpm-macros-python
  libasan8                            rpm-macros-python3
  libasm                              rpm-macros-systemd
  libatomic1                          rpmspec
  libattr                             sed
  libaudit1                           service
  libbeecrypt7                        setarch
  libblkid                            setup
  libcap                              sh
  libcap-ng                           sh5
  libcap-utils                        shadow-convert
  libcrypt                            shadow-utils
  libcrypt-devel                      sisyphus_check
  libctf-nobfd0                       sysvinit-utils
  libdb4.7                            tar
  libdw                               tcb-utils
  libelf                              terminfo
  libffi8                             termutils
  libgcc1                             time
  libgcrypt20                         tzdata
  libgmp10                            util-linux
  libgpg-error                        util-linux-control
  libgpm                              vim-minimal
  libhwasan0                          vitmp
  libitm1                             which
  liblsan0                            xml-common
  liblua5.3                           xz
  liblzma                             zlib
  libmagic                            zstd
0 будет обновлено, 178 новых установлено, 0 пакетов будет удалено и 0 не будет обновлено.
Необходимо получить 73,3MB/86,2MB архивов.
После распаковки потребуется дополнительно 514MB дискового пространства.
<...>
Завершено.

Running /usr/lib/rpm/posttrans-filetriggers hsh-initroot: RPM database updated.
<86>Jul  1 09:29:43 groupadd[10102]: group added to /etc/group: name=caller, GID=1000^M
<86>Jul  1 09:29:43 groupadd[10102]: group added to /etc/gshadow: name=caller^M
<86>Jul  1 09:29:43 groupadd[10102]: new group: name=caller, GID=1000^M
<86>Jul  1 09:29:43 useradd[10108]: new user: name=caller, UID=1000, GID=1000, home=/, shell=/bin/bash, from=none^M
<86>Jul  1 09:29:43 groupadd[10117]: group added to /etc/group: name=rooter, GID=1001^M
<86>Jul  1 09:29:43 groupadd[10117]: group added to /etc/gshadow: name=rooter^M
<86>Jul  1 09:29:43 groupadd[10117]: new group: name=rooter, GID=1001^M
<86>Jul  1 09:29:43 useradd[10123]: new user: name=rooter, UID=1001, GID=1001, home=/root, shell=/bin/bash, from=none^M
<86>Jul  1 09:29:43 groupadd[10132]: group added to /etc/group: name=builder, GID=1002^M
<86>Jul  1 09:29:43 groupadd[10132]: group added to /etc/gshadow: name=builder^M
<86>Jul  1 09:29:43 groupadd[10132]: new group: name=builder, GID=1002^M
<86>Jul  1 09:29:43 useradd[10138]: new user: name=builder, UID=1002, GID=1002, home=/usr/src, shell=/bin/bash, from=none^M
mode of '/usr/src' changed from 0755 (rwxr-xr-x) to 1777 (rwxrwxrwt)
hsh-initroot: First time initialization complete.
hsh-initroot: RPM database archivation complete.
hsh-initroot: Chroot archivation complete.

mkdir: created directory '/usr/src/tmp'
mkdir: created directory '/usr/src/RPM'
mkdir: created directory '/usr/src/RPM/BUILD'
mkdir: created directory '/usr/src/RPM/SOURCES'
mkdir: created directory '/usr/src/RPM/SPECS'
mkdir: created directory '/usr/src/RPM/SRPMS'
mkdir: created directory '/usr/src/RPM/RPMS'
mkdir: created directory '/usr/src/RPM/RPMS/noarch'
hsh-initroot: Created RPM build directory tree.
В состав hasher по умолчанию идёт набор утилит, связанных с работой самого инструмента (в частности, fakeroot, за счёт которого реализован псевдосуперпользователь). Также по умолчанию hasher устанавливает классический набор утилит для разработки, в том числе использующихся в рамках данного курса (autoconf, automake, gcc, diffutils и т. д.).
Внутри hasher основной пользователь и два дополнительных обретают описанные выше характеристики: основной пользователь (внутри он называется caller) имеет право лишь просматривать данные и получать доступ к готовым пакетам, A-пользователь (@rooter) выполняет действия суперпользователя в рамках инструмента, B-пользователь (@builder) осуществляет сборку пакетов.
Hasher предоставляет минимальное необходимое для сборки окружение. Вследствие этого все инструменты по разработке или отладке, требуемые в рамках работы с hasher, необходимо устанавливать после каждого пересоздания окружения. Всюду далее при рассмотрении отдельных сборок будут опускаться команды пересоздания окружения и установки постоянно необходимых для разработки утилит:
  • hsh --init для пересоздания окружения;
  • hsh-install для установки пакетов из репозиториев Альт.
Например:
[user@VM ~]$ hsh --init
<...>
[user@VM ~]$ hsh-install vim-console tree
<...>
[user@VM ~]$
Также будут опускаться команды входа в изолированное окружение от имени @builder и @rooter, все кодовые вставки будут сопровождаться отметками о том, от имени какого пользователя проведён вход:
  • hsh-shell для входа от имени @builder;
  • hsh-shell --rooter для входа от имени @rooter.

2.1.3. Создание нулевого пакета

Разберём структуру hasher согласно правилам разработки RPM-пакетов. RPM-пакет состоит из архива файлов, а также заголовка, содержащего метаданные о пакете. Различают пакеты с исходным кодом (.src.rpm), состоящих из исходников и spec-файла, представляющего из себя инструкцию по сборке пакета, и собственно пакеты (.rpm), непосредственно устанавливающиеся в систему.
Hasher для работы содержит специальное дерево директорий, по которому автоматически или вручную распределяются файлы для сборки:
@builder
[builder@localhost ~]$ tree RPM
RPM
├── BUILD
├── RPMS
│   └── noarch
├── SOURCES
├── SPECS
└── SRPMS

7 directories, 0 files
Директории RPMS/ и SRPMS/ содержат готовые пакеты, SOURCES/ содержит исходные файлы. Исходники чаще всего хранятся в виде архива (обычно .tar.gz). Директория SPECS/ хранит соответствующий .spec-файл. В директории BUILD/ проводится сборка пакета, перед началом сборки содержимое директории очищается, что позволяет повторно проводить независимую сборку для одного и того же пакета.
Напишем самый простой пакет, не содержащий ничего кроме spec-файла:
@builder: RPM/SPECS/null-pkg.spec
Name: null-pkg
Version: 1.0
Release: alt1

Summary: Null package

License: GPL-3.0-or-later
Group: Development/Other


%description
This is the smallest ever alt package without any functionality

%files

%changelog
* Tue Jul 01 2025 UsamG1t <usamg1t@altlinux.org> 1.0-alt1
- Initial build
@builder
[builder@localhost ~]$ tree RPM
RPM
├── BUILD
├── RPMS
│   └── noarch
├── SOURCES
├── SPECS
│   └── null-pkg.spec
└── SRPMS

7 directories, 1 file
[builder@localhost ~]$
Текст внутри spec-файла имеет специальный синтаксис. Синтаксические определения имеют значения, задающие порядок сборки, номер версии, информацию о зависимостях и вообще всю информацию о пакете, которая может быть необходима для сборки и идентификации пакета.
Spec состоит из преамбулы, содержащей метаданные пакета, и основной части, содержащей инструкции по сборке и установке пакета.
Минимально необходимые параметры spec-файла для сборки пакета:
  • преамбула:
    • имя пакета;
    • версия согласно правилам версионирования;
    • релиз пакета;
    • краткое описание пакета;
    • лицензия на собираемое ПО;
    • категория пакета (это поле морально устарело, но в ALT продолжает использоваться);
  • основная часть:
    • директива %files для описания устанавливаемых файлов у конечного пользователя (даже если этих файлов нет);
    • директива %changelog для записи изменений, произошедших в пакете между сборками разных версий или релизов.
Подробнее познакомиться с другими директивами можно по ссылке. В рамках лабораторных работ в дальнейшем будут рассмотрены и другие директивы (например, необязательная директива %description, содержащая более подробное описание функциональности пакета).
Сборка пакетов осуществляется с помощью команды rpmbuild. Ключ -ba (build all) собирает как двоичный пакет, так и новый пакет с исходным кодом:
@builder
[builder@localhost ~]$ rpmbuild -ba RPM/SPECS/null-pkg.spec
Processing files: null-pkg-1.0-alt1
Wrote: /usr/src/RPM/SRPMS/null-pkg-1.0-alt1.src.rpm (w2.lzdio)
Wrote: /usr/src/RPM/RPMS/x86_64/null-pkg-1.0-alt1.x86_64.rpm (w2.lzdio)

[builder@localhost ~]$ tree RPM
RPM
├── BUILD
├── RPMS
│   ├── noarch
│   └── x86_64
│       └── null-pkg-1.0-alt1.x86_64.rpm
├── SOURCES
├── SPECS
│   └── null-pkg.spec
└── SRPMS
   └── null-pkg-1.0-alt1.src.rpm

8 directories, 3 files
[builder@localhost ~]$
Попробуем установить полученный пакет в hasher, для этого необходимо от имени суперпользователя воспользоваться установщиком rpm с ключом -i:
@user
[user@VM ~]$ hsh-shell --rooter
@rooter
[root@localhost .in]# rpm -i /usr/src/RPM/RPMS/x86_64/null-pkg-1.0-alt1.x86_64.rpm
<13>Jul  1 16:46:01 rpm: null-pkg-1.0-alt1 1751388308 installed
                                                              [root@localhost .in]#
[root@localhost .in]# which null-pkg
which: no null-pkg in (/root/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/games)
[root@localhost .in]#
Пакет успешно установился, и, поскольку он пустой, он никак не отображается среди других программ (потому что никаких исполняемых программ в нем нет).

2.1.4. Создание примитивного пакета

Теперь соберём пакет, состоящий из одного shell-сценария, чтобы проверить реальную функциональность пакета. Напомним, что необходимо пересоздать окружение, а также добавить те инструменты разработки, которыми вы пользуетесь:
@builder
[builder@localhost ~]$ tree RPM
RPM
├── BUILD
├── RPMS
│   └── noarch
├── SOURCES
├── SPECS
└── SRPMS
@builder: RPM/SPECS/not-null-pkg.spec
Name: not-null-pkg
Version: 1.0
Release: alt1

Summary: Not Null package

License: GPL-3.0-or-later
Group: Development/Other

Source: %name-%version.sh

%description
This is not the smallest ever alt package cause of functionality

%install
install -D -pm 755 %SOURCE0 %buildroot%_bindir/%name

%files
%_bindir/*

%changelog
* Tue Jul 08 2025 UsamG1t <usamg1t@altlinux.org> 1.0-alt1
- Initial build
@builder: RPM/SOURCES/not-null-pkg-1.0.sh
echo "This is not null pkg"
Разберём новые директивы и команды.
Обычно при сборке RPM каталог с исходными текстами программы упакован в .tar.gz-архив, в названии которого встречается имя программы и её версия — их удобно сразу заменять на соответствующие макросы. Мы же для упрощения укажем исключительно один скрипт, сохранив правила именования.
В основной части spec-файла добавилась директива %install, которая описывает команды установки/копирования файлов из сборочного каталога в псевдокорневой каталог. Утилита install занимается размещением всех файлов, которые должны входить в пакет (исполняемых файлов, документации, библиотек; в нашем случае — исполняемого скрипта), по их конечным директориям. При этом используются предопределённые макросы, описывающие место установки данных. Все исходные файлы размещаются в каталоге RPM/SOURCES/. Явно к объекту, указанному в директиве Source (или Source0) можно обращаться через макрос %SOURCE0, Source1: —  %SOURCE1 и т. д.
Для сборки пакета не нужны (в ALT — запрещены) права суперпользователя. Во время сборки файлы устанавливаются в псевдокорневой каталог (как правило, /usr/src/tmp/_имя-пакета_-buildroot/; он обозначается макросом %buildroot). Сценарий попадает в поддиректорию /usr/bin.
В директиве %files указывается расположение итоговых данных. В нашем случае в итоговый пакет должен попасть исполняемый файл.
Запустим сборку пакета и соберём информацию о сборке:
@builder
builder@localhost ~]$ rpmbuild -ba RPM/SPECS/not-null-pkg.spec >& log
  • создание каталога сборки (в примере он остаётся пустым) и удаление старого псевдокорневого каталога:
    Executing(%install): /bin/sh -e /usr/src/tmp/rpm-tmp.81856
    + umask 022
    + /bin/mkdir -p /usr/src/RPM/BUILD
    + cd /usr/src/RPM/BUILD
    + /bin/chmod -Rf u+rwX -- /usr/src/tmp/not-null-pkg-buildroot
    + /bin/rm -rf -- /usr/src/tmp/not-null-pkg-buildroot
    
  • установка файлов пакета (в примере это единственный сценарий):
    + PATH=/usr/libexec/rpm-build:/usr/src/bin:/usr/bin:/bin:/usr/local/bin:/usr/games
    + install -D -pm 755 /usr/src/RPM/SOURCES/not-null-pkg-1.0.sh /usr/src/tmp/not-null-pkg-buildroot/usr/bin/not-null-pkg
    
  • проверка соответствия файлов пакета Build ALT Policy (дисциплине сборки пакетов ALT):
    + /usr/lib/rpm/brp-alt
    Cleaning files in /usr/src/tmp/not-null-pkg-buildroot (auto)
    Verifying and fixing files in /usr/src/tmp/not-null-pkg-buildroot (binconfig,pkgconfig,libtool,desktop,gnuconfig)
    Checking contents of files in /usr/src/tmp/not-null-pkg-buildroot/ (default)
    Compressing files in /usr/src/tmp/not-null-pkg-buildroot (auto)
    Verifying ELF objects in /usr/src/tmp/not-null-pkg-buildroot (arch=normal,fhs=normal,lfs=relaxed,lint=relaxed,rpath=normal,stack=normal,textrel=normal,unresolved=normal)
    Splitting links to aliased files under /{,s}bin in /usr/src/tmp/not-null-pkg-buildroot
    
  • определение эксплуатационных зависимостей пакета, а также предоставляемых им зависимостей и возможных отладочных компонентов:
    Processing files: not-null-pkg-1.0-alt1
    Finding Provides (using /usr/lib/rpm/find-provides)
    Executing: /bin/sh -e /usr/src/tmp/rpm-tmp.QrK1pE
    find-provides: running scripts (alternatives,debuginfo,lib,pam,perl,pkgconfig,python,python3,shell)
    Finding Requires (using /usr/lib/rpm/find-requires)
    Executing: /bin/sh -e /usr/src/tmp/rpm-tmp.aiR5Fd
    find-requires: running scripts (cpp,debuginfo,files,lib,pam,perl,pkgconfig,pkgconfiglib,python,python3,
    rpmlib,shebang,shell,static,symlinks,systemd-services)
    Finding debuginfo files (using /usr/lib/rpm/find-debuginfo-files)
    
  • сборка .prm и .src.rpm:
    Executing: /bin/sh -e /usr/src/tmp/rpm-tmp.CsoTgW
    
    Wrote: /usr/src/RPM/SRPMS/not-null-pkg-1.0-alt1.src.rpm (w2.lzdio)
    Wrote: /usr/src/RPM/RPMS/x86_64/not-null-pkg-1.0-alt1.x86_64.rpm (w2.lzdio)
    
Результат:
[builder@localhost ~]$ tree RPM/
RPM/
├── BUILD
├── RPMS
│   ├── noarch
│   └── x86_64
│       └── not-null-pkg-1.0-alt1.x86_64.rpm
├── SOURCES
│   └── not-null-pkg-1.0.sh
├── SPECS
│   └── not-null-pkg.spec
└── SRPMS
   └── not-null-pkg-1.0-alt1.src.rpm

8 directories, 5 files
[builder@localhost ~]$
После сборки пакета в /tmp некоторое время хранятся данные с последней сборки:
[builder@localhost ~]$ tree -A tmp
tmp
└── not-null-pkg-buildroot
   └── usr
       └── bin
           └── not-null-pkg

4 directories, 1 file
В данных двоичного пакета размещаются описание составляющих его файлов, а также зависимости пакета:
[builder@localhost ~]$ rpmquery --list --package RPM/RPMS/x86_64/not-null-pkg-1.0-alt1.x86_64.rpm
/usr/bin/not-null-pkg
[builder@localhost ~]$ rpmquery --requires --package RPM/RPMS/x86_64/not-null-pkg-1.0-alt1.x86_64.rpm
rpmlib(PayloadIsLzma)
[builder@localhost ~]$
При установке пакета в систему файлы раскладываются по соответствующим поддиректориям корневого каталога. Поскольку скрипт исполняемый и лежит в /usr/bin, а эта директория входит в стандартный $PATH, скрипт можно запустить просто по имени:
@user
[user@VM ~]$ hsh-shell --rooter
@rooter
[root@localhost .in]# rpm -i /usr/src/RPM/RPMS/x86_64/not-null-pkg-1.0-alt1.x86_64.rpm
<13>Jul  1 16:33:50 rpm: not-null-pkg-1.0-alt1 1751387597 installed
[root@localhost .in]# which not-null-pkg
/usr/bin/not-null-pkg
[root@localhost .in]# /usr/bin/not-null-pkg
This is not null pkg
[root@localhost .in]# not-null-pkg
This is not null pkg
[root@localhost .in]#