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 <openssl/crypto.h>
25 #include <openssl/evp.h>
27 #include <solv/pool_fileconflicts.h>
28 #include <solv/transaction.h>
30 #include <pakfire/archive.h>
31 #include <pakfire/db.h>
32 #include <pakfire/downloader.h>
33 #include <pakfire/file.h>
34 #include <pakfire/filelist.h>
35 #include <pakfire/i18n.h>
36 #include <pakfire/jail.h>
37 #include <pakfire/logging.h>
38 #include <pakfire/package.h>
39 #include <pakfire/pakfire.h>
40 #include <pakfire/private.h>
41 #include <pakfire/repo.h>
42 #include <pakfire/transaction.h>
43 #include <pakfire/ui.h>
44 #include <pakfire/util.h>
46 struct pakfire_transaction
{
47 struct pakfire
* pakfire
;
50 Transaction
* transaction
;
53 struct pakfire_archive
** archives
;
54 struct pakfire_package
** packages
;
59 struct pakfire_transaction_callbacks
{
61 pakfire_status_callback status
;
66 enum pakfire_actions
{
67 PAKFIRE_ACTION_NOOP
= 0,
68 PAKFIRE_ACTION_VERIFY
,
69 PAKFIRE_ACTION_EXECUTE
,
70 PAKFIRE_ACTION_PRETRANS
,
71 PAKFIRE_ACTION_POSTTRANS
,
75 PAKFIRE_STEP_IGNORE
= 0,
77 PAKFIRE_STEP_REINSTALL
,
80 PAKFIRE_STEP_DOWNGRADE
,
81 PAKFIRE_STEP_OBSOLETE
,
84 static enum pakfire_steps
pakfire_transaction_get_step_type(
85 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
86 int type
= transaction_type(transaction
->transaction
, pakfire_package_id(pkg
),
87 SOLVER_TRANSACTION_SHOW_ACTIVE
|SOLVER_TRANSACTION_CHANGE_IS_REINSTALL
);
89 // Translate solver types into our own types
91 case SOLVER_TRANSACTION_INSTALL
:
92 case SOLVER_TRANSACTION_MULTIINSTALL
:
93 return PAKFIRE_STEP_INSTALL
;
95 case SOLVER_TRANSACTION_REINSTALL
:
96 case SOLVER_TRANSACTION_MULTIREINSTALL
:
97 return PAKFIRE_STEP_REINSTALL
;
99 case SOLVER_TRANSACTION_ERASE
:
100 return PAKFIRE_STEP_ERASE
;
102 case SOLVER_TRANSACTION_DOWNGRADE
:
103 return PAKFIRE_STEP_DOWNGRADE
;
105 case SOLVER_TRANSACTION_UPGRADE
:
106 return PAKFIRE_STEP_UPGRADE
;
108 case SOLVER_TRANSACTION_OBSOLETES
:
109 return PAKFIRE_STEP_OBSOLETE
;
111 // Anything we don't care about
112 case SOLVER_TRANSACTION_IGNORE
:
113 case SOLVER_TRANSACTION_REINSTALLED
:
114 case SOLVER_TRANSACTION_DOWNGRADED
:
116 return PAKFIRE_STEP_IGNORE
;
120 static void pakfire_transaction_free_archives_and_packages(
121 struct pakfire_transaction
* transaction
) {
122 if (transaction
->archives
) {
123 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
124 if (transaction
->archives
[i
])
125 pakfire_archive_unref(transaction
->archives
[i
]);
126 free(transaction
->archives
);
128 transaction
->archives
= NULL
;
131 if (transaction
->packages
) {
132 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
133 if (transaction
->packages
[i
])
134 pakfire_package_unref(transaction
->packages
[i
]);
135 free(transaction
->packages
);
137 transaction
->packages
= NULL
;
141 static void pakfire_transaction_free(struct pakfire_transaction
* transaction
) {
142 pakfire_transaction_free_archives_and_packages(transaction
);
144 if (transaction
->userinstalled
) {
145 for (char** userinstalled
= transaction
->userinstalled
; *userinstalled
; userinstalled
++)
146 free(*userinstalled
);
147 free(transaction
->userinstalled
);
149 transaction_free(transaction
->transaction
);
151 pakfire_unref(transaction
->pakfire
);
155 static int pakfire_transaction_import_transaction(
156 struct pakfire_transaction
* transaction
, Solver
* solver
) {
157 // Clone the transaction to keep a copy of it
158 Transaction
* t
= solver_create_transaction(solver
);
162 transaction
->transaction
= t
;
164 // Order the transaction
165 transaction_order(t
, 0);
167 // Free any previous content
168 pakfire_transaction_free_archives_and_packages(transaction
);
171 transaction
->num
= t
->steps
.count
;
173 // Allocate space for packages
174 transaction
->packages
= calloc(transaction
->num
, sizeof(*transaction
->packages
));
175 if (!transaction
->packages
)
178 // Allocate space for archives
179 transaction
->archives
= calloc(transaction
->num
, sizeof(*transaction
->archives
));
180 if (!transaction
->archives
)
183 // Create all packages
184 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
185 transaction
->packages
[i
] = pakfire_package_create_from_solvable(
186 transaction
->pakfire
, t
->steps
.elements
[i
]);
192 static int pakfire_transaction_import_userinstalled(
193 struct pakfire_transaction
* t
, Solver
* solver
) {
194 if (t
->userinstalled
) {
195 free(t
->userinstalled
);
196 t
->userinstalled
= NULL
;
200 queue_init(&userinstalled
);
202 // Fetch a list of all packages that are installed by the user
203 solver_get_userinstalled(solver
, &userinstalled
, GET_USERINSTALLED_NAMES
);
205 // Skip everything if the queue is empty
206 if (!userinstalled
.count
)
209 t
->userinstalled
= calloc(userinstalled
.count
+ 1, sizeof(*t
->userinstalled
));
210 if (!t
->userinstalled
) {
211 ERROR(t
->pakfire
, "Could not allocate userinstalled\n");
215 Pool
* pool
= pakfire_get_solv_pool(t
->pakfire
);
217 // Store the names of all userinstalled packages
218 for (int i
= 0; i
< userinstalled
.count
; i
++) {
219 const char* package
= pool_id2str(pool
, userinstalled
.elements
[i
]);
220 t
->userinstalled
[i
] = strdup(package
);
226 int pakfire_transaction_create(struct pakfire_transaction
** transaction
,
227 struct pakfire
* pakfire
, Solver
* solver
) {
228 struct pakfire_transaction
* t
= calloc(1, sizeof(*t
));
232 // Store reference to Pakfire
233 t
->pakfire
= pakfire_ref(pakfire
);
235 // Initialize the reference counter
238 // Import transaction
239 int r
= pakfire_transaction_import_transaction(t
, solver
);
243 // Import userinstalled
244 r
= pakfire_transaction_import_userinstalled(t
, solver
);
252 pakfire_transaction_free(t
);
256 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_ref(
257 struct pakfire_transaction
* transaction
) {
258 transaction
->nrefs
++;
263 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_unref(
264 struct pakfire_transaction
* transaction
) {
265 if (--transaction
->nrefs
> 0)
268 pakfire_transaction_free(transaction
);
272 void pakfire_transaction_set_status_callback(struct pakfire_transaction
* transaction
,
273 pakfire_status_callback callback
, void* data
) {
274 transaction
->callbacks
.status
= callback
;
275 transaction
->callbacks
.status_data
= data
;
278 static int pakfire_transaction_get_progress(struct pakfire_transaction
* transaction
) {
279 return transaction
->progress
* 100 / transaction
->num
;
282 static void pakfire_transaction_status(struct pakfire_transaction
* transaction
,
283 const char* message
, ...) {
288 // Do nothing if callback isn't set
289 if (!transaction
->callbacks
.status
)
292 // Format the message
294 va_start(args
, message
);
295 r
= vasprintf(&buffer
, message
, args
);
303 const int progress
= pakfire_transaction_get_progress(transaction
);
306 transaction
->callbacks
.status(transaction
->pakfire
,
307 transaction
->callbacks
.status_data
, progress
, buffer
);
314 PAKFIRE_EXPORT
size_t pakfire_transaction_count(struct pakfire_transaction
* transaction
) {
315 return transaction
->num
;
318 static ssize_t
pakfire_transaction_installsizechange(struct pakfire_transaction
* transaction
) {
319 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
321 // Convert from kbytes to bytes
322 return sizechange
* 1024;
325 static ssize_t
pakfire_transaction_downloadsize(struct pakfire_transaction
* transaction
) {
328 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
329 size
+= pakfire_package_get_downloadsize(transaction
->packages
[i
]);
334 static void pakfire_transaction_append_line(char*** lines
, const char* format
, ...) {
342 va_start(args
, format
);
343 r
= vasprintf(&buffer
, format
, args
);
350 unsigned int count
= 0;
352 for (char** l
= *lines
; *l
; l
++)
356 // Increase size of array
357 *lines
= reallocarray(*lines
, count
+ 2, sizeof(**lines
));
361 // Append line and terminate lines
362 (*lines
)[count
] = buffer
;
363 (*lines
)[count
+ 1] = NULL
;
366 static void pakfire_transaction_add_headline(char*** lines
, size_t width
, const char* headline
) {
367 pakfire_transaction_append_line(lines
, "%s\n", headline
);
370 static void pakfire_transaction_add_newline(char*** lines
, size_t width
) {
371 pakfire_transaction_append_line(lines
, "\n");
374 static void pakfire_transaction_add_line(char*** lines
, size_t width
, const char* name
,
375 const char* arch
, const char* version
, const char* repo
, const char* size
) {
376 pakfire_transaction_append_line(lines
, " %-21s %-8s %-21s %-18s %6s \n",
377 name
, arch
, version
, repo
, size
);
380 static void pakfire_transaction_add_package(char*** lines
, size_t width
, struct pakfire_package
* pkg
) {
383 struct pakfire_repo
* repo
= pakfire_package_get_repo(pkg
);
386 int r
= pakfire_format_size(size
, pakfire_package_get_size(pkg
));
390 pakfire_transaction_add_line(lines
, width
,
391 pakfire_package_get_name(pkg
),
392 pakfire_package_get_arch(pkg
),
393 pakfire_package_get_evr(pkg
),
394 pakfire_repo_get_name(repo
),
398 pakfire_repo_unref(repo
);
401 static void pakfire_transaction_add_package_change(char*** lines
, size_t width
,
402 struct pakfire_package
* old_pkg
, struct pakfire_package
* new_pkg
) {
403 // Print the new package first
404 pakfire_transaction_add_package(lines
, width
, new_pkg
);
406 pakfire_transaction_append_line(lines
,
407 " --> %s\n", pakfire_package_get_nevra(old_pkg
));
410 static void pakfire_transaction_add_separator(char*** lines
, size_t width
) {
411 char* separator
= alloca(width
+ 1);
413 for (unsigned int i
= 0; i
< width
; i
++)
415 separator
[width
] = '\0';
417 pakfire_transaction_append_line(lines
, "%s\n", separator
);
420 static void pakfire_transaction_add_usage_line(char*** lines
, size_t width
,
421 const char* headline
, ssize_t size
) {
424 int r
= pakfire_format_size(buffer
, size
);
428 pakfire_transaction_append_line(lines
, "%-21s: %s\n", headline
, buffer
);
431 static char* pakfire_transaction_join_lines(char** lines
) {
437 // Determine total length
438 for (char** line
= lines
; *line
; line
++)
439 size
+= strlen(*line
);
441 // Allocate memory large enough to hold the result
442 char* s
= calloc(1, size
+ 1);
448 for (char** line
= lines
; *line
; line
++) {
449 p
+= snprintf(p
, s
- p
- 1, "%s", *line
);
455 PAKFIRE_EXPORT
char* pakfire_transaction_dump(struct pakfire_transaction
* transaction
, size_t width
) {
458 Pool
* pool
= transaction
->transaction
->pool
;
460 SOLVER_TRANSACTION_SHOW_OBSOLETES
|
461 SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE
;
466 pakfire_transaction_add_separator(&lines
, width
);
467 pakfire_transaction_add_line(&lines
, width
,
474 pakfire_transaction_add_separator(&lines
, width
);
477 queue_init(&classes
);
480 transaction_classify(transaction
->transaction
, mode
, &classes
);
486 The classes queue now contains a list of all classes as a tuple of:
488 * The number of packages in this class
489 * The from ID (for arch/vendor change)
490 * The to ID (for arch/vendor change)
492 for (int i
= 0; i
< classes
.count
; i
+= 4) {
493 Id
class = classes
.elements
[i
];
494 unsigned int count
= classes
.elements
[i
+1];
496 const char* from
= pool_id2str(pool
, classes
.elements
[i
+2]);
497 const char* to
= pool_id2str(pool
, classes
.elements
[i
+3]);
500 case SOLVER_TRANSACTION_INSTALL
:
502 pakfire_string_format(headline
, _("Installing %u packages:"), count
);
504 pakfire_string_set(headline
, _("Installing one package:"));
507 case SOLVER_TRANSACTION_REINSTALLED
:
509 pakfire_string_format(headline
, _("Reinstalling %u packages:"), count
);
511 pakfire_string_set(headline
, _("Reinstalling one package:"));
514 case SOLVER_TRANSACTION_ERASE
:
516 pakfire_string_format(headline
, _("Removing %u packages:"), count
);
518 pakfire_string_set(headline
, _("Removing one package:"));
521 case SOLVER_TRANSACTION_UPGRADED
:
523 pakfire_string_format(headline
, _("Updating %u packages:"), count
);
525 pakfire_string_set(headline
, _("Updating one package:"));
528 case SOLVER_TRANSACTION_DOWNGRADED
:
530 pakfire_string_format(headline
, _("Downgrading %u packages:"), count
);
532 pakfire_string_set(headline
, _("Downgrading one package:"));
535 case SOLVER_TRANSACTION_CHANGED
:
537 pakfire_string_format(headline
, _("Changing %u packages:"), count
);
539 pakfire_string_set(headline
, _("Changing one package:"));
542 case SOLVER_TRANSACTION_ARCHCHANGE
:
544 pakfire_string_format(headline
,
545 _("%u architecture changes from '%s' to '%s':"), count
, from
, to
);
547 pakfire_string_format(headline
,
548 _("One architecture change from '%s' to '%s':"), from
, to
);
551 case SOLVER_TRANSACTION_VENDORCHANGE
:
553 pakfire_string_format(headline
,
554 _("%u vendor changes from '%s' to '%s':"), count
, from
, to
);
556 pakfire_string_format(headline
,
557 _("One vendor change from '%s' to '%s':"), from
, to
);
560 case SOLVER_TRANSACTION_IGNORE
:
564 // Show what we are doing
565 pakfire_transaction_add_headline(&lines
, width
, headline
);
567 // Fetch packages in this class
568 transaction_classify_pkgs(transaction
->transaction
, mode
, class,
569 classes
.elements
[i
+2], classes
.elements
[i
+3], &pkgs
);
572 for (int j
= 0; j
< pkgs
.count
; j
++) {
573 struct pakfire_package
* old_pkg
= pakfire_package_create_from_solvable(
574 transaction
->pakfire
, pkgs
.elements
[j
]);
575 struct pakfire_package
* new_pkg
= NULL
;
578 case SOLVER_TRANSACTION_UPGRADED
:
579 case SOLVER_TRANSACTION_DOWNGRADED
:
580 new_pkg
= pakfire_package_create_from_solvable(transaction
->pakfire
,
581 transaction_obs_pkg(transaction
->transaction
, pkgs
.elements
[j
]));
583 pakfire_transaction_add_package_change(&lines
, width
, old_pkg
, new_pkg
);
587 pakfire_transaction_add_package(&lines
, width
, old_pkg
);
591 pakfire_package_unref(old_pkg
);
593 pakfire_package_unref(new_pkg
);
597 pakfire_transaction_add_newline(&lines
, width
);
600 queue_free(&classes
);
604 pakfire_transaction_add_headline(&lines
, width
, _("Transaction Summary"));
605 pakfire_transaction_add_separator(&lines
, width
);
607 // How much do we need to download?
608 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
610 if (downloadsize
> 0)
611 pakfire_transaction_add_usage_line(&lines
, width
,
612 _("Total Download Size"), downloadsize
);
614 // How much more space do we need?
615 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
616 pakfire_transaction_add_usage_line(&lines
, width
,
617 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
619 // Join all lines together
620 char* string
= pakfire_transaction_join_lines(lines
);
622 DEBUG(transaction
->pakfire
, "Transaction: %s\n", string
);
626 for (char** line
= lines
; *line
; line
++)
634 static void* pakfire_transaction_fileconflict_callback(
635 Pool
* pool
, Id p
, void* data
) {
639 static int pakfire_transaction_check_fileconflicts(
640 struct pakfire_transaction
* transaction
) {
641 Pool
* pool
= pakfire_get_solv_pool(transaction
->pakfire
);
644 FINDFILECONFLICTS_USE_SOLVABLEFILELIST
|
645 FINDFILECONFLICTS_CHECK_DIRALIASING
|
646 FINDFILECONFLICTS_USE_ROOTDIR
;
652 queue_init(&conflicts
);
654 // Fetch all installed packages
655 int newpkgs
= transaction_installedresult(transaction
->transaction
, &pkgs
);
658 int count
= pool_findfileconflicts(pool
, &pkgs
, newpkgs
, &conflicts
, flags
,
659 pakfire_transaction_fileconflict_callback
, NULL
);
661 DEBUG(transaction
->pakfire
, "Found %d file conflict(s)\n", count
);
665 queue_free(&conflicts
);
670 static int pakfire_transaction_check(struct pakfire_transaction
* transaction
) {
673 // Check for any file conflicts
674 r
= pakfire_transaction_check_fileconflicts(transaction
);
681 static int pakfire_transaction_verify(struct pakfire_transaction
* transaction
,
682 struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
685 const char* nevra
= pakfire_package_get_nevra(pkg
);
687 // Nothing to do if this step does not have an archive
689 DEBUG(transaction
->pakfire
, "Package %s requires no archive\n", nevra
);
693 enum pakfire_digests digest_type
= PAKFIRE_DIGEST_NONE
;
695 // Fetch digest from package
696 const unsigned char* expected_digest
= pakfire_package_get_digest(pkg
, &digest_type
);
697 if (!expected_digest
) {
698 DEBUG(transaction
->pakfire
, "Package %s has no digest\n", nevra
);
702 unsigned char computed_digest
[EVP_MAX_MD_SIZE
];
703 size_t digest_length
= 0;
705 // Compute digest of the archive
706 r
= pakfire_archive_digest(archive
, digest_type
, computed_digest
, &digest_length
);
708 ERROR(transaction
->pakfire
, "Could not compute digest for %s: %m\n", nevra
);
713 r
= CRYPTO_memcmp(computed_digest
, expected_digest
, digest_length
);
715 ERROR(transaction
->pakfire
, "Digests of %s do not match\n", nevra
);
722 static int pakfire_transaction_run_script(struct pakfire_transaction
* transaction
,
723 struct pakfire_db
* db
, const char* type
, struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
724 struct pakfire_scriptlet
* scriptlet
= NULL
;
726 // Fetch scriptlet from archive if possible
728 scriptlet
= pakfire_archive_get_scriptlet(archive
, type
);
730 scriptlet
= pakfire_db_get_scriptlet(db
, pkg
, type
);
732 // Nothing to do if there are no scriptlets
736 // Execute the scriptlet
737 pakfire_scriptlet_execute(scriptlet
);
739 pakfire_scriptlet_unref(scriptlet
);
744 static int pakfire_transaction_extract(struct pakfire_transaction
* transaction
,
745 struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
746 const char* nevra
= pakfire_package_get_nevra(pkg
);
749 pakfire_transaction_status(transaction
, _("Installing %s..."), nevra
);
752 int r
= pakfire_archive_extract(archive
);
754 ERROR(transaction
->pakfire
, "Could not extract package %s: %m\n",
759 // Is it necessary to call ldconfig?
760 struct pakfire_filelist
* filelist
= pakfire_archive_get_filelist(archive
);
762 int need_ldconfig
= pakfire_filelist_contains(filelist
, "*/lib*.so.?");
764 // Update the runtime linker cache
766 pakfire_jail_ldconfig(transaction
->pakfire
);
768 pakfire_filelist_unref(filelist
);
774 static int pakfire_transaction_erase(struct pakfire_transaction
* transaction
,
775 struct pakfire_db
* db
, struct pakfire_package
* pkg
) {
776 struct pakfire_filelist
* filelist
= NULL
;
780 r
= pakfire_db_package_filelist(db
, &filelist
, pkg
);
784 const size_t length
= pakfire_filelist_size(filelist
);
787 for (unsigned int i
= 0; i
< length
; i
++) {
788 struct pakfire_file
* file
= pakfire_filelist_get(filelist
, i
);
791 r
= pakfire_file_remove(file
);
792 pakfire_file_unref(file
);
794 // Break on any errors
799 // Update the runtime linker cache after all files have been removed
800 pakfire_jail_ldconfig(transaction
->pakfire
);
804 pakfire_filelist_unref(filelist
);
809 static const char* pakfire_action_type_string(enum pakfire_actions type
) {
811 case PAKFIRE_ACTION_NOOP
:
814 case PAKFIRE_ACTION_VERIFY
:
817 case PAKFIRE_ACTION_EXECUTE
:
820 case PAKFIRE_ACTION_PRETRANS
:
823 case PAKFIRE_ACTION_POSTTRANS
:
830 static int pakfire_transaction_package_is_userinstalled(
831 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
832 // No packages on the list
833 if (!transaction
->userinstalled
)
836 const char* name
= pakfire_package_get_name(pkg
);
838 // Check if the package is on the list
839 for (char** elem
= transaction
->userinstalled
; *elem
; elem
++) {
840 if (strcmp(name
, *elem
) == 0)
848 static int pakfire_transaction_run_step(struct pakfire_transaction
* transaction
,
849 struct pakfire_db
* db
, const enum pakfire_actions action
, struct pakfire_package
* pkg
, struct pakfire_archive
* archive
) {
855 DEBUG(transaction
->pakfire
, "Running %s for %s\n",
856 pakfire_action_type_string(action
), pakfire_package_get_nevra(pkg
));
858 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
863 case PAKFIRE_ACTION_VERIFY
:
864 r
= pakfire_transaction_verify(transaction
, pkg
, archive
);
867 // Run the pre-transaction scripts
868 case PAKFIRE_ACTION_PRETRANS
:
870 case PAKFIRE_STEP_INSTALL
:
871 case PAKFIRE_STEP_REINSTALL
:
872 r
= pakfire_transaction_run_script(transaction
, db
,
873 "pretransin", pkg
, archive
);
876 case PAKFIRE_STEP_UPGRADE
:
877 case PAKFIRE_STEP_DOWNGRADE
:
878 r
= pakfire_transaction_run_script(transaction
, db
,
879 "pretransup", pkg
, archive
);
882 case PAKFIRE_STEP_ERASE
:
883 case PAKFIRE_STEP_OBSOLETE
:
884 r
= pakfire_transaction_run_script(transaction
, db
,
885 "pretransun", pkg
, archive
);
888 case PAKFIRE_STEP_IGNORE
:
893 // Run the post-transaction scripts
894 case PAKFIRE_ACTION_POSTTRANS
:
896 case PAKFIRE_STEP_INSTALL
:
897 case PAKFIRE_STEP_REINSTALL
:
898 r
= pakfire_transaction_run_script(transaction
, db
,
899 "posttransin", pkg
, archive
);
902 case PAKFIRE_STEP_UPGRADE
:
903 case PAKFIRE_STEP_DOWNGRADE
:
904 r
= pakfire_transaction_run_script(transaction
, db
,
905 "posttransup", pkg
, archive
);
908 case PAKFIRE_STEP_ERASE
:
909 case PAKFIRE_STEP_OBSOLETE
:
910 r
= pakfire_transaction_run_script(transaction
, db
,
911 "posttransun", pkg
, archive
);
914 case PAKFIRE_STEP_IGNORE
:
919 // Execute the action of this script
920 case PAKFIRE_ACTION_EXECUTE
:
921 // Increment progress
922 transaction
->progress
++;
924 // Update progress callback
925 pakfire_transaction_status(transaction
, NULL
);
928 case PAKFIRE_STEP_INSTALL
:
929 case PAKFIRE_STEP_REINSTALL
:
930 r
= pakfire_transaction_run_script(transaction
, db
,
931 "prein", pkg
, archive
);
935 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
939 // Remove package metadata first when reinstalling
940 if (type
== PAKFIRE_STEP_REINSTALL
) {
941 r
= pakfire_db_remove_package(db
, pkg
);
946 r
= pakfire_db_add_package(db
, pkg
, archive
,
947 pakfire_transaction_package_is_userinstalled(transaction
, pkg
));
951 r
= pakfire_transaction_run_script(transaction
, db
,
952 "postin", pkg
, archive
);
955 case PAKFIRE_STEP_UPGRADE
:
956 case PAKFIRE_STEP_DOWNGRADE
:
957 r
= pakfire_transaction_run_script(transaction
, db
,
958 "preup", pkg
, archive
);
962 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
966 r
= pakfire_db_add_package(db
, pkg
, archive
,
967 pakfire_transaction_package_is_userinstalled(transaction
, pkg
));
971 r
= pakfire_transaction_run_script(transaction
, db
,
972 "postup", pkg
, archive
);
975 case PAKFIRE_STEP_ERASE
:
976 case PAKFIRE_STEP_OBSOLETE
:
977 r
= pakfire_transaction_run_script(transaction
, db
,
978 "preun", pkg
, archive
);
982 r
= pakfire_transaction_erase(transaction
, db
, pkg
);
986 r
= pakfire_db_remove_package(db
, pkg
);
990 r
= pakfire_transaction_run_script(transaction
, db
,
991 "postun", pkg
, archive
);
994 case PAKFIRE_STEP_IGNORE
:
1000 case PAKFIRE_ACTION_NOOP
:
1005 ERROR(transaction
->pakfire
, "Step has failed: %s\n", strerror(r
));
1010 static int pakfire_transaction_run_steps(struct pakfire_transaction
* transaction
,
1011 struct pakfire_db
* db
, enum pakfire_actions action
) {
1016 case PAKFIRE_ACTION_VERIFY
:
1017 pakfire_transaction_status(transaction
, _("Verifying packages..."));
1020 case PAKFIRE_ACTION_PRETRANS
:
1021 pakfire_transaction_status(transaction
, _("Preparing installation..."));
1024 case PAKFIRE_ACTION_POSTTRANS
:
1025 pakfire_transaction_status(transaction
, _("Finishing up..."));
1032 // Walk through all steps
1033 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
1034 r
= pakfire_transaction_run_step(transaction
, db
, action
,
1035 transaction
->packages
[i
], transaction
->archives
[i
]);
1037 // End loop if action was unsuccessful
1039 DEBUG(transaction
->pakfire
, "Step %d failed: %m\n", i
);
1047 static int pakfire_transaction_open_archives(struct pakfire_transaction
* transaction
) {
1048 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
1049 struct pakfire_package
* pkg
= transaction
->packages
[i
];
1052 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
1054 // Do we need the archive?
1056 case PAKFIRE_STEP_INSTALL
:
1057 case PAKFIRE_STEP_REINSTALL
:
1058 case PAKFIRE_STEP_UPGRADE
:
1059 case PAKFIRE_STEP_DOWNGRADE
:
1060 case PAKFIRE_STEP_OBSOLETE
:
1063 case PAKFIRE_STEP_ERASE
:
1064 case PAKFIRE_STEP_IGNORE
:
1068 transaction
->archives
[i
] = pakfire_package_get_archive(pkg
);
1069 if (!transaction
->archives
[i
]) {
1070 ERROR(transaction
->pakfire
, "Could not open archive for %s: %m\n",
1071 pakfire_package_get_nevra(pkg
));
1079 static int pakfire_transaction_perform(struct pakfire_transaction
* transaction
) {
1080 struct pakfire_repo
* repo
= NULL
;
1081 struct pakfire_db
* db
;
1084 DEBUG(transaction
->pakfire
, "Running Transaction %p\n", transaction
);
1086 // Open all archives
1087 r
= pakfire_transaction_open_archives(transaction
);
1091 // Open the database
1092 r
= pakfire_db_open(&db
, transaction
->pakfire
, PAKFIRE_DB_READWRITE
);
1094 ERROR(transaction
->pakfire
, "Could not open the database\n");
1099 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_VERIFY
);
1103 // Execute all pre transaction actions
1104 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_PRETRANS
);
1108 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_EXECUTE
);
1112 // Execute all post transaction actions
1113 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_POSTTRANS
);
1117 DEBUG(transaction
->pakfire
, "The transaction has finished successfully\n");
1119 // Reload database for next transaction
1121 repo
= pakfire_get_installed_repo(transaction
->pakfire
);
1125 // Reload the database
1126 r
= pakfire_db_load(db
, repo
);
1130 pakfire_repo_unref(repo
);
1131 pakfire_db_unref(db
);
1136 static int pakfire_transaction_download_package(struct pakfire_transaction
* transaction
,
1137 struct pakfire_downloader
* downloader
, struct pakfire_package
* pkg
) {
1139 struct pakfire_repo
* repo
= NULL
;
1140 struct pakfire_mirrorlist
* mirrorlist
= NULL
;
1142 // Fetch the repository to download from
1143 repo
= pakfire_package_get_repo(pkg
);
1148 const char* baseurl
= pakfire_repo_get_baseurl(repo
);
1151 mirrorlist
= pakfire_repo_get_mirrorlist(repo
);
1153 const char* nevra
= pakfire_package_get_nevra(pkg
);
1157 // Where to store the package?
1158 const char* path
= pakfire_package_get_path(pkg
);
1160 ERROR(transaction
->pakfire
, "Could not retrieve package path for %s: %m\n", nevra
);
1164 // What file to download?
1165 const char* filename
= pakfire_package_get_filename(pkg
);
1167 ERROR(transaction
->pakfire
, "Could not retrieve filename for package %s: %m\n", nevra
);
1171 enum pakfire_digests digest_type
= PAKFIRE_DIGEST_NONE
;
1173 // Retrieve package digest
1174 const unsigned char* digest
= pakfire_package_get_digest(pkg
, &digest_type
);
1175 const size_t digest_length
= pakfire_digest_length(digest_type
);
1177 // Add transfer to downloader
1178 r
= pakfire_downloader_add_transfer(downloader
, baseurl
, mirrorlist
,
1179 nevra
, filename
, path
, digest_type
, digest
, digest_length
, 0);
1183 pakfire_mirrorlist_unref(mirrorlist
);
1185 pakfire_repo_unref(repo
);
1190 static int pakfire_transaction_package_needs_download(
1191 struct pakfire_transaction
* transaction
, struct pakfire_package
* pkg
) {
1192 enum pakfire_steps type
= pakfire_transaction_get_step_type(transaction
, pkg
);
1194 case PAKFIRE_STEP_INSTALL
:
1195 case PAKFIRE_STEP_REINSTALL
:
1196 case PAKFIRE_STEP_DOWNGRADE
:
1197 case PAKFIRE_STEP_UPGRADE
:
1200 // No need to download for these steps
1205 // No download required if this package is already installed
1206 if (pakfire_package_is_installed(pkg
))
1209 const char* path
= pakfire_package_get_path(pkg
);
1211 // Does the file exist?
1212 int r
= access(path
, R_OK
);
1216 // This package needs to be downloaded
1220 PAKFIRE_EXPORT
int pakfire_transaction_download(struct pakfire_transaction
* transaction
) {
1221 struct pakfire_downloader
* downloader
;
1224 // Initialize the downloader
1225 r
= pakfire_downloader_create(&downloader
, transaction
->pakfire
);
1227 ERROR(transaction
->pakfire
, "Could not initialize downloader: %m\n");
1231 // Add all packages that need to be downloaded
1232 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
1233 struct pakfire_package
* pkg
= transaction
->packages
[i
];
1235 if (!pakfire_transaction_package_needs_download(transaction
, pkg
))
1239 r
= pakfire_transaction_download_package(transaction
, downloader
, pkg
);
1241 const char* nevra
= pakfire_package_get_nevra(pkg
);
1243 ERROR(transaction
->pakfire
, "Could not add download to queue: %s: %m\n", nevra
);
1248 // Run the downloader
1249 r
= pakfire_downloader_run(downloader
);
1252 pakfire_downloader_unref(downloader
);
1257 PAKFIRE_EXPORT
int pakfire_transaction_run(
1258 struct pakfire_transaction
* transaction
, int flags
) {
1261 // Skip running an empty transaction
1262 if (!transaction
->num
) {
1263 DEBUG(transaction
->pakfire
, "Empty transaction. Skipping...\n");
1267 // Show what would be done
1268 char* dump
= pakfire_transaction_dump(transaction
, 80);
1270 // Check if we should continue
1271 r
= pakfire_confirm(transaction
->pakfire
, dump
, _("Is this okay? [y/N]"));
1273 ERROR(transaction
->pakfire
, "Transaction aborted upon user request\n");
1277 // Write transaction dump to log
1278 INFO(transaction
->pakfire
, "%s\n", dump
);
1280 // Perform a check if this can actually be run
1281 r
= pakfire_transaction_check(transaction
);
1285 // End here for a dry run
1286 if (flags
& PAKFIRE_TRANSACTION_DRY_RUN
)
1289 // Download what we need
1290 r
= pakfire_transaction_download(transaction
);
1294 // Perform all steps
1295 r
= pakfire_transaction_perform(transaction
);