]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/transaction.c
Show better error messages on download failures
[people/stevee/pakfire.git] / src / libpakfire / transaction.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 Pakfire development team #
5 # #
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. #
10 # #
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. #
15 # #
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/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <stdlib.h>
23
24 #include <solv/transaction.h>
25
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>
41
42 struct pakfire_transaction {
43 struct pakfire* pakfire;
44 int nrefs;
45
46 Transaction* transaction;
47 char** userinstalled;
48
49 struct pakfire_archive** archives;
50 struct pakfire_package** packages;
51 size_t num;
52 };
53
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,
60 };
61
62 enum pakfire_steps {
63 PAKFIRE_STEP_IGNORE = 0,
64 PAKFIRE_STEP_INSTALL,
65 PAKFIRE_STEP_REINSTALL,
66 PAKFIRE_STEP_ERASE,
67 PAKFIRE_STEP_UPGRADE,
68 PAKFIRE_STEP_DOWNGRADE,
69 PAKFIRE_STEP_OBSOLETE,
70 };
71
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);
76
77 // Translate solver types into our own types
78 switch (type) {
79 case SOLVER_TRANSACTION_INSTALL:
80 case SOLVER_TRANSACTION_MULTIINSTALL:
81 return PAKFIRE_STEP_INSTALL;
82
83 case SOLVER_TRANSACTION_REINSTALL:
84 case SOLVER_TRANSACTION_MULTIREINSTALL:
85 return PAKFIRE_STEP_REINSTALL;
86
87 case SOLVER_TRANSACTION_ERASE:
88 return PAKFIRE_STEP_ERASE;
89
90 case SOLVER_TRANSACTION_DOWNGRADE:
91 return PAKFIRE_STEP_DOWNGRADE;
92
93 case SOLVER_TRANSACTION_UPGRADE:
94 return PAKFIRE_STEP_UPGRADE;
95
96 case SOLVER_TRANSACTION_OBSOLETES:
97 return PAKFIRE_STEP_OBSOLETE;
98
99 // Anything we don't care about
100 case SOLVER_TRANSACTION_IGNORE:
101 case SOLVER_TRANSACTION_REINSTALLED:
102 case SOLVER_TRANSACTION_DOWNGRADED:
103 default:
104 return PAKFIRE_STEP_IGNORE;
105 }
106 }
107
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);
115
116 transaction->archives = NULL;
117 }
118
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);
124
125 transaction->packages = NULL;
126 }
127 }
128
129 static void pakfire_transaction_free(struct pakfire_transaction* transaction) {
130 pakfire_transaction_free_archives_and_packages(transaction);
131
132 if (transaction->userinstalled) {
133 for (char** userinstalled = transaction->userinstalled; *userinstalled; userinstalled++)
134 free(*userinstalled);
135 free(transaction->userinstalled);
136 }
137 transaction_free(transaction->transaction);
138
139 pakfire_unref(transaction->pakfire);
140 free(transaction);
141 }
142
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);
147 if (!t)
148 return 1;
149
150 transaction->transaction = t;
151
152 // Order the transaction
153 transaction_order(t, 0);
154
155 // Free any previous content
156 pakfire_transaction_free_archives_and_packages(transaction);
157
158 // How many steps?
159 transaction->num = t->steps.count;
160
161 // Allocate space for packages
162 transaction->packages = calloc(transaction->num, sizeof(*transaction->packages));
163 if (!transaction->packages)
164 return 1;
165
166 // Allocate space for archives
167 transaction->archives = calloc(transaction->num, sizeof(*transaction->archives));
168 if (!transaction->archives)
169 return 1;
170
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]);
175 }
176
177 return 0;
178 }
179
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;
185 }
186
187 Queue userinstalled;
188 queue_init(&userinstalled);
189
190 // Fetch a list of all packages that are installed by the user
191 solver_get_userinstalled(solver, &userinstalled, GET_USERINSTALLED_NAMES);
192
193 // Skip everything if the queue is empty
194 if (!userinstalled.count)
195 return 0;
196
197 t->userinstalled = calloc(userinstalled.count + 1, sizeof(*t->userinstalled));
198 if (!t->userinstalled) {
199 ERROR(t->pakfire, "Could not allocate userinstalled\n");
200 return 1;
201 }
202
203 Pool* pool = pakfire_get_solv_pool(t->pakfire);
204
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);
209 }
210
211 return 0;
212 }
213
214 int pakfire_transaction_create(struct pakfire_transaction** transaction,
215 struct pakfire* pakfire, Solver* solver) {
216 struct pakfire_transaction* t = calloc(1, sizeof(*t));
217 if (!t)
218 return ENOMEM;
219
220 // Store reference to Pakfire
221 t->pakfire = pakfire_ref(pakfire);
222
223 // Initialize the reference counter
224 t->nrefs = 1;
225
226 // Import transaction
227 int r = pakfire_transaction_import_transaction(t, solver);
228 if (r)
229 goto ERROR;
230
231 // Import userinstalled
232 r = pakfire_transaction_import_userinstalled(t, solver);
233 if (r)
234 goto ERROR;
235
236 *transaction = t;
237 return 0;
238
239 ERROR:
240 pakfire_transaction_free(t);
241 return 1;
242 }
243
244 PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_ref(
245 struct pakfire_transaction* transaction) {
246 transaction->nrefs++;
247
248 return transaction;
249 }
250
251 PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_unref(
252 struct pakfire_transaction* transaction) {
253 if (--transaction->nrefs > 0)
254 return transaction;
255
256 pakfire_transaction_free(transaction);
257 return NULL;
258 }
259
260 PAKFIRE_EXPORT size_t pakfire_transaction_count(struct pakfire_transaction* transaction) {
261 return transaction->num;
262 }
263
264 static ssize_t pakfire_transaction_installsizechange(struct pakfire_transaction* transaction) {
265 ssize_t sizechange = transaction_calc_installsizechange(transaction->transaction);
266
267 // Convert from kbytes to bytes
268 return sizechange * 1024;
269 }
270
271 PAKFIRE_EXPORT ssize_t pakfire_transaction_downloadsize(struct pakfire_transaction* transaction) {
272 ssize_t size = 0;
273
274 for (unsigned int i = 0; i < transaction->num; i++)
275 size += pakfire_package_get_downloadsize(transaction->packages[i]);
276
277 return size;
278 }
279
280 static void pakfire_transaction_append_line(char*** lines, const char* format, ...) {
281 if (!lines)
282 return;
283
284 char* buffer = NULL;
285 va_list args;
286 int r;
287
288 va_start(args, format);
289 r = vasprintf(&buffer, format, args);
290 va_end(args);
291
292 if (r < 0)
293 return;
294
295 // Count lines
296 unsigned int count = 0;
297 if (*lines) {
298 for (char** l = *lines; *l; l++)
299 count++;
300 }
301
302 // Increase size of array
303 *lines = reallocarray(*lines, count + 2, sizeof(**lines));
304 if (!*lines)
305 return;
306
307 // Append line and terminate lines
308 (*lines)[count] = buffer;
309 (*lines)[count + 1] = NULL;
310 }
311
312 static void pakfire_transaction_add_headline(char*** lines, size_t width, const char* headline) {
313 pakfire_transaction_append_line(lines, "%s\n", headline);
314 }
315
316 static void pakfire_transaction_add_newline(char*** lines, size_t width) {
317 pakfire_transaction_append_line(lines, "\n");
318 }
319
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);
324 }
325
326 static void pakfire_transaction_add_package(char*** lines, size_t width, struct pakfire_package* pkg) {
327 char size[128];
328
329 struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
330
331 // Format size
332 pakfire_format_size(size, sizeof(size) - 1, pakfire_package_get_size(pkg));
333
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),
339 size
340 );
341
342 pakfire_repo_unref(repo);
343 }
344
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);
349
350 pakfire_transaction_append_line(lines,
351 " --> %s\n", pakfire_package_get_nevra(old_pkg));
352 }
353
354 static void pakfire_transaction_add_separator(char*** lines, size_t width) {
355 char* separator = alloca(width + 1);
356
357 for (unsigned int i = 0; i < width; i++)
358 separator[i] = '=';
359 separator[width] = '\0';
360
361 pakfire_transaction_append_line(lines, "%s\n", separator);
362 }
363
364 static void pakfire_transaction_add_usage_line(char*** lines, size_t width,
365 const char* headline, ssize_t size) {
366 char buffer[128];
367 pakfire_format_size(buffer, sizeof(buffer) - 1, size);
368
369 pakfire_transaction_append_line(lines, "%-21s: %s\n", headline, buffer);
370 }
371
372 static char* pakfire_transaction_join_lines(char** lines) {
373 if (!lines)
374 return NULL;
375
376 size_t size = 0;
377
378 // Determine total length
379 for (char** line = lines; *line; line++)
380 size += strlen(*line);
381
382 // Allocate memory large enough to hold the result
383 char* s = calloc(1, size + 1);
384 if (!s)
385 return s;
386
387 char* p = s;
388
389 for (char** line = lines; *line; line++) {
390 p += snprintf(p, s - p - 1, "%s", *line);
391 }
392
393 return s;
394 }
395
396 PAKFIRE_EXPORT char* pakfire_transaction_dump(struct pakfire_transaction* transaction, size_t width) {
397 char headline[1024];
398
399 Pool* pool = transaction->transaction->pool;
400 const int mode =
401 SOLVER_TRANSACTION_SHOW_OBSOLETES |
402 SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
403
404 char** lines = NULL;
405
406 // Header
407 pakfire_transaction_add_separator(&lines, width);
408 pakfire_transaction_add_line(&lines, width,
409 _("Package"),
410 _("Arch"),
411 _("Version"),
412 _("Repository"),
413 _("Size")
414 );
415 pakfire_transaction_add_separator(&lines, width);
416
417 Queue classes;
418 queue_init(&classes);
419
420 // Get all classes
421 transaction_classify(transaction->transaction, mode, &classes);
422
423 Queue pkgs;
424 queue_init(&pkgs);
425
426 /*
427 The classes queue now contains a list of all classes as a tuple of:
428 * The class type
429 * The number of packages in this class
430 * The from ID (for arch/vendor change)
431 * The to ID (for arch/vendor change)
432 */
433 for (int i = 0; i < classes.count; i += 4) {
434 Id class = classes.elements[i];
435 unsigned int count = classes.elements[i+1];
436
437 const char* from = pool_id2str(pool, classes.elements[i+2]);
438 const char* to = pool_id2str(pool, classes.elements[i+3]);
439
440 switch (class) {
441 case SOLVER_TRANSACTION_INSTALL:
442 if (count)
443 pakfire_string_format(headline, _("Installing %u packages:"), count);
444 else
445 pakfire_string_set(headline, _("Installing one package:"));
446 break;
447
448 case SOLVER_TRANSACTION_REINSTALLED:
449 if (count)
450 pakfire_string_format(headline, _("Reinstalling %u packages:"), count);
451 else
452 pakfire_string_set(headline, _("Reinstalling one package:"));
453 break;
454
455 case SOLVER_TRANSACTION_ERASE:
456 if (count)
457 pakfire_string_format(headline, _("Removing %u packages:"), count);
458 else
459 pakfire_string_set(headline, _("Removing one package:"));
460 break;
461
462 case SOLVER_TRANSACTION_UPGRADED:
463 if (count)
464 pakfire_string_format(headline, _("Updating %u packages:"), count);
465 else
466 pakfire_string_set(headline, _("Updating one package:"));
467 break;
468
469 case SOLVER_TRANSACTION_DOWNGRADED:
470 if (count)
471 pakfire_string_format(headline, _("Downgrading %u packages:"), count);
472 else
473 pakfire_string_set(headline, _("Downgrading one package:"));
474 break;
475
476 case SOLVER_TRANSACTION_CHANGED:
477 if (count)
478 pakfire_string_format(headline, _("Changing %u packages:"), count);
479 else
480 pakfire_string_set(headline, _("Changing one package:"));
481 break;
482
483 case SOLVER_TRANSACTION_ARCHCHANGE:
484 if (count)
485 pakfire_string_format(headline,
486 _("%u architecture changes from '%s' to '%s':"), count, from, to);
487 else
488 pakfire_string_format(headline,
489 _("One architecture change from '%s' to '%s':"), from, to);
490 break;
491
492 case SOLVER_TRANSACTION_VENDORCHANGE:
493 if (count)
494 pakfire_string_format(headline,
495 _("%u vendor changes from '%s' to '%s':"), count, from, to);
496 else
497 pakfire_string_format(headline,
498 _("One vendor change from '%s' to '%s':"), from, to);
499 break;
500
501 case SOLVER_TRANSACTION_IGNORE:
502 continue;
503 }
504
505 // Show what we are doing
506 pakfire_transaction_add_headline(&lines, width, headline);
507
508 // Fetch packages in this class
509 transaction_classify_pkgs(transaction->transaction, mode, class,
510 classes.elements[i+2], classes.elements[i+3], &pkgs);
511
512 // List all packages
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;
517
518 switch (class) {
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]));
523
524 pakfire_transaction_add_package_change(&lines, width, old_pkg, new_pkg);
525 break;
526
527 default:
528 pakfire_transaction_add_package(&lines, width, old_pkg);
529 break;
530 }
531
532 pakfire_package_unref(old_pkg);
533 if (new_pkg)
534 pakfire_package_unref(new_pkg);
535 }
536
537 // Newline
538 pakfire_transaction_add_newline(&lines, width);
539 }
540
541 queue_free(&classes);
542 queue_free(&pkgs);
543
544 // Summary
545 pakfire_transaction_add_headline(&lines, width, _("Transaction Summary"));
546 pakfire_transaction_add_separator(&lines, width);
547
548 // How much do we need to download?
549 size_t downloadsize = pakfire_transaction_downloadsize(transaction);
550
551 if (downloadsize > 0)
552 pakfire_transaction_add_usage_line(&lines, width,
553 _("Total Download Size"), downloadsize);
554
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);
559
560 // Join all lines together
561 char* string = pakfire_transaction_join_lines(lines);
562
563 DEBUG(transaction->pakfire, "Transaction: %s\n", string);
564
565 // Free lines
566 if (lines) {
567 for (char** line = lines; *line; line++)
568 free(*line);
569 free(lines);
570 }
571
572 return string;
573 }
574
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
578 if (!archive)
579 return 0;
580
581 pakfire_archive_verify_status_t status;
582
583 // Verify the archive
584 int r = pakfire_archive_verify(archive, &status, NULL);
585 if (r)
586 return r;
587
588 // This function will return a binary status which is zero for success and
589 // anything else for errors, etc...
590 switch (status) {
591 // Good
592 case PAKFIRE_ARCHIVE_VERIFY_OK:
593 case PAKFIRE_ARCHIVE_VERIFY_KEY_EXPIRED:
594 return 0;
595
596 // Bad
597 default:
598 break;
599 }
600
601 return 1;
602 }
603
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;
607
608 // Fetch scriptlet from archive if possible
609 if (archive)
610 scriptlet = pakfire_archive_get_scriptlet(archive, type);
611 else
612 scriptlet = pakfire_db_get_scriptlet(db, pkg, type);
613
614 // Nothing to do if there are no scriptlets
615 if (!scriptlet)
616 return 0;
617
618 // Execute the scriptlet
619 pakfire_scriptlet_execute(scriptlet);
620
621 pakfire_scriptlet_unref(scriptlet);
622
623 return 0;
624 }
625
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);
630 if (r) {
631 ERROR(transaction->pakfire, "Could not extract package %s: %m\n",
632 pakfire_package_get_nevra(pkg));
633 return r;
634 }
635
636 // Is it necessary to call ldconfig?
637 struct pakfire_filelist* filelist = pakfire_archive_get_filelist(archive);
638 if (filelist) {
639 int need_ldconfig = pakfire_filelist_contains(filelist, "*/lib*.so.?");
640
641 // Update the runtime linker cache
642 if (need_ldconfig)
643 pakfire_execute_ldconfig(transaction->pakfire);
644
645 pakfire_filelist_unref(filelist);
646 }
647
648 return r;
649 }
650
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;
654 int r;
655
656 // Fetch filelist
657 r = pakfire_db_package_filelist(db, &filelist, pkg);
658 if (r)
659 goto ERROR;
660
661 const size_t length = pakfire_filelist_size(filelist);
662
663 // Delete all files
664 for (unsigned int i = 0; i < length; i++) {
665 struct pakfire_file* file = pakfire_filelist_get(filelist, i);
666
667 // Remove the file
668 r = pakfire_file_remove(file);
669 pakfire_file_unref(file);
670
671 // Break on any errors
672 if (r)
673 goto ERROR;
674 }
675
676 // Update the runtime linker cache after all files have been removed
677 pakfire_execute_ldconfig(transaction->pakfire);
678
679 ERROR:
680 if (filelist)
681 pakfire_filelist_unref(filelist);
682
683 return r;
684 }
685
686 static const char* pakfire_action_type_string(enum pakfire_actions type) {
687 switch (type) {
688 case PAKFIRE_ACTION_NOOP:
689 return "NOOP";
690
691 case PAKFIRE_ACTION_VERIFY:
692 return "VERIFY";
693
694 case PAKFIRE_ACTION_EXECUTE:
695 return "EXECUTE";
696
697 case PAKFIRE_ACTION_PRETRANS:
698 return "PRETRANS";
699
700 case PAKFIRE_ACTION_POSTTRANS:
701 return "POSTTRANS";
702 }
703
704 return NULL;
705 }
706
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)
711 return 0;
712
713 const char* name = pakfire_package_get_name(pkg);
714
715 // Check if the package is on the list
716 for (char** elem = transaction->userinstalled; *elem; elem++) {
717 if (strcmp(name, *elem) == 0)
718 return 1;
719 }
720
721 // Not found
722 return 0;
723 }
724
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) {
727 if (!pkg) {
728 errno = EINVAL;
729 return 1;
730 }
731
732 DEBUG(transaction->pakfire, "Running %s for %s\n",
733 pakfire_action_type_string(action), pakfire_package_get_nevra(pkg));
734
735 enum pakfire_steps type = pakfire_transaction_get_step_type(transaction, pkg);
736
737 int r = 0;
738 switch (action) {
739 // Verify this step
740 case PAKFIRE_ACTION_VERIFY:
741 r = pakfire_transaction_verify(transaction, pkg, archive);
742 break;
743
744 // Run the pre-transaction scripts
745 case PAKFIRE_ACTION_PRETRANS:
746 switch (type) {
747 case PAKFIRE_STEP_INSTALL:
748 case PAKFIRE_STEP_REINSTALL:
749 r = pakfire_transaction_run_script(transaction, db,
750 "pretransin", pkg, archive);
751 break;
752
753 case PAKFIRE_STEP_UPGRADE:
754 case PAKFIRE_STEP_DOWNGRADE:
755 r = pakfire_transaction_run_script(transaction, db,
756 "pretransup", pkg, archive);
757 break;
758
759 case PAKFIRE_STEP_ERASE:
760 case PAKFIRE_STEP_OBSOLETE:
761 r = pakfire_transaction_run_script(transaction, db,
762 "pretransun", pkg, archive);
763 break;
764
765 case PAKFIRE_STEP_IGNORE:
766 break;
767 }
768 break;
769
770 // Run the post-transaction scripts
771 case PAKFIRE_ACTION_POSTTRANS:
772 switch (type) {
773 case PAKFIRE_STEP_INSTALL:
774 case PAKFIRE_STEP_REINSTALL:
775 r = pakfire_transaction_run_script(transaction, db,
776 "posttransin", pkg, archive);
777 break;
778
779 case PAKFIRE_STEP_UPGRADE:
780 case PAKFIRE_STEP_DOWNGRADE:
781 r = pakfire_transaction_run_script(transaction, db,
782 "posttransup", pkg, archive);
783 break;
784
785 case PAKFIRE_STEP_ERASE:
786 case PAKFIRE_STEP_OBSOLETE:
787 r = pakfire_transaction_run_script(transaction, db,
788 "posttransun", pkg, archive);
789 break;
790
791 case PAKFIRE_STEP_IGNORE:
792 break;
793 }
794 break;
795
796 // Execute the action of this script
797 case PAKFIRE_ACTION_EXECUTE:
798 switch (type) {
799 case PAKFIRE_STEP_INSTALL:
800 case PAKFIRE_STEP_REINSTALL:
801 r = pakfire_transaction_run_script(transaction, db,
802 "prein", pkg, archive);
803 if (r)
804 break;
805
806 r = pakfire_transaction_extract(transaction, pkg, archive);
807 if (r)
808 break;
809
810 // Remove package metadata first when reinstalling
811 if (type == PAKFIRE_STEP_REINSTALL) {
812 r = pakfire_db_remove_package(db, pkg);
813 if (r)
814 break;
815 }
816
817 r = pakfire_db_add_package(db, pkg, archive,
818 pakfire_transaction_package_is_userinstalled(transaction, pkg));
819 if (r)
820 break;
821
822 r = pakfire_transaction_run_script(transaction, db,
823 "postin", pkg, archive);
824 break;
825
826 case PAKFIRE_STEP_UPGRADE:
827 case PAKFIRE_STEP_DOWNGRADE:
828 r = pakfire_transaction_run_script(transaction, db,
829 "preup", pkg, archive);
830 if (r)
831 break;
832
833 r = pakfire_transaction_extract(transaction, pkg, archive);
834 if (r)
835 break;
836
837 r = pakfire_db_add_package(db, pkg, archive,
838 pakfire_transaction_package_is_userinstalled(transaction, pkg));
839 if (r)
840 break;
841
842 r = pakfire_transaction_run_script(transaction, db,
843 "postup", pkg, archive);
844 break;
845
846 case PAKFIRE_STEP_ERASE:
847 case PAKFIRE_STEP_OBSOLETE:
848 r = pakfire_transaction_run_script(transaction, db,
849 "preun", pkg, archive);
850 if (r)
851 break;
852
853 r = pakfire_transaction_erase(transaction, db, pkg);
854 if (r)
855 break;
856
857 r = pakfire_db_remove_package(db, pkg);
858 if (r)
859 break;
860
861 r = pakfire_transaction_run_script(transaction, db,
862 "postun", pkg, archive);
863 break;
864
865 case PAKFIRE_STEP_IGNORE:
866 break;
867 }
868 break;
869
870 // Do nothing
871 case PAKFIRE_ACTION_NOOP:
872 break;
873 }
874
875 if (r)
876 ERROR(transaction->pakfire, "Step has failed: %s\n", strerror(r));
877
878 return r;
879 }
880
881 static int pakfire_transaction_run_steps(struct pakfire_transaction* transaction,
882 struct pakfire_db* db, enum pakfire_actions action) {
883 int r = 0;
884
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]);
889
890 // End loop if action was unsuccessful
891 if (r) {
892 DEBUG(transaction->pakfire, "Step %d failed: %m\n", i);
893 break;
894 }
895 }
896
897 return r;
898 }
899
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];
903
904 // Fetch the type
905 enum pakfire_steps type = pakfire_transaction_get_step_type(transaction, pkg);
906
907 // Do we need the archive?
908 switch (type) {
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:
914 break;
915
916 case PAKFIRE_STEP_ERASE:
917 case PAKFIRE_STEP_IGNORE:
918 continue;
919 }
920
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));
925 return 1;
926 }
927 }
928
929 return 0;
930 }
931
932 static int pakfire_transaction_perform(struct pakfire_transaction* transaction) {
933 struct pakfire_repo* repo = NULL;
934 struct pakfire_db* db;
935 int r;
936
937 DEBUG(transaction->pakfire, "Running Transaction %p\n", transaction);
938
939 // Open all archives
940 r = pakfire_transaction_open_archives(transaction);
941 if (r)
942 return r;
943
944 // Open the database
945 r = pakfire_db_open(&db, transaction->pakfire, PAKFIRE_DB_READWRITE);
946 if (r) {
947 ERROR(transaction->pakfire, "Could not open the database\n");
948 return r;
949 }
950
951 // Verify steps
952 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_VERIFY);
953 if (r)
954 goto ERROR;
955
956 // Execute all pre transaction actions
957 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_PRETRANS);
958 if (r)
959 goto ERROR;
960
961 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_EXECUTE);
962 if (r)
963 goto ERROR;
964
965 // Execute all post transaction actions
966 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_POSTTRANS);
967 if (r)
968 goto ERROR;
969
970 DEBUG(transaction->pakfire, "The transaction has finished successfully\n");
971
972 // Reload database for next transaction
973
974 repo = pakfire_get_installed_repo(transaction->pakfire);
975 if (!repo)
976 goto ERROR;
977
978 // Reload the database
979 r = pakfire_db_load(db, repo);
980
981 ERROR:
982 if (repo)
983 pakfire_repo_unref(repo);
984 pakfire_db_unref(db);
985
986 return r;
987 }
988
989 static int pakfire_transaction_download_package(struct pakfire_transaction* transaction,
990 struct pakfire_downloader* downloader, struct pakfire_package* pkg) {
991 int r = 1;
992 struct pakfire_repo* repo = NULL;
993 struct pakfire_mirrorlist* mirrorlist = NULL;
994
995 // Fetch the repository to download from
996 repo = pakfire_package_get_repo(pkg);
997 if (!repo)
998 goto ERROR;
999
1000 // Fetch baseurl
1001 const char* baseurl = pakfire_repo_get_baseurl(repo);
1002
1003 // Fetch mirrorlist
1004 mirrorlist = pakfire_repo_get_mirrorlist(repo);
1005
1006 const char* nevra = pakfire_package_get_nevra(pkg);
1007 if (!nevra)
1008 goto ERROR;
1009
1010 // Where to store the package?
1011 const char* path = pakfire_package_get_path(pkg);
1012 if (!path) {
1013 ERROR(transaction->pakfire, "Could not retrieve package path for %s: %m\n", nevra);
1014 goto ERROR;
1015 }
1016
1017 // What file to download?
1018 const char* filename = pakfire_package_get_filename(pkg);
1019 if (!filename) {
1020 ERROR(transaction->pakfire, "Could not retrieve filename for package %s: %m\n", nevra);
1021 goto ERROR;
1022 }
1023
1024 enum pakfire_digests digest_type = PAKFIRE_DIGEST_NONE;
1025
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);
1029
1030 // Add transfer to downloader
1031 r = pakfire_downloader_add_transfer(downloader, baseurl, mirrorlist,
1032 nevra, filename, path, digest_type, digest, digest_length, 0);
1033
1034 ERROR:
1035 if (mirrorlist)
1036 pakfire_mirrorlist_unref(mirrorlist);
1037 if (repo)
1038 pakfire_repo_unref(repo);
1039
1040 return r;
1041 }
1042
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);
1046 switch (type) {
1047 case PAKFIRE_STEP_INSTALL:
1048 case PAKFIRE_STEP_REINSTALL:
1049 case PAKFIRE_STEP_DOWNGRADE:
1050 case PAKFIRE_STEP_UPGRADE:
1051 break;
1052
1053 // No need to download for these steps
1054 default:
1055 return 0;
1056 }
1057
1058 // No download required if this package is already installed
1059 if (pakfire_package_is_installed(pkg))
1060 return 0;
1061
1062 const char* path = pakfire_package_get_path(pkg);
1063
1064 // Does the file exist?
1065 int r = access(path, R_OK);
1066 if (r == 0)
1067 return 0;
1068
1069 // This package needs to be downloaded
1070 return 1;
1071 }
1072
1073 PAKFIRE_EXPORT int pakfire_transaction_download(struct pakfire_transaction* transaction) {
1074 struct pakfire_downloader* downloader;
1075 int r;
1076
1077 // Initialize the downloader
1078 r = pakfire_downloader_create(&downloader, transaction->pakfire);
1079 if (r) {
1080 ERROR(transaction->pakfire, "Could not initialize downloader: %m\n");
1081 return 1;
1082 }
1083
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];
1087
1088 if (!pakfire_transaction_package_needs_download(transaction, pkg))
1089 continue;
1090
1091 // Enqueue download
1092 r = pakfire_transaction_download_package(transaction, downloader, pkg);
1093 if (r) {
1094 const char* nevra = pakfire_package_get_nevra(pkg);
1095
1096 ERROR(transaction->pakfire, "Could not add download to queue: %s: %m\n", nevra);
1097 goto ERROR;
1098 }
1099 }
1100
1101 // Run the downloader
1102 r = pakfire_downloader_run(downloader);
1103
1104 ERROR:
1105 pakfire_downloader_unref(downloader);
1106
1107 return r;
1108 }
1109
1110 PAKFIRE_EXPORT int pakfire_transaction_run(struct pakfire_transaction* transaction) {
1111 int r;
1112
1113 // Skip running an empty transaction
1114 if (!transaction->num) {
1115 DEBUG(transaction->pakfire, "Empty transaction. Skipping...\n");
1116 return 0;
1117 }
1118
1119 // Show what would be done
1120 char* dump = pakfire_transaction_dump(transaction, 80);
1121
1122 // Check if we should continue
1123 r = pakfire_ui_confirm(transaction->pakfire, dump, _("Is this okay? [y/N]"));
1124 if (r) {
1125 ERROR(transaction->pakfire, "Transaction aborted upon user request\n");
1126 goto ERROR;
1127 }
1128
1129 // Write transaction dump to log
1130 INFO(transaction->pakfire, "%s\n", dump);
1131
1132 // Download what we need
1133 r = pakfire_transaction_download(transaction);
1134 if (r)
1135 goto ERROR;
1136
1137 // Perform all steps
1138 r = pakfire_transaction_perform(transaction);
1139 if (r)
1140 goto ERROR;
1141
1142 ERROR:
1143 free(dump);
1144
1145 return r;
1146 }