18

I recently started packaging up some of my software and publishing it on Launchpad. The installation and removal works fine, but upgrading the package from one version to the next version is problematic.

The problem is that there are some scripts that only need to run during the first installation of the package. These scripts populate the DB, create a user, etc. They are currently called in the package.postinst configure) section. However this results in them being called during an upgrade as well as shown in the diagram.

Is there a way to include a maintainer script in a .deb package that only executes during the first installation of the package and not during an upgrade? Or what would be an elegant way to include some initial setup scripts in a .deb package?

5 Answers 5

36

Check out this diagram from the Debian wiki about how the maintainer scripts are called: Debian maintainer script flowchart

If you follow down the left hand side (the “everything goes ok” path) you'll see that the postinst script is called with the most-recently configured version. This gives you a chance to distinguish between an upgrade and a fresh install - in the upgrade case, your postinst will be called like

postinst configure 1.23-0ubuntu1

where 1.23-0ubuntu1 is the previously installed version of your package, whereas for a fresh install it will be called like

postinst configure

This also allows you to handle the case when you need to perform an action when upgrading from a particular version - you can check in the postinst for that version.

This makes it easy to check if the script is being done on an 'install' or an 'upgrade'. If $2 is null, then it's an install. so:

if [ -z "$2" ]; then
  do install stuff
else
  do upgrade stuff
fi
1
  • 3
    Note that the extra parameter is also passed in the case you've removed the package (but not purged it) and installs it again.
    – skyking
    Mar 5, 2019 at 18:27
16

With a debian/preinst file you can perform actions on install but not upgrade.

#!/bin/sh
set -e

case "$1" in
    install)
        # do some magic
        ;;

    upgrade|abort-upgrade)
        ;;

    *)
        echo "postinst called with unknown argument \`$1'" >&2
        exit 0
        ;;
esac

#DEBHELPER#

exit 0

Though as the name implies, this is run before your package is installed. So you might not be able to do what you need here. Most packages simply test in the configure stage of the postinst if the user has been created already. Here's colord

$ cat  /var/lib/dpkg/info/colord.postinst
#!/bin/sh

set -e

case "$1" in
    configure)

# create colord group if it isn't already there
    if ! getent group colord >/dev/null; then
            addgroup --quiet --system colord
    fi

# create the scanner group if it isn't already there
    if ! getent group scanner >/dev/null; then
        addgroup --quiet --system scanner
    fi

# create colord user if it isn't already there
    if ! getent passwd colord >/dev/null; then
            adduser --system --ingroup colord --home /var/lib/colord colord \
        --gecos "colord colour management daemon"
        # Add colord user to scanner group
        adduser --quiet colord scanner
    fi

# ensure /var/lib/colord has appropriate permissions
    chown -R colord:colord /var/lib/colord

    ;;
esac    



exit 0
3

You might be able to use a debian/preinst script in combination with postinst.

In the preinst script, check for a file your pkg definitely installs. If it is present, do nothing (because your package was previously installed), else, do your setup steps.

If your setup steps require that your pkg is installed (in which case the above will not work because preinst runs before the installation), then your preinst script could write a file, for example: /tmp/setupmypkg. Your postinst script could simply test whether that file is present and if so do two things:

  • your initial setup steps
  • delete the /tmp/setupmypkg file
1
  • 2
    Yes this would work and I am currently doing something similar. But it still looks a bit hacky... I was hoping for more native way to do it. It doesn't seem like such an exotic request right? Feb 6, 2012 at 23:28
1

I found that testing for $2 in your "postinst configure" script doesn't work properly if you have already installed your package once before, then uninstalled it (but without purging), then try to a reinstall again. In this case, the postinst script still gets a version argument for the "postinst configure" step.

However if you have installed the package before, then remove AND purge it, then reinstall again, the "postinst configure" script will NOT get a version argument in $2

0

I don't think so but you can easily modify the preinst/postinst scripts to check if package is being installed for the first time and take standard action.

May be something like this,

in preinst.

if not is_package_istalled():
    export MY_PACKAGE_FIRST_INSTALL

in postinst,

if MY_PACKAGE_FIRST_INSTALL:
    Do First Install Setup 

Edit

Hmm, may be you can just check all this directly in postinst because I think dpkg would not set the status of the package as installed before executing postinst but I'm not sure. So the above could be come,

in postinst,

if not is_package_istalled():
    Do First Install Setup 

Where, is_package_installed can be you function to detect the installation status. May be something like 'dpkg --status packagename'

OR

Why not just simply check if the changes you want to make are already there and only proceed if they are not.

2
  • I don't understand. Where does IS_INSTALLED come from? Feb 6, 2012 at 20:48
  • There is no IS_INSTALLED, it is just pseudo code. Just an example. IS_INSTALLED could be the output of a command like 'dpkg --status package_name' What I meant was you could check if package is installed in preinst, set a state var and then based on this state var take action in postinst.
    – Owais Lone
    Feb 6, 2012 at 21:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .