The FreeBSD Diary

The FreeBSD Diary (TM)

Providing practical examples since 1998

If you buy from Amazon USA, please support us by using this link.
[ HOME | TOPICS | INDEX | WEB RESOURCES | BOOKS | CONTRIBUTE | SEARCH | FEEDBACK | FAQ | FORUMS ]
Got ports? Here is THE way to upgrade them! 11 December 2001
Need more help on this topic? Click here
This article has 38 comments
Show me similar articles

There are many articles on ports in this Diary. Only a few deal specifically with upgrading your ports. This article beats them all!

Imagine, if you will, a command which allows you to upgrade all of your ports. Stop thinking about make install distclean. No, I mean one command to upgrade each and every port!

This isn't fantasy or fiction. It's real. And it's called portupgrade. I first heard about this great new tool a few months ago, but I never used it until Michael Lucas wrote an article about it in O'Reilly. This was the first time I've read about portupgrade. Coincidentally, I was just starting to install some new ports on my laptop in preparation for a talk I was going to give at a local Linux User Group. It wouldn't do if I gave my presentation on a Windows box....

What I will be giving here will be an overview. You really should read Michael's article first.

The problem

The ports tree is one of the best FreeBSD features I can think of. It's a great way to install software. Fortunately, software gets updated. Unfortunately, some ports expect a certain version of software. When they don't find it, they can sometimes get very uncooperative and refuse to run. When you upgrade a port and force the install (I'll provide an example later), sometimes other ports which depend on that newly upgraded port will break. It can become a vicious cycle, upgrading one port after another as they dependencies flow outwards. Fortunately, portupgrade does this for you.

pkg_version is your friend when it comes to seeing what ports are up to date. Of course, that does depend upon a recent cvsup of your ports tree. This is pretty easy to do:

# cvsup /usr/share/examples/cvsup/ports-supfile -h cvsup.yourhost.org

where cvsup.yourhost.org is your favorite cvsup mirror. Please refer to Using CVSup in the FreeBSD Handbook.

Here's an example of [manually] upgrading a port upon which other ports are dependant. In this case, I've tried to upgrade devel/glib12 and I'm not upgrading a port, I'm just reinstalling the same version of an already installed port. Not very useful, but it does illustrate part of the problem.

===>  Installing for glib-1.2.10_4
===>  glib-1.2.10_4 is already installed - perhaps an older version?
      If so, you may wish to ``make deinstall'' and install
      this port again by ``make reinstall'' to upgrade it properly.
      If you really wish to overwrite the old port of glib-1.2.10_4
      without deleting it first, set the variable "FORCE_PKG_REGISTER"
      in your environment or the "make install" command line.
*** Error code 1

Stop in /usr/ports/devel/glib12.
*** Error code 1

Stop in /usr/ports/devel/glib12.
[root@laptop:/usr/ports/devel/glib12] #
You could try doing a pkg_delete, but then you'd get this:
# pkg_delete glib-1.2.10_4
pkg_delete: package `glib-1.2.10_4' is required by these other packages
and may not be deinstalled:
xchat-1.7.8
imlib-1.9.11
fnlib-0.5
gtk-1.2.10
enlightenment-0.16.5_5
ORBit-0.5.7

And you could do a pkg_delete -f glib-1.2.10_4, but that would mess with the port database (/var/db/pkg). The ports listed above would then be referencing a version of glib which is no longer installed. If we were actually installing a new version of the port, the dependant ports would be pointing at glib-1.2.10_4 instead of the newly installed version.

Installing portupgrade

To install portupgrade, I did this:

# cd /usr/ports/sysutils/portupgrade/
# make install distclean

My environment does not include /usr/local/sbin (the install location for the portupgrade tools) so I had to prefix all my commands with that directory. This install actually gives you a collection of tools. Read man portupgrade for details.

Backup your data

Backup your package database before you start!

# cd /var/db
# tar cvfz var.db.pkg.tgz pkg

Keep that file safe....

Two versions of the same port

Sometimes you can wind up with two versions of the same port installed. For example:

# pkg_info | grep m4
m4-1.4              GNU's m4
m4-1.4_1            GNU's m4
/usr/local/sbin/pkgdb -F is your friend. For simplicity, I'll only show the interesting bits.
# /usr/local/sbin/pkgdb -F
[Rebuilding the pkgdb in /var/db/pkg ... - 34 packages found (-0 +34)
.................................. done]
Checking the origin of BitchX-1.0c18
Checking the origin of apache-1.3.14_1
Checking the origin of autoconf-2.13
Checking the origin of autoconf213-2.13.000227
Checking the origin of bash-2.04
Missing origin.
Guessing... [Updating the ports database in /usr/ports ... -
6077 port entries found .........1000.........2000........
.3000.........4000.........5000.........6000 (...) done]

shells/bash2 (bash-2.05a): Use this? [yes]
Fixed. (-> shells/bash2)

It couldn't find bash. So it went through /user/ports/INDEX and found the right one and updated the database. For more information on using pkgdb, see pkgdb - packages database tool.

Checking the origin of lynx-2.8.4d9
Missing origin.
Guessing...
www/lynx (lynx-2.8.4.1): Use this? [yes]
Fixed. (-> www/lynx)
Then it did similar for lynx.
Duplicated origin: devel/m4 - m4-1.4 m4-1.4_1
Remove any of them? [no] y
Remove the package record of m4-1.4 ? [no] y
-> m4-1.4_1 is kept.
--> Saving the m4-1.4's +CONTENTS file as /var/db/pkg/m4-1.4_1/+CONTENTS.m4-1.4
--> Removing the m4-1.4's record
--> Done
[Updating the pkgdb in /var/db/pkg ... - 33 packages found (-1 +0) (...) done]
Then I was asked about the duplicated port. So I removed the old one, keeping the new one. Then the ports database was updated with the changed information. But that's not the end. Now that a port has been removed, let's go through the dependencies, because that change probably affects another port.
Stale dependency: autoconf-2.13 -> m4-1.4:
m4-1.4_1 (score:100%) ? ([y]es/[n]o/[a]ll) [yes] a
Fixed. (-> m4-1.4_1)

Here, autoconf requires m4 but it's looking for the old version. pkgdb can update this for you. If you answer y it will be updated for this port. If you answer a, it will update this stale dependency for all ports (i.e. change all m4-1.4 references to be m4-1.4_1).

Updating all the ports!

I know this is the command you've been waiting for. It is very powerful. So be careful.

# /usr/local/sbin/portupgrade -ra
** The port directory for 'net/cvsup-bin' does not exist.
** No need to upgrade 'screen-3.9.10' (>= screen-3.9.10).
** No need to upgrade 'libtool-1.3.4_2' (>= libtool-1.3.4_2).

[snip]
Here you can see that the installed port screen-3.9.10 is at least as new as the one in the ports tree: screen-3.9.10. So the port is not upgraded.
** No need to upgrade 'autoconf213-2.13.000227' (>= autoconf213-2.13.000227).
** No need to upgrade 'bzip2-1.0.1' (>= bzip2-1.0.1).
** No need to upgrade 'gmake-3.79.1' (>= gmake-3.79.1).
===> Cleaning for XFree86-4.1.0_10
In this case, we're upgrading XFree86-4.1.0_10.

When I did this on another box, these were the ports waiting to be upgraded:

$ pkg_version -L =
apache                              <
autoconf                            <
bash                                *
bind                                <
cclient                             <
cvsup-bin                           ?
gettext                             *
lynx                                *
majordomo                           <
mkisofs                             <
nslint                              <
qpopper                             <
rsync                               <
screen                              <
siege                               <
sudo                                <
After running portupgrade -ar overnight, this is what portupgrade had to say:
Updating the pkgdb in /var/db/pkg ... - 34 packages found (-0 +1) . done]
** The following packages were not installed or upgraded (-:skipped / !:failed)
        ! (cvsup-bin-16.1) (missing origin)
        - lang/pm3-base (pm3-base-1.1.15)
        - lang/pm3-net (pm3-net-1.1.15)
        - lang/ruby (ruby-1.6.5.2001.11.23)
        - net/ruby-uri (ruby-uri-0.9,1)
        - devel/ruby-fnmatch (ruby-fnmatch-1.1b_1)
        - editors/joe (joe-2.8_3)
        ! net/bind8 (bind-8.2.3) (checksum mismatch)
        - devel/libtool (libtool-1.3.4_2)
        - devel/gettext (gettext-0.10.35)
        - www/lynx (lynx-2.8.4d9)
        - irc/bitchx (BitchX-1.0c18)
        - misc/pkg_tarup (pkg_tarup-1.2_3)
        - devel/ruby-optparse (ruby-optparse-0.8.4)
        - sysutils/portupgrade (portupgrade-20011118)
        - net/p5-Net (p5-Net-1.0703)
        - security/logcheck (logcheck-1.1.1)
        - devel/m4 (m4-1.4_1)
        - devel/autoconf213 (autoconf213-2.13.000227)
        - archivers/bzip2 (bzip2-1.0.1)
        - devel/gmake (gmake-3.79.1)
        - mail/cclient (cclient-2001,1)

Two ports did mot upgrade:

  1. cvsup-bin because it could not be found in the tree.
  2. net/bind8 because of a checksum mismatch. The downloaded tarball did not match that expected by the port.

I will show you how to get around that bind problem, but you should note that the example I provide below for bind8 is generic and could be applied to any other port. But also realize that bind8 is supplied with the base system in FreeBSD. Upgrading it from ports is possible but you need to follow slightly different instructions. That said, have a read of the following but keep in mind that I will be installing bind8 again just after this example.

I won't be upgrading cvsup-bin as it's an old port an no longer used on this box.

# cd /usr/ports/net/bind8/
# make distclean

That removed the existing tarball from /usr/ports/distfiles. Then I tried again:

# /usr/local/sbin/portupgrade bind
===> Cleaning for bind-8.2.5
>> bind-src.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
>> Attempting to fetch from ftp://ftp.isc.org/isc/bind/src/8.2.5/.
Receiving bind-src.tar.gz (1329713 bytes): 100%
1329713 bytes transferred in 15.2 seconds (85.61 kBps)
>> bind-doc.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
>> Attempting to fetch from ftp://ftp.isc.org/isc/bind/src/8.2.5/.
Receiving bind-doc.tar.gz (1486296 bytes): 100%
1486296 bytes transferred in 15.0 seconds (96.83 kBps)
===> Extracting for bind-8.2.5
>> Checksum OK for bind-src.tar.gz.
>> Checksum OK for bind-doc.tar.gz.
===> Patching for bind-8.2.5

[snip]

===> Compressing manual pages for bind-8.2.5
===> Registering installation for bind-8.2.5
===> Cleaning for bind-8.2.5
[Updating the pkgdb in /var/db/pkg ... - 34 packages found (-0 +1) . done]

That correctly installed the port. However, it did not install bind the way bind was included with the base system. The above will run, but it won't replace the built-in bind. To properly replace bind, I followed the instructions here.

Out of date ports

Even after I cvsup'd my ports, ran portupgrade, one port was still out of date.

# cd /usr/ports/devel/ruby-optparse
# make fetch
>> optparse-0.8.5.tar.gz is not in /usr/ports/devel/ruby-optparse/distinfo.
>> Either /usr/ports/devel/ruby-optparse/distinfo is out of date, or
>> optparse-0.8.5.tar.gz is spelled incorrectly.
*** Error code 1

Stop in /usr/ports/devel/ruby-optparse.
*** Error code 1

Stop in /usr/ports/devel/ruby-optparse.
*** Error code 1

Stop in /usr/ports/devel/ruby-optparse.

I think this means that the tarball optparse-0.8.5.tar.gz (which will have been downloaded to /usr/ports/distfiles) wasn't what the port expected. To be sure I had the latest and greatest, I deleted the tarball and did another cvsup. Then I did a

# /usr/local/sbin/portupgrade -ra

...and everything upgraded fine.

One port did a bad thing

There was one problem I encountered, but this wasn't the fault of portupgrade. It was the fault of the apache port which added a www:www user/group combination to my box. But it overwrote what I already had. Bad port! BAD BAD PORT! By the time you read this, I'm sure this bug will be fixed.

The problem was many of my webpages could not be read. They were chgrp www, but the group ID (GID) for www had changed in /etc/group, but the values on disk were the old value. Here's what it looked like:

-rw-r--r--  1 dan  99   39229 Nov  2  2000 marc_dan.jpg
drwxr-xr-x  2 dan  99     512 Oct 16  2000 pics
-rw-r--r--  1 dan  99   19057 Nov 30  2000 proposed_db.gif

See that 99? That is the group ID. That should be a name. The fact that it is a number means there is no entry in /etc/groups for this group. This is a result of www being removed and then added again, but with a different ID. If the problem were just these three files I wanted changed, I could do it easily. But here's a script that did the whole disk. Instead of using 99 here, be sure to use the value used on your system.

find / -user  99 -exec chown www {} \;
find / -group 99 -exec chgrp www {} \;

That fixed up the permissions.

Interactive ports

Another item to be aware of is ports that require interaction during their build. You might leave portupgrade running over night and come back and find that a port is waiting for input. For example, mail/majordomo will display a message at the end of the install and wait for you to hit enter. And www/mod_php4 asks for configuration values at the start.

Or you can use packages

portupgrade will also install packages, where available, if you use the -P option. And -PP will use packages only, never ports.

env: /usr/local/bin/ruby_s: No such file or directory

For details on this problem, please see what Akinori MUSHA had to say.

This was a rather annoying problem. Right after I tried upgrading a series of ports, I was greeted with this error message.

# /usr/local/sbin/portupgrade -r jpeg
env: /usr/local/bin/ruby_s: No such file or directory

I encountered it more than once. This time it was right after having issued this command:

# /usr/local/sbin/portupgrade -r jpeg ruby ruby-optparse cvsweb autoconf automake expat

I found it went away if I reinstalled portupgrade.

# cd /usr/ports/devel/linux_devtools]
# pkg_info | grep portupgrade
portupgrade-20011118 Very powerful FreeBSD ports/packages upgrading tool and more
# pkg_delete portupgrade-20011118
# make install

Then it worked fine.

Actually, I may have had to do a make install -DFORCE_PKG_REGISTER. I'm not sure about this point. I didn't keep notes for that step.


Need more help on this topic? Click here
This article has 38 comments
Show me similar articles