Urpkg User Manual

Sebastien Vasey

urpkg 20110630

I hereby release this software in the public domain. This means that you can use and distribute it in whatever way you see fit. However, if you want to re-publish it, I ask you to please put a link to its web page, and mention my name. You are not forced to do it, but that would be a way to say thanks ! See also: My copyright page


Table of Contents

Preface
1. Introduction
What is urpkg ?
How can urpkg be useful ?
2. Getting started
Compiling and installing urpkg
Prerequisites
Extracting the tarball
Configuring the build
Compiling urpkg
Installing urpkg
Creating a test package
Creating the destination directories
Creating the source files
Adding installation directories and shared files
Installing a program
Playing with the program's files
Pre and post install scripts
The preinstall script
The postinstall scripts
Creating a Slackware package
Listing the package's file
Creating the package
Uninstalling a program
3. How urpkg works
Introduction
Package user and package name
Generating a username
Finding the package user owning a file
Finding a package name
Installation groups and file permissions
The sticky bit
Package user groups
Owner and group of a package's file
Package directories
The configuration directory
The find script
The preinstall script
The postinstall scripts
Environment variables
Owned and added files
Which file belong to a package ?
What gets removed or listed ?
What about directories ?
4. Using urpkg
Manpages
Common problems
Programs writing in the current directory
Programs writing to non-install directories
Unwanted permission/ownership changes
Overwritten or deleted files
Ldconfig
Bugs
Todo
FAQ
5. Contributing to urpkg

Preface

This is the user manual for urpkg, a software to install programs in a safe and easily undoable way. Urpkg is public-domain software, written in C.

I first begun working on urpkg after reading the More Control and Package Management using Package Users LFS hint so a lot of ideas implemented in urpkg come from the hint's author Matthias S. Benkmann which I would like to credit here.

Even though this document should be complete enough, I strongly recommend you to read the hint first, as to better understand the ideas behind urpkg.

Chapter 1. Introduction

What is urpkg ?

urpkg is a software to install programs in a safe and undoable way. One could call it a package management software, although its features are somewhat scarce compared to the other tools in that domain. Urpkg let you install programs (usually from source, although you could also consider using another package manager for example) in such a way that you have complete controls over where the installation program has access. Once your software is installed, it is very easy to list its files and uninstall it in case you are not satisfied.

Under the hood, urpkg creates a user for each program that you install and run the installation command as this user. The command is therefore never given root access and will not be allowed to do any unwanted damages as it may happen if you run the usual sudo make install for example.

How can urpkg be useful ?

The first goal I had in mind when creating urpkg was to prevent installation programs from overwriting files or getting suid behind my back. I did not want to let the program run as root for a task as delicate as installing a program. So that's the first idea: complete control over what gets installed and how. You may trust your package manager, but do you trust all the installation scripts of all the programs you are ever going to install, remove and upgrade ?

The second goal was to be able to uninstall any software, even if there is no available package (for example for development versions), make uninstall target, or other means of uninstalling it. Urpkg lets you run any command, and then remove all files generated by that command easily. This way it is much easier to install software from source or to create packages for your favorite distro in an automated way, much like checkinstall.

By the way, since version 1.4, you can easily create Slackware packages using urpkg. See the section called “Creating a Slackware package”

In short, urpkg can be used to...

  • Keep control over what any installation program (including your favorite package manager) is doing

  • Install any program from source

  • Generate package for your favorite distribution

  • Anything you think it can be good at...

Chapter 2. Getting started

Compiling and installing urpkg

This section details how to compile and install urpkg from source on your machine.

Prerequisites

You need a UNIX-like system for urpkg to work. I have tested it on GNU/Linux (LFS and Slackware 12.1), but other systems should work as well. You will also need root access on that system. By design, urpkg is useless if you cannot get root access, since it needs to be able to create new users to install a package. Some scripts assume that your user list is in /etc/passwd and your group list in /etc/group. If that is not the case, you should change them accordingly.

Build time dependencies

urpkg uses CMake as build system, so you will need to download and install it. You will also need the standard make and gcc tools.

If you want to build the documentation yourself (this should not be necessary if you are installing a release tarball), you should have the necessary tools to build docbook documentation, that is

You must also have the useradd, usermod, etc. programs available, because urpkg looks for them before compiling the software. Any standard linux distribution has these tools.

Run time dependencies

urpkg relies on some external shell scripts using standard tools that should be available on your system. Those are:

Most of those software should already be on your system, so urpkg is indeed very light on dependencies.

Extracting the tarball

First, extract the urpkg tarball and cd to it.

    $ tar -xf <Your .tar.gz file>
    $ cd <filename without .tar.gz>
  

Then, you should create a build directory

    $  mkdir build
    $  cd build
  

Configuring the build

Now it is time to configure your build. The command is of the form

cmake -DBuildVariable1=Content1 ... -DBuildVariablen=Contentn ..

In general, you should not need to set a lot of variables. A simple

    $ cmake ..
  

should be enough. The possible variables and their default values are listed below.

  • CMAKE_BUILD_TYPE: specify what kind of build you want to do. It is either "release" or "debug". The default is "release".

  • DEBUG: If this variable is 1, the program will act in debug mode, e.g it will coredump if something is wrong. The default is 0 if CMAKE_BUILD_TYPE is release, 1 otherwise.

  • DESTDIR: The destination directory, defaulting to /. This is the root directory where everything will be copied. This can be useful if for example you want to install urpkg on some other filesystem, and then mount it as the root filesystem.
  • CMAKE_INSTALL_PREFIX: The installation prefix, defaulting to /usr/local. All urpkg files will be installed there.
  • DOCDIR: Where all the documentation will be installed. It defaults to ${CMAKE_INSTALL_PREFIX}/share/doc
  • MANDIR: Where the manpage are on the system. Default to ${CMAKE_INSTALL_PREFIX}/share/man
  • PKGDIR: Path to the package directories, where all package user will have their home directory. See the section called “Package directories” for more information. The default is ${CMAKE_INSTALL_PREFIX}/urpkg/
  • CONFIGDIR: Path to the configuration directory, where urpkg keeps its scripts and some information about what is installed (see the section called “The configuration directory”). The default is ${CMAKE_INSTALL_PREFIX}/etc/urpkg/

  • INST_LOG: Where error outputted by the installation script will be logged. By default, /var/tmp/install.log

  • FINDCMD: The script urpkg uses to find the files belonging to a given package. See also the section called “The find script”. You should not change that variable unless you know what you are doing. It defaults to ${CONFIGDIR}/find

  • PREINST: The script urpkg runs before any installation. See also the section called “Pre and post install scripts”. You should not change that variable unless you know what you are doing. It defaults to ${CONFIGDIR}/preinst

  • POSTINST_DIR: Directory where all the scripts urpkg runs after an installation should be. See also the section called “Pre and post install scripts”. You should not change that variable unless you know what you are doing. It defaults to ${CONFIGDIR}/postinst/

  • UADD_PATH, UMOD_PATH, UDEL_PATH, GADD_PATH, GDEL_PATH: Specify the path for respectively useradd, usermod, userdel, groupadd and groupdel. You need to change those only if cmake cannot find them automatically.

Compiling urpkg

Now everything should be ready. Compile the program.

    $ make
  

If you want to compile the documentation as well (if you downloaded a release tarball that should not be necessary, as it has already been compiled to most format for you), run

    $ make doc
  

Installing urpkg

To install urpkg, you have two choices: the first is to directly run

    $ make install
  

with root privileges if necessary. However, if you have read all I said in the section called “How can urpkg be useful ?” about installation programs changing file permissions behind your back, you may not even want to trust the installation commands generated by cmake.

This is perfectly fine. Since you have compiled urpkg, you can use it to install itself in a secure way. The following section lists the necessary steps. I recommend this method only to users already familiar with how urpkg works. If you are doing this often, you should write yourself a script that automates this action. One such script is in helpers/bootstrap.sh in the top level directory of urpkg's source.

Bootstrapping urpkg

In these instructions, I assume you are at urpkg's top level directory and you have already build the software in build/. The shell variable VERSION is assumed to contain urpkg's version number. You can replace it with whatever you like.

First, cd to the build directory.

      $ cd build/
    

For various reasons, you should create the package directory first, as root. Replace PKGDIR in the following instructions with whatever you configured the program with in the section called “Configuring the build”

      $ mkdir ${PKGDIR}
    

You should not forget to create the install and shared group, and then mark places where you want urpkg to be installed as install directories.

      $ groupadd urpkgrp-install
      $ groupadd urpkgrp-shared
      $ src/urpkg --gen ${CMAKE_INSTALL_PREFIX}/bin
      $ src/urpkg --gen $DOCDIR
      $ src/urpkg --gen ${MANDIR}/man*
      $ src/urpkg --gen $(dirname $CONFIGDIR)
    

Then, you have to create a temporary package directory where urpkg will put all files of the urpkg package. You will then copy this temporary package directory to the real package directory (which is created during urpkg's installation).

      $ PKGDIR="$(mktemp -d /var/tmp/urpkg.XXXXXXX)"
    

To avoid any permission problem when the install script tries to create files in the build directory, change its access permissions.

      $ chmod -Rv o+xrw .
    

You are now ready to run urpkg. Be aware though that no find command, no postinstall script and no preinstall script are available so you have to either specify the path explicitly or disable them when you invoke urpkg.

      $ src/urpkg --install --pkg-name=urpkg-$VERSION \
      --findcmd=../scripts/find --pkg-dir=$PKGDIR --no-preinst --no-postinst \
      make install
    

Normally, everything should go fine and urpkg should be installed. Check it by running

      $ urpkg --info
    

You still have to copy the temporary package directory to the real package directory. You can know its location by looking at the output of urpkg --info. I will refer to it as TRUE_PKGDIR

      $ cp -rav ${PKGDIR}/urpkg-$VERSION $TRUE_PKGDIR
    

That's not completely finished. The package user has been created with the temporary package directory as its home directory. To change that, you need to know what the package user is. You can find it using

      $ USERNAME="$(stat --format=%U ${TRUE_PKGDIR}/urpkg-$VERSION)"
    

Finally, change the package user's home directory and remove the temporary package directory

      $ usermod --home ${TRUE_PKGDIR}/urpkg-$VERSION $USERNAME
      $ rm -rv $PKGDIR
    

I leave up to you whether you want the package to own the package directory. I like to keep the package directory owned by root, because even if you remove urpkg from your system, you might want to keep some files from various package directories.

Creating a test package

In order to test urpkg's feature, we are going to create a test package, with some files and an installation command that will try everything it can to mess up with the system. We will then install this package using urpkg, play a little bit with it, and finally uninstall it.

Creating the destination directories

We will create two destination directories. One where the program will be allowed to be installed, and one where it should not write any files. We will create those directories in /usr/urpkg-test, or any other directory you wish (just be sure that it is not listed in the EXCLUDE variable of the find command). We will assume /usr/urpkg-test/ has been chosen.

    $ cd /usr
    $ sudo mkdir urpkg-test
    $ cd urpkg-test
    $ sudo mkdir allowed
    $ sudo mkdir restricted
  

Now we put some files in the two directories. Those files should not be overwritten by our test package.

    $ sudo touch allowed/{file1,file2}
    $ sudo touch restricted/{file1,file2}
  

Creating the source files

Let's name our package foo, and create some files in it.

    $ sudo mkdir foo
    $ sudo touch foo/{foo1,file2}
    $ cd foo
  

Let's say that foo1 is specific to the package foo, while file2 is a more recent version of allowed/file2. So we would like to overwrite allowed/file2 with foo/file2 . The installation command will be given to urpkg in the next chapter.

Adding installation directories and shared files

Once you have installed urpkg, you cannot install a program with it right away. If you try, you will find that files can only be written where everybody has write permission. Concretely, the package foo cannot be installed in allowed or in restricted at the moment. Let's make sure of this.

  $ sudo urpkg --install install -v foo1 ../restricted/.

Should output something like this

  Installing package foo-20080527...
  Preinstall script
  Running install command: install -v foo1 ../restricted/.
  install: cannot create regular file `../restricted/./foo1': Permission denied
  `foo1' -> `../allowed/./foo1'
  *** WARNING: The install command printed something to stderr (see /var/tmp/install.log): 
  install: cannot create regular file `../restricted/./foo1': Permission denied
  *** ERROR ***
  urpkg: Command install with arguments '-v foo1 ../restricted/.' returned non-zero status 1
  Cleaning up...
  Terminating all processes...
  Closing all files...
  Uninstalling uncompletely installed package. PLEASE DO NOT KILL
  Uninstalling package foo-20080527...
  Listing and removing files...
  Removing package user...

What happened was that our package user had no permission to write in ../restricted, so the installation command failed and the program was immediately uninstalled.

To allow programs to be installed in a directory, you need to change the directory's permissions.

Before doing that, you have to create two special groups. They are described in more details in the section called “Package user groups”

  $ sudo groupadd urpkgrp-install
  $ sudo groupadd urpkgrp-shared

Now you can invoke the gen command on the directories in which you want to allow packages to be installed.

  $ sudo urpkg --gen ../allowed

This allows any package user to write in ../allowed. However, existing files in these directories cannot be overwritten or removed by anything else than the package those files belong to. As an example

  $ sudo urpkg --install install -v file2 ../allowed/file2

Will not work. You might simply want to remove ../allowed/file2 and then retry, but what if the installation script needs the content of file2 ? For example, file2 could be an index, and the installation script might just want to append something to the index. The solution to this is to change the permission of file2 to allow it to be overwritten. It will still not be possible to remove it though. This is done using the share command.

  $ sudo urpkg --share ../allowed/file2

Directories where one can install program are referred to as installation directories while regular files that package user can overwrite are called shared files. In a real system, installation directories would for example be /usr/bin/ or /etc. Shared files are rarer but can for example include /usr/share/info/dir, the index of all installed info documentation files.

To make a shared file a normal file, or make an install directory a usual directory, use respectively --unshare and --ungen. If you want to list your shared files, use --list-shared, --list-instdir is used to list installation directories.

Installing a program

We are finally ready to install our foo package. Make sure that ../allowed is an installation directory and that ../allowed/file2 is a shared file. Then run

  $ sudo urpkg --install cp -v foo1 file2 ../allowed/.

The command should terminate without error. The package foo has now been installed and is part of the system. To list all installed packages, do

  $ urpkg --list

Notice that a date string has been happened to foo. In fact, the package name was guessed from the current directory. Had the directory been named foo-1.1, the package name would have been foo-1.1 , as a version string already existed. If you don't want the name to be guessed, you can use --pkg-name to give any name you want.

Playing with the program's files

You can also use --list with the package name as an argument to list all files belonging to a given package.

  $ urpkg --list foo

Notice that there is no need to give the package's full name. An unambiguous name is enough (e.g if there were two versions of foo installed, say foo-1.1 and foo-1.2, then we would have had to be more precise).

You should also see that there is only one file, foo1 that is listed. This is because file2 is a shared file. Now what if you want to add it to the package, so that it is removed if we uninstall foo ?

We first have to strip file2 of its status of shared file. Even though urpkg does not forbid shared files part of a package, it is a bad habit to take. Then we simply use the --add-files action.

  $ sudo urpkg --unshare ../allowed/file2
  $ sudo urpkg --add-files --change-owner --change-group foo ../allowed/file2

The --change-owner and --change-group deserve a more detailed explanation on what it exactly means to add a file to a package. This is presented in the section called “Owned and added files”. For the moment, it is enough to say that unless it is necessary for the file to keep its owner or group (e.g because it's a suid file), then those options should be used.

Another option since version 1.4 is to use the urpkgize script. This script adds a bunch of files to a given package, trying to figure out the correct options for each file on the way. For example, to perform the same action as before you would do:

  $ sudo urpkgize foo ../allowed/file2

In general, you should use --add-files, and take care of the options yourself. urpkgize only comes in handy when you want to add a lot of files to a package. You can find more information on urpkgize in urpkgize(1).

Now let's check that the file has correctly been added

  $ urpkg --list foo

What if you don't want foo1 to be part of the package anymore ? In that case, you should do

  $ sudo urpkg --free-files --change-owner=OWNER --change-group=GROUP foo ../allowed/foo1

You should replace OWNER and GROUP by the owner and group you want the file to have. If those options are not specified, they will both be set to root.

What if you don't remember which package(s) the file file2 belongs to ? Then you can use --find

  $ urpkg --find ../allowed/file2

Pre and post install scripts

You might have remarked by looking at the output of the --install command that some commands are run after the installation, like ldconfig for example. In fact, it is very easy to add scripts to be automatically executed before or after a package's installation.

The preinstall script

The preinstall script should be in ${CONFIGDIR}/preinst, by default /usr/local/etc/urpkg/preinst. The default script that comes with the urpkg tarball does not run any command. It is up to you to change it if you want certain command to be run before any package is installed. Pay attention though, because this script will be invoked with the same privileges you had when you invoked urpkg. They will not be run as the package user. If you want to exclude the preinstall script from being run, you have to use the --no-preinst option.

The postinstall scripts

Every postinstall script should be put in ${CONFIGDIR}/postinst/, by default /usr/local/etc/urpkg/postinst/. Every script here is run after the installation. The scripts are run in an undefined order. By default, ldconfig and a script installing the program's source are run.

The source script is run only if it is passed the source files as an argument. To pass an argument to a postinstall script, use --SCRIPT-arg. For example, if the sources of foo are in a foo.tar.gz file, you would do

    $ sudo urpkg --install --source-arg=foo.tar.gz make install
  

The sources are installed in the package directory, in src/. For a package named foo-1.1 that would be ${PKGDIR}/foo-1.1/src

You can use the --no-postinst option to not run any postinstall script or --exclude-script to exclude a particular one.

Creating a Slackware package

Since version 1.4, it is possible to create a slackware package of whatever program we installed with urpkg. In this section, we are going to create a Slackware package of foo, the test package we are using. To do that, you will need to download and install another of my utilities: list2pkg . This is a tool which converts a list of files to a Slackware package. The idea is to use urpkg's --list action to create a file list to be used by list2pkg.

Note that you should first read list2pkg's user manual before using it to create serious packages. The content of this section is just meant as an overview of list2pkg's possibilities.

Listing the package's file

We already know we can use the --list action to list all files which are part of foo. However, what is outputted does not only contain files, as list2pkg require. We must add the --quiet option for a pure list of files to be generated.

Creating the package

That's all we need. We now only have to use the file listing command, and pipe its output to list2pkg.

    $ urpkg --list --quiet foo | sudo list2pkg foo-0.1-noarch-1usr.tgz
  

Note that we absolutely need to invoke list2pkg with root privilege, in order for all metadata to be preserved.

Uninstalling a program

Finally, it is time to remove foo from the system. It is a good idea to list the files that would be removed before actually removing anything. To do that, you should use the --pretend option.

  $ urpkg --uninstall --pretend foo

Once you have checked that the action the program would take satisfy you, you can uninstall it.

  $ urpkg --uninstall foo

You can check that foo has been correctly removed using

  $ urpkg --list

Chapter 3. How urpkg works

Introduction

This chapter details the concept behind urpkg and you should read it if you want to know exactly what is being done to your system e.g when you install a package. It also provides useful hint in the terminology that is used in this manual. Last but not least once you understand how things are done you will be better prepared to deal with the problems you might encounter when you install a program.

Package user and package name

There is an importance distinction to make between a package name and a package user. As already mentioned, urpkg creates a new user for each program (urpkg calls them package) you install. The files that are then created all have the new user as owner and can therefore easily be found.

Generating a username

However, urpkg first has to come up with a name for this user. The name should conform to the syntax of a username (e.g, no dot in the name) and should not be the same as other users in the system. One could simply come up with a unique number as username, however that would be really confusing and not really helpful e.g to someone listing a file belonging to that package.

The solution that urpkg uses is the following. We ask the user for, or guess, a package name that is basically the name of the program we are installing. This name can syntactically be anything the user wants. Then, from that name we generate a package user name. The package name is kept in the comment field of the user name in /etc/passwd.

The package user name always begins with urpkg-. This is a prefix to avoid that the name collides with another user of the system. Urpkg then generates the rest of the username using the beginning of the package name, and adding some numbers if necessary. You should look at the source if you want more details on the exact algorithm which is used. Special characters in the package name are replaced by _. For example, from a package name emacs-22, the package user could be urpkg-emacs-22. You shouldn't rely on this, however, as the algorithm used by urpkg to generate user names can change at any release without notice !

Note that package names (and package users) are always all in lowercase letters. Even if you give your name explicitly, the case does not matter and your name will automatically be converted to lowercase. For example, running

    $ urpkg --install --pkg-name=Emacs-22 make install
  

Will still create a package name emacs-22 and a package user urpkg-emacs-22.

Finding the package user owning a file

In general, you don't have to worry about package users, but it's good to know about them, as you can still see them mentioned from time to time. For example, assuming you really have emacs installed as a package named emacs-22, doing

    $ ls -l $(which emacs)
    -rwxr-xr-t 2 urpkg-emacs-22 urpkg-emacs-22 13576490 2008-03-21 17:59 /usr/bin/emacs
  

will really give you the package user name of the package the file /usr/bin/emacs belongs to.

Finding a package name

As you learned in the previous chapter, you can specify a package name explicitly using --pkg-name. Urpkg can also guess a package name for you from the current directory. Now how does it do it ?

Urpkg will simply take the basename of your current directory (i.e if your current directory is /var/tmp/emacs-22.1, the basename is emacs-22.1). It will then check if it has a version string. A version string is defined as anything following a dash (-). In our example, there is a version string so the package name would be emacs-22.1. If there is no version string, urpkg will append one with the date in the following format: YYYYmmdd. For example, if you are developing your own program, foo which is in a directory /var/tmp/foo, then if you install it on June, 30th 2010 the package name will be foo-20100630.

Of course, there cannot be two package with the same name installed on the system, so urpkg will signal an error if you try to give a package name which is already the name of an existing package.

Installation groups and file permissions

The sticky bit

Now that we have created a user for the package, we still have to decide where it has permission to write. This is done, as seen previously, using the --gen option. Ideally, we would like the package not to be able to overwrite other package files in the install directories, nor remove them. There is a permission bit on UNIX systems that achieve just that: the sticky bit.

The sticky bit prevents unprivileged user (i.e the package user in our case) from changing or removing a file that they don't own. It is typically used in directories like /tmp, where everyone has write access.

The idea is that you are going to give write access in the install directory to all package users, but since the sticky bit is on, they won't be able to damage files from other packages.

Package user groups

How do we give write access to all package users ? In short, we put every package user in a given group, called the install group, as they are created. When --gen is invoked, all urpkg do is to change the directory's group to this install group, enable write access for this group and turn on the sticky bit.

Something similar happens for shared files, although we don't need the sticky bit here, and a different group is used: the shared group.

The install group is urpkgrp-install and the shared group is urpkgrp-group. Every package user is a member of those groups once it is created. This means it is possible for any package to write to a shared file or put files in an installation directory. Keep this in mind when you make a file shared for example.

Owner and group of a package's file

As we have already seen, all files created by a package user have by default its name as owner and its group as group. Why do we need to have both ? In fact we don't, for simple cases. As a matter of fact, urpkg will consider any file that has the package user as its owner or as its group. The nice thing about this is that you can easily change the owner or group of any file of the package.

For example, suppose you are installing the sudo program. It obviously needs to be suid root by the very nature of the task it performs. In that case, you can just change its owner to root and set the suid bit as usual. The file will still be detected as belonging to the sudo package since its group still has the package user name of sudo.

Sometimes it may happen that both the group and the owner have to be changed. This is the case for some daemon that uses both the suid and the sgid bit. Fcron is an example of this. In that case, you can still force the file to belong to the package using --add without any --change-owner or --change-group option. The file name will then be added to a text file containing a list of supplementary files belonging to fcron. The disadvantage here is that you cannot move or remove the file without having urpkg complaining, so don't do it unless you really have to. More details are given in the section called “Owned and added files”

Package directories

Every user on a UNIX system has a home directory. The question is, where do we put a package user's home directory, and what do we do with it ?

Urpkg deals with this problem the following way. A root package directory is created (by default /usr/local/urpkg) where each package has its home directory, named like the package name. For example, the package emacs-22.1 would have a home directory at /usr/local/urpkg/emacs-22.1. Users can put anything they want in the home directory. It is typically used for putting the program's source.

Urpkg stores some metadata concerning the package (for the moment only the files that belong to the package but whose owner or group have not been changed) in a subdirectory .urpkg of the package's home directory. This directory should not be modified by the human user.

It is possible to give another package directory root when installing the package, using the --pkg-dir option.

The configuration directory

Urpkg's configuration directory is kept by default in /usr/local/etc/urpkg. This is where all the files urpkg needs to run correctly are stored. Those are mostly shell scripts that you can change to fit your needs. They are documented here. Pay attention: they are invoked with the privileges that were used to invoke urpkg.

The find script

This is the script urpkg uses to find files whose owner or group is a given package user. It is also used to list install directories or shared files. It takes one argument: a user or group name. It should print the list of files in the system that are owned by this user or group, excluding the package's home directory

By default, a few locations such as /tmp or /mnt, or the package home directory are excluded from the search. They are given in the EXCLUDE variable at the beginning of the script. Please check that they match your expectation.

The preinstall script

It is run before any installation. It takes no argument, and by default does nothing but printing a line or two to confirm it was executed.

The postinstall scripts

All files in the directory postinst relative to the configuration directory will be run after the installation. Each can be passed exactly one argument using the --SCRIPT-arg option.

  • The complog script will install a compilation log in the package's home directory. The file must be named svcompile.log, or you must pass it as argument. If no such file exist, nothing will be done.

  • The ldconfig script will only run the ldconfig command and exit.

  • The source script will install the source file/directory, given as its argument in a subdirectory src/ of the package directory.

Environment variables

If you decide to write your own scripts, you can count on several environment variables to help you:

  • URPKG_USER: gives the package username

  • URPKG_PKGNAME: gives the package name

  • URPKG_HOMEDIR: gives the package directory

  • PWD is set to the directory from which urpkg was invoked.

Owned and added files

What do I exactly mean when I say that a file belongs to a package ? Can a file belong to more than one package ? What exactly gets uninstalled or listed then ? This section tries to answer those questions.

Which file belong to a package ?

Urpkg considers a file as belonging to a given package if one of the two conditions below is satisfied.

  1. The file has the package user as owner or group

  2. The file is listed in ${HOMEDIR}/.urpkg/added, where HOMEDIR is the path to the package's home directory.

Given this definition, it is easy to see that a file can belong to more than one package. For example, it could have a given package user as its owner , another as its group, and be listed in the added list of a third package. Most of the time though, a file will be only part of one package and you should really keep it that way.

If you use the --find command, urpkg will list you all packages the given file belongs to.

What gets removed or listed ?

When you use the --list action, urpkg will list you the files that are unique to the given package, and the files that are shared with other packages. Only the former category will be deleted when you uninstall the package. Keep in mind that you can always use --pretend to know for sure what would be removed.

What about directories ?

First, urpkg will never remove a directory that does not belong to the package you want to uninstall, even if it is empty. Second, a directory that belongs to the package you are considering must be empty (after you deleted all the other files in it belonging to the package) to be deleted. This prevents other files from other packages that are in the directory to be deleted as well. This can happen if, for example you temporarily set a directory as an install directory and then revert it to belong to the given package.

Urpkg will take no risk and only warn you that the directory is not empty. The uninstallation will not fail just because of that. You will have to remove those directories manually. If you are careful the way you manage your system, this should only happen rarely.

Chapter 4. Using urpkg

Manpages

This section contains the manpages of the commands part of urpkg.

Name

urpkg — Install programs in a safe and undoable way

Synopsis

urpkg {ACTION} [OPTIONS] [ARGUMENTS]

Description

Urpkg is a software to install programs so that we can easily uninstall them afterward. It does so by creating a new user for each package that gets installed on the system. The package is then installed with this user's privileges instead of root's. This guarantees a much better security during installation.

Note that this manpage is only a short reference. You should read the user manual (published on urpkg's homepage) if you want to know more about urpkg.

When invoking urpkg, you must always specify exactly one action first. You can then give options and arguments if required.

Actions

-h, --help

Print a short description of each option and exit.

-v, --version

Output information about the program's version and exit.

-I, --info

Output some information on the settings urpkg was compiled with and exit.

-i, --install

Install a package by running the command given as argument.

-u, --uninstall

Uninstall the package(s) whose name(s) are given as argument.

-l, --list

Without argument, list all installed packages on the system. Otherwise, list all files part of the package(s) that are given.

-W, --list-instdir

List all the installation directories that are in the path(s) specified as argument. If no path is given, / is assumed.

-L, --list-shared

Same as --list-instdir but for shared directories.

-a, --add-files

Add some files to a package, without changing their owner or group unless the --change-owner and/or --change-group options are given. The package name must be the first argument, then the files should follow

-T, --free-files

Remove some files from a given package i.e urpkg will not remove those files if we remove the package. The files are of course not removed from the filesystem.

-g, --gen

Make the given directories to install directories (i.e place where package can install files).

-w, --ungen

Make the given install directories normal directories again.

-s, --share

Make the given files shared files (i.e files packages can write to)

-S, --unshare

Make the given shared files ordinary file again.

-f, --find

Find which package the given files belong to.

Global Options

Global options can be used with any action

-D, --debug

Print debugging information to stderr. Implies --verbose

-V, --verbose

Print more details on what urpkg is doing to stdout.

-q, --quiet

Only print warnings, errors, and what the user asks for.

Install Options

-p, --pretend

Print what would have been done but do not install the package.

-P, --no-preinst

Don't run the preinstall script.

-G, --no-postinst

Don't run any postinstall scripts

-e, --exclude-script=NAME

Do not run the postinstall script NAME, where NAME is the beginning of the script's name such that it can be recognized unambiguously.

--NAME-arg=A

Pass the argument A to the postinstall script NAME.

-H, --pkg-dir=PATH

Use PATH/NAME as the package's home directory, where NAME is the package's name (guessed or given explicitly using --pkg-name).

-n, --pkg-name=NAME

Explicitly specify the package's name. Otherwise, urpkg will try to guess it from the current directory.

-F, --findcmd=SCRIPT

Give a custom script to be used to find files part of a given package.

Uninstall Options

List Options

List-instdir Options

List-instdir Options

Add-files Options

-U, --change-owner

Change the file's owner (set it to the package user). By default, the file's owner is not changed.

-d, --change-group

Change the file's group (set it to the package user). By default, the file's group is not changed.

Free-files Options

-U, --change-owner=USER

Restore the file's owner to USER. By default, the program will set it to root.

-d, --change-group=GROUP

Restore the file's group to GROUP. By default, the program will set it to root.

Ungen and Unshare Options

-d, --change-group=GROUP

See the section called “Free-files Options”

-m, --change-perm=PERM

Change the files access permission to PERM (given in octal form). If not given, urpkg will try to set the permissions to a reasonable default.

See Also

urpkgize(1)

Contributing

Please report bugs and other inconsistencies you find to the author (address is below). If you have implemented a patch, please do send it there. Any contribution is welcome. See also urpkg's website: http://svasey.org/projects/urpkg/

Unrestrictions

Urpkg is public-domain software. See the COPYING file for more information.

Author

The author is Sebastien Vasey (sebastien dot vasey at gmail dot com)


Name

urpkgize — Add a bunch of file to an existing urpkg package

Synopsis

urpkgize [OPTIONS] {PKGNAME} {FILES}

Description

Urpkgize is a small script to add files to an existing urpkg package. For each file, it tries to invoke urpkg with the correct options so that the file is added cleanly. It is especially useful when you have a lot of files to add and don't want to figure out the options for each one.

How it works

There are three ways urpkg can add a file to a package. It can change the file's owner to the package username, it can change the file's group to the package username or it can add the file to a list of all files belonging to the package. It is usually better to change the file's owner or group (often, both are changed), since the information is then embedded in the file itself. However, this is not always possible as sometimes the file's owner matters (e.g because the file is set user id). Urpkgize tries to keep it simple and adopts the following rules concerning how a file is added to a package.

First of all, if the file is set user id or set group id, urpkgize will not change respectively the owner or the group of the file. Otherwise, urpkgize will consider its list of "neutral" user and group name. A neutral name is one that can be overwritten without problem. By default, only root is in this list, since most system-wide files have the root owner. You can use the --neutral family of options to add other user/group names to that list, or the --no-neutral-root option to remove root from the neutral list.

If a file owner or group name is considered neutral, then it will be changed to the package username to add the file to the package. Otherwise, urpkgize will not modify it. In the end, if neither the owner, nor the group of a file can be changed, then the file will be added to the list of all files belonging to the given package.

Options

Note that each option can be abbreviated and will be recognized if unambiguous.

--help

Print a short description of each option and exit.

--neutral=NAMES

Specify group and owner names that are not considered important and that can be replaced by the package user name (except if the file is set user id or set group id). Each value should be comma-separated. By default, only root is in this list.

--neutral-owners=NAMES

Same as --neutral but concerns only owner names.

--neutral-groups=NAMES

Same as --neutral but concerns only group names.

--no-neutral-root

If this is given, then root will not be in the list of neutral owner and group names anymore.

See Also

urpkg(1)

Contributing

Please report bugs and other inconsistencies you find to the author (address is below). If you have implemented a patch, please do send it there. Any contribution is welcome. See also urpkg's website: http://svasey.org/projects/urpkg/

Unrestrictions

Urpkgize is public-domain software. See the COPYING file for more information.

Author

The author is Sebastien Vasey (sebastien dot vasey at gmail dot com)

Common problems

Urpkg is enforcing a lot of restrictions on the installation script it runs, compared to a "classical" installation with root privileges. Since a lot of installation programs were not written to deal with an unprivileged installation, problems involving permission denied errors can and will occur occasionally. You can usually find the installation command's error message in urpkg's installation log file (by default in /var/tmp/install.log). You should always read that file after an installation, successful or not.

Those errors are not considered bugs in urpkg, as they are due to the installation command. However, you should know how to deal with them as they occur pretty often when installing large software. In the LFS package user hint, the author suggests using special versions of commonly used programs, like install, modified to catch possible errors and arrange for the installation scripts to use them. In my opinion, this is not general enough, so this has not been implemented in urpkg (you could try to do it using the preinstall script though). If you have ideas on how to solve the problems described in this section, please share them. See Chapter 5, Contributing to urpkg.

Programs writing in the current directory

Problem

Sometimes the installation command needs write access to the current directory. This is often due to libtool wanting to relink some libraries at installation time. Sometimes also the installation program wants to use some log file or touch some temporary file.

Most of the time, the package user does not have write access to the build directory. What you usually do is to extract the tarball as a normal user, cd to it and begin to build. In that case, the default permission of the current, build directory should be something like 0755. Therefore the package user does not have write access.

Solution

You should definitely arrange for the current directory to be world writable. A quick and dirty way to do that is

      $ chmod o+w .
    

If that is not enough (sometimes the installation script needs write access to other existing files for example), you could just go with

      $ chmod -R o+w .
    

Programs writing to non-install directories

Problem

The installation program wants to write somewhere it is not allowed to.

Solution

If you want to allow the program to write there, just use --gen to make the location an install directory.

If you don't want the program to write there, then you have a bit more work to do. Maybe you made a mistake specifying the destination paths at configure time (e.g you gave the /usr/local prefix instead of /usr). Sometimes the program just wants to install some locales and in that case you just have to create the destination directories, make them installation directories and run the install command again. As a last resort, you can consider going into the Makefile (or whatever installation script you are using) and changing the lines that cause problems. You can then complain to the program's maintainer about this unexpected behavior.

Unwanted permission/ownership changes

Problem

The installation program wants to change the permission of some directories like /usr or /usr/bin, e.g to 0755 while they are install directories. It can also happen that it wants to change their owner and group to root.

The installation program could also want to change the ownership of some of its executable to root, or some other user.

Solution

The permission / ownership change of install directories is due to poorly written installation script. The command that causes this is usually something like

      $ install -d /usr/bin
    

If the directory already exists, its permissions will be changed to 0755 which is typically not wanted in our case. A command like

      $ install -d --owner=root --group=root /usr/bin
    

is even worse since it does not take into account the possibility of installation in a user's home directory for example. In both cases, the solution is simple: remove those commands from the offending Makefile / installation script and complain to the maintainer.

If the installation program tries to change the ownership of its own executable, this is also unwanted except if the executable are suid or sgid. In any case, you cannot allow this change to happen so just remove the offending lines from the Makefile and change the ownership and / or permissions of the files afterward if you really want to.

Regarding suid and sgid programs, you should never use the package user as a user or group for a suid or sgid file. The reason for this is that package user still have more privileges than ordinary user, and should not be used for anything else but installing packages.

Overwritten or deleted files

Problem

Some installation program sometimes try to overwrite files from another package, or even delete them so that they can be replaced with the new versions the installation program provides. Since urpkg does not allow them to overwrite files, the installation command fails.

Solution

The solution depends on what the installation command intends to do with the files. If they are e.g index files, like /usr/share/info then you can consider making them shared files using --share. If you don't want your old files to be erased, just copy them somewhere and copy them back after the installation. If you want your old files to be erased, just remove them or move them somewhere else.

In the end, make sure to check what packages the files you moved around belong to. Don't hesitate to use the --free-files and --add-files options to move files to a different package.

Ldconfig

Problem

Some install script run ldconfig. Since they don't have permission to write to /etc/ld.so.cache, this command fails

Solution

Most script won't fail just because ldconfig fails. In any case, ldconfig will be run automatically afterward by a postinstall script.

Bugs

Urpkg is far from perfect. Here is a list of bugs that are known and should be fixed in a subsequent release. If you want to help, see Chapter 5, Contributing to urpkg

  • Urpkg does not support users or groups of more than 127 characters. If you have any user or group with 128 characters or more on your system, consider changing their name or changing UGRP_RE_MAX_LENGTH in src/ugrp.h to fit your maximum size.

Todo

This section lists some tasks that haven't been done and might show up in a future release. They are only at the stage of random ideas. If you want to implement one of them, please see Chapter 5, Contributing to urpkg

  • Implement a better system of package group so that some packages are allowed to write to some file but others are not (e.g if they are part of urpkgrp-emacs they can write into /usr/share/emacs but otherwise it is not possible).

  • Write scripts to create binary packages for various distributions

  • Write the find script in C and integrate it better with urpkg.

  • Write some tests so that we can make sure urpkg works more or less before releasing a new version.

FAQ

Don't hesitate to ask questions. See Chapter 5, Contributing to urpkg

Chapter 5. Contributing to urpkg

There are several ways you can contribute to urpkg. One way is to report bugs, another way is to help writing documentation (or correct the existing one. I think there is already a fair number of English mistakes in that document :-) ). You could also try writing patches implementing the features you want that are not yet in urpkg. Also, simply asking questions (that are not answered within this manual) is a great way to participate.

Whatever you decide to do, please send the content to sebastien dot vasey at gmail dot com

Urpkg also has a webpage. See the urpkg webpage for the most up to date information.

Reporting bugs

So you have found a bug ? Great ! Please report it to me. But before doing that, ensure that...

  • The bug still exists in the latest version of urpkg

  • You are able to reproduce the bug.

When you report a bug, you should always, if possible

  • Include information on how to reproduce the bug

  • Include as verbose as possible output from your program. This means running urpkg with the --debug switch if possible.

  • Include the versions of urpkg on which the bug applies (use --version).

  • Include the output of urpkg --info