4242#include < libdnf5/utils/fs/file.hpp>
4343#include < libdnf5/utils/patterns.hpp>
4444#include < rpm/rpmtypes.h>
45+ #include < signal.h>
4546
4647#include < algorithm>
4748#include < cctype>
@@ -58,6 +59,47 @@ namespace dnf5 {
5859
5960namespace {
6061
62+ // Helper function to format active transaction information for error messages
63+ std::string format_active_transaction_info (const libdnf5::base::ActiveTransactionInfo & info) {
64+ std::string result;
65+
66+ if (!info.get_description ().empty ()) {
67+ result += libdnf5::utils::sformat (_ (" Command: {}" ), info.get_description ());
68+ }
69+
70+ if (info.get_pid () > 0 ) {
71+ if (!result.empty ()) {
72+ result += " \n " ;
73+ }
74+ if (kill (info.get_pid (), 0 ) == 0 ) {
75+ result += libdnf5::utils::sformat (_ (" Process ID: {} (still running)" ), info.get_pid ());
76+ } else {
77+ result += libdnf5::utils::sformat (_ (" Process ID: {}" ), info.get_pid ());
78+ }
79+ }
80+
81+ if (info.get_start_time () > 0 ) {
82+ if (!result.empty ()) {
83+ result += " \n " ;
84+ }
85+ result +=
86+ libdnf5::utils::sformat (_ (" Started: {}" ), libdnf5::utils::string::format_epoch (info.get_start_time ()));
87+ }
88+
89+ if (!info.get_comment ().empty ()) {
90+ if (!result.empty ()) {
91+ result += " \n " ;
92+ }
93+ result += libdnf5::utils::sformat (_ (" Comment: {}" ), info.get_comment ());
94+ }
95+
96+ if (!result.empty ()) {
97+ result = _ (" Details about the currently running transaction:\n " ) + result;
98+ }
99+
100+ return result;
101+ }
102+
61103// The `KeyImportRepoCB` class implements callback only for importing repository key.
62104class KeyImportRepoCB : public libdnf5 ::repo::RepoCallbacks2_1 {
63105public:
@@ -377,6 +419,18 @@ void Context::Impl::store_offline(libdnf5::base::Transaction & transaction) {
377419 if (result != libdnf5::base::Transaction::TransactionRunResult::SUCCESS) {
378420 print_error (libdnf5::utils::sformat (
379421 _ (" Transaction failed: {}" ), libdnf5::base::Transaction::transaction_result_to_string (result)));
422+
423+ // For transaction lock errors, provide detailed information about the running transaction
424+ if (result == libdnf5::base::Transaction::TransactionRunResult::ERROR_LOCK) {
425+ auto * active_info = transaction.get_concurrent_transaction ();
426+ if (active_info) {
427+ auto info_str = format_active_transaction_info (*active_info);
428+ if (!info_str.empty ()) {
429+ print_error (info_str);
430+ }
431+ }
432+ }
433+
380434 for (auto const & entry : transaction.get_gpg_signature_problems ()) {
381435 print_error (entry);
382436 }
@@ -530,6 +584,18 @@ void Context::Impl::download_and_run(libdnf5::base::Transaction & transaction) {
530584 if (result != libdnf5::base::Transaction::TransactionRunResult::SUCCESS) {
531585 print_error (libdnf5::utils::sformat (
532586 _ (" Transaction failed: {}" ), libdnf5::base::Transaction::transaction_result_to_string (result)));
587+
588+ // For transaction lock errors, provide detailed information about the running transaction
589+ if (result == libdnf5::base::Transaction::TransactionRunResult::ERROR_LOCK) {
590+ auto * active_info = transaction.get_concurrent_transaction ();
591+ if (active_info) {
592+ auto info_str = format_active_transaction_info (*active_info);
593+ if (!info_str.empty ()) {
594+ print_error (info_str);
595+ }
596+ }
597+ }
598+
533599 for (auto const & entry : transaction.get_gpg_signature_problems ()) {
534600 print_error (entry);
535601 }
0 commit comments