From Fedora Project Wiki

(Add BR: systemd although we may be able to move this section to EPEL guidelines: https://fedorahosted.org/fpc/ticket/318)
(Texinfo scriplets are F27 only. https://pagure.io/packaging-committee/issue/773)
(46 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<!-- page was renamed from PackagingDrafts/ScriptletSnippets
{{DISPLAYTITLE:Fedora Packaging Guidelines for RPM Scriptlets}}
-->
<div style="float: right; margin-left: 0.5em;" class="toclimit-2">__TOC__</div>
= RPM scriptlet recipes =
Rpm spec files have several sections which allow packages to run code on installation and removal.  These scriptlets are mostly used to update the running system with information from the package.  This page offers a quick overview of the RPM scriptlets and a number of common recipes for scriptlets in packages.  For a more complete treatment of scriptlets, please see the [http://www.rpm.org/max-rpm-snapshot/ Maximum RPM book] .


'''Contents:'''
RPM spec files have several sections which allow packages to run code on installation and removal.  These bits of code are called scriptlets and are mostly used to update the running system with information from the package.  This page offers a quick overview of RPM scriptlets and a number of common recipes for scriptlets in packages.  For a more complete treatment of scriptlets, please see the [http://www.rpm.org/max-rpm-snapshot/ Maximum RPM book].


= Default Shell =
The version of RPM in Fedora also has functionality to automatically run scripts when files are placed in certain locations.  (See [http://www.rpm.org/wiki/FileTriggers].) This potentially obviates the need for most of the scriptlets on this page, but is not currently implemented in all cases where it could be.
In Fedora, you can assume that the default shell (/bin/sh) is bash. Thus, all scriptlets can safely assume that if they are running in shell code, they are running within bash.


= Syntax =
== Default Shell ==
In Fedora, all scriptlets can safely assume they are running under the bash shell unless a different language has been specified.
 
== Syntax ==
The basic syntax is similar to the %build, %install, and other sections of the rpm spec file.  The scripts support a special flag, -p which allows the scriptlet to invoke a single program directly rather than having to spawn a shell to invoke the programs.  (ie: %post -p /sbin/ldconfig)
The basic syntax is similar to the %build, %install, and other sections of the rpm spec file.  The scripts support a special flag, -p which allows the scriptlet to invoke a single program directly rather than having to spawn a shell to invoke the programs.  (ie: %post -p /sbin/ldconfig)


The scriptlets also take an argument, passed into them by the controlling rpmbuild process.  This argument, accessed via $1 is the number of packages of this name which will be left on the system when the action completes, except for %pretrans and %posttrans which are always run with $1 as 0 (%pretrans and %posttrans are available in rpm 4.4 and later).  So for the common case of install, upgrade, and uninstall we have:
When scriptlets are called, they will be supplied aith an argument.  This argument, accessed via $1 (for shell scripts) is the number of packages of this name which will be left on the system when the action completes, except for %pretrans and %posttrans which are always run with $1 as 0..  So for the common case of install, upgrade, and uninstall we have:


{| border="1"
{| border="1"
Line 39: Line 39:
...for %pre and %post scripts rather than checking that it equals 2.
...for %pre and %post scripts rather than checking that it equals 2.


Except in some really exceptional cases (if any), we want all scriptlets to exit with the zero exit status. Because rpm in its default configuration does not at the moment execute shell scriptlets with the <code>-e</code> argument to the shell, excluding explicit <code>exit</code> calls (frowned upon with a non-zero argument!), the exit status of the last command in a scriptlet determines its exit status. Most commands in the snippets in this document have a "<code>|| :</code>" appended to them, which is a generic trick to force the zero exit status for those commands whether they worked or not. Usually the most important bit is to apply this to the last command executed in a scriptlet, or to add a separate command such as plain "<code>:</code>" or "<code>exit 0</code>" as the last one in a scriptlet. Note that depending on the case, other error checking/prevention measures may be more appropriate, as well as running some commands only if we saw a previous command in the scriptlet which is a must prerequisite to succeed.
All scriptlets MUST exit with the zero exit status. Because RPM in its default configuration does not execute shell scriptlets with the <code>-e</code> argument to the shell, excluding explicit <code>exit</code> calls (frowned upon with a non-zero argument!), the exit status of the last command in a scriptlet determines its exit status. Most commands in the snippets in this document have a "<code>|| :</code>" appended to them, which is a generic trick to force the zero exit status for those commands whether they worked or not. Usually the most important bit is to apply this to the last command executed in a scriptlet, or to add a separate command such as plain "<code>:</code>" or "<code>exit 0</code>" as the last one in a scriptlet. Note that depending on the case, other error checking/prevention measures may be more appropriate.
 
Non-zero exit codes from scriptlets break installs/upgrades/erases so that no further actions will be taken for that package in a transaction (see scriptlet ordering below), which may for example prevent an old version of a package from being erased on upgrades, leaving behind duplicate rpmdb entries and possibly stale, unowned files on the filesystem. There are some cases where letting the transaction to proceed when some things in scriptlets failed may result in partially broken setup. It is however often limited to that package only whereas letting a transaction to proceed with some packages dropped out on the fly is more likely to result in broader system wide problems.


{{Anchor|order}}
Non-zero exit codes from scriptlets can break installs/upgrades/erases such that no further actions will be taken for that package in a transaction (see [[#Scriptlet Ordering]] below), which may for example prevent an old version of a package from being erased on upgrades, leaving behind duplicate rpmdb entries and possibly stale, unowned files on the filesystem. There are some cases where letting the transaction to proceed when some things in scriptlets failed may result in partially broken setup. It is however often limited to that package only whereas letting a transaction to proceed with some packages dropped out on the fly is more likely to result in broader system wide problems.


= Scriptlet Ordering =
== Ordering ==
The scriptlets in %pre and %post are respectively run before and after a package is installed.  The scriptlets %preun and %postun are run before and after a package is uninstalled.  The scriptlets %pretrans and %posttrans are run at start and end of a transaction.  On upgrade, the scripts are run in the following order:
The scriptlets in %pre and %post are respectively run before and after a package is installed.  The scriptlets %preun and %postun are run before and after a package is uninstalled.  The scriptlets %pretrans and %posttrans are run at start and end of a transaction.  On upgrade, the scripts are run in the following order:


Line 63: Line 61:
# %posttrans of new package
# %posttrans of new package


= Writing scriptlets =
=== The %pretrans Scriptlet ===
 
Note that the <code>%pretrans</code> scriptlet will, in the particular case of system installation, run before anything at all has been installed. This implies that it cannot have any dependencies at all. For this reason, <code>%pretrans</code> is best avoided, but if used it MUST (by necessity) be written in Lua. See http://rpm.org/user_doc/lua.html for more information.
 
== Writing Scriptlets ==


Some tips for writing good scriptlets
Some tips for writing good scriptlets


== Saving state between scriptlets ==
=== Saving state between scriptlets ===


Sometimes a scriptlet needs to save some state from an earlier running scriptlet in order to use it at a later running scriptlet.  This is especially common when trying to optimize the scriptlets.  Examples:
Sometimes a scriptlet needs to save some state from an earlier running scriptlet in order to use it at a later running scriptlet.  This is especially common when trying to optimize the scriptlets.  Examples:
Line 76: Line 78:
To address these issues scriptlets that run earlier need to write out information that is used in <code>%posttrans</code>.  We recommend using a subdirectory of <code>%{_localstatedir}/lib/rpm-state/</code> for that.  For instance, the eclipse plugin scripts touch a file in <code>%{_localstatedir}/lib/rpm-state/eclipse/</code> when they're installed.  The <code>%posttrans</code> runs a script that checks if that file exists.  If it does, it performs its action and then deletes the file.  That way the script only performs its action once per transaction.
To address these issues scriptlets that run earlier need to write out information that is used in <code>%posttrans</code>.  We recommend using a subdirectory of <code>%{_localstatedir}/lib/rpm-state/</code> for that.  For instance, the eclipse plugin scripts touch a file in <code>%{_localstatedir}/lib/rpm-state/eclipse/</code> when they're installed.  The <code>%posttrans</code> runs a script that checks if that file exists.  If it does, it performs its action and then deletes the file.  That way the script only performs its action once per transaction.


{{admon/note||We're asking that the <code>%{_localstatedir}/lib/rpm-state/</code> directory be owned by either the rpm or filesystem packages in Fedora.  Until that happens, a package that is providing this functionality needs to own <code>%{_localstatedir}/lib/rpm-state/</code> as well as their subdirectory of it.}}
=== Macros ===
If RPM file triggers are not appropriate, complex scriptlets which are shared between multiple packages MAY be placed in RPM macros.  This has two benefits:
 
* The standard package authors only have to remember the macros, not the complex stuff that it does
* The macros' implementations may change without having to update the package
 
When writing the macros, the FPC will still want to review the macros (and perhaps include the implementation of the macros in the guideline to show packagers what's happening behind the scenes).
 
One principle that the FPC follows is that macros generally don't contain the start of scriptlet tags (for instance, <code>%pre</code>) because this makes it difficult to do additional work in the scriptlet.  This also means that a single macro can not be defined to do things in both <code>%pre</code> and <code>%post</code>.  Instead, write one macro that performs the actions in <code>%pre</code> and a separate macro that performs the actions in <code>%post</code>.  This principle makes it so that all spec files can use your macros in the same manner even if they already have a <code>%pre</code> or <code>%post</code> defined.
 
Of course, in the above situation it is better to use RPM file triggers if at all possible.
 
== Snippets ==
 
=== Shared Libraries ===
On Fedora 28 and newer, no scriptlets are required when shared libraries are installedHowever, the following scriptlets MAY be used, as they will simply evaluate to nothing on newer Fedora releases.
 
On Fedora 27 and older, ldconfig MUST be called properly in order to regenerate the dynamic linker's cache.  If the package or subpackage has no existing <code>%post</code> or <code>%postun</code> scriptlets, simply include the <code>%ldconfig_scriptlets</code> macro on its own line before the %files list.
 
<pre>
[...]
%install
# Install the program
 
%ldconfig_scriptlets libs


== Macros ==
%files libs
Complex scriptlets may be placed in rpm macros. This has two benefits:
%license GPL
[...]
</pre>


# The standard package authors only have to remember the macros, not the complex stuff that it does
Using the <code>%ldconfig_scriptlets</code> macro will automatically generate a dependency on ldconfig where necessary.  The macro will do nothing at all on F28 and later releases.
# The macros' implementations may change without having to update the package


When writing the macros, the FPC will still want to review the macros (and perhaps include the implementation of the macros in the guideline to show packagers what's happening behind the scenes).
If the package or subpackage already has existing <code>%post</code> or <code>%postun</code> scriptlet, then use of <code>%ldconfig_scriptlets</code> will cause an error.  You can use <code>%ldconfig_post</code> or <code>%ldconfig_postun</code> individually to generate a scriptlet which doesn't already conflict.


One principle that the FPC follows is that macros must not contain the start of scriptlet tags (for instance, <code>%pre</code>).  This also means that a single macro must not be defined to do things in both <code>%pre</code> and <code>%post</code>.  Instead, write one macro that performs the actions in <code>%pre</code> and a separate macro that performs the actions in <code>%post</code>.  This principle makes it so that all spec files can use your macros in the same manner even if they already have a <code>%pre</code> or <code>%post</code> defined.
Within an existing <code>%post</code> or <code>%postun</code> scriptlet, use <code>%{?ldconfig}</code> on its own line to call ldconfig on those releases which need it.  This will do nothing when not neededWhen calling ldconfig in this way, you MUST also have the proper dependency on /sbin/ldconfig: <code>Requires(post): /sbin/ldconfig</code> and/or <code>Requires(postun): /sbin/ldconfig</code> as appropriate(This will generate an unnecessary dependency on releases which do not strictly need it, but this does no harm.)


= Snippets =
=== Linker Configuration Files ===
Packages which place linker configuration files in <code>/etc/ld.so.config.d</code> MUST call ldconfig in <code>%post</code> and <code>%postun</code> (on all Fedora releases) even if they install no actual libraries.  They MUST NOT use the <code>%ldconfig</code>, <code>%ldconfig_post</code>, <code>%ldconfig_postun</code> or <code>%ldconfig_scriptlets</code> macros to do this, since these macros do not have any effect on Fedora 28 and newer.  Instead simply call <code>/sbin/ldconfig</code> directly in both <code>%post</code> and <code>%postun</code> as well as adding the necessary dependencies when necessary:


{{Anchor|shlibs}}
== Shared libraries ==
Installing shared libraries requires running /sbin/ldconfig to update the dynamic linker's cache files.  These can be invoked like:
<pre>
<pre>
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
</pre>
or, as part of existing <code>%post</code> or <code>%postun</code> scriptlets:
<pre>
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
[...]
%post
%post
[...]
/sbin/ldconfig
/sbin/ldconfig
[...]
%postun
%postun
[...]
/sbin/ldconfig
/sbin/ldconfig
[...]
</pre>
</pre>
It is also common to invoke these with the '-p' option as they are often the only program invoked in a scriptlet:
 
In addition, in Fedora 28 or newer the following applies: If the configuration file added to <code>/etc/ld.so.conf.d</code> specifies a directory into which other other packages may install files, and that directory is not located in the directory hierarchy beneath one of <code>/lib</code>, <code>/usr/lib</code, <code>/lib64</code> or <code>/usr/lib64</code>, then the package adding the configuration file MUST also include the following file triggers which cause ldconfig to be run automatically when necessary:
 
<pre>
<pre>
%post -p /sbin/ldconfig
%transfiletriggerin -P 2000000 -- DIRECTORIES
%postun -p /sbin/ldconfig
/sbin/ldconfig
 
%transfiletriggerpostun -P 2000000 -- DIRECTORIES
/sbin/ldconfig
</pre>
</pre>
If applicable, the latter way is recommended because doing so will automatically add appropriate dependencies on /sbin/ldconfig to the package (and FWIW, will prevent unnecessarily launching a shell process in the scriptlets).


{{Anchor|users}}
Replace <code>DIRECTORIES</code> with the space-separated list of directories which the package adds to to the library search path via the configuration files in <code>/etc/ld.so.conf.d</code>.
== Users and groups ==
 
=== Users and groups ===
These are discussed on a [[Packaging/UsersAndGroups|  separate page]]  
These are discussed on a [[Packaging/UsersAndGroups|  separate page]]  


{{Anchor|services}}
=== GConf ===
== Services ==
=== Initscripts Conventions ===
 
Full guidelines for SysV-style initscripts can be found here: [[Packaging/SysVInitScript]]  <BR>
Scriptlet specifics can be found here: [[Packaging/SysVInitScript#InitscriptScriptlets]]
 
{{Anchor|gconf}}
 
== GConf ==
GConf is a configuration scheme currently used by the GNOME desktop.  Programs which use it setup default values in a [NAME] .schemas file which is installed under %{_sysconfdir}/gconf/schemas/[NAME] .schemas.  These defaults are then registered with the gconf daemon which monitors the configuration values and alerts applications when values the applications are interested in change.  The schema files also provide documentation about what each value in the configuration system means (which gets displayed when you browse the database in the gconf-editor program).
GConf is a configuration scheme currently used by the GNOME desktop.  Programs which use it setup default values in a [NAME] .schemas file which is installed under %{_sysconfdir}/gconf/schemas/[NAME] .schemas.  These defaults are then registered with the gconf daemon which monitors the configuration values and alerts applications when values the applications are interested in change.  The schema files also provide documentation about what each value in the configuration system means (which gets displayed when you browse the database in the gconf-editor program).


Line 193: Line 228:
the list of schemas that this package currently provides and removes them for us.
the list of schemas that this package currently provides and removes them for us.


=== Rebuilds for changes to macros ===
==== Rebuilds for changes to macros ====
When macros change, packages that make use of them have to be rebuilt to
When macros change, packages that make use of them have to be rebuilt to
pick up the changes.  This repoquery command can be used to find the schema
pick up the changes.  This repoquery command can be used to find the schema
Line 201: Line 236:
</pre>
</pre>


=== EPEL Notes ===
==== EPEL Notes ====
EPEL does not have macros.gconf2, so please follow the instructions found here: [[Packaging:EPEL#GConf]]
EPEL does not have macros.gconf2, so please follow the instructions found here: [[Packaging:EPEL#GConf]]


== GSettings Schema ==
=== Texinfo ===
 
{{admon/note|F27 only|This scriptlet SHOULD NOT be used in Fedora 28 or later.}}
GSettings is the configuration system used by the GNOME 3 desktop. It replaces the older GConf
system, which was used in GNOME 2. GSettings has pluggable backends, the 'native' one for GNOME is using DConf to store settings. The GSettings API and utilities are part of the glib2 package.
 
Programs which use GSettings install schema information including default values in the directory %{_datadir}/glib-2.0/schemas. Schema files are xml files with the extension .gschema.xml. At runtime, GSettings uses the schemas in a compiled binary (but arch-neutral) form, which is created by running the glib-compile-schemas utility. /usr/bin/glib-compile-schemas must be run whenever the set of installed schemas changes.
 
<pre>
%postun
if [ $1 -eq 0 ] ; then
    /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
fi
 
%posttrans
    /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
</pre>
 
== gdk-pixbuf loaders ==
 
gdk-pixbuf is a library that is part of the gdk-pixbuf2 package. It is for loading images in various formats in GNOME. gdk-pixbuf can be extended by implementing loaders for image formats in loadable modules. These loadable modules have to be installed in %{_libdir}/gdk-pixbuf-2.0/2.10.0/loaders. To avoid opening all modules in that directory unnecessarily, gdk-pixbuf maintains a cache with information about the available modules in the text file %{_libdir}/gdk-pixbuf-2.0/2.10.0/loaders.cache. This cache file needs to be updated when the set of installed modules changes, by calling the /usr/bin/gdk-pixbuf-query-loaders binary. Multilib considerations force us to install the binary in -32 and -64 variants.
 
The scriptlets to maintain the cache file are:
<pre>
%postun
    /usr/bin/gdk-pixbuf-query-loaders-%{__isa_bits} --update-cache &> /dev/null || :
 
%post
if [ $1 -eq 1 ] ; then
    # For upgrades, the cache will be regenerated by the new package's %postun
    /usr/bin/gdk-pixbuf-query-loaders-%{__isa_bits} --update-cache &> /dev/null || :
fi
</pre>
 
Note the use of %{__isa_bits}, which is an rpm macro that expands to either 32 or 64,
depending on the architecture of the package.
 
== GTK+ modules ==
 
The GTK+ toolkit (in the gtk3 package) can be extended by loadable modules which can provide theme engines, input methods, print backends or other functionality. These modules have to be installed in subdirectories of %{_libdir}/gtk-3.0 or %{_libdir}/gtk-3.0/3.0.0. For the input methods, GTK+ maintains a cache in the text file %{_libdir}/gtk-3.0/3.0.0/immodules.cache. This cache file needs to be updated when the set of installed input methods changes, by calling the gtk-query-immodules-3.0 binary. Multilib considerations force us to install the binary in -32 and -64 variants.
 
The scriptlets to maintain the cache file are:
<pre>
%postun
/usr/bin/gtk-query-immodules-3.0-%{__isa_bits} --update-cache &> /dev/null || :
 
%post
if [ $1 -eq 1 ] ; then
    # For upgrades, the cache will be regenerated by the new package's %postun
    /usr/bin/gtk-query-immodules-3.0-%{__isa_bits} --update-cache &> /dev/null || :
fi
</pre>
 
The 3.0 in the binary name is there because gtk2 has its own utility for the same purpose, called gtk-query-immodules-2.0. Note the use of %{__isa_bits}, which is an rpm macro that expands to either 32 or 64, depending on the architecture of the package.
 
== GIO modules ==
GIO is a library that is part of the glib2 package. It is a low-level part of the GNOME stack. GIO can be extended by implementing [http://library.gnome.org/devel/gio/2.26/extending-gio.html extension points] in loadable modules. These loadable modules have to be installed in %{_libdir}/gio/modules. To avoid opening all modules in that directory
unnecessarily, GIO maintains a cache with information about the available modules in the
text file giomodule.cache in the same directory. This cache file needs to be updated when the set of installed modules changes, by calling the gio-querymodules binary. Multilib considerations force us to install the binary in -32 and -64 variants.
 
The scriptlets to maintain the cache file are:
<pre>
%postun
/usr/bin/gio-querymodules-%{__isa_bits} %{_libdir}/gio/modules &> /dev/null || :
 
%post
# We run this after every install or upgrade because of a cornercase
# when installing the second architecture of a multilib package
/usr/bin/gio-querymodules-%{__isa_bits} %{_libdir}/gio/modules || :
</pre>
 
Note the use of %{__isa_bits}, which is an rpm macro that expands to either 32 or 64,
depending on the architecture of the package.
 
{{Anchor|info}}


== Texinfo ==
The GNU project and many other programs use the texinfo file format for much of its documentation. These info files are usually located in /usr/share/info/.
The GNU project and many other programs use the texinfo file format for much of its documentation. These info files are usually located in /usr/share/info/.
When installing or removing a package, install-info from the info package takes care of adding the newly installed files to the main info index and removing them again on deinstallation.
When installing or removing a package in Fedora 27, install-info from the info package takes care of adding the newly installed files to the main info index and removing them again on deinstallation. (In Fedora 28 and newer, this is done automatically and no scriptlets are required.)


<pre>
<pre>
Line 298: Line 260:
These two scriptlets tell install-info to add entries for the info pages to the main index file on installation and remove them at erase time.  The "|| :" in this case prevents failures that would typically affect systems that have been configured not to install any %doc files, or have read-only mounted, %_netsharedpath /usr/share.
These two scriptlets tell install-info to add entries for the info pages to the main index file on installation and remove them at erase time.  The "|| :" in this case prevents failures that would typically affect systems that have been configured not to install any %doc files, or have read-only mounted, %_netsharedpath /usr/share.


{{Anchor|scrollkeeper}}
=== Systemd ===
== Scrollkeeper ==
Packages containing systemd unit files need to use scriptlets to ensure proper handling of those services. Services can either be enabled or disabled by default. To determine which case your specific service falls into, please refer to FESCo's policy here: [[Packaging:DefaultServices]]. On upgrade, a package may only restart a service if it is running; it may not start it if it is off.  Also, the service may not enable itself if it is currently disabled.
In all current Fedora, rarian has replaced scrollkeeper. There is no scriptlet needed for rarian. For instructions on what to do in EPEL releases, see [[Packaging:EPEL#Scrollkeeper]]


{{Anchor|desktopdb}}
==== Scriptlets ====
== desktop-database ==
The systemd package provides a set of helper macros to handle systemd scriptlet operations. These macros support systemd "presets", as documented in [[Features/PackagePresets]].  The <code>%systemd_requires</code> macro is a shortcut for listing the per-scriptlet dependencies on systemd.
Use this when a desktop entry has a ''''''MimeType key.
<pre>
<pre>
%{?systemd_requires}
BuildRequires: systemd
[...]
%post
%post
/usr/bin/update-desktop-database &> /dev/null || :
%systemd_post apache-httpd.service


%postun
%preun
/usr/bin/update-desktop-database &> /dev/null || :
%systemd_preun apache-httpd.service
</pre>
Note: For FC5+, this scriptlet follows the same convention as mimeinfo files and gtk-icon-cache.  Namely, the spec file should not Require desktop-file-utils for this. For older releases, one should
<pre>
Requires(post): desktop-file-utils
Requires(postun): desktop-file-utils
</pre>
(See http://bugzilla.redhat.com/180898 and http://bugzilla.redhat.com/180899)
 
{{Anchor|mimeinfo}}
== mimeinfo ==
Use this when a package drops an XML file in %{_datadir}/mime/packages.
<pre>
%post
/usr/bin/update-mime-database %{_datadir}/mime &> /dev/null || :


%postun
%postun
/usr/bin/update-mime-database %{_datadir}/mime &> /dev/null || :
%systemd_postun_with_restart apache-httpd.service
</pre>
</pre>
Note that similarly to the gtk-update-icon-cache code, these scriptlets should be run only if the user has update-mime-info installed and without a specific Requires: shared-mime-info.  If shared-mime-info is not installed, update-mime-database won't be run when this package is installed.  This does not matter because it will be run when the shared-mime-info package is installed.
{{Anchor|iconcache}}
== Icon Cache ==
If an application installs icons into one of the subdirectories in <code>%{_datadir}/icons/</code> (such as <code>hicolor</code> in the following examples), icon caches must be updated so that the installed icons show up in menus right after package installation.  This consists of updating the timestamp of the top-level icon directory where the icons were installed, and running <code>gtk-update-icon-cache</code>.  'touch'ing the top-level dir is done so that environments compatible with the [http://standards.freedesktop.org/icon-theme-spec/latest/ar01s08.html Icon theme specification] can refresh their caches, and <code>gtk-update-icon-cache</code> which is additionally required for GNOME also does its work based on the dir timestamp.
Note that no dependencies should be added for this. If gtk-update-icon-cache is not available, there's nothing that would be needing the cache update, ditto if "touch" is not available, there's nothing that would benefit from icon cache updates installed yet either. Not adding the dependency on gtk-update-icon-cache (ie. gtk2 >= 2.6.0) or "touch" makes it easier to use the package (or the same specfile) on systems where it's not available nor needed, such as older distro versions or (very) trimmed down installations, and generally results in less entries in specfiles, rpmdb, and repo metadatas.


Some services do not support being restarted (e.g. D-Bus and various storage daemons). If your service should not be restarted upon upgrade, then use the following <code>%postun</code> scriptlet instead of the one shown above:
<pre>
<pre>
%post
/bin/touch --no-create %{_datadir}/icons/hicolor &>/dev/null || :
%postun
%postun
if [ $1 -eq 0 ] ; then
%systemd_postun apache-httpd.service
    /bin/touch --no-create %{_datadir}/icons/hicolor &>/dev/null
    /usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
fi
 
%posttrans
/usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
</pre>
</pre>


== Systemd ==
If your package includes one or more systemd units that need to be enabled by default on package installation, they MUST be covered by the [[Packaging:DefaultServices | Fedora preset policy]].


Packages containing systemd unit files need to use scriptlets to ensure proper handling of those services. Services can either be enabled or disabled by default. To determine which case your specific service falls into, please refer to FESCo's policy here: [[Starting_services_by_default]]. On upgrade, a package may only restart a service if it is running; it may not start it if it is off. Also, the service may not enable itself if it is currently disabled.
If a package is suitable for installation without systemd (in a container image, for example) and does not require any of the systemd mechanisms such as tmpfiles.d, then the <code>%systemd_ordering</code> macro MAY be used instead of the <code>%systemd_requires</code> macro.


=== New Packages ===
===== User units =====
{{admon/note|What is a new package?|In this context, a new package is a package which has never included a SysV initscript.}}


==== Macroized scriptlets (Fedora 18+) ====
There are additional macros for user units (those installed under <code>%_userunitdir</code>) that should be used similarly to those for system units.   These enable and disable user units according to presets, and are <code>%systemd_user_post</code> (to be used in <code>%post</code>) and <code>%systemd_user_preun</code> (to be used in <code>%preun</code>).
The systemd package in Fedora 18+ provides a set of helper macros to handle systemd scriptlet operations. These macros are functionally equivalent to the manual scriptlets used in older versions of Fedora, but they also add support for systemd "presets", as documented here: https://fedoraproject.org/wiki/Features/PackagePresets


<pre>
<pre>
Requires(post): systemd
%{?systemd_requires}
Requires(preun): systemd
Requires(postun): systemd
BuildRequires: systemd
BuildRequires: systemd


[...]
[...]
%post
%post
%systemd_post apache-httpd.service
%systemd_user_post %{name}.service


%preun
%preun
%systemd_preun apache-httpd.service
%systemd_user_preun %{name}.service
</pre>
 
===== Macro details =====
 
For details on what these macros evaluate to, refer to the following sources:<br>
https://github.com/systemd/systemd/blob/master/src/core/macros.systemd.in,<br>
https://github.com/systemd/systemd/blob/master/src/core/triggers.systemd.in and<br>
http://www.freedesktop.org/software/systemd/man/daemon.html.


%postun
[[Category:Packaging guidelines]]
%systemd_postun_with_restart apache-httpd.service
</pre>


Some services do not support being restarted (e.g. D-Bus and various storage daemons). If your service should not be restarted upon upgrade, then use the following <code>%post</code> scriptlet instead of the one shown above:
=== Shells ===
<pre>
%postun
%systemd_postun
</pre>


If your package includes one or more systemd units that need to be enabled by default on package installation, they need to be covered by the default Fedora preset policy. [http://pkgs.fedoraproject.org/cgit/systemd.git/plain/90-default.preset The default fedora preset policy is shipped as part of systemd.rpm]. If your unit files are missing from this list, please file a bug against the systemd package. Only services covered by the [https://fedoraproject.org/wiki/Starting_services_by_default policy on which services that may be enabled by default on package installation] are eligible for this, and you will need to receive special permission from FESCo to have a package start a service by default if it is not covered by the existing policy.
<code>/etc/shells</code> is a text file which controls whether an application can be used as a system login shell of users. It contains the set of valid shells which can be used in the system. If you are packaging a new shell, you need to add entries to this file that reference the added shells. See: <code>man 5 SHELLS</code> for more information.


For details on what these macros evaluate to, refer to the following sources:<BR>
As this file can be edited by sysadmins, we need to first determine if relevant lines are already in the file.
http://cgit.freedesktop.org/systemd/systemd/tree/src/core/macros.systemd.in<BR>
If they don't already exist then we just need to echo the shell's binary path to the file. Since the UsrMove Feature in Fedora 17 made <code>/bin</code> a symlink to <code>/usr/bin</code> we need to place both paths into the <code>/etc/shells</code> file. Here is an example of the scriptlet to package with shell named "foo":
http://www.freedesktop.org/software/systemd/man/daemon.html


==== Manual scriptlets (Fedora 17 or older) ====
<pre>
<pre>
Requires(post): systemd-units
Requires(preun): systemd-units
Requires(postun): systemd-units
BuildRequires: systemd
[...]
%post
%post
if [ $1 -eq 1 ] ; then  
if [ "$1" = 1 ]; then
    # Initial installation
  if [ ! -f %{_sysconfdir}/shells ] ; then
    /bin/systemctl daemon-reload >/dev/null 2>&1 || :
     echo "%{_bindir}/foo" > %{_sysconfdir}/shells
fi
     echo "/bin/foo" >> %{_sysconfdir}/shells
 
  else
%preun
    grep -q "^%{_bindir}/foo$" %{_sysconfdir}/shells || echo "%{_bindir}/foo" >> %{_sysconfdir}/shells
if [ $1 -eq 0 ] ; then
     grep -q "^/bin/foo$" %{_sysconfdir}/shells || echo "/bin/foo" >> %{_sysconfdir}/shells
     # Package removal, not upgrade
     /bin/systemctl --no-reload disable apache-httpd.service > /dev/null 2>&1 || :
     /bin/systemctl stop apache-httpd.service > /dev/null 2>&1 || :
fi
fi


%postun
%postun
/bin/systemctl daemon-reload >/dev/null 2>&1 || :
if [ "$1" = 0 ] && [ -f %{_sysconfdir}/shells ] ; then
if [ $1 -ge 1 ] ; then
  sed -i '\!^%{_bindir}/foo$!d' %{_sysconfdir}/shells
    # Package upgrade, not uninstall
  sed -i '\!^/bin/foo$!d' %{_sysconfdir}/shells
    /bin/systemctl try-restart apache-httpd.service >/dev/null 2>&1 || :
fi
fi
</pre>
</pre>
Note that /bin/systemctl daemon-reload will automatically detect new systemd unit .service files placed into %{_unitdir}. There is no equivalent to 'chkconfig --add <service>', because it is unnecessary. However, if the service is not enabled by default, systemctl will not list your service until it is either manually started (<code>systemctl start foo.service</code>) or manually enabled (<code>systemctl enable foo.service</code>).
If your service should be enabled by default, then use the following <code>%post</code> scriptlet instead of the one shown above:
<pre>
%post
if [ $1 -eq 1 ] ; then
    # Initial installation
    /bin/systemctl enable apache-httpd.service >/dev/null 2>&1 || :
fi
</pre>
=== Packages migrating to a systemd unit file from a SysV initscript ===
When updating from a package containing a SysV initscript to a package containing a systemd unit file, we "start-over fresh" with default start and stop policy from the new package and do not migrate what the user had previously configured.  For this reason, you can simply use the above scriptlets and not worry about converting the sysv information to something relevant to systemd.
{{admon/warning|Only migrate between releases|Packages are strictly forbidden from migrating to systemd within updates to a Fedora release because migration will reset the user's choices about whether to start or stop the service. Migration is only allowed between Fedora releases.}}


[[Category:Packaging guidelines]]
[[Category:Packaging guidelines]]

Revision as of 16:59, 15 June 2018

RPM spec files have several sections which allow packages to run code on installation and removal. These bits of code are called scriptlets and are mostly used to update the running system with information from the package. This page offers a quick overview of RPM scriptlets and a number of common recipes for scriptlets in packages. For a more complete treatment of scriptlets, please see the Maximum RPM book.

The version of RPM in Fedora also has functionality to automatically run scripts when files are placed in certain locations. (See [1].) This potentially obviates the need for most of the scriptlets on this page, but is not currently implemented in all cases where it could be.

Default Shell

In Fedora, all scriptlets can safely assume they are running under the bash shell unless a different language has been specified.

Syntax

The basic syntax is similar to the %build, %install, and other sections of the rpm spec file. The scripts support a special flag, -p which allows the scriptlet to invoke a single program directly rather than having to spawn a shell to invoke the programs. (ie: %post -p /sbin/ldconfig)

When scriptlets are called, they will be supplied aith an argument. This argument, accessed via $1 (for shell scripts) is the number of packages of this name which will be left on the system when the action completes, except for %pretrans and %posttrans which are always run with $1 as 0.. So for the common case of install, upgrade, and uninstall we have:

install upgrade uninstall
%pretrans $1 == 0 $1 == 0 (N/A)
%pre $1 == 1 $1 == 2 (N/A)
%post $1 == 1 $1 == 2 (N/A)
%preun (N/A) $1 == 1 $1 == 0
%postun (N/A) $1 == 1 $1 == 0
%posttrans $1 == 0 $1 == 0 (N/A)

Note that these values will vary if there are multiple versions of the same package installed (This mostly occurs with parallel installable packages such as the kernel and multilib packages. However, it can also occur when errors prevent a package upgrade from completing.) So it is a good idea to use this construct:

%pre
if [ $1 -gt 1 ] ; then
fi

...for %pre and %post scripts rather than checking that it equals 2.

All scriptlets MUST exit with the zero exit status. Because RPM in its default configuration does not execute shell scriptlets with the -e argument to the shell, excluding explicit exit calls (frowned upon with a non-zero argument!), the exit status of the last command in a scriptlet determines its exit status. Most commands in the snippets in this document have a "|| :" appended to them, which is a generic trick to force the zero exit status for those commands whether they worked or not. Usually the most important bit is to apply this to the last command executed in a scriptlet, or to add a separate command such as plain ":" or "exit 0" as the last one in a scriptlet. Note that depending on the case, other error checking/prevention measures may be more appropriate.

Non-zero exit codes from scriptlets can break installs/upgrades/erases such that no further actions will be taken for that package in a transaction (see #Scriptlet Ordering below), which may for example prevent an old version of a package from being erased on upgrades, leaving behind duplicate rpmdb entries and possibly stale, unowned files on the filesystem. There are some cases where letting the transaction to proceed when some things in scriptlets failed may result in partially broken setup. It is however often limited to that package only whereas letting a transaction to proceed with some packages dropped out on the fly is more likely to result in broader system wide problems.

Ordering

The scriptlets in %pre and %post are respectively run before and after a package is installed. The scriptlets %preun and %postun are run before and after a package is uninstalled. The scriptlets %pretrans and %posttrans are run at start and end of a transaction. On upgrade, the scripts are run in the following order:

  1. %pretrans of new package
  2. %pre of new package
  3. (package install)
  4. %post of new package
  5. %triggerin of other packages (set off by installing new package)
  6. %triggerin of new package (if any are true)
  7. %triggerun of old package (if it's set off by uninstalling the old package)
  8. %triggerun of other packages (set off by uninstalling old package)
  9. %preun of old package
  10. (removal of old package)
  11. %postun of old package
  12. %triggerpostun of old package (if it's set off by uninstalling the old package)
  13. %triggerpostun of other packages (if they're setu off by uninstalling the old package)
  14. %posttrans of new package

The %pretrans Scriptlet

Note that the %pretrans scriptlet will, in the particular case of system installation, run before anything at all has been installed. This implies that it cannot have any dependencies at all. For this reason, %pretrans is best avoided, but if used it MUST (by necessity) be written in Lua. See http://rpm.org/user_doc/lua.html for more information.

Writing Scriptlets

Some tips for writing good scriptlets

Saving state between scriptlets

Sometimes a scriptlet needs to save some state from an earlier running scriptlet in order to use it at a later running scriptlet. This is especially common when trying to optimize the scriptlets. Examples:

  • If a %posttrans needs to de-register some piece of information when upgrading but the file that has that information is removed when the old package is removed the scriptlets need to save that file during %pre or %post so that the script in %posttrans can access it.
  • If we only want the program in %posttrans to do its work once per-transaction, we may need to write out a flag file so that the %posttrans knows whether to perform an action.

To address these issues scriptlets that run earlier need to write out information that is used in %posttrans. We recommend using a subdirectory of %{_localstatedir}/lib/rpm-state/ for that. For instance, the eclipse plugin scripts touch a file in %{_localstatedir}/lib/rpm-state/eclipse/ when they're installed. The %posttrans runs a script that checks if that file exists. If it does, it performs its action and then deletes the file. That way the script only performs its action once per transaction.

Macros

If RPM file triggers are not appropriate, complex scriptlets which are shared between multiple packages MAY be placed in RPM macros. This has two benefits:

  • The standard package authors only have to remember the macros, not the complex stuff that it does
  • The macros' implementations may change without having to update the package

When writing the macros, the FPC will still want to review the macros (and perhaps include the implementation of the macros in the guideline to show packagers what's happening behind the scenes).

One principle that the FPC follows is that macros generally don't contain the start of scriptlet tags (for instance, %pre) because this makes it difficult to do additional work in the scriptlet. This also means that a single macro can not be defined to do things in both %pre and %post. Instead, write one macro that performs the actions in %pre and a separate macro that performs the actions in %post. This principle makes it so that all spec files can use your macros in the same manner even if they already have a %pre or %post defined.

Of course, in the above situation it is better to use RPM file triggers if at all possible.

Snippets

Shared Libraries

On Fedora 28 and newer, no scriptlets are required when shared libraries are installed. However, the following scriptlets MAY be used, as they will simply evaluate to nothing on newer Fedora releases.

On Fedora 27 and older, ldconfig MUST be called properly in order to regenerate the dynamic linker's cache. If the package or subpackage has no existing %post or %postun scriptlets, simply include the %ldconfig_scriptlets macro on its own line before the %files list.

[...]
%install
# Install the program

%ldconfig_scriptlets libs

%files libs
%license GPL
[...]

Using the %ldconfig_scriptlets macro will automatically generate a dependency on ldconfig where necessary. The macro will do nothing at all on F28 and later releases.

If the package or subpackage already has existing %post or %postun scriptlet, then use of %ldconfig_scriptlets will cause an error. You can use %ldconfig_post or %ldconfig_postun individually to generate a scriptlet which doesn't already conflict.

Within an existing %post or %postun scriptlet, use %{?ldconfig} on its own line to call ldconfig on those releases which need it. This will do nothing when not needed. When calling ldconfig in this way, you MUST also have the proper dependency on /sbin/ldconfig: Requires(post): /sbin/ldconfig and/or Requires(postun): /sbin/ldconfig as appropriate. (This will generate an unnecessary dependency on releases which do not strictly need it, but this does no harm.)

Linker Configuration Files

Packages which place linker configuration files in /etc/ld.so.config.d MUST call ldconfig in %post and %postun (on all Fedora releases) even if they install no actual libraries. They MUST NOT use the %ldconfig, %ldconfig_post, %ldconfig_postun or %ldconfig_scriptlets macros to do this, since these macros do not have any effect on Fedora 28 and newer. Instead simply call /sbin/ldconfig directly in both %post and %postun as well as adding the necessary dependencies when necessary:

%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig

or, as part of existing %post or %postun scriptlets:

Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
[...]
%post
[...]
/sbin/ldconfig
[...]
%postun
[...]
/sbin/ldconfig
[...]

In addition, in Fedora 28 or newer the following applies: If the configuration file added to /etc/ld.so.conf.d specifies a directory into which other other packages may install files, and that directory is not located in the directory hierarchy beneath one of /lib, /usr/lib</code, /lib64 or /usr/lib64, then the package adding the configuration file MUST also include the following file triggers which cause ldconfig to be run automatically when necessary:

%transfiletriggerin -P 2000000 -- DIRECTORIES
/sbin/ldconfig

%transfiletriggerpostun -P 2000000 -- DIRECTORIES
/sbin/ldconfig

Replace DIRECTORIES with the space-separated list of directories which the package adds to to the library search path via the configuration files in /etc/ld.so.conf.d.

Users and groups

These are discussed on a separate page

GConf

GConf is a configuration scheme currently used by the GNOME desktop. Programs which use it setup default values in a [NAME] .schemas file which is installed under %{_sysconfdir}/gconf/schemas/[NAME] .schemas. These defaults are then registered with the gconf daemon which monitors the configuration values and alerts applications when values the applications are interested in change. The schema files also provide documentation about what each value in the configuration system means (which gets displayed when you browse the database in the gconf-editor program).

For packaging purposes, we have to disable schema installation during build, and also register the values in the [NAME] .schemas file with the gconf daemon on installation and unregister them on removal. Due to the ordering of the scriptlets, this is a four step process.

Disabling the GConf installation during the package creation can be done like so:

%install
export GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL=1
make install DESTDIR=$RPM_BUILD_ROOT
...

The GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL environment variable suppresses the installation of the schema during the building of the package. An alternative for some packages is to pass a configure flag:

%build
%configure --disable-schemas
...

Unfortunately, this configure switch only works if the upstream packager has adapted their Makefile.am to handle it. If the Makefile.am is not configured, this switch won't do anything and you'll need to use the environment variable instead.

Here's the second part:

BuildRequires: GConf2
Requires(pre): GConf2
Requires(post): GConf2
Requires(preun): GConf2
...
%pre
%gconf_schema_prepare schema1 schema2
%gconf_schema_obsolete schema3

In this section we uninstall old schemas during upgrade using one of two macros.

%gconf_schema_prepare is used for any current GConf schemas. It takes care of uninstalling previous versions of schemas that this package currently installs. It takes a space separated list of schema names without path or suffix that the package installs. Note that behind the scenes, this macro works with the %post scriptlet to only process GConf schemas if changes have occurred.

%gconf_schema_obsolete is used for schemas that this package previously provided but no longer does. It will deregister the old schema if it is present on the system. Nothing will happen if the old schema is not present. This macro takes a space separated list of schemas to uninstall. One example of using this might be if the package changed names. If the old schema was named foo.schemas and the new schema is named foobar.schemas you'd use:

%gconf_schema_prepare foobar
%gconf_schema_obsolete foo

The next section does the processing of the newly installed schemas:

%post
%gconf_schema_upgrade schema1 schema2

%gconf_schema_upgrade takes a space separated list of schemas that the package currently installs just like %gconf_schema_prepare. Behind the scenes, it does the actual work of registering the new version of the schema and deregistering the old version.

The last section is for unregistering schemas when a package is removed:

%preun
%gconf_schema_remove schema1 schema2

When a package is upgraded rpm invokes the %pre scriptlet to register and deregister the schemas. When a package is uninstalled, the %preun scriptlet is used. %gconf_schema_remove takes the list of schemas that this package currently provides and removes them for us.

Rebuilds for changes to macros

When macros change, packages that make use of them have to be rebuilt to pick up the changes. This repoquery command can be used to find the schema including packages to rebuild:

repoquery --whatprovides "/etc/gconf/schemas/*" |sort |uniq |wc -l

EPEL Notes

EPEL does not have macros.gconf2, so please follow the instructions found here: Packaging:EPEL#GConf

Texinfo

Note.png
F27 only
This scriptlet SHOULD NOT be used in Fedora 28 or later.

The GNU project and many other programs use the texinfo file format for much of its documentation. These info files are usually located in /usr/share/info/. When installing or removing a package in Fedora 27, install-info from the info package takes care of adding the newly installed files to the main info index and removing them again on deinstallation. (In Fedora 28 and newer, this is done automatically and no scriptlets are required.)

Requires(post): info
Requires(preun): info
...
%post
/sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || :

%preun
if [ $1 = 0 ] ; then
  /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || :
fi

These two scriptlets tell install-info to add entries for the info pages to the main index file on installation and remove them at erase time. The "|| :" in this case prevents failures that would typically affect systems that have been configured not to install any %doc files, or have read-only mounted, %_netsharedpath /usr/share.

Systemd

Packages containing systemd unit files need to use scriptlets to ensure proper handling of those services. Services can either be enabled or disabled by default. To determine which case your specific service falls into, please refer to FESCo's policy here: Packaging:DefaultServices. On upgrade, a package may only restart a service if it is running; it may not start it if it is off. Also, the service may not enable itself if it is currently disabled.

Scriptlets

The systemd package provides a set of helper macros to handle systemd scriptlet operations. These macros support systemd "presets", as documented in Features/PackagePresets. The %systemd_requires macro is a shortcut for listing the per-scriptlet dependencies on systemd.

%{?systemd_requires}
BuildRequires: systemd

[...]
%post
%systemd_post apache-httpd.service

%preun
%systemd_preun apache-httpd.service

%postun
%systemd_postun_with_restart apache-httpd.service

Some services do not support being restarted (e.g. D-Bus and various storage daemons). If your service should not be restarted upon upgrade, then use the following %postun scriptlet instead of the one shown above:

%postun
%systemd_postun apache-httpd.service

If your package includes one or more systemd units that need to be enabled by default on package installation, they MUST be covered by the Fedora preset policy.

If a package is suitable for installation without systemd (in a container image, for example) and does not require any of the systemd mechanisms such as tmpfiles.d, then the %systemd_ordering macro MAY be used instead of the %systemd_requires macro.

User units

There are additional macros for user units (those installed under %_userunitdir) that should be used similarly to those for system units. These enable and disable user units according to presets, and are %systemd_user_post (to be used in %post) and %systemd_user_preun (to be used in %preun).

%{?systemd_requires}
BuildRequires: systemd

[...]
%post
%systemd_user_post %{name}.service

%preun
%systemd_user_preun %{name}.service
Macro details

For details on what these macros evaluate to, refer to the following sources:
https://github.com/systemd/systemd/blob/master/src/core/macros.systemd.in,
https://github.com/systemd/systemd/blob/master/src/core/triggers.systemd.in and
http://www.freedesktop.org/software/systemd/man/daemon.html.

Shells

/etc/shells is a text file which controls whether an application can be used as a system login shell of users. It contains the set of valid shells which can be used in the system. If you are packaging a new shell, you need to add entries to this file that reference the added shells. See: man 5 SHELLS for more information.

As this file can be edited by sysadmins, we need to first determine if relevant lines are already in the file. If they don't already exist then we just need to echo the shell's binary path to the file. Since the UsrMove Feature in Fedora 17 made /bin a symlink to /usr/bin we need to place both paths into the /etc/shells file. Here is an example of the scriptlet to package with shell named "foo":

%post
if [ "$1" = 1 ]; then
  if [ ! -f %{_sysconfdir}/shells ] ; then
    echo "%{_bindir}/foo" > %{_sysconfdir}/shells
    echo "/bin/foo" >> %{_sysconfdir}/shells
  else
    grep -q "^%{_bindir}/foo$" %{_sysconfdir}/shells || echo "%{_bindir}/foo" >> %{_sysconfdir}/shells
    grep -q "^/bin/foo$" %{_sysconfdir}/shells || echo "/bin/foo" >> %{_sysconfdir}/shells
fi

%postun
if [ "$1" = 0 ] && [ -f %{_sysconfdir}/shells ] ; then
  sed -i '\!^%{_bindir}/foo$!d' %{_sysconfdir}/shells
  sed -i '\!^/bin/foo$!d' %{_sysconfdir}/shells
fi