12 KiB
rpm-ostree install Command Flow Analysis
Overview
This document provides a detailed, step-by-step analysis of what happens when a user runs rpm-ostree install htop. The analysis is based on examination of the rpm-ostree source code and reveals the complex orchestration between client-side CLI parsing, D-Bus communication, daemon-side processing, and the underlying OSTree and DNF (libdnf) systems.
Command Entry Point
1. CLI Parsing and Validation
File: src/app/rpmostree-pkg-builtins.cxx
Function: rpmostree_builtin_install()
gboolean
rpmostree_builtin_install (int argc, char **argv, RpmOstreeCommandInvocation *invocation,
GCancellable *cancellable, GError **error)
Steps:
-
Option Parsing: Parse command-line options using GLib's
GOptionContext--reboot,--dry-run,--apply-live,--idempotent, etc.- Package names are extracted from positional arguments
-
Argument Validation: Ensure at least one package is specified
if (argc < 2) { rpmostree_usage_error (context, "At least one PACKAGE must be specified", error); return FALSE; } -
Interactive Confirmation: Handle
--apply-livewithout--assumeyes- If running interactively, perform a dry-run first and prompt for confirmation
- If non-interactive (script), auto-infer
--assumeyeswith a warning
-
Container Detection: Check if running in an OSTree container
- If in container, use different code path for container rebuilds
- Otherwise, proceed with normal system installation
2. Core Package Change Logic
Function: pkg_change()
Steps:
-
Package Classification: Determine package types
gboolean met_local_pkg = FALSE; for (const char *const *it = packages_to_add; it && *it; it++) met_local_pkg = met_local_pkg || g_str_has_suffix (*it, ".rpm") || g_str_has_prefix (*it, "file://"); -
Option Dictionary Creation: Build GVariant dictionary with all options
GVariantDict dict; g_variant_dict_init (&dict, NULL); g_variant_dict_insert (&dict, "reboot", "b", opt_reboot); g_variant_dict_insert (&dict, "cache-only", "b", opt_cache_only); g_variant_dict_insert (&dict, "download-only", "b", opt_download_only); // ... more options -
API Selection: Choose between legacy and new D-Bus APIs
- Legacy API:
rpmostree_os_call_pkg_change_sync()for simple cases - New API:
rpmostree_update_deployment()for complex cases (local packages, apply-live, etc.)
- Legacy API:
D-Bus Communication Layer
3. Client-Side D-Bus Setup
File: src/app/rpmostree-clientlib.cxx
Steps:
-
Daemon Startup: Ensure rpm-ostreed daemon is running
ROSCXX_TRY (client_start_daemon (), error); -
System Bus Connection: Connect to system D-Bus
g_autoptr (GDBusConnection) connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error); -
Client Registration: Register as a client with the daemon
g_dbus_connection_call_sync (connection, bus_name, sysroot_objpath, "org.projectatomic.rpmostree1.Sysroot", "RegisterClient", ...); -
OS Proxy Creation: Get proxy to the OS interface
glnx_unref_object RPMOSTreeOS *os_proxy = NULL; if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname, cancellable, &os_proxy, error)) return FALSE;
4. D-Bus Method Invocation
Legacy API Path (rpmostree_os_call_pkg_change_sync):
if (!rpmostree_os_call_pkg_change_sync (os_proxy, options, install_pkgs, uninstall_pkgs, NULL,
&transaction_address, NULL, cancellable, error))
return FALSE;
New API Path (rpmostree_update_deployment):
if (!rpmostree_update_deployment (os_proxy, NULL, /* refspec */
NULL, /* revision */
install_pkgs, install_fileoverride_pkgs, uninstall_pkgs,
NULL, /* override replace */
NULL, /* override remove */
NULL, /* override reset */
NULL, /* local_repo_remote */
NULL, /* treefile */
options, &transaction_address, cancellable, error))
return FALSE;
Daemon-Side Processing
5. D-Bus Method Handler
File: src/daemon/rpmostreed-os.cxx
Steps:
-
Authorization Check: Verify user permissions via Polkit
else if (g_strcmp0 (method_name, "PkgChange") == 0) { g_ptr_array_add (actions, (void *)"org.projectatomic.rpmostree1.install-uninstall-packages"); } -
Transaction Management: Check for existing transactions or create new one
if (!rpmostreed_sysroot_prep_for_txn (rsysroot, invocation, &transaction, &local_error)) return os_throw_dbus_invocation_error (invocation, &local_error); -
Transaction Creation: Create appropriate transaction type
- For package changes:
rpmostreed_transaction_new_pkg_change() - For deployment updates:
rpmostreed_transaction_new_update_deployment()
- For package changes:
-
Transaction Address Return: Return D-Bus object path for transaction monitoring
const char *client_address = rpmostreed_transaction_get_client_address (transaction); rpmostree_os_complete_pkg_change (interface, invocation, client_address);
6. Transaction Processing
File: src/daemon/rpmostreed-transaction.cxx
Steps:
- Transaction State Management: Track transaction progress and state
- Dependency Resolution: Use libdnf to resolve package dependencies
- Package Download: Download required RPM packages from repositories
- OSTree Integration: Prepare for OSTree commit creation
Core Package Management
7. DNF Integration (libdnf)
Steps:
-
Repository Setup: Initialize DNF context with configured repositories
g_autoptr (DnfContext) dnfctx = dnf_context_new (); -
Package Resolution: Resolve package names to specific RPM packages
hy_autoquery HyQuery query = hy_query_create (dnf_context_get_sack (dnfctx)); hy_query_filter (query, HY_PKG_NAME, HY_EQ, package_name); -
Dependency Resolution: Calculate full dependency tree
- Resolve all required dependencies
- Handle conflicts and alternatives
- Determine download order
-
Package Download: Download RPM files to local cache
- Use DNF's download infrastructure
- Verify package integrity
- Handle network failures and retries
8. OSTree Integration
Steps:
-
Base Tree Preparation: Get current OSTree deployment as base
OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot); -
Package Import: Import downloaded RPMs into OSTree repository
- Extract RPM contents
- Apply to filesystem tree
- Handle file conflicts and replacements
-
Commit Creation: Create new OSTree commit with layered packages
// Create new commit with package changes ostree_repo_prepare_transaction (repo, NULL, NULL, error); // ... package application logic ... ostree_repo_commit_transaction (repo, NULL, error); -
Metadata Generation: Generate commit metadata
- Package lists and versions
- Dependency information
- Origin and timestamp data
Filesystem and Deployment
9. Filesystem Assembly
Steps:
-
Base Tree Checkout: Checkout base OSTree commit to temporary location
-
Package Application: Apply RPM contents to filesystem
- Extract files from RPMs
- Handle file permissions and ownership
- Apply package scripts (preinst, postinst)
-
Layer Management: Create layered filesystem structure
/usr- Base system files (immutable)/var- Variable data (mutable)/etc- Configuration (merged)- Package overlays in
/usr/lib/rpm-ostree/
-
Script Execution: Run package installation scripts
- Pre-installation scripts
- Post-installation scripts
- Handle script failures and rollback
10. Deployment Management
Steps:
-
Deployment Creation: Create new OSTree deployment
ostree_sysroot_deploy_tree (sysroot, osname, new_commit, ...); -
Boot Configuration: Update bootloader configuration
- Generate new initramfs if needed
- Update kernel arguments
- Configure boot entries
-
State Persistence: Save deployment state
- Update deployment index
- Save package metadata
- Update rollback information
Transaction Monitoring
11. Progress Reporting
Steps:
-
Signal Emission: Emit D-Bus signals for progress
// Progress signals rpmostree_transaction_emit_percent_progress (transaction, "Downloading packages", 50); rpmostree_transaction_emit_message (transaction, "Installing htop-2.2.0-1.fc33.x86_64"); -
Client Monitoring: Client receives and displays progress
// Client connects to transaction and monitors signals rpmostree_transaction_client_run (invocation, sysroot_proxy, os_proxy, options, ...); -
Error Handling: Handle failures and provide rollback
- Network failures during download
- Package conflicts
- Script execution failures
- OSTree commit failures
12. Transaction Completion
Steps:
-
Success Path:
- Mark transaction as successful
- Emit completion signals
- Clean up temporary files
- Update system state
-
Failure Path:
- Rollback to previous state
- Clean up partial changes
- Emit error signals
- Provide error details
-
Reboot Handling: If
--rebootspecifiedif (opt_reboot) { // Schedule reboot after transaction completion rpmostree_sysroot_deploy_tree (sysroot, osname, new_commit, OSTREE_SYSROOT_DEPLOY_FLAGS_REBOOT, ...); }
Final Steps
13. System State Update
Steps:
-
Deployment Activation: Activate new deployment
- Update bootloader entries
- Set new deployment as default
- Preserve rollback deployment
-
Cache Updates: Update package metadata cache
- Refresh repository metadata
- Update package lists
- Cache dependency information
-
Cleanup: Remove temporary files and caches
- Clean downloaded RPMs
- Remove temporary directories
- Update system journal
14. User Feedback
Steps:
-
Status Display: Show final status
# Example output Checking out packages...done Running pre scripts...done Running post scripts...done Writing rpmdb...done Writing OSTree commit...done -
Deployment Information: Display deployment details
- New deployment checksum
- Package changes summary
- Reboot requirement (if applicable)
-
Next Steps: Provide guidance for user
- Reboot instructions if needed
- Package verification commands
- Rollback instructions
Key Architectural Insights
1. Client-Daemon Architecture
- CLI client handles user interaction and D-Bus communication
- Daemon (rpm-ostreed) handles all privileged operations
- Clear separation of concerns and security boundaries
2. Transaction-Based Design
- All operations wrapped in transactions
- Atomic operations with rollback capability
- Progress monitoring and cancellation support
3. Layered Filesystem Model
- Base OSTree commit remains immutable
- Package changes applied as overlays
- Clear separation between system and user packages
4. Dependency Management
- Full dependency resolution via libdnf
- Handles complex dependency graphs
- Conflict resolution and alternatives
5. Error Handling and Recovery
- Comprehensive error handling at each stage
- Automatic rollback on failures
- Detailed error reporting and logging
This analysis reveals the sophisticated architecture of rpm-ostree, which combines the atomic deployment model of OSTree with the powerful package management capabilities of DNF, all orchestrated through a robust client-daemon architecture with comprehensive transaction management.