Arrow of time
Arrow of time

Why FreeBSD's pkg sucks

Share Tweet Share

A not too long time ago I was a big FreeBSD user, with dozens of production installs. Gradually, I've been …

A not too long time ago I was a big FreeBSD user, with dozens of production installs. Gradually, I've been using it less and less and now I feel I must describe why, in a hopefully productive and positive fashion.

In short: it's all about the packages and ports. An operating system is useless without its applications, and the currently blessed binary package management system, the pkg is seriously broken.

I was very enthusiastic about pkg (then called pkgng), and I'm very much dissapointed that several YEARS of its existence and bug reports (yes, I've submitted them to the right mailing list), have had no effect and it is now as broken as it was in the beginning in a critical area: it doesn't handle inter-package dependencies in a robust manner.

Currently, the only significant way package dependancies are honoured at all is when a package is first installed. At that time, it will bring up all the dependancies required for the package to work. Unfortunately, once installed, common install and upgrade operations which must take dependancies into effect don't do it, or do it incompletely or erronousely, so upgrading a complex package can leave the system in a broken state.

As an illustration, consider a system which has the following packages installed:

php53-5.3.27                   PHP Scripting Language
php53-bz2-5.3.27               The bz2 shared extension for php
php53-ctype-5.3.27             The ctype shared extension for php
php53-curl-5.3.27_1            The curl shared extension for php
php53-dom-5.3.27               The dom shared extension for php
php53-exif-5.3.27              The exif shared extension for php
php53-extensions-1.6           A "meta-port" to install PHP extensions
php53-filter-5.3.27            The filter shared extension for php
php53-gd-5.3.27                The gd shared extension for php
php53-hash-5.3.27              The hash shared extension for php
php53-iconv-5.3.27             The iconv shared extension for php
php53-json-5.3.27              The json shared extension for php
php53-ldap-5.3.27              The ldap shared extension for php
php53-mbstring-5.3.27          The mbstring shared extension for php
php53-mcrypt-5.3.27            The mcrypt shared extension for php
php53-openssl-5.3.27_1         The openssl shared extension for php
php53-pcntl-5.3.27             The pcntl shared extension for php
php53-pdo-5.3.27               The pdo shared extension for php
php53-pdo_sqlite-5.3.27        The pdo_sqlite shared extension for php
php53-pgsql-5.3.27             The pgsql shared extension for php
php53-posix-5.3.27             The posix shared extension for php
php53-session-5.3.27           The session shared extension for php
php53-simplexml-5.3.27         The simplexml shared extension for php
php53-soap-5.3.27              The soap shared extension for php
php53-sockets-5.3.27           The sockets shared extension for php
php53-sqlite-5.3.27            The sqlite shared extension for php
php53-sqlite3-5.3.27           The sqlite3 shared extension for php
php53-tokenizer-5.3.27         The tokenizer shared extension for php
php53-xml-5.3.27               The xml shared extension for php
php53-xmlreader-5.3.27         The xmlreader shared extension for php
php53-xmlwriter-5.3.27         The xmlwriter shared extension for php
php53-zip-5.3.27               The zip shared extension for php
php53-zlib-5.3.27              The zlib shared extension for php

This was obviously a system installed some time ago, last upgraded when the current version of PHP was 5.3.27. The current version of PHP is 5.3.29 and when I tried to install another PHP extension (which is a very common requirement and operation in practice), I gave the following command:

# pkg install php53-fileinfo

This is the right command, no problems there. It's effect, though, was for practical intents and purposes, broken:

# pkg install php53-fileinfo
Updating FreeBSD repository catalogue...
FreeBSD repository is up-to-date.
All repositories are up-to-date.
Updating database digests format: 100%
pkg: libxml2 has a missing dependency: pkg-config
pkg: php53 has a missing dependency: pkg-config
The following 1 packages will be affected (of 0 checked):

New packages to be INSTALLED:
        php53-fileinfo: 5.3.29_3

The process will require 2 MiB more space.
171 KiB to be downloaded.

Proceed with this action? [y/N]: y
Fetching php53-fileinfo-5.3.29_3.txz: 100%  171 KiB 175.5kB/s    00:01
Checking integrity... done (0 conflicting)
[1/1] Installing php53-fileinfo-5.3.29_3...
[1/1] Extracting php53-fileinfo-5.3.29_3: 100%

So now, I have a mismatched PHP module installed, which is a common source of PHP crashes and problems. Even worse, if I tried to upgrade PHP, this would happen:

# pkg upgrade php53
Updating FreeBSD repository catalogue...
FreeBSD repository is up-to-date.
All repositories are up-to-date.
The following 6 packages will be affected (of 0 checked):

New packages to be INSTALLED:
        indexinfo: 0.2.2
        gettext-runtime: 0.19.4
        perl5: 5.18.4_11
        p5-Locale-gettext: 1.05_4

Installed packages to be UPGRADED:
        php53: 5.3.27 -> 5.3.29_3
        libxml2: 2.7.8_1 -> 2.9.2_2

The process will require 50 MiB more space.
15 MiB to be downloaded.

Proceed with this action? [y/N]: ^C

So, now I would have the base PHP package out of sync with 30-something PHP modules, which is actually a catastrophe! This must never happen!

The recorded dependancies are, suprisingly, correct:

# pkg info -d php53-gd
php53-gd-5.3.27:
        libxml2-2.7.8_1
        freetype2-2.4.6
        php53-5.3.27
        png-1.5.17
        jpeg-8_4
        t1lib-5.1.2_1,1
        pcre-8.33
        libiconv-1.14_1

... which means that the pkg dependancy solver in the install and upgrade commands is effectively and very seriously broken.

This is a major issue for FreeBSD, since its packages are on a "rolling release" track. This means that new versions of popular packages arrive into the repositories shortly after they are released by the upstream project. In case of PHP, the installed versions become out of sync with the freshest ones in the repos very fast, and currently the only possible way of upgrading PHP is to upgrade each and every extension separately - an operation which, because of the broken dependancy tracking, may install new binaries (.so) linked to new versions of dependant libraries, whose packages would NOT be upgraded by pkg. I.e. it would install .so libraries depending on newer versions of other .so libraries than those currently present on the system, i.e. missing files.

I've had cases where I would upgrade apache, this operation would sometimes upgrade apr, but it would then always fail to upgrade subversion, which depends on apr, leaving it broken until manually and individually fixed.

The situation I have described exists since pkgng was released, since at least 2012. This blog post describes what I did today, at the end of February 2015. Note that there is a -R switch to pkg install which is described as When used with -f, reinstalls any packages that require the given package., but it apparently will not do anything about packages already installed, and has no equivalent in pkg upgrade.

Can anyone else confirm this? Is it fixable?


comments powered by Disqus