Пакет­ный мене­джер «portage» в «Gentoo GNU/Linux» - система с огром­ными воз­мож­но­стями. Раз­ра­бот­чики «portage» поза­бо­ти­лись о том, чтобы поль­зо­ва­тели были мак­си­мально сво­бодны в выборе, как уста­нав­ли­вать любой пакет в системе с пара­мет­рами, отлич­ными от тех, что зало­жены в офи­ци­аль­ном дереве «Portage». Я не буду рас­ска­зы­вать о исполь­зо­ва­нии раз­лич­ных овер­леев - рано или поздно об их исполь­зо­ва­нии узнает любой поль­зо­ва­тель «Gentoo GNU/Linux». В дан­ной заметке я хочу рас­ска­зать, как вли­ять на про­цесс сборки пакета, по жела­нию изме­няя чуть ли не все содер­жи­мое файла «ebuild», не внося ника­ких изме­не­ний в дерево «Portage». Это будет полезно в первую оче­редь поль­зо­ва­те­лям, уже пора­бо­тав­шим неко­то­рое время с «Gentoo GNU/Linux», и жела­ю­щим вне­сти неко­то­рые кор­рек­тивы в уста­нав­ли­ва­е­мые пакеты.

Итак, пер­вым на оче­реди будет файл «/etc/portage/bashrc». Если его нет, то его можно легко создать. Этот файл выпол­ня­ется все­гда при уста­новке любого пакета. В него можно поме­стить все, что угодно. При­веду про­стые при­меры с реше­нием кон­крет­ных задач.

Напри­мер, мне не нужны сер­ти­фи­каты, кото­рые уста­нав­ли­ва­ются неко­то­рыми паке­тами по умол­ча­нию, так как я исполь­зую соб­ствен­ные сер­ти­фи­каты. Я хочу отка­заться от их уста­новки. Это реша­ется про­сто добав­ле­нием сле­ду­ю­щего содер­жа­ния в файл «/etc/portage/bashrc».
/etc/portage/bashrcinstall_cert() {
    einfo "No need SSL certs install"
}

Этим дей­ствием я заме­няю функ­цию уста­новки сер­ти­фи­ка­тов, содер­жа­щу­юся в офи­ци­аль­ном дереве в файле «eclass/ssl-cert.eclass». То есть, можно заме­нить любую функ­цию, содер­жа­щу­юся в ката­логе «eclass» офи­ци­аль­ного дерева. Уже неплохо. Идем далее.

При уста­новке из бинар­ных паке­тов, собран­ных на дру­гом ком­пью­тере, как я рас­ска­зы­вал в этой ста­тье, совер­шенно неин­те­ресно дер­жать кэш этих паке­тов, если они все­гда доступны с ком­пью­тера, где про­из­во­ди­лась их ком­пи­ля­ция. Поэтому я буду про­сто чистить кэш сразу после уста­новки оче­ред­ного пакета. Для этого в файле «/etc/make.conf» в пере­мен­ную «FEATURES» я доба­вил пара­метр «-parallel-fetch», чтобы пакеты уста­нав­ли­ва­лись после­до­ва­тельно. А в файл «/etc/portage/bashrc» доба­вил сле­ду­ю­щее.
/etc/portage/bashrcpost_pkg_postinst() {
    rm -f "${PORTAGE_BINPKG_FILE}"
    [ ! "$(ls -A "${PKGDIR}/${CATEGORY}")" ] && \
        rm -rf "${PKGDIR}/${CATEGORY}"
    rm -f "${PKGDIR}/Packages"
}

Теперь, после уста­новки любого бинар­ного пакета, файл «.tbz2» будет уда­лен из кэша, что поз­во­лит уве­ли­чить доступ­ное место в системе.

В послед­нем при­мере при­ме­ня­ется необыч­ная функ­ция - «post_pkg_postinst». Откуда она и что из себя пред­став­ляет я рас­скажу ниже.

Итак, пакет на ста­дии уста­новки про­хо­дит несколько фаз. При этом выпол­ня­ются соот­вет­ству­ю­щие функ­ции. Ниже я при­веду при­мер­ный спи­сок функ­ций в порядке их выполнения:

pkg_setup
src_unpack
src_prepare
src_configure
src_compile
src_test
src_install
pkg_preinst
pkg_postinst
pkg_prerm
pkg_postrm

Более пол­ный спи­сок и опи­са­ние функ­ций фаз уста­новки можно полу­чить из сле­ду­ю­щей справки.
# man 5 ebuild

Так вот, с неко­то­рых пор пакет­ный мене­джер «portage» умеет обра­ба­ты­вать функ­ции, состо­я­щие из пре­фик­сов «pre_» и «post_» с име­нем функ­ции фазы уста­новки, то есть либо «до», либо «после» опре­де­лен­ной фазы. Как я пока­зал выше, напри­мер «post_pkg_postinst» будет выпол­няться после вызова функ­ции «pkg_postinst». И вот тут-то и откры­ва­ются поис­тине без­гра­нич­ные воз­мож­но­сти по управ­ле­нию паке­тами с помо­щью «portage». Созда­вая свои соб­ствен­ные функ­ции, можно вли­ять на про­цесс уста­новки пакета самым раз­но­об­раз­ным способом.

Как известно, «portage» выпол­няет не только файл «/etc/portage/bashrc», но и файлы в ката­логе «/etc/portage/env», с име­нами паке­тов, раз­ло­жен­ные по ката­ло­гам с име­нами кате­го­рий паке­тов. Напри­мер, как я уже рас­ска­зы­вал в этой заметке, для пакета «sys-kernel/gentoo-sources» будет выпол­няться файл «/etc/portage/env/sys-kernel/gentoo-sources».

Как все это можно исполь­зо­вать, я рас­скажу на примерах.

В послед­них вер­сиях про­граммы «portage» пере­мен­ную из «/etc/make.conf» «PORTAGE_BINPKG_TAR_OPTS» почему-то сде­лали «только для чте­ния» в про­цессе уста­новки пакета. Мне такое поло­же­ние вещей совер­шенно не под­хо­дит, поэтому я про­сто изме­няю исход­ные тек­сты пакета «portage» прямо в про­цессе уста­новки, чтобы не бро­сать пакет в локаль­ный овер­лей и потом сле­дить за выхо­дом новых вер­сий, что крайне неудобно. Для этого я про­сто создаю файл «/etc/portage/env/sys-apps/portage» сле­ду­ю­щего содер­жа­ния.
/etc/portage/env/sys-apps/portagepre_src_compile() {
    sed -e 's/PORTAGE_BINPKG_TAR_OPTS//' -i "${S}/bin/ebuild.sh"
}

Что же делает этот файл? Перед про­цес­сом ком­пи­ля­ции, что видно по имени функ­ции «pre_src_compile», про­ис­хо­дит редак­ти­ро­ва­ние опре­де­лен­ного файла, в кото­ром уби­ра­ется един­ствен­ное упо­ми­на­ние о пере­мен­ной «PORTAGE_BINPKG_TAR_OPTS». Пакет «portage» уста­нав­ли­ва­ется, как обычно, а я полу­чаю необ­хо­ди­мый мне функционал.

Можно выпол­нять раз­лич­ные функ­ции не только «до» и «после» неко­то­рой фазы уста­новки пакета, но и пол­но­стью заме­нять функ­ции, опи­сан­ные в файле «ebuild» пакета.

Напри­мер, при уста­новке бинар­ного пакета «sys-devel/bison», мне не понра­ви­лась функ­ция «pkg_postinst». Я создал файл «/etc/portage/env/sys-devel/bison» сле­ду­ю­щего содер­жа­ния с функ­цией, кото­рая мне под­хо­дит.
/etc/portage/env/sys-devel/bisonpkg_postinst() {
    if [[ ! -e ${ROOT}/usr/bin/yacc ]] ; then
        einfo "No need link"
    fi
}

При уста­новке пакета «sys-devel/bison» будет выпол­няться именно та функ­ция, кото­рая задана в файле «/etc/portage/env/sys-devel/bison». И так можно посту­пить с любой функ­цией, задан­ной в файле «ebuild».

С помо­щью всего этого функ­ци­о­нала можно делать с «неудоб­ными» паке­тами все, что угодно. Напри­мер, накла­ды­вать необ­хо­ди­мые патчи, не копи­руя пакет в локаль­ный овер­лей и не изме­няя его. Покажу это на при­мере пакета «net-fs/samba». Ветка «3.5.X» имеет извест­ную про­блему с NTLM-аутентификацией. В сети нашелся патч для ее решения.

Я хочу сде­лать неко­то­рую авто­ма­ти­за­цию про­цесса нало­же­ния пат­чей. Для начала нужно решить, где будут хра­ниться все допол­ни­тель­ные патчи. Для этих целей я создал ката­лог «/var/portage/patches».
# mkdir -p /var/portage/patches

Затем, внутри этого ката­лога можно созда­вать под­ка­та­логи, состо­я­щие из кате­го­рии и имени пакета. В моем при­мере я создал ката­лог «/var/portage/patches/net-fs/samba».
# mkdir -p /var/portage/patches/net-fs/samba

Сюда я и ско­пи­рую най­ден­ный в сети патч. Кстати, вот он.
/var/portage/patches/net-fs/samba/samba-3.5.6-winbindd.patchdiff -Nuar samba-3.5.6.orig/source3/winbindd/winbindd_util.c samba-3.5.6/source3/winbindd/winbindd_util.c
--- samba-3.5.6.orig/source3/winbindd/winbindd_util.c   2010-10-07 19:41:16.000000000 +0300
+++ samba-3.5.6/source3/winbindd/winbindd_util.c        2010-11-15 01:03:51.000000000 +0200
@@ -76,6 +76,17 @@
        if (sid == NULL)
                return False;
 
+       /* This is to show the different results of this function between
+          samba versions 3.4.8 and 3.5.4, for bug 7481 */
+       static bool res_v34x, res_v35x;
+       res_v35x = (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
+       if ( IS_DC ) {
+               res_v34x = sid_check_is_builtin(sid);
+               DEBUG(3,("is_internal_domain(): 3.5.x would return %d\n", res_v35x));
+               DEBUG(3,("is_internal_domain(): 3.4.x would return %d\n", res_v34x));
+               return (res_v34x);
+       }
+
        return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
 }
 

Оста­лось доба­вить в файл «/etc/portage/bashrc» сле­ду­ю­щие функ­ции.
/etc/portage/bashrcpost_src_unpack() {
    src_autopatcher
}

src_autopatcher() {

    # Specify a directory for patches.
    PATCH_DIR="/var/portage/patches"

    PATCH_OPTS="-g0 -E --no-backup-if-mismatch"
    local count=0
 
    if [ -d "${PATCH_DIR}/${CATEGORY}/${PN}" ]; then
        for PATCH in $(find "${PATCH_DIR}/${CATEGORY}/${PN}" -type f -name "*.patch"|sort)
        do
            einfo "Patching ${PATCH/*\//} ..."
            while [[ ${count} -lt 5 ]]; do
                if (patch -p${count} ${PATCH_OPTS} --dry-run -f < "${PATCH}") >/dev/null; then
                    patch -p${count} ${PATCH_OPTS} < "${PATCH}" >/dev/null
                    break
                fi
            (( count++ ))
            done
            if [[ ${count} -ge 5 ]] ; then
                eerror "Failed Patch: ${PATCH/*\//} !"
                die "Failed Patch: ${PATCH/*\//} !"
            fi
        done
    fi
}

В функ­ции «src_autopatcher» можно изме­нить место для хра­не­ния пат­чей. Оно задано в пере­мен­ной «PATCH_DIR».

Попро­буем обно­вить пакет «net-fs/samba».
# emerge samba -1

These are the packages that would be merged, in order:

Calculating dependencies  .... done!
[ebuild   R   ] net-fs/samba-3.5.6  USE="acl -addns -ads aio -avahi caps client -cluster cups -debug -doc -examples -fam ldap -ldb netapi pam quota readline server smbclient -smbsharemodes -swat -syslog winbind" 0 kB

Total: 1 package (1 reinstall), Size of downloads: 0 kB

>>> Verifying ebuild manifests

>>> Emerging (1 of 1) net-fs/samba-3.5.6
 * samba-3.5.6.tar.gz RMD160 SHA1 SHA256 size ...                                                       [ ok ]
 * Package:    net-fs/samba-3.5.6
 * Repository: gentoo
 * Maintainer: samba@gentoo.org
 * USE:  acl aio caps client cups elibc_glibc kernel_linux ldap netapi pam quota readline server smbclient userland_GNU winbind x86
>>> Unpacking source...
>>> Unpacking samba-3.5.6.tar.gz to /var/tmp/portage/net-fs/samba-3.5.6/work
>>> Source unpacked in /var/tmp/portage/net-fs/samba-3.5.6/work
 * Patching samba-3.5.6-winbindd.patch ...
>>> Preparing source in /var/tmp/portage/net-fs/samba-3.5.6/work/samba-3.5.6/source3 ...
>>> Source prepared.
...

Как видно из вывода команды «emerge», допол­ни­тель­ный патч успешно нало­жился, что и требовалось.

Теперь у меня есть воз­мож­ность накла­ды­вать патчи на любой пакет, не изме­няя файл «ebuild». Можно попро­бо­вать сде­лать в файле «/etc/portage/bashrc» в функ­ции «post_src_unpack» еще и про­верку на вер­сию пакета и в зави­си­мо­сти от этого накла­ды­вать соот­вет­ству­ю­щий патч, но, я думаю, с этим вы уж и сами справитесь.

Пока что это все, что я хотел рас­ска­зать о допол­ни­тель­ных воз­мож­но­стях пакет­ного мене­джера «portage». Наде­юсь, этот мате­риал будет поле­зен поль­зо­ва­те­лям «Gentoo GNU/Linux», жела­ю­щих узнать свою систему немного глубже.