Building an RPM

This section describes the process for building an RPM - step by step.

  1. Choose a name and version number for your package. We are going to package the complete loggerdemo example and will use loggerdemo and 1.0.0 as the name and version number.

  2. Collect all of the files which have been created in the previous sections into the /tmp/ directory. There is one additional file createlinks which looks like this:

    #!/usr/bin/perl -w
    use esmith::Build::CreateLinks qw(:all);
    use File::Basename;
    my $panel = "manager";
    panel_link("loggerdemo", $panel);
  3. Create the directory hierarchy required for building the RPM. This is very close to the hierarchy on the installed system.

    # Change to the SOURCES directory
    cd ~/rpms/SOURCES
    # Remove old files (check that you don't need anything here!)
    rm -rf loggerdemo-1.0.0
    # Create new directory
    mkdir loggerdemo-1.0.0
    cd loggerdemo-1.0.0
    # The crontab template fragment
    mkdir -p root/etc/e-smith/templates/etc/crontab
    cp /tmp/25templatedemo root/etc/e-smith/templates/etc/crontab
    # The web panel description
    mkdir -p root/etc/e-smith/web/functions
    cp -p /tmp/loggerdemo !$
    # The web panel implementation
    mkdir -p root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel
    cp -p /tmp/ !$
    # The web panel English localisation
    mkdir -p root/etc/e-smith/locale/en-us/etc/e-smith/web/functions
    cp -p /tmp/loggerdemo-en !$
    # The createlinks auxiliary file
    cp -p /tmp/createlinks .

    Your directory structure should now look like this:

    [gordonr@sevendev1 loggerdemo-1.0.0]$ find . -type f
  4. Package the directory into a tarball:

    cd ~/rpms/SOURCES
    tar zcvf loggerdemo-1.0.0.tar.gz loggerdemo-1.0.0
  5. Create the RPM specification "SPEC" file ~/rpms/SPECS/loggerdemo.spec which looks like this:

%define name loggerdemo
    %define version 1.0.0
    %define release 01
    Summary: SME Server logger demo
    Name: %{name}
    Version: %{version}
    Release: %{release}
    License: GPL
    Group: Networking/Daemons
    Source: %{name}-%{version}.tar.gz
    Packager: Fred Frog <>
    BuildRoot: /var/tmp/%{name}-%{version}-%{release}-buildroot
    BuildArchitectures: noarch
    Logger Demo sample application.
    * Thu Feb 2 2006 Fred Frog <>
    - 1.0.0-01
    - Original version
    perl createlinks
    mkdir -p $DEFAULTS
    echo "service"  > $DEFAULTS/type
    echo "enabled"  > $DEFAULTS/status
    echo "10"       > $DEFAULTS/Interval
    rm -rf $RPM_BUILD_ROOT
    (cd root ; find . -depth -print | cpio -dump $RPM_BUILD_ROOT)
    rm -f %{name}-%{version}-filelist
    /sbin/e-smith/genfilelist $RPM_BUILD_ROOT > %{name}-%{version}-filelist
    rm -rf $RPM_BUILD_ROOT
    /sbin/e-smith/expand-template /etc/crontab
    /sbin/e-smith/expand-template /etc/crontab
    %files -f %{name}-%{version}-filelist

    Note the %post (post-installation) and %postun (post-uninstallation) statements which expand the /etc/crontab template after installing or uninstalling the RPM.

  6. Check that your RPM will build OK with "build prepare":

    cd ~/rpms/SPECS
    rpmbuild -bp loggerdemo.spec

    The last line of output should be + exit 0 if rpmbuild is successful.

  7. Run the rpmbuild command again to actually create your RPM with the "build all" options:

    rpmbuild -ba loggerdemo.spec

    If everything was successful, the last line of output should again be + exit 0.

  8. The RPMs should have been generated and put into ~/rpms/RPMS/noarch/ as this program can run equally well on any platform. A source RPM should also exist in ~/rpms/SRPMS/.

  9. Test your RPM by installing it on an SME Server test box.

    Note: RPMs need to be installed as root, but you should not log in as the root user. Instead, you should create a normal user and provide them with 'root' privileges via the sudo command. To provide full sudo rights to the user joe, use the su - -c /usr/sbin/visudo and add the following line to the end of the file:

    joe    ALL=(ALL) ALL

    You can then use the sudo to run commands as root when required. You will be prompted for your password (not the root password) which ensures that someone else isn't using your terminal.

    [joe@sevendev1 SPECS]$ sudo rpm -Uvh \
    Preparing...                ########################################### [100%]
       1:loggerdemo             ########################################### [100%]
    Migrating existing database mailpatterns
    Migrating existing database hosts
    Migrating existing database configuration
    Migrating existing database yum_repositories
    Migrating existing database networks
    Migrating existing database yum_updates
    Migrating existing database yum_installed
    Migrating existing database spamassassin
    Migrating existing database accounts
    Migrating existing database backups
    Migrating existing database yum_available
    Migrating existing database domains

    Note: In almost all instances you should use the -U (upgrade) option to rpm instead of the -i (install) option. The -i option should be reserved for special operations, such as installing kernels.

    The customization should be fully installed, and the /etc/crontab file should show the customization. Then remove the customization:

    # remove the RPM
    sudo rpm -e loggerdemo

    The customization should be completely gone, and the /etc/crontab file should look the way it did before.

The createlinks script

The source tarballs of an RPM should not include symbolic links as they are difficult to store under many version control systems and cause issues when generating patches. Since the SME Server uses many symbolic links, there are simple methods for creating the ones required. This is done through the createlinks script which is called from the %build section of the SPEC file. Let's examine one. It starts with the standard Perl script header and an import of the required module:

#!/usr/bin/perl -w

use esmith::Build::CreateLinks qw(:all);

The templates2events function can be used to create the appropriate templates2expand links in various events:

my $imap  = "/var/service/imap";
my $imaps = "/var/service/imaps";

templates2events("/etc/dovecot.conf", qw(bootstrap-console-save console-save));
templates2events("$imap/config",      qw(bootstrap-console-save email-update));
templates2events("$imaps/config",     qw(bootstrap-console-save email-update));

Note that the first argument is a filename and the second argument is a list of events in which to create the link. The safe_symlink function can be used to create a generic symbolic link, as well as the directory hierarchy enclosing that link:

for my $event (qw(
    safe_symlink("sigusr1", "root/etc/e-smith/events/$event/services2adjust/imap");

safe_symlink("daemontools", "root/etc/rc.d/init.d/imap");

The event_link function is used to create the links from the event directories to the generic actions directory. For example:

for my $event (qw(post-upgrade))
    event_link("imap-relocate-maildirs", $event, "05");

creates a symbolic link S05imap-relocate-maildirs in the post-upgrade event. The target of the symbolic link will be the imap-relocate-maildirs script in the /etc/e-smith/events/actions/ directory.

Finally, the service_link_enhanced function makes it simple to create the /etc/rc.d/rc7.d and similar startup symlinks:

service_link_enhanced("imap", "S55", "7");
service_link_enhanced("imap", "K45", "6");
service_link_enhanced("imap", "K45", "0");
service_link_enhanced("imap", "K45", "1");

More documentation on this module can be seen with the command perldoc esmith::Build::CreateLinks.