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/ui.h>
40 #include <pakfire/util.h>
42 struct pakfire_transaction
{
43 struct pakfire
* pakfire
;
46 Transaction
* transaction
;
49 struct pakfire_archive
** archives
;
50 struct pakfire_package
** packages
;
54 enum pakfire_actions
{
55 PAKFIRE_ACTION_NOOP
= 0,
56 PAKFIRE_ACTION_VERIFY
,
57 PAKFIRE_ACTION_EXECUTE
,
58 PAKFIRE_ACTION_PRETRANS
,
59 PAKFIRE_ACTION_POSTTRANS
,
63 PAKFIRE_STEP_IGNORE
= 0,
65 PAKFIRE_STEP_REINSTALL
,
68 PAKFIRE_STEP_DOWNGRADE
,
69 PAKFIRE_STEP_OBSOLETE
,
72 static enum pakfire_steps
pakfire_transaction_get_step_type(
73 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
74 int type
= transaction_type(transaction
->transaction
, pakfire_package_id(pkg
),
75 SOLVER_TRANSACTION_SHOW_ACTIVE
|SOLVER_TRANSACTION_CHANGE_IS_REINSTALL
);
77 // Translate solver types into our own types
79 case SOLVER_TRANSACTION_INSTALL
:
80 case SOLVER_TRANSACTION_MULTIINSTALL
:
81 return PAKFIRE_STEP_INSTALL
;
83 case SOLVER_TRANSACTION_REINSTALL
:
84 case SOLVER_TRANSACTION_MULTIREINSTALL
:
85 return PAKFIRE_STEP_REINSTALL
;
87 case SOLVER_TRANSACTION_ERASE
:
88 return PAKFIRE_STEP_ERASE
;
90 case SOLVER_TRANSACTION_DOWNGRADE
:
91 return PAKFIRE_STEP_DOWNGRADE
;
93 case SOLVER_TRANSACTION_UPGRADE
:
94 return PAKFIRE_STEP_UPGRADE
;
96 case SOLVER_TRANSACTION_OBSOLETES
:
97 return PAKFIRE_STEP_OBSOLETE
;
99 // Anything we don't care about
100 case SOLVER_TRANSACTION_IGNORE
:
101 case SOLVER_TRANSACTION_REINSTALLED
:
102 case SOLVER_TRANSACTION_DOWNGRADED
:
104 return PAKFIRE_STEP_IGNORE
;
108 static void pakfire_transaction_free_archives_and_packages(
109 struct pakfire_transaction
* transaction
) {
110 if (transaction
->archives
) {
111 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
112 if (transaction
->archives
[i
])
113 pakfire_archive_unref(transaction
->archives
[i
]);
114 free(transaction
->archives
);
116 transaction
->archives
= NULL
;
119 if (transaction
->packages
) {
120 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
121 if (transaction
->packages
[i
])
122 pakfire_package_unref(transaction
->packages
[i
]);
123 free(transaction
->packages
);
125 transaction
->packages
= NULL
;
129 static void pakfire_transaction_free(struct pakfire_transaction
* transaction
) {
130 pakfire_transaction_free_archives_and_packages(transaction
);
132 if (transaction
->userinstalled
) {
133 for (char** userinstalled
= transaction
->userinstalled
; *userinstalled
; userinstalled
++)
134 free(*userinstalled
);
135 free(transaction
->userinstalled
);
137 transaction_free(transaction
->transaction
);
139 pakfire_unref(transaction
->pakfire
);
143 static int pakfire_transaction_import_transaction(
144 struct pakfire_transaction
* transaction
, Solver
* solver
) {
145 // Clone the transaction to keep a copy of it
146 Transaction
* t
= solver_create_transaction(solver
);
150 transaction
->transaction
= t
;
152 // Order the transaction
153 transaction_order(t
, 0);
155 // Free any previous content
156 pakfire_transaction_free_archives_and_packages(transaction
);
159 transaction
->num
= t
->steps
.count
;
161 // Allocate space for packages
162 transaction
->packages
= calloc(transaction
->num
, sizeof(*transaction
->packages
));
163 if (!transaction
->packages
)
166 // Allocate space for archives
167 transaction
->archives
= calloc(transaction
->num
, sizeof(*transaction
->archives
));
168 if (!transaction
->archives
)
171 // Create all packages
172 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
173 transaction
->packages
[i
] = pakfire_package_create_from_solvable(
174 transaction
->pakfire
, t
->steps
.elements
[i
]);
180 static int pakfire_transaction_import_userinstalled(
181 struct pakfire_transaction
* t
, Solver
* solver
) {
182 if (t
->userinstalled
) {
183 free(t
->userinstalled
);
184 t
->userinstalled
= NULL
;
188 queue_init(&userinstalled
);
190 // Fetch a list of all packages that are installed by the user
191 solver_get_userinstalled(solver
, &userinstalled
, GET_USERINSTALLED_NAMES
);
193 // Skip everything if the queue is empty
194 if (!userinstalled
.count
)
197 t
->userinstalled
= calloc(userinstalled
.count
+ 1, sizeof(*t
->userinstalled
));
198 if (!t
->userinstalled
) {
199 ERROR(t
->pakfire
, "Could not allocate userinstalled\n");
203 Pool
* pool
= pakfire_get_solv_pool(t
->pakfire
);
205 // Store the names of all userinstalled packages
206 for (int i
= 0; i
< userinstalled
.count
; i
++) {
207 const char* package
= pool_id2str(pool
, userinstalled
.elements
[i
]);
208 t
->userinstalled
[i
] = strdup(package
);
214 int pakfire_transaction_create(struct pakfire_transaction
** transaction
,
215 struct pakfire
* pakfire
, Solver
* solver
) {
216 struct pakfire_transaction
* t
= calloc(1, sizeof(*t
));
220 // Store reference to Pakfire
221 t
->pakfire
= pakfire_ref(pakfire
);
223 // Initialize the reference counter
226 // Import transaction
227 int r
= pakfire_transaction_import_transaction(t
, solver
);
231 // Import userinstalled
232 r
= pakfire_transaction_import_userinstalled(t
, solver
);
240 pakfire_transaction_free(t
);
244 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_ref(
245 struct pakfire_transaction
* transaction
) {
246 transaction
->nrefs
++;
251 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_unref(
252 struct pakfire_transaction
* transaction
) {
253 if (--transaction
->nrefs
> 0)
256 pakfire_transaction_free(transaction
);
260 PAKFIRE_EXPORT
size_t pakfire_transaction_count(struct pakfire_transaction
* transaction
) {
261 return transaction
->num
;
264 static ssize_t
pakfire_transaction_installsizechange(struct pakfire_transaction
* transaction
) {
265 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
267 // Convert from kbytes to bytes
268 return sizechange
* 1024;
271 PAKFIRE_EXPORT ssize_t
pakfire_transaction_downloadsize(struct pakfire_transaction
* transaction
) {
274 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
275 size
+= pakfire_package_get_downloadsize(transaction
->packages
[i
]);
280 static void pakfire_transaction_append_line(char*** lines
, const char* format
, ...) {
288 va_start(args
, format
);
289 r
= vasprintf(&buffer
, format
, args
);
296 unsigned int count
= 0;
298 for (char** l
= *lines
; *l
; l
++)
302 // Increase size of array
303 *lines
= reallocarray(*lines
, count
+ 2, sizeof(**lines
));
307 // Append line and terminate lines
308 (*lines
)[count
] = buffer
;
309 (*lines
)[count
+ 1] = NULL
;
312 static void pakfire_transaction_add_headline(char*** lines
, size_t width
, const char* headline
) {
313 pakfire_transaction_append_line(lines
, "%s\n", headline
);
316 static void pakfire_transaction_add_newline(char*** lines
, size_t width
) {
317 pakfire_transaction_append_line(lines
, "\n");
320 static void pakfire_transaction_add_line(char*** lines
, size_t width
, const char* name
,
321 const char* arch
, const char* version
, const char* repo
, const char* size
) {
322 pakfire_transaction_append_line(lines
, " %-21s %-8s %-21s %-18s %6s \n",
323 name
, arch
, version
, repo
, size
);
326 static void pakfire_transaction_add_package(char*** lines
, size_t width
, struct pakfire_package
* pkg
) {
329 struct pakfire_repo
* repo
= pakfire_package_get_repo(pkg
);
332 pakfire_format_size(size
, sizeof(size
) - 1, pakfire_package_get_size(pkg
));
334 pakfire_transaction_add_line(lines
, width
,
335 pakfire_package_get_name(pkg
),
336 pakfire_package_get_arch(pkg
),
337 pakfire_package_get_evr(pkg
),
338 pakfire_repo_get_name(repo
),
342 pakfire_repo_unref(repo
);
345 static void pakfire_transaction_add_package_change(char*** lines
, size_t width
,
346 struct pakfire_package
* old_pkg
, struct pakfire_package
* new_pkg
) {
347 // Print the new package first
348 pakfire_transaction_add_package(lines
, width
, new_pkg
);
350 pakfire_transaction_append_line(lines
,
351 " --> %s\n", pakfire_package_get_nevra(old_pkg
));
354 static void pakfire_transaction_add_separator(char*** lines
, size_t width
) {
355 char* separator
= alloca(width
+ 1);
357 for (unsigned int i
= 0; i
< width
; i
++)
359 separator
[width
] = '\0';
361 pakfire_transaction_append_line(lines
, "%s\n", separator
);
364 static void pakfire_transaction_add_usage_line(char*** lines
, size_t width
,
365 const char* headline
, ssize_t size
) {
367 pakfire_format_size(buffer
, sizeof(buffer
) - 1, size
);
369 pakfire_transaction_append_line(lines
, "%-21s: %s\n", headline
, buffer
);
372 static char* pakfire_transaction_join_lines(char** lines
) {
378 // Determine total length
379 for (char** line
= lines
; *line
; line
++)
380 size
+= strlen(*line
);
382 // Allocate memory large enough to hold the result
383 char* s
= calloc(1, size
+ 1);
389 for (char** line
= lines
; *line
; line
++) {
390 p
+= snprintf(p
, s
- p
- 1, "%s", *line
);
396 PAKFIRE_EXPORT
char* pakfire_transaction_dump(struct pakfire_transaction
* transaction
, size_t width
) {
399 Pool
* pool
= transaction
->transaction
->pool
;
401 SOLVER_TRANSACTION_SHOW_OBSOLETES
|
402 SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE
;
407 pakfire_transaction_add_separator(&lines
, width
);
408 pakfire_transaction_add_line(&lines
, width
,
415 pakfire_transaction_add_separator(&lines
, width
);
418 queue_init(&classes
);
421 transaction_classify(transaction
->transaction
, mode
, &classes
);
427 The classes queue now contains a list of all classes as a tuple of:
429 * The number of packages in this class
430 * The from ID (for arch/vendor change)
431 * The to ID (for arch/vendor change)
433 for (int i
= 0; i
< classes
.count
; i
+= 4) {
434 Id
class = classes
.elements
[i
];
435 unsigned int count
= classes
.elements
[i
+1];
437 const char* from
= pool_id2str(pool
, classes
.elements
[i
+2]);
438 const char* to
= pool_id2str(pool
, classes
.elements
[i
+3]);
441 case SOLVER_TRANSACTION_INSTALL
:
443 pakfire_string_format(headline
, _("Installing %u packages:"), count
);
445 pakfire_string_set(headline
, _("Installing one package:"));
448 case SOLVER_TRANSACTION_REINSTALLED
:
450 pakfire_string_format(headline
, _("Reinstalling %u packages:"), count
);
452 pakfire_string_set(headline
, _("Reinstalling one package:"));
455 case SOLVER_TRANSACTION_ERASE
:
457 pakfire_string_format(headline
, _("Removing %u packages:"), count
);
459 pakfire_string_set(headline
, _("Removing one package:"));
462 case SOLVER_TRANSACTION_UPGRADED
:
464 pakfire_string_format(headline
, _("Updating %u packages:"), count
);
466 pakfire_string_set(headline
, _("Updating one package:"));
469 case SOLVER_TRANSACTION_DOWNGRADED
:
471 pakfire_string_format(headline
, _("Downgrading %u packages:"), count
);
473 pakfire_string_set(headline
, _("Downgrading one package:"));
476 case SOLVER_TRANSACTION_CHANGED
:
478 pakfire_string_format(headline
, _("Changing %u packages:"), count
);
480 pakfire_string_set(headline
, _("Changing one package:"));
483 case SOLVER_TRANSACTION_ARCHCHANGE
:
485 pakfire_string_format(headline
,
486 _("%u architecture changes from '%s' to '%s':"), count
, from
, to
);
488 pakfire_string_format(headline
,
489 _("One architecture change from '%s' to '%s':"), from
, to
);
492 case SOLVER_TRANSACTION_VENDORCHANGE
:
494 pakfire_string_format(headline
,
495 _("%u vendor changes from '%s' to '%s':"), count
, from
, to
);
497 pakfire_string_format(headline
,
498 _("One vendor change from '%s' to '%s':"), from
, to
);
501 case SOLVER_TRANSACTION_IGNORE
:
505 // Show what we are doing
506 pakfire_transaction_add_headline(&lines
, width
, headline
);
508 // Fetch packages in this class
509 transaction_classify_pkgs(transaction
->transaction
, mode
, class,
510 classes
.elements
[i
+2], classes
.elements
[i
+3], &pkgs
);
513 for (int j
= 0; j
< pkgs
.count
; j
++) {
514 struct pakfire_package
* old_pkg
= pakfire_package_create_from_solvable(
515 transaction
->pakfire
, pkgs
.elements
[j
]);
516 struct pakfire_package
* new_pkg
= NULL
;
519 case SOLVER_TRANSACTION_UPGRADED
:
520 case SOLVER_TRANSACTION_DOWNGRADED
:
521 new_pkg
= pakfire_package_create_from_solvable(transaction
->pakfire
,
522 transaction_obs_pkg(transaction
->transaction
, pkgs
.elements
[j
]));
524 pakfire_transaction_add_package_change(&lines
, width
, old_pkg
, new_pkg
);
528 pakfire_transaction_add_package(&lines
, width
, old_pkg
);
532 pakfire_package_unref(old_pkg
);
534 pakfire_package_unref(new_pkg
);
538 pakfire_transaction_add_newline(&lines
, width
);
541 queue_free(&classes
);
545 pakfire_transaction_add_headline(&lines
, width
, _("Transaction Summary"));
546 pakfire_transaction_add_separator(&lines
, width
);
548 // How much do we need to download?
549 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
551 if (downloadsize
> 0)
552 pakfire_transaction_add_usage_line(&lines
, width
,
553 _("Total Download Size"), downloadsize
);
555 // How much more space do we need?
556 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
557 pakfire_transaction_add_usage_line(&lines
, width
,
558 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
560 // Join all lines together
561 char* string
= pakfire_transaction_join_lines(lines
);
563 DEBUG(transaction
->pakfire
, "Transaction: %s\n", string
);
567 for (char** line
= lines
; *line
; line
++)
575 static int pakfire_transaction_verify(struct pakfire_transaction
* transaction
,
576 struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
577 // Nothing to do if this step does not have an archive
581 pakfire_archive_verify_status_t status
;
583 // Verify the archive
584 int r
= pakfire_archive_verify(archive
, &status
, NULL
);
588 // This function will return a binary status which is zero for success and
589 // anything else for errors, etc...
592 case PAKFIRE_ARCHIVE_VERIFY_OK
:
593 case PAKFIRE_ARCHIVE_VERIFY_KEY_EXPIRED
:
604 static int pakfire_transaction_run_script(struct pakfire_transaction
* transaction
,
605 struct pakfire_db
* db
, const char* type
, struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
606 struct pakfire_scriptlet
* scriptlet
= NULL
;
608 // Fetch scriptlet from archive if possible
610 scriptlet
= pakfire_archive_get_scriptlet(archive
, type
);
612 scriptlet
= pakfire_db_get_scriptlet(db
, pkg
, type
);
614 // Nothing to do if there are no scriptlets
618 // Execute the scriptlet
619 pakfire_scriptlet_execute(scriptlet
);
621 pakfire_scriptlet_unref(scriptlet
);
626 static int pakfire_transaction_extract(struct pakfire_transaction
* transaction
,
627 struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
628 // Extract payload to the root of the Pakfire instance
629 int r
= pakfire_archive_extract(archive
, NULL
);
631 ERROR(transaction
->pakfire
, "Could not extract package %s: %m\n",
632 pakfire_package_get_nevra(pkg
));
636 // Is it necessary to call ldconfig?
637 struct pakfire_filelist
* filelist
= pakfire_archive_get_filelist(archive
);
639 int need_ldconfig
= pakfire_filelist_contains(filelist
, "*/lib*.so.?");
641 // Update the runtime linker cache
643 pakfire_execute_ldconfig(transaction
->pakfire
);
645 pakfire_filelist_unref(filelist
);
651 static int pakfire_transaction_erase(struct pakfire_transaction
* transaction
,
652 struct pakfire_db
* db
, struct pakfire_package
* pkg
) {
653 struct pakfire_filelist
* filelist
= NULL
;
657 r
= pakfire_db_package_filelist(db
, &filelist
, pkg
);
661 const size_t length
= pakfire_filelist_size(filelist
);
664 for (unsigned int i
= 0; i
< length
; i
++) {
665 struct pakfire_file
* file
= pakfire_filelist_get(filelist
, i
);
668 r
= pakfire_file_remove(file
);
669 pakfire_file_unref(file
);
671 // Break on any errors
676 // Update the runtime linker cache after all files have been removed
677 pakfire_execute_ldconfig(transaction
->pakfire
);
681 pakfire_filelist_unref(filelist
);
686 static const char* pakfire_action_type_string(enum pakfire_actions type
) {
688 case PAKFIRE_ACTION_NOOP
:
691 case PAKFIRE_ACTION_VERIFY
:
694 case PAKFIRE_ACTION_EXECUTE
:
697 case PAKFIRE_ACTION_PRETRANS
:
700 case PAKFIRE_ACTION_POSTTRANS
:
707 static int pakfire_transaction_package_is_userinstalled(
708 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
709 // No packages on the list
710 if (!transaction
->userinstalled
)
713 const char* name
= pakfire_package_get_name(pkg
);
715 // Check if the package is on the list
716 for (char** elem
= transaction
->userinstalled
; *elem
; elem
++) {
717 if (strcmp(name
, *elem
) == 0)
725 static int pakfire_transaction_run_step(struct pakfire_transaction
* transaction
,
726 struct pakfire_db
* db
, const enum pakfire_actions action
, struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
732 DEBUG(transaction
->pakfire
, "Running %s for %s\n",
733 pakfire_action_type_string(action
), pakfire_package_get_nevra(pkg
));
735 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
740 case PAKFIRE_ACTION_VERIFY
:
741 r
= pakfire_transaction_verify(transaction
, pkg
, archive
);
744 // Run the pre-transaction scripts
745 case PAKFIRE_ACTION_PRETRANS
:
747 case PAKFIRE_STEP_INSTALL
:
748 case PAKFIRE_STEP_REINSTALL
:
749 r
= pakfire_transaction_run_script(transaction
, db
,
750 "pretransin", pkg
, archive
);
753 case PAKFIRE_STEP_UPGRADE
:
754 case PAKFIRE_STEP_DOWNGRADE
:
755 r
= pakfire_transaction_run_script(transaction
, db
,
756 "pretransup", pkg
, archive
);
759 case PAKFIRE_STEP_ERASE
:
760 case PAKFIRE_STEP_OBSOLETE
:
761 r
= pakfire_transaction_run_script(transaction
, db
,
762 "pretransun", pkg
, archive
);
765 case PAKFIRE_STEP_IGNORE
:
770 // Run the post-transaction scripts
771 case PAKFIRE_ACTION_POSTTRANS
:
773 case PAKFIRE_STEP_INSTALL
:
774 case PAKFIRE_STEP_REINSTALL
:
775 r
= pakfire_transaction_run_script(transaction
, db
,
776 "posttransin", pkg
, archive
);
779 case PAKFIRE_STEP_UPGRADE
:
780 case PAKFIRE_STEP_DOWNGRADE
:
781 r
= pakfire_transaction_run_script(transaction
, db
,
782 "posttransup", pkg
, archive
);
785 case PAKFIRE_STEP_ERASE
:
786 case PAKFIRE_STEP_OBSOLETE
:
787 r
= pakfire_transaction_run_script(transaction
, db
,
788 "posttransun", pkg
, archive
);
791 case PAKFIRE_STEP_IGNORE
:
796 // Execute the action of this script
797 case PAKFIRE_ACTION_EXECUTE
:
799 case PAKFIRE_STEP_INSTALL
:
800 case PAKFIRE_STEP_REINSTALL
:
801 r
= pakfire_transaction_run_script(transaction
, db
,
802 "prein", pkg
, archive
);
806 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
810 // Remove package metadata first when reinstalling
811 if (type
== PAKFIRE_STEP_REINSTALL
) {
812 r
= pakfire_db_remove_package(db
, pkg
);
817 r
= pakfire_db_add_package(db
, pkg
, archive
,
818 pakfire_transaction_package_is_userinstalled(transaction
, pkg
));
822 r
= pakfire_transaction_run_script(transaction
, db
,
823 "postin", pkg
, archive
);
826 case PAKFIRE_STEP_UPGRADE
:
827 case PAKFIRE_STEP_DOWNGRADE
:
828 r
= pakfire_transaction_run_script(transaction
, db
,
829 "preup", pkg
, archive
);
833 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
837 r
= pakfire_db_add_package(db
, pkg
, archive
,
838 pakfire_transaction_package_is_userinstalled(transaction
, pkg
));
842 r
= pakfire_transaction_run_script(transaction
, db
,
843 "postup", pkg
, archive
);
846 case PAKFIRE_STEP_ERASE
:
847 case PAKFIRE_STEP_OBSOLETE
:
848 r
= pakfire_transaction_run_script(transaction
, db
,
849 "preun", pkg
, archive
);
853 r
= pakfire_transaction_erase(transaction
, db
, pkg
);
857 r
= pakfire_db_remove_package(db
, pkg
);
861 r
= pakfire_transaction_run_script(transaction
, db
,
862 "postun", pkg
, archive
);
865 case PAKFIRE_STEP_IGNORE
:
871 case PAKFIRE_ACTION_NOOP
:
876 ERROR(transaction
->pakfire
, "Step has failed: %s\n", strerror(r
));
881 static int pakfire_transaction_run_steps(struct pakfire_transaction
* transaction
,
882 struct pakfire_db
* db
, enum pakfire_actions action
) {
885 // Walk through all steps
886 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
887 r
= pakfire_transaction_run_step(transaction
, db
, action
,
888 transaction
->packages
[i
], transaction
->archives
[i
]);
890 // End loop if action was unsuccessful
892 DEBUG(transaction
->pakfire
, "Step %d failed: %m\n", i
);
900 static int pakfire_transaction_open_archives(struct pakfire_transaction
* transaction
) {
901 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
902 struct pakfire_package
* pkg
= transaction
->packages
[i
];
905 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
907 // Do we need the archive?
909 case PAKFIRE_STEP_INSTALL
:
910 case PAKFIRE_STEP_REINSTALL
:
911 case PAKFIRE_STEP_UPGRADE
:
912 case PAKFIRE_STEP_DOWNGRADE
:
913 case PAKFIRE_STEP_OBSOLETE
:
916 case PAKFIRE_STEP_ERASE
:
917 case PAKFIRE_STEP_IGNORE
:
921 transaction
->archives
[i
] = pakfire_package_get_archive(pkg
);
922 if (!transaction
->archives
[i
]) {
923 ERROR(transaction
->pakfire
, "Could not open archive for %s: %m\n",
924 pakfire_package_get_nevra(pkg
));
932 static int pakfire_transaction_perform(struct pakfire_transaction
* transaction
) {
933 struct pakfire_repo
* repo
= NULL
;
934 struct pakfire_db
* db
;
937 DEBUG(transaction
->pakfire
, "Running Transaction %p\n", transaction
);
940 r
= pakfire_transaction_open_archives(transaction
);
945 r
= pakfire_db_open(&db
, transaction
->pakfire
, PAKFIRE_DB_READWRITE
);
947 ERROR(transaction
->pakfire
, "Could not open the database\n");
952 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_VERIFY
);
956 // Execute all pre transaction actions
957 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_PRETRANS
);
961 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_EXECUTE
);
965 // Execute all post transaction actions
966 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_POSTTRANS
);
970 DEBUG(transaction
->pakfire
, "The transaction has finished successfully\n");
972 // Reload database for next transaction
974 repo
= pakfire_get_installed_repo(transaction
->pakfire
);
978 // Reload the database
979 r
= pakfire_db_load(db
, repo
);
983 pakfire_repo_unref(repo
);
984 pakfire_db_unref(db
);
989 static int pakfire_transaction_download_package(struct pakfire_transaction
* transaction
,
990 struct pakfire_downloader
* downloader
, struct pakfire_package
* pkg
) {
992 struct pakfire_repo
* repo
= NULL
;
993 struct pakfire_mirrorlist
* mirrorlist
= NULL
;
995 // Fetch the repository to download from
996 repo
= pakfire_package_get_repo(pkg
);
1001 const char* baseurl
= pakfire_repo_get_baseurl(repo
);
1004 mirrorlist
= pakfire_repo_get_mirrorlist(repo
);
1006 const char* nevra
= pakfire_package_get_nevra(pkg
);
1010 // Where to store the package?
1011 const char* path
= pakfire_package_get_path(pkg
);
1013 ERROR(transaction
->pakfire
, "Could not retrieve package path for %s: %m\n", nevra
);
1017 // What file to download?
1018 const char* filename
= pakfire_package_get_filename(pkg
);
1020 ERROR(transaction
->pakfire
, "Could not retrieve filename for package %s: %m\n", nevra
);
1024 enum pakfire_digests digest_type
= PAKFIRE_DIGEST_NONE
;
1026 // Retrieve package digest
1027 const unsigned char* digest
= pakfire_package_get_digest(pkg
, &digest_type
);
1028 const size_t digest_length
= pakfire_digest_length(digest_type
);
1030 // Add transfer to downloader
1031 r
= pakfire_downloader_add_transfer(downloader
, baseurl
, mirrorlist
,
1032 nevra
, filename
, path
, digest_type
, digest
, digest_length
, 0);
1036 pakfire_mirrorlist_unref(mirrorlist
);
1038 pakfire_repo_unref(repo
);
1043 static int pakfire_transaction_package_needs_download(
1044 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
1045 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
1047 case PAKFIRE_STEP_INSTALL
:
1048 case PAKFIRE_STEP_REINSTALL
:
1049 case PAKFIRE_STEP_DOWNGRADE
:
1050 case PAKFIRE_STEP_UPGRADE
:
1053 // No need to download for these steps
1058 // No download required if this package is already installed
1059 if (pakfire_package_is_installed(pkg
))
1062 const char* path
= pakfire_package_get_path(pkg
);
1064 // Does the file exist?
1065 int r
= access(path
, R_OK
);
1069 // This package needs to be downloaded
1073 PAKFIRE_EXPORT
int pakfire_transaction_download(struct pakfire_transaction
* transaction
) {
1074 struct pakfire_downloader
* downloader
;
1077 // Initialize the downloader
1078 r
= pakfire_downloader_create(&downloader
, transaction
->pakfire
);
1080 ERROR(transaction
->pakfire
, "Could not initialize downloader: %m\n");
1084 // Add all packages that need to be downloaded
1085 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
1086 struct pakfire_package
* pkg
= transaction
->packages
[i
];
1088 if (!pakfire_transaction_package_needs_download(transaction
, pkg
))
1092 r
= pakfire_transaction_download_package(transaction
, downloader
, pkg
);
1094 const char* nevra
= pakfire_package_get_nevra(pkg
);
1096 ERROR(transaction
->pakfire
, "Could not add download to queue: %s: %m\n", nevra
);
1101 // Run the downloader
1102 r
= pakfire_downloader_run(downloader
);
1105 pakfire_downloader_unref(downloader
);
1110 PAKFIRE_EXPORT
int pakfire_transaction_run(struct pakfire_transaction
* transaction
) {
1113 // Skip running an empty transaction
1114 if (!transaction
->num
) {
1115 DEBUG(transaction
->pakfire
, "Empty transaction. Skipping...\n");
1119 // Show what would be done
1120 char* dump
= pakfire_transaction_dump(transaction
, 80);
1122 // Check if we should continue
1123 r
= pakfire_ui_confirm(transaction
->pakfire
, dump
, _("Is this okay? [y/N]"));
1125 ERROR(transaction
->pakfire
, "Transaction aborted upon user request\n");
1129 // Write transaction dump to log
1130 INFO(transaction
->pakfire
, "%s\n", dump
);
1132 // Download what we need
1133 r
= pakfire_transaction_download(transaction
);
1137 // Perform all steps
1138 r
= pakfire_transaction_perform(transaction
);