执行RPM更新时如何保留旧配置/元数据文件
问题拆解与解决方案
Let's break down your problem and walk through the solutions step by step:
1. How to implement the requirement
The core idea is to delay overwriting the old file Y1 until after the system reboots, which requires combining RPM's installation scripts with a system startup service. Here's the workflow:
- Backup the old Y1 before installing the new RPM.
- Install the updated Y1 to a temporary location instead of overwriting the original directly.
- Set up a one-time service that runs after the next system reboot to replace the old Y1 with the new one.
- Handle rollback scenarios in case the new RPM is uninstalled before reboot.
2. Are rpmsave/rpmnew suitable?
Short answer: No, they don't fit this specific requirement. Here's why:
.rpmsaveis only created automatically if the existing Y1 was modified by the user (differs from the original content in the old RPM). If Y1 is unmodified, RPM will overwrite it immediately—violating your need to keep the old file until reboot..rpmnewapplies to%config(noreplace)files. When a new RPM has an updated config file, it saves the new version as.rpmnewinstead of overwriting the modified old file. But this doesn't automate the replacement after reboot—you'd have to manually swap them later, which isn't what you want.
These features are designed for handling user-modified files, not scheduling delayed overwrites regardless of file state.
3. Concrete Example
Let's assume your package is named mypkg, and the file Y1 is /etc/mypkg/config.yaml. Here's how to adjust the RPM spec file for version 2 (rpm2):
Step 1: Adjust the file installation path
In the %files section of your spec file, install the updated Y1 to a temporary path instead of the original:
%files /etc/mypkg/config.yaml.new /usr/lib/systemd/system/mypkg-post-update.service # Include other files from your package here
Step 2: Backup the old Y1 in the %pre script
Add a pre-install script to save the existing Y1 if it exists:
%pre # Create backup directory if it doesn't exist mkdir -p /var/lib/mypkg/backups # Backup the old config file if [ -f /etc/mypkg/config.yaml ]; then cp -a /etc/mypkg/config.yaml /var/lib/mypkg/backups/config.yaml.old fi
Step 3: Create a systemd one-shot service for post-reboot replacement
Create a service file mypkg-post-update.service with the following content:
[Unit] Description=Apply mypkg config update after system reboot After=multi-user.target # Run after the system reaches multi-user mode [Service] Type=oneshot # Replace the old config with the new one ExecStart=/usr/bin/mv -f /etc/mypkg/config.yaml.new /etc/mypkg/config.yaml # Clean up the backup after successful replacement ExecStartPost=/usr/bin/rm -rf /var/lib/mypkg/backups # Mark the service as completed after running RemainAfterExit=yes [Install] WantedBy=multi-user.target
Step 4: Enable the service in the %post script
After installing the RPM, reload systemd and enable the service to run on next reboot:
%post systemctl daemon-reload systemctl enable --now mypkg-post-update.service
Step 5: Handle rollback in %postun script
If the user uninstalls rpm2 before rebooting, restore the old Y1 and clean up:
%postun # $1 equals 0 when performing a full uninstall if [ $1 -eq 0 ]; then # Disable and stop the service systemctl disable --now mypkg-post-update.service # Restore the old config file if backup exists if [ -f /var/lib/mypkg/backups/config.yaml.old ]; then mv -f /var/lib/mypkg/backups/config.yaml.old /etc/mypkg/config.yaml rm -rf /var/lib/mypkg/backups fi # Remove the temporary new config file rm -f /etc/mypkg/config.yaml.new fi
Usage
Install the RPM as usual:
rpm -Uvh mypkg-2.0.rpm
After installation:
- The old
/etc/mypkg/config.yamlremains intact. - The new config is at
/etc/mypkg/config.yaml.new. - The systemd service is enabled to run on the next reboot.
Once the system reboots, the service will automatically replace the old config with the new one, completing the update.
内容的提问来源于stack exchange,提问作者xyz

