How To Create RPMs and Init Scripts That Are Compatible On Both SUSE Linux and Red Hat Linux
Novell Cool Solutions: Feature
By Arun Singh, Bart Whiteley, Paul MacKay
|
Digg This -
Slashdot This
Posted: 16 Nov 2004 |
SUSE by default is LSB compliant. Red Hat is LSB compliant if the lsb.rpm is installed (which is not by default). The best solution is to create LSB compliant rpms and init scripts and require lsb.rpm to be pre-installed on Red Hat systems. However, for various reasons sometimes this requirement cannot be enforced. To create rpms and init scripts that can be installed on default Red Hat and SUSE (LSB) systems requires knowing how to support both environments. This document outlines how to create such init scripts and rpms.
Overview
The Linux Standard Base (LSB) provides an extensive set of standards which promote increased application binary compatibility among LSB compliant Linux distributions. The LSB specification also details compatibility conventions for software package installation and system services management.
If you follow the LSB specification while developing your rpms and init scripts, your work to support SUSE(LSB) and LSB compliant systems is simplified and you only need to worry about whether or not you want to support SUSE specific features (e.g. YaST etc.). IBM and others have created an excellent guide that outlines the steps necessary for developing LSB compliant applications.
SUSE by default is LSB compliant. Red Hat is also LSB compliant if lsb.rpm is installed. However, by default Red Hat does not install lsb.rpm. Sometimes the requirement to have lsb.rpm installed on Red Hat systems cannot be enforced.
To create rpms and init scripts that can be used on default Red Hat (without lsb.rpm being installed) and SUSE (LSB) requires knowing how to support both environments. This document outlines how to create such init scripts and rpms.
| Init Scripts | |||
Red Hat's specific handling of init scripts is different than how SUSE (LSB) handles them. It is possible to code for both the Red Hat's (using chkconfig) way of doing things as well as to follow the LSB specification.
First: The Comment Block
Near the top of the init script, you need to include comment blocks such as the following:
# chkconfig: 345 85 60 # description: Novell Thingy is a fly-trap server. # processname: lengine ### BEGIN INIT INFO # Provides: lengine # Required-Start: $local_fs $network $syslog # Should-Start: nthd # Required-Stop: # Default-Start: 3 4 5 # Default-Stop: 0 1 2 6 # Short-Description: Novell Thingy # Description: Novell Thingy Secure Fly Trap Server ### END INIT INFO
Refer to the following links for detailed information on chkconfig and INIT INFO:
or for LSB 1.3
For LSB 1.3 compliant systems you should use the X-UnitedLinux-Should-Start tag instead of the new LSB 2.0 Should-Start. Basically both keywords mean that nthd should start before novell-thingy if nthd is present on the system. If nthd is not on the system, the init script will still continue.
The item(s) that are provided via the Provides directive must be unique. It is wise to prefix them with a LANANA approved name (i.e. "novell-") to ensure uniqueness.
Second: Init Script Location
According to the LSB specification init scripts go in /etc/init.d, not the old, deprecated location /etc/rc.d/init.d. Linux Standard Base Project Specification
Next: The init Start/Stop Order
On Red Hat and SUSE systems, the symbolic links, in the given run level directory, determine the order by which services are started and stopped. For example:
/etc/rc.d/rc5.d/K06novell-thingy -> /etc/init.d/novell-thingy /etc/rc.d/rc5.d/S17novell-thingy -> /etc/init.d/novell-thingy
The symbolic link is named using the following convention:
{S,K}[0-9][0-9]<name>The 'K' means that the script is executed with a "stop" argument when leaving the runlevel. A 'S' means the script is executed with a "start" argument when entering the runlevel. The numbers determine the order in which the scripts are executed. The number field (e.g the 17 in S17novell-thingy) doesn't mean that the init script is the nth script invoked, it just means that the init script starts after any lower number specified init script and before any higher numbered init script.
On Red Hat systems using chkconfig you have explicit control over these numbers. You are responsible to make sure that you use a higher start number than the services you require started before yours (and vice-a-versa for stopping services).
With SUSE (LSB) you do not have explicit control. Instead you must list your dependencies using the Required-Start and Required-Stop keywords (Should-Start and Should-Stop can also be used in LSB 2.0 systems). When SUSE init script tools (insserv, etc.) are run they handle the numerical ordering of the symbolic links for you based on the dependency information you provide in the init script.
In the previous comment block example, the line:
Required-Start: $local_fs $network $syslogindicates, by start order, that local_fs, network and syslog services must be running before the current service is started. The Required-Stop keyword indicates what services must still be running during the shutdown of the service (however, this is currently ignored in SUSE; the reverse order of the Required-Start is used instead).
| RPM Issues | |||
To ensure that an rpm behaves the same in Red Hat and SUSE (LSB) there are a couple of changes that need to be made.
First: RPM %post scripts
In the rpm %post script you can enable services to be started automatically when the OS boots.
In the %post script, do something like:
if [ -x /usr/lib/lsb/install_initd ]; then
/usr/lib/lsb/install_initd /etc/init.d/novell-httpd
elif [ -x /sbin/chkconfig ]; then
/sbin/chkconfig --add novell-httpd
else
for i in 2 3 4 5; do
ln -sf /etc/init.d/novell-httpd /etc/rc.d/rc${i}.d/S90novell-httpd
done
for i in 1 6; do
ln -sf /etc/init.d/novell-httpd /etc/rc.d/rc${i}.d/K10novell-httpd
done
fi
Second: RPM %preun Scripts
To disable services when the package is being removed you do this in the %preun section of your rpm.
In the %preun script,do something like:
#only on uninstall, not on upgrades.
if [ $1 = 0 ]; then
/etc/init.d/novell-httpd stop > /dev/null 2>&1
if [ -x /usr/lib/lsb/remove_initd ]; then
/usr/lib/lsb/install_initd /etc/init.d/novell-httpd
elif [ -x /sbin/chkconfig ]; then
/sbin/chkconfig --del novell-httpd
else
rm -f /etc/rc.d/rc?.d/???novell-httpd
fi
fi
| Points to Remember | |||
Point 1:
On SUSE you must use their utilities to install and remove the init scripts. If you don't use them, the system won't know that the service is enabled. For instance, if nthd is installed but the symlinks are created through means other than install_initd, SUSE won't know that nthd is enabled at boot-time. When an application is installed that has a service listed in Required-Start, install_initd will fail to enable the service at boot-time because it thinks that service isn't enabled yet.
Also note that you must include INIT INFO comments in your init script on SUSE. If you don't, the next time insserv (install_initd) is executed your symlinks will be re-numbered to S01.
Point 2:
Avoid the following in your init scripts:
- Don't include the symlinks in /etc/rc.d/rc?.d in the %files section of the spec file.
- Don't install an init script on SUSE that doesn't have INIT INFO comments.
- Don't create symlinks in /etc/rc.d/rc?.d on SUSE by any means other then /usr/lib/lsb/install_initd.
Point 3:
Naming conventions and return codes for init scripts:
- There are certain actions that should be supported by init scripts (see the LSB specification).
- The return codes for those actions are also specified in the LSB specification.
- Use LSB/LANANA naming for init scripts to avoid collisions.
Point 4:
- There are also bash functions specified in the LSB specification that are available to be used in init scripts. It is also useful to have a common set of function names that can be used in init scripts that can be used on either platform.
# sample:Not all cases are tested.
MyStatus()
{
ps wt? | grep "$DAEMON" 2>&1 > /dev/null
if [ "x$?" = "x0" ]; then
RVAL=0
echo "Apache is running"
else
RVAL=3
echo "Apache is not running"
fi
}
if [ -f /lib/lsb/init-functions ]; then
. /lib/lsb/init-functions
alias START_DAEMON=start_daemon
alias STATUS=MyStatus
alias LOG_SUCCESS=log_success_msg
alias LOG_FAILURE=log_failure_msg
alias LOG_WARNING=log_warning_msg
elif [ -f /etc/init.d/functions ]; then
. /etc/init.d/functions
alias START_DAEMON=daemon
alias STATUS=status
alias LOG_SUCCESS=success
alias LOG_FAILURE=failure
alias LOG_WARNING=passed
else
echo "Error: your platform is not supported by $0" > /dev/stderr
exit 1
fi
| Conclusion | |||
Adhering to the LSB specifications is the best way to create init scripts and rpms. However, when LSB system compliance cannot be assured, the information contained in this document can be used to mitigate the differences between Red Hat specific conventions and SUSE (LSB) when creating init scripts and rpms.
Resources
- Read the complete LSB specification here.
- The FHS specification is found here.
- Another tutorial on creating LSB compliant applications is found here.
- For a complete description and usage of rpm go here.
- Linux Assigned Names and Numbers Authority (LANANA)
Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

