Пригодная для работы пользователя система состоит из множества (сотен и тысяч) программ и утилит. В Linux каждый компонент системы представлен в виде пакета. Все операции, связанные с изменением состава системы: установка, удаление, проверка, обновление компонентов, — производятся над пакетами. В целом, пакет — это средство сделать так, чтобы пользователь-администратор, изменяя или обновляя программное наполнение системы, работал не с файлами (имена которых ему подчас неизвестны), а с определёнными функциональностями самой системы: например, добавлял в неё не «500 файлов», а «WWW-сервер apache
».
Архив файлов
На первый взгляд, программа состоит из одного — исполняемого — файла: запускаем файл, получаем работающую программу. Однако во время работы даже самая простая программа использует другие файлы, содержащие различные ресурсы: библиотеки, конфигурационные файлы, файлы-дырки и даже запускает другие программы. Чтобы программа действительно заработала, необходимо помимо главного исполняемого файла обеспечить наличие в системе всех нужных файлов с ресурсами.
Понятно, что при установке или удалении программы нужно позаботиться и обо всех используемых ею файлах (которых может быть даже очень много). Это — первая задача пакетирования: все файлы, используемые программой, объединяются в один файл — архив. Это позволяет не копировать при установке программы все файлы по-отдельности, а потом не удалять их таким же способом, а работать со всеми данными программы как с одним целым — устанавливать и удалять один пакет.
- файловый архив
- Дерево каталогов, представленное в виде единого файла, состоящего из содержимого всех файлов в этом дереве и информации об имени и атрибутах каждого файла.
Нет жёсткого требования, чтобы один пакет содержал только одну программу. В пакет естественно объединять такие ресурсы, с которыми удобно работать как с одним целым. Это может быть отдельная программа или набор утилит (например, coreutils
, основные утилиты, унаследованные Linux от UNIX) или модуль с дополнительными возможностями программы, или общие для нескольких программ ресурсы. В процессе развития и/или устаревания программного обеспечения выделение некоторых задач в отдельный пакет может приобретать или терять смысл, поэтому способ объединения ресурсов в пакеты — это не что-то раз и навсегда выбранное: пакеты могут разделяться и сливаться.
Самый простой и традиционный для Linux способ объединить несколько файлов в один — использовать утилиту tar
.
tar
появился намного раньше Linux и изначально служил для создания файловых архивов на магнитной ленте. Отсюда и его название — tape archiver, «архиватор для (магнитных) лент». В настоящее время tar
присутствует в любой UNIX-подобной системе и позволяет работать с файловыми архивами на любых носителях.
Мефодий, написав несколько программ и сценариев, решил собрать их в одном файловом архиве, чтобы их удобнее было переносить на все системы, в которых ему случается работать. Для этого Мефодий создал архив со всем содержимым своего подкаталога bin/
.
methody@localhost:~ $ tar -cf methody.progs.tar bin/
methody@localhost:~ $ tar -tf methody.progs.tar
bin/
bin/loop
bin/script
bin/to.sort
bin/two
Пример 1. Создание файлового архива при помощи tar
Первый параметр tar
состоит из двух частей: операция, которую следует произвести над архивом, в данном случае «c
» (create, создать), и ключ «f
», который указывает, что архив следует создать в файле, имя файла архива — следующий параметр. Имя архива может быть любым, но Гуревич посоветовал снабдить его расширением «.tar
», чтобы потом не путаться. После имени архива следуют имена файлов и каталогов, которые следует запаковать.
С каждым указанным каталогом tar
работает рекурсивно, т. е. запаковывает все содержащиеся в нём файлы и подкаталоги.
Чтобы проверить, какие файлы попали в архив, Мефодий просмотрел содержимое получившегося архива командой «tar -tf имя_архива
» («t
» — просмотреть, «f
» использовать файл, указанный следующим параметром). Тут Мефодий обратил тут внимание на два обстоятельства. Во-первых, в архиве имена файлов сохранились вместе с путём. Во-вторых, все пути, сохранённые в архиве — относительные.
При распаковке архива tar
файлы извлекаются вместе с путём, недостающие подкаталоги создаются по мере необходимости. Все пути tar
считает относительными от своего рабочего каталога. Если теперь Мефодий распакует свой архив (командой «tar xf имя_архива
»), то в рабочем каталоге будет создан подкаталог «bin/
» и в него будут записаны все файлы из архива.
methody@localhost:~ $ tar -xvf methody.progs.tar
bin/
bin/loop
bin/script
bin/to.sort
bin/two
Пример 2. Распаковка архива
Ключ «v
» велит tar
быть «разговорчивым» (verbose), т. е. выводить больше диагностичских сообщений, блаодаря этому tar
при распаковке выводит имена (с путём) всех записываемых файлов. Если в рабочем каталоге уже есть файл, который tar
собирается создать при распаковке, то этот файл будет попросту заменён файлом из архива. Так, когда Мефодий распаковал свой архив, подкаталог «bin/
» со всем его содержимым заменился на подкаталог из архива. В данной ситуации это не страшно, поскольку в архиве файлы такие же, но вот если бы Мефодий перед распаковкой изменил какие-то из своих файлов в «bin/
», он лишился бы всех изменений.
Формат пакета
Помимо хранения архива файлов у пакета есть и другие задачи (они обсуждаются в двух следующих разделах), поэтому для пакета в Linux не очень подходит обычный файловый архив, наподобие .tar
, а нужен специальный формат. Таких форматов в Linux бывает несколько (краткое перечисление и характеристика — в разделе Package.Установщики пакетов), в системе Мефодия используется один из наиболее распространённых — rpm
, поэтому все примеры в данной лекции будут с его участием. Для работы с пакетами в специальном формате нужна специальная программа-установщик, которая так же и называется — rpm
: она занимается установкой, удалением, обновлением и проверкой пакетов.
Пакет в формате rpm
— это единый файл со всеми необходимыми данными. Существуют определённые (хотя и не очень жёсткие и последовательные) соглашения относительно названий файлов-пакетов. Например, rpm
-файл, содержащий комплект стандартных утилит coreutils
, в системе Мефодия называется coreutils-5.2.1-some5.rpm
: сначала — имя пакета, затем через дефис — служебная информация о номерах версий программного обеспчения и самого пакета.
Регистрация в системе
Итак, пакет с компонентом системы — это в первую очередь файловый архив, в котором хранятся все необходимые файлы вместе с путями к ним (т. е. каталогами). Когда компонентов много, нужно обеспечить, чтобы в разных пакетах не оказалось файлов с одинаковым именем и путём, чтобы файл, принадлежащий одному пакету, не мог быть заменён файлом другого пакета при установке. Отслеживать такого рода конфликты пакетов — вторая задача пакетирования.
Чтобы предупреждать конфликты, в системе должна храниться информация обо всех уже установленных пакетах и принадлежащих им файлах. Когда точно известно, какие файлы принадлежат пакету, можно полностью удалить пакет, не оставив и не удалив при этом ничего лишнего. Такой подход препятствует образованию в системе «мусора» — бесполезных файлов, оставшихся от удалённых программ — и делает операцию установки/удаления пакета полностью обратимой.
Rpm
хранит информацию обо всех установленных в системе пакетах и принадлежащих им файлах и может выдать эту информацию по запросу пользователя. Почитав руководство по rpm
, Мефодий выяснил, что список всех установленных в системе пакетов (скорее всего, очень длинный, в несколько тысяч строк) можно получить командой «rpm -qa
», список всех файлов, принадлежащих пакету, командой «rpm -ql имя_пакета
». Он решил проверить, есть ли в его системе уже известный ему по предыдущим лекциям пакет coreutils
и узнать, какие утилиты ему принадлежат:
methody@localhost:~ $ rpm -qa | grep coreutils
coreutils-5.2.1-some5
methody@localhost:~ $ rpm -ql coreutils | grep bin
/bin/basename
/bin/cat
/bin/chgrp
/bin/chmod
. . .
Пример 3. Какие файлы принадлежат пакету?
Мефодий получил довольно длинный список имён файлов, среди которых встретил многие из уже знакомых ему утилит и кое-какие незнакомые. Причём запрашивая список файлов, Мефодий использовал только имя пакета, без версии — rpm
позволяет обращаться так любому из установленных пакетов2. Можно выполнить и обратную процедуру — выяснить про любой файл, какому пакету он принадлежит:
methody@localhost:~ $ rpm -qf /etc/passwd
setup-2.2.5-some1
Пример 4. Какому пакету принадлежит файл?
Файлы, принадлежащие пакету, могут быть не только удалены, но и изменены. Это может быть сделано сознательно (например, отредактирован конфигурационный файл), в таком случае при обновлении или удалении пакета изменённый файл нужно сохранить, потому что в нём содержится результат работы, проделанной администратором. Для этого система должна уметь определять, что принадлежащий пакету файл изменился. Для этого в пакете должна храниться информация обо всех файлах архива: размер, атрибуты, контрольная сумма — в этом случае процедура проверки сможет проверить соответствие атрибутов файла в пакете атрибутам установленного в системе файла. Мефодий может проверить, что изменилось в пакете командой «rpm -V имя_пакета
».
methody@localhost:~ $ rpm -V setup
S.5....T c /etc/X11/fs/config
S.5....T c /etc/exports
S.5....T c /etc/fstab
S.5....T c /etc/printcap
..?..... c /etc/securetty
Пример 5. Что изменилось в пакете?
Мефодий получил список изменившихся с момента установки пакета файлов. Видимо, всё это — конфигурационные файлы, отредактированные администратором системы. Мефодий догадался, что комбинация цифр, букв и точек — это список атрибутов, по которым rpm
сравнивал установленные файлы с данными пакета, однако чтобы разобраться, что именно означает каждая буква, ему придётся внимательнее читать руководство. Система Linux раскладывается на компоненты без остатка: каждый файл в Linux принадлежит какому-нибудь (и только одному!) пакету.
Естественно, кроме тех файлов, которые созданы пользователями.
Это позволяет свести любые изменения в составе системы к операциям над пакетами — от начальной установки до сложных комплексных обновлений. В этом случае для всех изменений будет использоваться одна и та же программа-установщик, например, rpm
.
Изменение настроек системы
Для полноценной регистрации пакета в системе обычно недостаточно, чтобы система хранила список файлов, принадлежащих пакету. При установке, удалении или обновлении пакета часто требуется выполнить ряд операций, чтобы обновить сведения о пакете, адаптировать настройки — как самого пакета к уже имеющимися в системе, так и наоборот. К тому же, некоторые изменения в системе, например, добавление и удаление псевдопользователя, не сводятся к добавлению и удалению файлов, и вдобавок зависят от текущего состояния системы. Получается, что регистрация в системе — дело не только системы, но и самого пакета. Поэтому в каждом пакете должны храниться сведения о том, какие действия следует выполнить в момент различных операций с ним — в этом состоит третья задача пакетирования.
Списки необходимых действий представлены в пакете в виде сценариев. Эти сценарии привязаны к процедурам установки и удаления пакета, причём могут быть вызваны по необходимости как до, так и после соответствующей процедуры. В результате процедуры установки и удаления пакета выглядят так:
- выполнение предшествующих установке/удалению сценариев;
- копирование файлов из архива в систему или удаление файлов из системы
- выполнение следующих за установкой/удалением сценариев.
methody@localhost:~ $ rpm -q --scripts coreutils
preinstall scriptlet (through /bin/sh):
# Remove info pages from fileutils, textutils and sh-utils.
for f in /usr/share/info/{fileutils,textutils,sh-utils}.info*; do
[ -f "$f" ] || continue
RPM_INSTALL_ARG1=0 /usr/sbin/uninstall_info "$f" ||:
done
postinstall scriptlet (through /bin/sh):
/usr/sbin/install_info coreutils.info
preuninstall scriptlet (through /bin/sh):
/usr/sbin/uninstall_info coreutils.info
Пример 6. Просмотр сценариев в пакете
Мефодий выяснил, что сценарии в пакете coreutils
запускаются перед началом установки (preinstall), после установки (postinstall) и перед удалением (preuninstall), они выполняются стандартным командным интерпретатором (/bin/sh
). Все эти сценарии нужны для того, чтобы зарегистрировать в системе info установленную пакетом документацию или удалить эту документацию из системы (командами /usr/sbin/install_info
и /usr/sbin/uninstall_info
соответственно). Поскольку info строит общее оглавление всей имеющейся в системе документации, простого копирования файлов было бы недостаточно.
В результате подобных операций по интеграции пакета в систему могут быть изменены или удалены файлы, не принадлежащие данному пакету, созданы новые файлы. Если программа, содержащаяся в пакете, пользуется услугами какой-нибудь уже установленной службы (например, syslogd
), может понадобиться регистрация этой программы в конфигурационных файлах службы. Конечно, изменение «чужих» файлов в процессе установки пакета нежелательно: впоследствии, удаляя пакет, потребуется вернуть файл в исходное состояние, что не всегда возможно (например, после вдумчивого редактирования администратором). Избежать редактирования конфигурационных файлов позволяет схема «. d», описанная в лекции Этапы загрузки системы.
Цена удобства
Удобство, которое получает пользователь при работе с пакетами достигается не само собой, а человеческим трудом: пакеты должен создавать человек, его работа называется «сопровождающий» («package maintainer» или «packager»). В обязанности сопровождающего пакет входит подготовка файлового архива, необходимых для установки и удаления сценариев и прочей информации о пакете и его содержимом, и объединение их в одном файле-пакете.
Функции по созданию пакета в формате rpm
также выполняет программа rpm
.
Узнать, кто и когда создал пакет, получить краткую справку о программном обеспечении, которое в нём содержится, можно командой «rpm -qi имя_пакета
».
methody@localhost:~ $ rpm -qi setup
Name : setup Relocations: (not relocateable)
Version : 2.2.5 Vendor: Some Linux Team
Release : some1 Build Date: Чтв 29 Янв 2004 18:08:05
Install date: Пнд 23 Авг 2004 15:08:45 Build Host: shogun.somelinux.org
Group : Система/Настройка/Прочее Source RPM: setup-2.2.5-some1.src.rpm
Size : 39969 License: GPL
Packager : Leon B. Gourievitch <shogun@somelinux.org>
Summary : Initial set of configuration files
Description :
Initial set of configuration files to be placed into /etc.
Пример 7. Описание пакета
Нужно принимать во внимание, что любой пакет, содержащий программное обеспечение для Linux, не является универсальным. Если у вас есть такой пакет, это ещё не означает, что его можно установить в вашей системе. Дело в том, что разные дистрибутивы Linux различаются именно тем, каким образом программное обеспечение организовано в систему (о дистрибутивах речь пойдёт в лекции Политика свободного лицензирования. История Linux: от ядра к дистрибутивам). Дистрибутивы могут различаться размещением файлов и процедурами, предусмотренными для интеграции в систему программного обеспечения, не говоря уже о том, что в разных дистрибутивах используется разный формат пакетов. Это значит, что пакет, подготовленный с ориентацией на один дистрибутив, может оказаться несовместимым с другим. Чтобы в вашем дистрибутиве появилась некоторая программа, кто-то должен подготовить и сделать доступным соответствующий пакет.
- пакет
- Ресурсы, необходимые для установки и интеграции в систему некоторого компонента (архив файлов, до- и послеустановочные сценарии, информация о пакете и его сопровождающем), объединённые в одном файле.
Несмотря на частные различия, дистрибутивы Linux представляют собой варианты одной и той же системы, поэтому в конечном итоге любую программу, работающую в одном дистрибутиве, можно «приспособить» к любому другому. Только для этого нужно располагать исходными текстами соответствующей программы. До сих пор речь шла только о так называемых двоичных пакетах, в которых программы содержатся в виде уже скомпилированных двоичных (исполняемых) файлов, в таком виде программа может зависеть от некоторых свойств системы и работать не везде. Чтобы получить работающую программу в системе, нужно установить именно двоичный пакет. Однако пакет может содержать и исходные тексты программ, такие пакеты называются исходными. Доступность исходных кодов — обязательное условие распространения большей части программного обеспечения для Linux, см. лекцию Политика свободного лицензирования. История Linux: от ядра к дистрибутивам. Если получилось так, что никто не подготовил пакет с нужной вам программой для вашего дистрибутива, у вас есть возможность установить исходный пакет и скомпилировать программу самостоятельно.
Слухи о том, что для сборки программы из исходных текстов не обязательно даже знать, что такое «компилятор», далеки от действительности.
При успешной компиляции из исходного пакета получается соответствующий двоичный, который уже можно установить в системе.