1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
24 #include <solv/transaction.h>
26 #include <pakfire/archive.h>
27 #include <pakfire/db.h>
28 #include <pakfire/downloader.h>
29 #include <pakfire/execute.h>
30 #include <pakfire/file.h>
31 #include <pakfire/filelist.h>
32 #include <pakfire/i18n.h>
33 #include <pakfire/logging.h>
34 #include <pakfire/package.h>
35 #include <pakfire/pakfire.h>
36 #include <pakfire/private.h>
37 #include <pakfire/repo.h>
38 #include <pakfire/transaction.h>
39 #include <pakfire/types.h>
40 #include <pakfire/ui.h>
41 #include <pakfire/util.h>
43 struct pakfire_transaction
{
47 Transaction
* transaction
;
50 PakfireArchive
* archives
;
51 struct pakfire_package
** packages
;
55 enum pakfire_actions
{
56 PAKFIRE_ACTION_NOOP
= 0,
57 PAKFIRE_ACTION_VERIFY
,
58 PAKFIRE_ACTION_EXECUTE
,
59 PAKFIRE_ACTION_PRETRANS
,
60 PAKFIRE_ACTION_POSTTRANS
,
64 PAKFIRE_STEP_IGNORE
= 0,
66 PAKFIRE_STEP_REINSTALL
,
69 PAKFIRE_STEP_DOWNGRADE
,
70 PAKFIRE_STEP_OBSOLETE
,
73 static enum pakfire_steps
pakfire_transaction_get_step_type(
74 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
75 int type
= transaction_type(transaction
->transaction
, pakfire_package_id(pkg
),
76 SOLVER_TRANSACTION_SHOW_ACTIVE
|SOLVER_TRANSACTION_CHANGE_IS_REINSTALL
);
78 // Translate solver types into our own types
80 case SOLVER_TRANSACTION_INSTALL
:
81 case SOLVER_TRANSACTION_MULTIINSTALL
:
82 return PAKFIRE_STEP_INSTALL
;
84 case SOLVER_TRANSACTION_REINSTALL
:
85 case SOLVER_TRANSACTION_MULTIREINSTALL
:
86 return PAKFIRE_STEP_REINSTALL
;
88 case SOLVER_TRANSACTION_ERASE
:
89 return PAKFIRE_STEP_ERASE
;
91 case SOLVER_TRANSACTION_DOWNGRADE
:
92 return PAKFIRE_STEP_DOWNGRADE
;
94 case SOLVER_TRANSACTION_UPGRADE
:
95 return PAKFIRE_STEP_UPGRADE
;
97 case SOLVER_TRANSACTION_OBSOLETES
:
98 return PAKFIRE_STEP_OBSOLETE
;
100 // Anything we don't care about
101 case SOLVER_TRANSACTION_IGNORE
:
102 case SOLVER_TRANSACTION_REINSTALLED
:
103 case SOLVER_TRANSACTION_DOWNGRADED
:
105 return PAKFIRE_STEP_IGNORE
;
109 static void pakfire_transaction_free_archives_and_packages(
110 struct pakfire_transaction
* transaction
) {
111 if (transaction
->archives
) {
112 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
113 if (transaction
->archives
[i
])
114 pakfire_archive_unref(transaction
->archives
[i
]);
115 free(transaction
->archives
);
117 transaction
->archives
= NULL
;
120 if (transaction
->packages
) {
121 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
122 if (transaction
->packages
[i
])
123 pakfire_package_unref(transaction
->packages
[i
]);
124 free(transaction
->packages
);
126 transaction
->packages
= NULL
;
130 static void pakfire_transaction_free(struct pakfire_transaction
* transaction
) {
131 pakfire_transaction_free_archives_and_packages(transaction
);
133 if (transaction
->userinstalled
) {
134 for (char** userinstalled
= transaction
->userinstalled
; *userinstalled
; userinstalled
++)
135 free(*userinstalled
);
136 free(transaction
->userinstalled
);
138 transaction_free(transaction
->transaction
);
140 pakfire_unref(transaction
->pakfire
);
144 static int pakfire_transaction_import_transaction(
145 struct pakfire_transaction
* transaction
, Solver
* solver
) {
146 // Clone the transaction to keep a copy of it
147 Transaction
* t
= solver_create_transaction(solver
);
151 transaction
->transaction
= t
;
153 // Order the transaction
154 transaction_order(t
, 0);
156 // Free any previous content
157 pakfire_transaction_free_archives_and_packages(transaction
);
160 transaction
->num
= t
->steps
.count
;
162 // Allocate space for packages
163 transaction
->packages
= calloc(transaction
->num
, sizeof(*transaction
->packages
));
164 if (!transaction
->packages
)
167 // Allocate space for archives
168 transaction
->archives
= calloc(transaction
->num
, sizeof(*transaction
->archives
));
169 if (!transaction
->archives
)
172 // Create all packages
173 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
174 transaction
->packages
[i
] = pakfire_package_create_from_solvable(
175 transaction
->pakfire
, t
->steps
.elements
[i
]);
181 static int pakfire_transaction_import_userinstalled(
182 struct pakfire_transaction
* t
, Solver
* solver
) {
183 if (t
->userinstalled
) {
184 free(t
->userinstalled
);
185 t
->userinstalled
= NULL
;
189 queue_init(&userinstalled
);
191 // Fetch a list of all packages that are installed by the user
192 solver_get_userinstalled(solver
, &userinstalled
, GET_USERINSTALLED_NAMES
);
194 // Skip everything if the queue is empty
195 if (!userinstalled
.count
)
198 t
->userinstalled
= calloc(userinstalled
.count
+ 1, sizeof(*t
->userinstalled
));
199 if (!t
->userinstalled
) {
200 ERROR(t
->pakfire
, "Could not allocate userinstalled\n");
204 Pool
* pool
= pakfire_get_solv_pool(t
->pakfire
);
206 // Store the names of all userinstalled packages
207 for (int i
= 0; i
< userinstalled
.count
; i
++) {
208 const char* package
= pool_id2str(pool
, userinstalled
.elements
[i
]);
209 t
->userinstalled
[i
] = strdup(package
);
215 int pakfire_transaction_create(struct pakfire_transaction
** transaction
,
216 Pakfire pakfire
, Solver
* solver
) {
217 struct pakfire_transaction
* t
= calloc(1, sizeof(*t
));
221 // Store reference to Pakfire
222 t
->pakfire
= pakfire_ref(pakfire
);
224 // Initialize the reference counter
227 // Import transaction
228 int r
= pakfire_transaction_import_transaction(t
, solver
);
232 // Import userinstalled
233 r
= pakfire_transaction_import_userinstalled(t
, solver
);
241 pakfire_transaction_free(t
);
245 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_ref(
246 struct pakfire_transaction
* transaction
) {
247 transaction
->nrefs
++;
252 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_unref(
253 struct pakfire_transaction
* transaction
) {
254 if (--transaction
->nrefs
> 0)
257 pakfire_transaction_free(transaction
);
261 PAKFIRE_EXPORT
size_t pakfire_transaction_count(struct pakfire_transaction
* transaction
) {
262 return transaction
->num
;
265 static ssize_t
pakfire_transaction_installsizechange(struct pakfire_transaction
* transaction
) {
266 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
268 // Convert from kbytes to bytes
269 return sizechange
* 1024;
272 PAKFIRE_EXPORT ssize_t
pakfire_transaction_downloadsize(struct pakfire_transaction
* transaction
) {
275 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
276 size
+= pakfire_package_get_downloadsize(transaction
->packages
[i
]);
281 static void pakfire_transaction_append_line(char*** lines
, const char* format
, ...) {
289 va_start(args
, format
);
290 r
= vasprintf(&buffer
, format
, args
);
297 unsigned int count
= 0;
299 for (char** l
= *lines
; *l
; l
++)
303 // Increase size of array
304 *lines
= reallocarray(*lines
, count
+ 2, sizeof(**lines
));
308 // Append line and terminate lines
309 (*lines
)[count
] = buffer
;
310 (*lines
)[count
+ 1] = NULL
;
313 static void pakfire_transaction_add_headline(char*** lines
, size_t width
, const char* headline
) {
314 pakfire_transaction_append_line(lines
, "%s\n", headline
);
317 static void pakfire_transaction_add_newline(char*** lines
, size_t width
) {
318 pakfire_transaction_append_line(lines
, "\n");
321 static void pakfire_transaction_add_line(char*** lines
, size_t width
, const char* name
,
322 const char* arch
, const char* version
, const char* repo
, const char* size
) {
323 pakfire_transaction_append_line(lines
, " %-21s %-8s %-21s %-18s %6s \n",
324 name
, arch
, version
, repo
, size
);
327 static void pakfire_transaction_add_package(char*** lines
, size_t width
, struct pakfire_package
* pkg
) {
330 PakfireRepo repo
= pakfire_package_get_repo(pkg
);
333 pakfire_format_size(size
, sizeof(size
) - 1, pakfire_package_get_size(pkg
));
335 pakfire_transaction_add_line(lines
, width
,
336 pakfire_package_get_name(pkg
),
337 pakfire_package_get_arch(pkg
),
338 pakfire_package_get_evr(pkg
),
339 pakfire_repo_get_name(repo
),
343 pakfire_repo_unref(repo
);
346 static void pakfire_transaction_add_package_change(char*** lines
, size_t width
,
347 struct pakfire_package
* old_pkg
, struct pakfire_package
* new_pkg
) {
348 // Print the new package first
349 pakfire_transaction_add_package(lines
, width
, new_pkg
);
351 pakfire_transaction_append_line(lines
,
352 " --> %s\n", pakfire_package_get_nevra(old_pkg
));
355 static void pakfire_transaction_add_separator(char*** lines
, size_t width
) {
356 char* separator
= alloca(width
+ 1);
358 for (unsigned int i
= 0; i
< width
; i
++)
360 separator
[width
] = '\0';
362 pakfire_transaction_append_line(lines
, "%s\n", separator
);
365 static void pakfire_transaction_add_usage_line(char*** lines
, size_t width
,
366 const char* headline
, ssize_t size
) {
368 pakfire_format_size(buffer
, sizeof(buffer
) - 1, size
);
370 pakfire_transaction_append_line(lines
, "%-21s: %s\n", headline
, buffer
);
373 static char* pakfire_transaction_join_lines(char** lines
) {
379 // Determine total length
380 for (char** line
= lines
; *line
; line
++)
381 size
+= strlen(*line
);
383 // Allocate memory large enough to hold the result
384 char* s
= calloc(1, size
+ 1);
390 for (char** line
= lines
; *line
; line
++) {
391 p
+= snprintf(p
, s
- p
- 1, "%s", *line
);
397 PAKFIRE_EXPORT
char* pakfire_transaction_dump(struct pakfire_transaction
* transaction
, size_t width
) {
400 Pool
* pool
= transaction
->transaction
->pool
;
402 SOLVER_TRANSACTION_SHOW_OBSOLETES
|
403 SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE
;
408 pakfire_transaction_add_separator(&lines
, width
);
409 pakfire_transaction_add_line(&lines
, width
,
416 pakfire_transaction_add_separator(&lines
, width
);
419 queue_init(&classes
);
422 transaction_classify(transaction
->transaction
, mode
, &classes
);
428 The classes queue now contains a list of all classes as a tuple of:
430 * The number of packages in this class
431 * The from ID (for arch/vendor change)
432 * The to ID (for arch/vendor change)
434 for (int i
= 0; i
< classes
.count
; i
+= 4) {
435 Id
class = classes
.elements
[i
];
436 unsigned int count
= classes
.elements
[i
+1];
438 const char* from
= pool_id2str(pool
, classes
.elements
[i
+2]);
439 const char* to
= pool_id2str(pool
, classes
.elements
[i
+3]);
442 case SOLVER_TRANSACTION_INSTALL
:
444 pakfire_string_format(headline
, _("Installing %u packages:"), count
);
446 pakfire_string_set(headline
, _("Installing one package:"));
449 case SOLVER_TRANSACTION_REINSTALLED
:
451 pakfire_string_format(headline
, _("Reinstalling %u packages:"), count
);
453 pakfire_string_set(headline
, _("Reinstalling one package:"));
456 case SOLVER_TRANSACTION_ERASE
:
458 pakfire_string_format(headline
, _("Removing %u packages:"), count
);
460 pakfire_string_set(headline
, _("Removing one package:"));
463 case SOLVER_TRANSACTION_UPGRADED
:
465 pakfire_string_format(headline
, _("Updating %u packages:"), count
);
467 pakfire_string_set(headline
, _("Updating one package:"));
470 case SOLVER_TRANSACTION_DOWNGRADED
:
472 pakfire_string_format(headline
, _("Downgrading %u packages:"), count
);
474 pakfire_string_set(headline
, _("Downgrading one package:"));
477 case SOLVER_TRANSACTION_CHANGED
:
479 pakfire_string_format(headline
, _("Changing %u packages:"), count
);
481 pakfire_string_set(headline
, _("Changing one package:"));
484 case SOLVER_TRANSACTION_ARCHCHANGE
:
486 pakfire_string_format(headline
,
487 _("%u architecture changes from '%s' to '%s':"), count
, from
, to
);
489 pakfire_string_format(headline
,
490 _("One architecture change from '%s' to '%s':"), from
, to
);
493 case SOLVER_TRANSACTION_VENDORCHANGE
:
495 pakfire_string_format(headline
,
496 _("%u vendor changes from '%s' to '%s':"), count
, from
, to
);
498 pakfire_string_format(headline
,
499 _("One vendor change from '%s' to '%s':"), from
, to
);
502 case SOLVER_TRANSACTION_IGNORE
:
506 // Show what we are doing
507 pakfire_transaction_add_headline(&lines
, width
, headline
);
509 // Fetch packages in this class
510 transaction_classify_pkgs(transaction
->transaction
, mode
, class,
511 classes
.elements
[i
+2], classes
.elements
[i
+3], &pkgs
);
514 for (int j
= 0; j
< pkgs
.count
; j
++) {
515 struct pakfire_package
* old_pkg
= pakfire_package_create_from_solvable(
516 transaction
->pakfire
, pkgs
.elements
[j
]);
517 struct pakfire_package
* new_pkg
= NULL
;
520 case SOLVER_TRANSACTION_UPGRADED
:
521 case SOLVER_TRANSACTION_DOWNGRADED
:
522 new_pkg
= pakfire_package_create_from_solvable(transaction
->pakfire
,
523 transaction_obs_pkg(transaction
->transaction
, pkgs
.elements
[j
]));
525 pakfire_transaction_add_package_change(&lines
, width
, old_pkg
, new_pkg
);
529 pakfire_transaction_add_package(&lines
, width
, old_pkg
);
533 pakfire_package_unref(old_pkg
);
535 pakfire_package_unref(new_pkg
);
539 pakfire_transaction_add_newline(&lines
, width
);
542 queue_free(&classes
);
546 pakfire_transaction_add_headline(&lines
, width
, _("Transaction Summary"));
547 pakfire_transaction_add_separator(&lines
, width
);
549 // How much do we need to download?
550 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
552 if (downloadsize
> 0)
553 pakfire_transaction_add_usage_line(&lines
, width
,
554 _("Total Download Size"), downloadsize
);
556 // How much more space do we need?
557 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
558 pakfire_transaction_add_usage_line(&lines
, width
,
559 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
561 // Join all lines together
562 char* string
= pakfire_transaction_join_lines(lines
);
564 DEBUG(transaction
->pakfire
, "Transaction: %s\n", string
);
568 for (char** line
= lines
; *line
; line
++)
576 static int pakfire_transaction_verify(struct pakfire_transaction
* transaction
,
577 struct pakfire_package
* pkg
, PakfireArchive archive
) {
578 // Nothing to do if this step does not have an archive
582 // Verify the archive
583 pakfire_archive_verify_status_t status
= pakfire_archive_verify(archive
);
587 const char* error
= pakfire_archive_verify_strerror(status
);
588 ERROR(transaction
->pakfire
, "Archive verification failed: %s\n", error
);
594 static int pakfire_transaction_run_script(struct pakfire_transaction
* transaction
,
595 struct pakfire_db
* db
, const char* type
, struct pakfire_package
* pkg
, PakfireArchive archive
) {
596 struct pakfire_scriptlet
* scriptlet
= NULL
;
598 // Fetch scriptlet from archive if possible
600 scriptlet
= pakfire_archive_get_scriptlet(archive
, type
);
602 scriptlet
= pakfire_db_get_scriptlet(db
, pkg
, type
);
604 // Nothing to do if there are no scriptlets
608 // Execute the scriptlet
609 pakfire_scriptlet_execute(scriptlet
);
611 pakfire_scriptlet_unref(scriptlet
);
616 static int pakfire_transaction_extract(struct pakfire_transaction
* transaction
,
617 struct pakfire_package
* pkg
, PakfireArchive archive
) {
618 // Extract payload to the root of the Pakfire instance
619 int r
= pakfire_archive_extract(archive
, NULL
);
621 ERROR(transaction
->pakfire
, "Could not extract package %s: %m\n",
622 pakfire_package_get_nevra(pkg
));
626 // Is it necessary to call ldconfig?
627 PakfireFilelist filelist
= pakfire_archive_get_filelist(archive
);
629 int need_ldconfig
= pakfire_filelist_contains(filelist
, "*/lib*.so.?");
631 // Update the runtime linker cache
633 pakfire_execute_ldconfig(transaction
->pakfire
);
635 pakfire_filelist_unref(filelist
);
641 static int pakfire_transaction_erase(struct pakfire_transaction
* transaction
,
642 struct pakfire_db
* db
, struct pakfire_package
* pkg
) {
643 PakfireFilelist filelist
= NULL
;
647 r
= pakfire_db_package_filelist(db
, &filelist
, pkg
);
651 const size_t length
= pakfire_filelist_size(filelist
);
654 for (unsigned int i
= 0; i
< length
; i
++) {
655 struct pakfire_file
* file
= pakfire_filelist_get(filelist
, i
);
658 r
= pakfire_file_remove(file
);
659 pakfire_file_unref(file
);
661 // Break on any errors
666 // Update the runtime linker cache after all files have been removed
667 pakfire_execute_ldconfig(transaction
->pakfire
);
671 pakfire_filelist_unref(filelist
);
676 static const char* pakfire_action_type_string(enum pakfire_actions type
) {
678 case PAKFIRE_ACTION_NOOP
:
681 case PAKFIRE_ACTION_VERIFY
:
684 case PAKFIRE_ACTION_EXECUTE
:
687 case PAKFIRE_ACTION_PRETRANS
:
690 case PAKFIRE_ACTION_POSTTRANS
:
697 static int pakfire_transaction_package_is_userinstalled(
698 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
699 // No packages on the list
700 if (!transaction
->userinstalled
)
703 const char* name
= pakfire_package_get_name(pkg
);
705 // Check if the package is on the list
706 for (char** elem
= transaction
->userinstalled
; *elem
; elem
++) {
707 if (strcmp(name
, *elem
) == 0)
715 static int pakfire_transaction_run_step(struct pakfire_transaction
* transaction
,
716 struct pakfire_db
* db
, const enum pakfire_actions action
, struct pakfire_package
* pkg
, PakfireArchive archive
) {
722 DEBUG(transaction
->pakfire
, "Running %s for %s\n",
723 pakfire_action_type_string(action
), pakfire_package_get_nevra(pkg
));
725 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
730 case PAKFIRE_ACTION_VERIFY
:
731 r
= pakfire_transaction_verify(transaction
, pkg
, archive
);
734 // Run the pre-transaction scripts
735 case PAKFIRE_ACTION_PRETRANS
:
737 case PAKFIRE_STEP_INSTALL
:
738 case PAKFIRE_STEP_REINSTALL
:
739 r
= pakfire_transaction_run_script(transaction
, db
,
740 "pretransin", pkg
, archive
);
743 case PAKFIRE_STEP_UPGRADE
:
744 case PAKFIRE_STEP_DOWNGRADE
:
745 r
= pakfire_transaction_run_script(transaction
, db
,
746 "pretransup", pkg
, archive
);
749 case PAKFIRE_STEP_ERASE
:
750 case PAKFIRE_STEP_OBSOLETE
:
751 r
= pakfire_transaction_run_script(transaction
, db
,
752 "pretransun", pkg
, archive
);
755 case PAKFIRE_STEP_IGNORE
:
760 // Run the post-transaction scripts
761 case PAKFIRE_ACTION_POSTTRANS
:
763 case PAKFIRE_STEP_INSTALL
:
764 case PAKFIRE_STEP_REINSTALL
:
765 r
= pakfire_transaction_run_script(transaction
, db
,
766 "posttransin", pkg
, archive
);
769 case PAKFIRE_STEP_UPGRADE
:
770 case PAKFIRE_STEP_DOWNGRADE
:
771 r
= pakfire_transaction_run_script(transaction
, db
,
772 "posttransup", pkg
, archive
);
775 case PAKFIRE_STEP_ERASE
:
776 case PAKFIRE_STEP_OBSOLETE
:
777 r
= pakfire_transaction_run_script(transaction
, db
,
778 "posttransun", pkg
, archive
);
781 case PAKFIRE_STEP_IGNORE
:
786 // Execute the action of this script
787 case PAKFIRE_ACTION_EXECUTE
:
789 case PAKFIRE_STEP_INSTALL
:
790 case PAKFIRE_STEP_REINSTALL
:
791 r
= pakfire_transaction_run_script(transaction
, db
,
792 "prein", pkg
, archive
);
796 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
800 // Remove package metadata first when reinstalling
801 if (type
== PAKFIRE_STEP_REINSTALL
) {
802 r
= pakfire_db_remove_package(db
, pkg
);
807 r
= pakfire_db_add_package(db
, pkg
, archive
,
808 pakfire_transaction_package_is_userinstalled(transaction
, pkg
));
812 r
= pakfire_transaction_run_script(transaction
, db
,
813 "postin", pkg
, archive
);
816 case PAKFIRE_STEP_UPGRADE
:
817 case PAKFIRE_STEP_DOWNGRADE
:
818 r
= pakfire_transaction_run_script(transaction
, db
,
819 "preup", pkg
, archive
);
823 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
827 r
= pakfire_db_add_package(db
, pkg
, archive
,
828 pakfire_transaction_package_is_userinstalled(transaction
, pkg
));
832 r
= pakfire_transaction_run_script(transaction
, db
,
833 "postup", pkg
, archive
);
836 case PAKFIRE_STEP_ERASE
:
837 case PAKFIRE_STEP_OBSOLETE
:
838 r
= pakfire_transaction_run_script(transaction
, db
,
839 "preun", pkg
, archive
);
843 r
= pakfire_transaction_erase(transaction
, db
, pkg
);
847 r
= pakfire_db_remove_package(db
, pkg
);
851 r
= pakfire_transaction_run_script(transaction
, db
,
852 "postun", pkg
, archive
);
855 case PAKFIRE_STEP_IGNORE
:
861 case PAKFIRE_ACTION_NOOP
:
866 ERROR(transaction
->pakfire
, "Step has failed: %s\n", strerror(r
));
871 static int pakfire_transaction_run_steps(struct pakfire_transaction
* transaction
,
872 struct pakfire_db
* db
, enum pakfire_actions action
) {
875 // Walk through all steps
876 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
877 r
= pakfire_transaction_run_step(transaction
, db
, action
,
878 transaction
->packages
[i
], transaction
->archives
[i
]);
880 // End loop if action was unsuccessful
882 DEBUG(transaction
->pakfire
, "Step %d failed: %m\n", i
);
890 static int pakfire_transaction_open_archives(struct pakfire_transaction
* transaction
) {
891 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
892 struct pakfire_package
* pkg
= transaction
->packages
[i
];
895 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
897 // Do we need the archive?
899 case PAKFIRE_STEP_INSTALL
:
900 case PAKFIRE_STEP_REINSTALL
:
901 case PAKFIRE_STEP_UPGRADE
:
902 case PAKFIRE_STEP_DOWNGRADE
:
903 case PAKFIRE_STEP_OBSOLETE
:
906 case PAKFIRE_STEP_ERASE
:
907 case PAKFIRE_STEP_IGNORE
:
911 transaction
->archives
[i
] = pakfire_package_get_archive(pkg
);
912 if (!transaction
->archives
[i
]) {
913 ERROR(transaction
->pakfire
, "Could not open archive for %s: %m\n",
914 pakfire_package_get_nevra(pkg
));
922 static int pakfire_transaction_perform(struct pakfire_transaction
* transaction
) {
923 PakfireRepo repo
= NULL
;
924 struct pakfire_db
* db
;
927 DEBUG(transaction
->pakfire
, "Running Transaction %p\n", transaction
);
930 r
= pakfire_transaction_open_archives(transaction
);
935 r
= pakfire_db_open(&db
, transaction
->pakfire
, PAKFIRE_DB_READWRITE
);
937 ERROR(transaction
->pakfire
, "Could not open the database\n");
942 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_VERIFY
);
946 // Execute all pre transaction actions
947 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_PRETRANS
);
951 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_EXECUTE
);
955 // Execute all post transaction actions
956 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_POSTTRANS
);
960 DEBUG(transaction
->pakfire
, "The transaction has finished successfully\n");
962 // Reload database for next transaction
964 repo
= pakfire_get_installed_repo(transaction
->pakfire
);
968 // Reload the database
969 r
= pakfire_db_load(db
, repo
);
973 pakfire_repo_unref(repo
);
974 pakfire_db_unref(db
);
979 static int pakfire_transaction_download_package(struct pakfire_transaction
* transaction
,
980 struct pakfire_downloader
* downloader
, struct pakfire_package
* pkg
) {
982 PakfireRepo repo
= NULL
;
983 struct pakfire_mirrorlist
* mirrorlist
= NULL
;
985 // Fetch the repository to download from
986 repo
= pakfire_package_get_repo(pkg
);
991 const char* baseurl
= pakfire_repo_get_baseurl(repo
);
994 mirrorlist
= pakfire_repo_get_mirrorlist(repo
);
996 // Where to store the package?
997 const char* path
= pakfire_package_get_path(pkg
);
1001 // What file to download?
1002 const char* filename
= pakfire_package_get_filename(pkg
);
1006 const char* nevra
= pakfire_package_get_nevra(pkg
);
1010 // Add transfer to downloader
1011 r
= pakfire_downloader_add_transfer(downloader
, baseurl
, mirrorlist
,
1012 nevra
, filename
, path
, 0);
1016 pakfire_mirrorlist_unref(mirrorlist
);
1018 pakfire_repo_unref(repo
);
1023 static int pakfire_transaction_package_needs_download(
1024 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
1025 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
1027 case PAKFIRE_STEP_INSTALL
:
1028 case PAKFIRE_STEP_REINSTALL
:
1029 case PAKFIRE_STEP_DOWNGRADE
:
1030 case PAKFIRE_STEP_UPGRADE
:
1033 // No need to download for these steps
1038 // No download required if this package is already installed
1039 if (pakfire_package_is_installed(pkg
))
1042 const char* path
= pakfire_package_get_path(pkg
);
1044 // Does the file exist?
1045 int r
= access(path
, R_OK
);
1049 // This package needs to be downloaded
1053 PAKFIRE_EXPORT
int pakfire_transaction_download(struct pakfire_transaction
* transaction
) {
1054 struct pakfire_downloader
* downloader
;
1057 // Initialize the downloader
1058 r
= pakfire_downloader_create(&downloader
, transaction
->pakfire
);
1060 ERROR(transaction
->pakfire
, "Could not initialize downloader: %m\n");
1064 // Add all packages that need to be downloaded
1065 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
1066 struct pakfire_package
* pkg
= transaction
->packages
[i
];
1068 if (!pakfire_transaction_package_needs_download(transaction
, pkg
))
1072 r
= pakfire_transaction_download_package(transaction
, downloader
, pkg
);
1077 // Run the downloader
1078 r
= pakfire_downloader_run(downloader
);
1081 pakfire_downloader_unref(downloader
);
1086 PAKFIRE_EXPORT
int pakfire_transaction_run(struct pakfire_transaction
* transaction
) {
1089 // Skip running an empty transaction
1090 if (!transaction
->num
) {
1091 DEBUG(transaction
->pakfire
, "Empty transaction. Skipping...\n");
1095 // Show what would be done
1096 char* dump
= pakfire_transaction_dump(transaction
, 80);
1098 // Check if we should continue
1099 r
= pakfire_ui_confirm(transaction
->pakfire
, dump
, _("Is this okay? [y/N]"));
1101 ERROR(transaction
->pakfire
, "Transaction aborted upon user request\n");
1105 // Write transaction dump to log
1106 INFO(transaction
->pakfire
, "%s\n", dump
);
1108 // Download what we need
1109 r
= pakfire_transaction_download(transaction
);
1113 // Perform all steps
1114 r
= pakfire_transaction_perform(transaction
);