Home Wiki > openSUSE:Packaging checks
Sign up | Login

openSUSE:Packaging checks

tagline: From openSUSE

To maintain quality and consistency a set of automated checks help catching common packaging errors or enforce packaging policy during package build.

Contents

Overview

There are three methods of how automated packaging checks are invoked:

brp-check-suse
build root policy scripts are invoked by rpmbuild after %install, just before generating the actual binary packages. They have access to the package's build root. They are mostly useful to modify files in there, e.g. to compress man pages.
post-build-checks
run by the build script as root. Such scripts have access to the installation in the virtual machine and to properties of the build system. They may alter the installation or build result.
rpmlint
run by the build script as unprivileged user. Rpmlint checks one package a time. Packagers may suppress false positives via per package config file.

post-build-checks and brp-scripts

Due to its flexibility, rpmlint is the preferred method for checking packages. If possible, new checks should be implemented in rpmlint and old ones should be ported to rpmlint. The following subsections offers some help with non-rpmlint issues, while all subsequent chapters of this article relate to rpmlint. More details (often Fedora-specific) can be found in the old-en wiki.

Disable post-build-checks

BuildRequires:	-post-build-checks

Beware of Rpath

Sometimes, code will hardcode specific library paths when linking binaries (using the -rpath or -R flag). This is commonly referred to as an rpath, and in Fedora it is forbidden. Normally, the dynamic linker and loader (ld.so) resolve the executable's dependencies on shared libraries and load what is required. However, when -rpath or -R is used, the location information is then hardcoded into the binary and is examined by ld.so in the beginning of the execution.

OBS runs /usr/lib/rpm/brp-rpath (and several other brp-* scripts) after your %install section is done. RPATH checks can be disabled by adding

export NO_BRP_CHECK_RPATH true

to the end of your %install section. When brp-rpath is run, you might see output like this:

ERROR: RPATH "/usr/Mod/PartDesign" on /home/abuild/rpmbuild/BUILDROOT/freecad-0.13rc.svn5443-20.1.i386/usr/Mod/PartDesign/PartDesign.so is not allowed


Often, rpath is used because a binary is looking for libraries in a non-standard location (standard locations are /lib, /usr/lib, /lib64, /usr/lib64). If you are storing a library in a non-standard location (e.g. /usr/lib/foo/), you should include a custom config file in /etc/ld.so.conf.d/. For example, if I was putting 32 bit libraries of libfoo in /usr/lib/foo, I would want to make a file called "foo32.conf" in /etc/ld.so.conf.d/, which contained the following:

/usr/lib/foo

Make sure that you also make a 64bit version of this file (e.g. foo64.conf) as well (unless the package is disabled for 64bit architectures, of course).

Removing Rpath

There are several different ways to fix the rpath issue:

  • If the application uses configure, try passing the --disable-rpath flag to configure.
  • If the application uses a local copy of libtool, add the following lines to the spec after %configure:
%configure
sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool
sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
  • Sometimes, the code/Makefiles can be patched to remove the -rpath or -R flag from being called. This is not always easy or sane to do, however.
  • As a last resort, openSUSE and Fedora have a package called chrpath. When this package is installed, you can run chrpath --delete on the files which contain rpaths. So, in our earlier example, we'd run:
chrpath --delete $RPM_BUILD_ROOT/usr/Mod/PartDesign

Make sure that you remember to add a BuildRequires: chrpath if you end up using this method.

Building Packages despite of errors

It is only possible to suppress or disarm errors triggered by rpmlint but not those triggered by post-build-checks or brp-check-suse. There is no way to filter individual errors from those methods. You need to BuildIgnore those package if you really need to temporarily avoid the checks until a proper solution is found

rpmlint knows three kinds of results: information, warning and error. Not every error is severe enough to cause build failures though. Therefore a badness score is assigned to some errors. The score accumulates among packages in one build run. Only if the score surpasses a certain threshold the build fails.

rpmlint is not always right so it may make sense to suppress certain error messages or to reduce the badness score. For this purpose a package may contain a package specific config file with commands that override the global settings.

For that to work, add a file named %name-rpmlintrc to your sources and list it in the spec file.

Example:

[...]
Source5:  perl-rpmlintrc
[...]

Suppressing False Positives

Use this method only for false positives (if in doubt consult the mailinglists). To disarm errors about distribution packaging policy violations use the method described in the next section


The addFilter command can be used to filter error messages with a regular expression.

addFilter("perl.* devel-file-in-non-devel-package")

This example filters suppresses any hits of the warning named devel-file-in-non-devel-package when the (sub-)package name is perl. In general, you should write the check to be as specific as possible and as unspecific as needed. So, in order to suppress only a hit about one particular file, you should write something like

addFilter("spurious-executable-perm .*/usr/share/doc/packages/cups/PrintAnalyzer")

In general, you can use any valid Perl/Python regular expression for filtering, and it will match it directly on the line of text as it was printed by rpmlint.

As this suppression file is however not part of the binary package. Running rpmlint manually on the resulting rpm will again print even the suppressed warnings. This is by intention. If there is a systematic rpmlint warning that should be removed in general, please file a bug report.

Certain errors, such as violations of security policy are not allowed to be filtered for packages in openSUSE Factory


Disarming Fatal Errors

Some checks, such as security checks have such a high badness score that a single occurence already fails the build. Packages that are not intended for inclusion in openSUSE may want to turn such fatal errors into warnings. To do that use the 'setBadness' comand.

For example to allow building a package that includes an unauthorized permissions file add the following line:

setBadness('permissions-unauthorized-file', 0)


rpmlint checks in openSUSE

arch-dependent-file-in-usr-share

This package installs an ELF binary in the /usr/share hierarchy, which is reserved for architecture-independent files. Binaries that are only usable on a certain architecture (e.g. compiled C code), should be installed under %libexecdir/packagename.

As an exception for certain packages, this check tries to avoid a warning if the path is architecture-specific, like for example /usr/share/tetex/bin/linux/x86/tetex. The use of this exception is however not recommended.

wrong-script-interpreter

This script uses an incorrect interpreter in its shebang. the script interpreter should be a full path to a packaged interpreter, which means it should not point to /usr/local/bin for example.

arch-independent-package-contains-binary-or-object

Your package has been marked as noarch, but contains a binary that is architecture-specific.

library-without-ldconfig-postin

The package installs a library, but does not call ldconfig in its %post section. without an updated ldconfig cache, the library cannot be used reliably. This is a frequent problem during installation, because following packages might require the library in their %post script.

file-contains-buildroot

A string in the file is an exact match to the build root. The package files should not include such details about package creation.

files-duplicate

The package contains some files duplicate, which wastes installation space and package size. Consider using the %fdupes macro.

summary-not-capitalized

Package summaries should start with a capital letter, but should not end with a dot (.).

executable-docs

Documentation under %docdir contains executable files. Documentation should not be executable.

spurious-executable-perm

Files that are likely not supposed to be executable are marked as such. This can be subject of false positives, so carefully review if those are correct or if not, suppress them.

devel-file-in-non-devel-package

The package contains content that should be in a -devel subpackage. The advantage of cleaning your package up and splitting it properly into a -devel package is twofold:

  1. it will keep installation size for customers/users who do not compile source on their own small
  2. it will allow you to add proper build dependencies to the -devel subpackage as required, which makes life of your customer easier: In order to install the -devel package, s/he also has to install all the tools that are commonly required for this package, making troubleshooting a lot easier for them.

There a several subchecks that could cause this check to be triggered.

  • A header file under /usr/include. It detects files ending in .h and a couple of other extensions as header files
  • A .so symlink in %libdir that points to a versioned so file. Usually, those files are only needed during building. However, there can be the exception that the application tries to dlopen(3) the library for some reason, so there might be valid reasons for not splitting the .so file into a subpackage. However, this should be a rare event.

In most cases however, the error is triggered because of versioned libtool modules. Plugins should be built with -avoid-version and -module parameters in LDFLAGS, which will avoid triggering this check as well.

If, for example, the sole purpose of your the particular shared library is to be a plugin that is loaded by some other application (a good indication for this is that it is installed not directly in %libdir, but a subdirectory of it, and this subdirectory is not in /etc/ld.so.conf path), then you should validate the LDFLAGS that were used for building this module, and make sure that -module and -avoid-version were in it. To apply versioning, the subdirectory the plugins are installed to should be versioned instead.

wrong-file-end-of-line-encoding

Some of the files have DOS-style (CRLF) line ending. Under certain circumstances, this can cause incompatibilities with viewer applications. The check is scored very low, so you might just not care about it. If you care, you should try recoding the files in question to Unix-style LF only.

You must not use dos2unix in iso mode, because that not only changes CRLF to LF, but also changes the encoding from CP437 to ISO-8859-1. Use one of

  • dos2unix -c ascii file
  • perl -i -pe 's/\r\n/\n/gs' file
  • sed -i 's/\r$//' file
  • sed -i 's/\r//' file (this is inaccurate and may kill '\r's that do not precede a '\n'.)

in the %prep section. (Other sections may also be ok, for example, if packaging content only that is extracted in %install.)

wrong-script-end-of-line-encoding

E: foo-package wrong-script-end-of-line-encoding /var/www/foo-package/plugins/foo.php

This script has wrong end-of-line encoding, usually caused by creation or modification on a non-Unix system. It will prevent its execution. Solution: Create files on Linux only. Do not create files on non-Unix environment and add it in package.

hardlink-across-partition

Your package contains two files that are apparently hardlinked and that are likely on different partitions. Installation of such an RPM will fail due to RPM being unable to unpack the hardlink, if the files that are hardlinked are ending up on two different physical partitions. By policy, do not hardlink across the first two levels of a path, e.g. between /srv/ftp and /srv/www or /etc and /usr.

invalid-spec-name

The specfile should be name %name.spec.

no-packager-tag

The spec file does not contain a "Packager" tag. (Annotation: A specfile should never include this, because it will confuse the hell out of people when someone rebuilds a package and then cannot contact the right person when there is a bug with the package.)

static-library-without-debuginfo

A static library included in your package does not contain debug information, in general they are not useful, use --disable-static configure option or rm %buildroot/%_libdir/*.a at the end of the %install section if and only if there is no such option available.

shlib-legacy-policy-name-error

Your package does not follow the SUSE library packaging policy.

shlib-policy-name-error

Your package does not follow the SUSE library packaging policy.

ghost-files-without-postin

The files are not in the RPM archive itself but created dynamically by the package, at install time or most often later when a daemon is run, i.e. the files are some status or log files. They get erased with the package when you rpm -e.

no-default-runlevel

The init script should have a non-empty "Default-Start" tag in its INIT INFO section.

init-script-runlevel-4

The init script refers to runlevel 4 which is admin defined. No distribution script must use it. Remove '4' from 'Default-Start'.

dbus-policy-missing-allow

The dbus package used a too permissive configuration in the past, which led to security problems (CVE-2008-4311). During investigation of this problem, it was found that many packages contain dbus configuration files that contain useless settings, settings that harm other services or settings that even break after the dbus security update.

Solution: Fix the dbus configuration file. In most cases, the config can be reduced to a few lines. See also https://bugs.launchpad.net/ubuntu/+source/avahi/+bug/318783

In this case the dbus config normally needs a line of the form <allow send_destination="org.foo.bar"/> or similar. If that is missing the service will not work as dbus uses deny as default policy.

dbus-policy-deny-without-destination

'deny' directives must always specify a 'send_destination' otherwise messages to other services could be blocked

Solution: add a 'send_destination' tag to the listed file

dbus-policy-allow-without-destination

'allow' directives must always specify a 'send_destination' otherwise messages to other services may unintentionally be allowed.

Solution: add a 'send_destination' tag to the listed file

dbus-policy-allow-receive

The dbus file contains a superfluous "allow receive_..." directive.

Solution: remove it

executable-stack

rpmlint output: “The binary declares the stack as executable. Executable stack is usually an error as it is only needed if the code contains GCC trampolines or similar constructs which uses code on the stack. One common source for needlessly executable stack cases are object files built from assembler files which do not define a proper .note.GNU-stack section.

Solutions:

generic-name-not-in-filelist

rpmlint output: “The generic name is not in a filelist of package, add it to list marked as %ghost. Note: this error will be raised, if you use a hash ($) in file name, use rpm macros in spec file instead.

Solutions: See the section below.

generic-name-not-marked-as-ghost

rpmlint output: “The generic name is not marked as a ghost, which may cause a problems during update. Mark it as a %ghost in %files section.”

Solution: The generic name (/usr/bin/java for java virtual machines) should be listed in filelist as a %ghost files to make the update or replacement process reliable. In other case, it is — under some circumstances — possible that rpm will remove the generic name from filesystem, which breaks the link.

Warning: This policy is applicable for packages for openSUSE 11.2 and newer only. Previous versions contains a version of RPM which disallows a same ghost file owned by several packages, so this would results in a conflict on installation.

Example from the zabbix package (project server:monitoring):

%install
...
# Ghost files must exists in a build root
touch %buildroot/%_sbindir/zabbix-server
touch %buildroot/%_sbindir/zabbix-proxy
%post server-mysql
%_sbindir/update-alternatives \
   --install %_sbindir/zabbix-server \
   zabbix-server \
   %_sbindir/zabbix-server-mysql 11
%files server-mysql
%defattr(-,root,root)
%if 0%{?suse_version} >= 1120
%ghost %_sbindir/zabbix-server
%endif
%_sbindir/zabbix-server-mysql

Note that ghost file must exists in a buildroot!

no-binary

E: foo-package no-binary

The package should be of the noarch architecture because it does not contain any binaries. Solution: Add "BuildArchitectures: noarch" to the spec file — unless it is a python package, in which case you should ignore this warning.

standard-dir-owned-by-package

E: foo-package standard-dir-owned-by-package /usr/share

This package owns a directory that is part of the standard hierarchy, which can lead to default directory permissions or ownerships being changed to something non-standard. Solution: Do not include systems standard directories in your %files list.

non-conffile-in-etc

W: foo-package non-conffile-in-etc /etc/xdg/menus/applications-merged/foo-package.menu

A non-executable file in your package is being installed in /etc, but is not a configuration file. All non-executable files in /etc should be configuration files. Mark the file as %config or %config(noreplace) in the spec file.

summary-ended-with-dot

W: foo-package summary-ended-with-dot A content management system for foo package.

Summary ends with a dot. Remove the dot.

script-without-shebang

E: foo-package script-without-shebang /var/www/foo-package/plugins/foo.php

This executable text file does not contain a shebang, thus it cannot be propely executed. Often, this is a sign of spurious executable bits for a non-script file, but can also be a case of a missing shebang. To fix this error, find out which case of the above it is, and either remove the executable bits or add the shebang.

version-control-internal-file

E: foo-package version-control-internal-file /var/www/foo-package/CVS/Entries

You have included file(s) internally used by a version control system in the package. Move these files out of the package and rebuild it.

Solution: CVS directories and anything under them should just be deleted.

zero-length

E: foo-package zero-length /var/www/foo-package/foo.js

Solution: Most likely not installed by intention. Should be removed. This could be accomplished with the following command in the install section after all files have been installed:

find %{buildroot} -size 0 -delete

non-standard-group

W: foo-package non-standard-group Networking/Other

The group specified in your spec file is not valid. Choose a well known one.

strange-permission

W: foo-package strange-permission foo-package.spec 0744

A file that you listed to include in your package has strange permissions. Usually a file should have 0644 (rw-r--r--) and a directory 0755 (rwxr-xr-x) permissions.

hardcoded-library-path

E: foo-package hardcoded-library-path in %{buildroot}/usr/lib/menu/

A library path is hardcoded to one of the following paths: /lib, /usr/lib. It should be replaced by something like /%_lib or %_libdir.

suse-filelist-forbidden-noarch

E: suse-filelist-forbidden-noarch /usr/lib64/aspell-0.60/english-huge.multi is not allowed in a noarch package

The path in question is architecture specific while the package is marked architecture independent. Either move the file to a architecture neutral location or remove the noarch tag from the package.

incoherent-init-script-name

W: incoherent-init-script-name haldaemon ('hal', 'hald')

The init script name should be the same as the package name in lower case, or one with 'd' appended if it invokes a process by that name.

Solution: rename the init script as suggested by the check

unstripped-binary-or-object

This error should actually never show up in the build service. The build script automatically strips binaries according to global project settings. Left over unstripped binaries could therefore indicate a bug in the automatic tripping process so please file a bug report. Please do not strip binaries manually as that will break debuginfo creation.

binary-or-shlib-calls-gethostbyname

The gethostbyname*() and gethostbyaddr*() functions are deprecated as among other things they are not IPv6 ready. Applications should use getaddrinfo(3) and getnameinfo(3) instead. Please work with upstream to port the applictation to the modern interface. Ulrich Drepper explains the issues in more detail.

file-not-in-%lang

W: file-not-in-%lang /usr/share/sarg/sarg-php/locale/en_EN/LC_MESSAGES/messages.mo

A gettext translation file (those ending in .mo) is not properly tagged by language. This information might be useful in the future to be able to leave out certain languages during installation. The %find_lang macro can be used to automatically tag files.

untranslated-desktop-file

Icon-cleanup.png This section is in need of attention!
You are welcome to improve this section. Refer to this article's discussion page for more information.

We frequently get translation bugs that occur because .desktop files were not tagged for SUSE translations. In order to do that, you have to run %suse_update_desktop_file on each of those files. Doing so will allow the openSUSE translators and the SUSE translation team to add translations for your desktop files automatically during your package build.

Note that if this is a KDE3 or KDE4 package, the error is caused by a missing call to %kde_post_install at the end of the %install section.

init-script-without-%stop_on_removal-preun

The package contains an /etc/init.d script does not contain a call to %stop_on_removal in the %preun script. See the Packaging Conventions

init-script-without-%insserv_cleanup-postun

The package contains an /etc/init.d script and the package does not call %insserv_cleanup in the %postun script. See the Packaging Conventions

no-prereq-on

The package contains a %pre, %post, %preun or %postun script that references an external binary that is however not explicitely listed in the appropriate requires tag (Requires(pre):, Requires(post):, Requires: or Requires:, respectively). Fixing this is necessary so that (de)installation of the package happens in the correct order, e.g. the packages necessary for executing the %post script are already installed.

non-ghost-in-var-run

/var/run is mounted as tmpfs in newer distributions so the content there is volatile and it doesn't make sense to package content in this directory.

Solution: mark the file in as %ghost in the spec file and create it at run time instead. E.g. by touching it in the init script. Or, if the package doesn't have an init script via /usr/lib/tmpfiles.d.

non-ghost-in-var-lock

/var/lock is mounted as tmpfs in newer distributions so the content there is volatile and it doesn't make sense to package content in this directory. Moreover, the directory is intended for legacy device lock files (e.g. LCK..ttyS0) which are managed by lockdev. Don't use it for other purposes.

subsys-unsupported

/var/lock/subsys is neither used nor supported on openSUSE. Other distributions use it to mark that an init script has run. There is no equivalent on openSUSE. So in most cases refereces to /var/lock/subsys can be removed without replacement. In cases where init scripts actually need to store init script specific state information use e.g. /var/run/rcNAME. See previous paragraph for why to not use /var/lock for this purpose.

non-position-independent-executable

As per distribution policy some binaries, such as important network facing programs as well as setuid binaries, need to be compiled as position independent executable (PIE). PIE randomizes the start address of programs to make it harder for attackers to create reliable exploits. Add -fPIE to CFLAGS and -pie to LDFLAGS of the specified binary.

util-linux for example solves this by adding the following to Makefile.am:

 write_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS)
 write_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS)

Then in the spec file:

 export SUID_CFLAGS=-fPIE
 export SUID_LDFLAGS=-pie
 %configure ...

polkit-unauthorized-privilege

The package allows unprivileged users to carry out privileged operations without authentication. This could cause security problems if not done carefully. If the package is intended for inclusion in any SUSE product please open a bug report to request review of the package by the security team.

suse-dbus-unauthorized-service

The package installs a DBUS system service file. DBUS services usually run a service as root on behalf of unprivileged users which could be a source of security problems. So if the package is intended for inclusion in any SUSE product please open a bug report to request review of the service by the security team.

no-changelogname-tag

The package has no changelog. Please add %changelog as last line to the .spec file and use 'osc vc' to create a .changes file.

suse-logrotate-user-writable-log-dir

A directory listed in a /etc/logrotate.d/* file is writable by a non-root user or group. Since logrotate runs as root a compromised user account could play tricks on a logrotate when it tries to rotate log files (e.g. via symlinks, CVE-2011-1155). The sane fix is to only allow root to write the log directory (e.g. 0755 root:root). It is ok for log files to be owned by another user. logrotate's 'create' option makes sure rotated log files have the correct permissions in that case. If for whatever reason the service in question requires different ownership of the directory you may set the "su" option in the logrotate config (see man page). This should only by used as last resort if proper directory permissions are not possible.

suse-logrotate-log-dir-not-packaged

A directory listed in a /etc/logrotate.d/* file is not contained in the %files section of the package. rpmlint therefore can't check whether the permissions on the directory are safe. So please add the directory in questions to %files.

permissions-suseconfig-obsolete

The %run_permissions macro calls SuSEconfig which sets permissions for all files in the system. Please use %set_permissions instead to only set permissions for files contained in the package.

 %if 0%{?suse_version} <= 1130
 %run_permissions
 %else
 %set_permissions /usr/bin/foo /usr/bin/bar
 %endif

permissions-missing-verifyscript

The package does not have a verifyscript that checks the binary in question. Please add a correct %verifyscript section

 %verifyscript
 %verify_permissions -e /usr/bin/foo -e /usr/bin/bar

suse-missing-rclink

packages with init scripts or systemd unit files should include a symlink that consist of the prefix 'rc' and the name of the service that allows for convenient restart of the service.

Ie if the package has an init script /etc/init.d/foo, there should be a symlink /usr/sbin/rcfoo that points to /etc/init.d/foo.

If the package has a systemd unit /usr/lib/systemd/system/foo.service, the symlink /usr/sbin/rcfoo should point to /usr/sbin/service instead which wraps systemctl.

suse-systemd-shadowed-initscript

The package contains both an init script and a systemd service file. Since the init script is ignored by systemd if a unit with the same name exists the init script should be removed to avoid confusion.

suse-branding-specific-branding-req

packages must not require a specific branding or theme package to allow for differnt themes

Example:

 Name: foo
 Requires: foo-branding
 Name: foo-branding-upstream
 Provides: foo-branding
 Name: foo-branding-openSUSE
 Provides: foo-branding

dir-or-file-in-var-run

/var/run is a symlink nowadays, don't package files below that prefix anymore. Use /run instead.

dir-or-file-in-var-lock

/var/lock is a symlink nowadays, don't package files below that prefix. In fact don't use it at all. It's meant to be only used by the lockdev package.

rpmbuild

Files not owned by a package

If you get messages from rpmbuild reading like

foobar-0-0.noarch.rpm: directories not owned by a package:
 - /etc/php5
 - /etc/php5/conf.d

Always list everything in %files, unless it triggers the standard-dir-owned-by-package rpmlint warning. This is because, if you delete both foobar and php5 from the system, and php5 happens to be removed before foobar (which can happen), /etc/php5 will not be deleted because /etc/php5/conf.d/foobar.ini still exists. But because the only owner php5 has already been removed, /etc/php5 will not be owned by any package anymore.