developerWorks: Linux : Packaging software with RPM, Part 3

Feb 26, 2002 - The GNU indent program reformats C code to any of a variety of formatting ... %clean rm -rf $RPM_BUILD_ROOT. %files. %defattr(-,root,root).
63KB taille 2 téléchargements 238 vues
developerWorks: Linux : Packaging software with RPM, Part 3 .................

Advanced search IBM home | Products & services | Support & downloads | My account IBM developerWorks : Linux : Linux articles Packaging software with RPM, Part 3 Running scripts at install and uninstall Dan Poirier ([email protected]) Software engineer, IBM February 2002 RPM is a widely-used tool for delivering software for Linux. Users can easily install an RPM-packaged product. In this article, third in a series, Dan explains how to run scripts when your package is installed or uninstalled, or when other packages are installed or uninstalled. It's often useful to be able to execute commands when your program is installed or uninstalled on a user's machine. For example, you might need to edit a system configuration file to enable a new service, or need to define a new user to own the program that you're installing.

Contents: How install and uninstall scripts work Not so simple: upgrades complicate everything Triggers Advanced scripting Things to avoid Things to remember Resources About the author

To get the most out of the advice and examples in this article, take a look at Part 1 and Part 2 of this series, which show you how to use RPM and how to distribute your work, respectively.

Rate this article

Related content: How install and uninstall scripts work Packaging software with Install and uninstall scripts seem simple, but a few surprises in how they work can cause RPM, Part 1 big problems. Packaging software with Here are the basics. You can add any of the following four sections to your .spec file, RPM, Part 2 which lists shell scripts to run at various points in the install life of your package: Subscribe to the %pre developerWorks newsletter Runs before the package is installed Also in the Linux zone: %post Tutorials Runs after the package is installed Tools and products %preun Code and components Runs before the package is uninstalled Articles %postun Runs after the package is uninstalled In particular, note the difference between %install and these sections. %install runs on your development machine when you are building the RPM; it should install the product on your development machine, or into a build root. These sections, on the other hand, specify what will run on the user's machine when the user is installing or uninstalling your RPM package. Here's an example, building on the previous articles. We want to use install-info to add GNU indent's info file to the directory. Listing 1. indent-4.spec

http://www-106.ibm.com/developerworks/library/l-rpm3.html (1 of 8) [2/26/2002 8:41:44 AM]

developerWorks: Linux : Packaging software with RPM, Part 3

# Simplistic example of install scripts - do not use Summary: GNU indent Name: indent Version: 2.2.6 Release: 4 Source0: %{name}-%{version}.tar.gz License: GPL Group: Development/Tools BuildRoot: %{_builddir}/%{name}-root %description The GNU indent program reformats C code to any of a variety of formatting standards, or you can define your own. %prep %setup -q %build ./configure make %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %post if [ -x /sbin/install-info ]; then /sbin/install-info /usr/local/info/indent.info /usr/local/info/dir fi %preun if [ -x /sbin/install-info ]; then /sbin/install-info --delete /usr/local/info/indent.info /usr/local/info/dir fi %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) /usr/local/bin/indent %doc /usr/local/info/indent.info %doc %attr(0444,root,root) /usr/local/man/man1/indent.1 %doc COPYING AUTHORS README NEWS Note first that we check for the install-info tool before trying to use it. We don't want our install to fail just because we cannot provide a link to the product documentation. But there might be cases where you would like an installation to fail. A good technique is to use the %pre script to check for installation prerequisites that are more complex than what RPM can support directly. If the prerequisites are not met, the script exits with a non-zero status, and RPM does not continue with the installation. Notice also that we are careful to undo our install script using an uninstall script. Not so simple: upgrades complicate everything Now let's turn to upgrades. The instructions in the previous section work fine if users only install and delete your package; they fail badly during upgrades. http://www-106.ibm.com/developerworks/library/l-rpm3.html (2 of 8) [2/26/2002 8:41:44 AM]

developerWorks: Linux : Packaging software with RPM, Part 3

Here's how RPM performs an upgrade: ● Run %pre of new package ● Install new files ● Run %post of new package ● Run %preun of old package ● Delete any old files not overwritten by newer ones ● Run %postun of old package If we do an upgrade using our previous example, the last thing that RPM runs is the %postun script, which removes all the work we did in our install script! This is not exactly what the average RPM-using developer would have guessed. I won't try to explain the reasons for this, just what you have to do about it. Luckily, there is a way for a script to tell if the package is being installed, deleted, or upgraded -- sort of. Each script is passed a single command-line argument, a number. This is supposed to tell the script how many copies of the package will be installed after the current package has finished installing or uninstalling. Rather than trying to figure this out, it's probably easier to just look at the values that get passed in various cases. Here are the actual values passed during an install: ● Run %pre of new package (1) ● Install new files ● Run %post of new package (1) Here are the values passed during an upgrade: ● Run %pre of new package (2) ● Install new files ● Run %post of new package (2) ● Run %preun of old package (1) ● Delete any old files not overwritten by newer ones ● Run %postun of old package (1) Here are the values passed during a delete: ● Run %preun of old package (0) ● Delete files ● Run %postun of old package (0) You can test this yourself by adding something like the next example to your package. Then make a new package with a slightly higher release number, and you can install the first, then upgrade to the second, and finally uninstall it, to see all the possibilities. And of course, you will always want to try this several times yourself before releasing any RPM on an unsuspecting public. Listing 2. Test order and arguments for script execution %pre echo This is pre for %{version}-%{release}: arg=$1 %post echo This is post for %{version}-%{release}: arg=$1 %preun echo This is preun for %{version}-%{release}: arg=$1 %postun echo This is postun for %{version}-%{release}: arg=$1

http://www-106.ibm.com/developerworks/library/l-rpm3.html (3 of 8) [2/26/2002 8:41:44 AM]

developerWorks: Linux : Packaging software with RPM, Part 3

Here's another example, this time coping correctly with the upgrade process: Listing 3. indent-5.spec Summary: GNU indent Name: indent Version: 2.2.6 Release: 5 Source0: %{name}-%{version}.tar.gz License: GPL Group: Development/Tools BuildRoot: %{_builddir}/%{name}-root %description The GNU indent program reformats C code to any of a variety of formatting standards, or you can define your own. %prep %setup -q %build ./configure make %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %post if [ "$1" = "1" ] ; then # first install if [ -x /sbin/install-info ]; then /sbin/install-info /usr/local/info/indent.info /usr/local/info/dir fi fi %preun if [ "$1" = "0" ] ; then # last uninstall if [ -x /sbin/install-info ]; then /sbin/install-info --delete /usr/local/info/indent.info /usr/local/info/dir fi fi %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) /usr/local/bin/indent %doc /usr/local/info/indent.info %doc %attr(0444,root,root) /usr/local/man/man1/indent.1 %doc COPYING AUTHORS README NEWS Now the info link will be removed only when the package is being completely deleted. Triggers -- running scripts when other packages are installed or uninstalled Suppose you want to run some code in your package when other packages are installed or uninstalled. You can do it with trigger scripts.

http://www-106.ibm.com/developerworks/library/l-rpm3.html (4 of 8) [2/26/2002 8:41:44 AM]

developerWorks: Linux : Packaging software with RPM, Part 3

Why would you want to do this? Usually because your package uses the services of one or more other packages, or provides services to one or more other packages. Here's an example. Suppose you're packaging up a nifty add-on tool for the Emacs and Xemacs editors. It can work with either or both, but you need to do some minor configuration depending on which editors are installed. At install time, you can test for Emacs and Xemacs and configure your tool to be accessible by the available editors. But what happens if the user installs Xemacs later? Your tool won't be usable in Xemacs unless the user uninstalls and reinstalls your tool. Wouldn't it be better if your package could tell RPM, "let me know if Xemacs gets installed"? That's the idea of trigger scripts. You can add this to your .spec file: Listing 4. Trigger example %triggerin -- emacs # Insert code here to run if your package is already installed, # then emacs is installed, # OR if emacs is already installed, then your package is installed %triggerin -- xemacs # Insert code here to run if your package is already installed, # then xemacs is installed, # OR if xemacs is already installed, then your package is installed %triggerun -- emacs # insert code here to run if your package is already installed, # then emacs is uninstalled %triggerun -- xemacs # insert code here to run if your package is already installed, # then xemacs is uninstalled %postun # Insert code here to run if your package is uninstalled Trigger scripts are passed two arguments. The first argument is the number of instances of your package that will be installed when your trigger script has completed running. The second argument is the number of instances of the triggering package that will be installed when your trigger script has completed running. From the triggers file in the RPM distribution, here's the complete ordering of script executions and file installs and uninstalls during an RPM upgrade: Listing 5. Script ordering new-%pre ... new-%post

for new version of package being installed (all new files are installed) for new version of package being installed

any-%triggerin (%triggerin from other packages set off by new install) new-%triggerin old-%triggerun any-%triggerun (%triggerun from other packages set off by old uninstall) old-%preun ... old-%postun

for old version of package being removed (all old files are removed) for old version of package being removed

old-%triggerpostun any-%triggerpostun (%triggerpostun from other packages set off by old un http://www-106.ibm.com/developerworks/library/l-rpm3.html (5 of 8) [2/26/2002 8:41:44 AM]

developerWorks: Linux : Packaging software with RPM, Part 3

install) Advanced scripting Alternate interpreters Ordinarily, all install-time scripts and trigger scripts are run using the /bin/sh shell program. If you prefer another scripting language, say Perl, you can tell RPM that your script should be run using another interpreter by adding -p interpreter to the script line. For example: Listing 6. Example of alternate interpreters %post -p /usr/bin/perl # Perl script here %triggerun -p /usr/bin/perl -- xemacs # Another Perl script here Note that this does not apply to the build-time scripts of RPM, such as %install. RPM variables RPM expands RPM variables in your scripts before storing them into the RPM package file, which can be useful sometimes. For example, you can define your own variables near the top of your .spec file, and then refer to them using %{variable_name} all through your .spec file -- and even in your scripts: Listing 7. Example of RPM variables ... %define foo_dir /usr/lib/foo ... %install cp install.time.message $RPM_BUILD_ROOT/%{foo_dir} %files %{foo_dir}/install.time.message %post /bin/cat %{foo_dir}/install.time.message Things to avoid You might be tempted to do some things at install time that turn out to be a bad idea. For example, any attempt to interact with the user probably won't work very well. RPM is designed to allow batch installs, during which no user is necessarily present. If an RPM package stops during an install to ask a question, and no one sees the question, the install will appear to just hang forever. Another thing you probably want to avoid is starting any services. During a complete installation, you can't be sure if everything that your program needs is there already (for example, there might not be any network yet); also, if every RPM service tried to start during a complete operating system install, the entire install would probably take significantly longer. What you can do in such cases is print a message telling the user about any required configuration or service that needs to be started. If a user is installing your RPM package manually, he or she will see it; if it's part of a larger batch install, it won't hurt anything, and the machine will almost certainly be rebooted at the end, starting your service. Things to remember If your package installs an init script, you can use chkconfig to arrange for your service to be started and stopped in the appropriate run-levels. Though you can accomplish the same thing by installing the necessary symbolic links directly as part of your package, getting them right is a pesky detail that you might prefer to leave to chkconfig.

http://www-106.ibm.com/developerworks/library/l-rpm3.html (6 of 8) [2/26/2002 8:41:44 AM]

developerWorks: Linux : Packaging software with RPM, Part 3

A number of services run under a specific user id for security; if yours does, you will need to create that user on the system if it doesn't already exist. If your package installs any GNU info files, they won't be visible in the Info directory unless you use the install-info tool to add them at install time. Before uninstalling, you should almost certainly attempt to stop any services your package might be running (but be sure the uninstall won't fail if the service isn't running). At uninstall, of course you should reverse most changes you might have made to the system at install-time. But give a little thought to your actions; uninstalling an RPM package should not, for example, accidentally delete any user-created files. So you might be better off not trying to remove a user ID, or deleting entire directory trees. Resources ● Part 1 in this RPM series introduces the process for building software packages with RPM, and Part 2 explains how to build without root, patch software, and distribute RPM. ●

Some Linux distributions use Debian's APT tool for package management.



The RPM Web site has pointers to many useful resources. The RPM e-mail list is a good place to ask questions.



Maximum RPM is a book about using RPM. It has become quite outdated, but an effort is underway to update it.



The RPM HOWTO is also getting somewhat dated. It covers some of the same ground as this article.



Eric S. Raymond's Software Release Practice HOWTO document is not specific to RPM or Linux. But it does give many good tips on releasing software in a way that makes it easy for users to use and programmers to contribute fixes and improvements.



The Free Software Foundation is the source for GNU Indent and many other useful software packages -including glibc and emacs.



Browse more Linux resources on developerWorks.



Browse more Open source resources on developerWorks.

About the author Dan Poirier is an Advisory Software Engineer at IBM. He currently works in Research Triangle Park, North Carolina, on network appliances that run Linux. Contact Dan at [email protected].

What do you think of this article? Killer! (5)

Good stuff (4)

So-so; not bad (3)

Needs work (2)

Comments?

Submit feedback

http://www-106.ibm.com/developerworks/library/l-rpm3.html (7 of 8) [2/26/2002 8:41:44 AM]

Lame! (1)

developerWorks: Linux : Packaging software with RPM, Part 3

About IBM | Privacy | Legal | Contact

http://www-106.ibm.com/developerworks/library/l-rpm3.html (8 of 8) [2/26/2002 8:41:44 AM]