openSUSE:Packaging checks
To maintain quality and consistency a set of automated checks help catching common packaging errors or enforce packaging policy during package build.
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.
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 openSUSE 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 has 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 %{buildroot}/usr/Mod/PartDesign
Make sure that you remember to add a BuildRequires: chrpath if you end up using this method.
Building Packages in spite of errors
RPM Lint 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.
RPM Lint 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
The addFilter() function 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 RPM Lint.
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 RPM Lint warning that should be removed in general, please file a bug report.
Disarming Fatal Errors
Some checks, such as security checks have such a high badness score that a single occurrence 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() function.
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
This list is sorted alphabetical. Please keep the order if you add new checks!
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.
arch-independent-package-contains-binary-or-object
Your package has been marked as noarch, but contains a binary that is architecture-specific.
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 application to the modern interface. Ulrich Drepper explains the issues in more detail.
dbus-policy-allow-receive
The dbus file contains a superfluous "allow receive_..." directive.
Solution: remove it
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-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-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.
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:
- it will keep installation size for customers/users who do not compile source on their own small
- 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.
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.
dir-or-file-in-var-run
/var/run is a symlink nowadays, don't package files below that prefix anymore. Use /run instead.
executable-docs
Documentation under %docdir contains executable files. Documentation should not be executable.
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:
- A comprehensive article about this problem can be found at http://www.gentoo.org/proj/en/hardened/gnu-stack.xml
- Probably the easiest solution is to pass -Wl,-z,noexecstack to the linker.
- Do not forget to enable debuginfo subpackage generation in your build service project or call `
obs build --debug
`
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.
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.
filelist-forbidden-debuginfo
E: filelist-forbidden-debuginfo (Badness: 10000) /usr/lib/debug/.build-id
There are files meant for the -debuginfo
subpackage in the main package. This can be fixed by adding a %files debuginfo
section and listing the files there.
For example:
%files debuginfo %{_exec_prefix}/lib/debug
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 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 the file list as a %ghost files to make the update or replacement process reliable. In the other case, it is — under some circumstances — possible that rpm will remove the generic name from file system 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 result 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 %if 0%{?suse_version} >= 1120 %ghost %_sbindir/zabbix-server %endif %_sbindir/zabbix-server-mysql
Note that ghost file must exists in a buildroot!
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
.
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.
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.
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
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'.
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
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
invalid-spec-name
The specfile should be named %name.spec.
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.
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.
no-version-in-last-changelog
If the latest changelog entry doesn't contain a version, rpmlint shows a no-version-in-last-changelog warning.
Take a look at openSUSE:Creating_a_changes_file_(RPM)#Version_updates.
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.
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-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.
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 ...
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.
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.
no-default-runlevel
The init script should have a non-empty "Default-Start" tag in its INIT INFO section.
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.)
no-prereq-on
The package contains a %pre, %post, %preun or %postun script that references an external binary that is however not explicitly 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.
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
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
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.
polkit-untracked-privilege
This is just like polkit-unauthorized-privilege. It appears when a polkit action is only set to values consisting of auth_admin and no. Although these configurations seem to look safe it still depends on the code in the package in question whether no security issues entail.
postin-without-tmpfile-creation
The package uses the temporary file mechanism of systemd to e.g. create %ghost files but doesn't actually create the files in %post. That means the package may be only usable after a reboot.
Please add something like this to your %post section:
%tmpfiles_create %_tmpfilesdir/FILE.conf
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 properly 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.
shlib-policy-name-error
Your package does not follow the SUSE library packaging policy
shlib-legacy-policy-name-error
Your package does not follow the SUSE library packaging policy.
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.
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.
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.
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.
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.
summary-not-capitalized
Package summaries should start with a capital letter, but should not end with a dot (.).
suse-branding-specific-branding-req
packages must not require a specific branding or theme package to allow for different themes
Example:
Name: foo Requires: foo-branding
Name: foo-branding-upstream Provides: foo-branding
Name: foo-branding-openSUSE Provides: foo-branding
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.
suse-deprecated-boot-script
The package installs SysVinit boot scripts which are nowadays deprecated on systemd driven systems. All boot scripts should be migrated to one or more systemd unit files.
suse-deprecated-init-script
The package installs SysVinit init scripts which are nowadays deprecated on systemd driven systems. All init scripts should be migrated to one or more systemd unit files.
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.
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.
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-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 a convenient restart of the service.
SysV
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
.
systemd
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-obsolete-insserv-requirement
The package depends on insserv which has become obsolete on systemd driven systems. Packages should not require insserv anymore.
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.
Init scripts sometimes implement additional actions besides the usual start/stop/status etc. For systemd service files that extra feature doesn't exist. Therefore, /usr/sbin/service implements "legacy actions", see openSUSE:Systemd_packaging_guidelines#extra_actions for details.
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 stripping process so please file a bug report. Please do not strip binaries manually as that will break debuginfo creation.
untranslated-desktop-file
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.
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.
wrong-file-end-of-line-encoding
Some 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.
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.
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
See also openSUSE:Systemd_packaging_guidelines
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.