]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/transaction.c
transaction: Show correct package order for upgrades/downgrades
[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/i18n.h>
31 #include <pakfire/logging.h>
32 #include <pakfire/package.h>
33 #include <pakfire/pakfire.h>
34 #include <pakfire/private.h>
35 #include <pakfire/repo.h>
36 #include <pakfire/transaction.h>
37 #include <pakfire/types.h>
38 #include <pakfire/util.h>
39
40 struct pakfire_transaction {
41 Pakfire pakfire;
42 int nrefs;
43
44 Transaction* transaction;
45
46 PakfireArchive* archives;
47 PakfirePackage* packages;
48 size_t num;
49 };
50
51 static pakfire_step_type_t pakfire_transaction_get_step_type(
52 struct pakfire_transaction* transaction, PakfirePackage pkg) {
53 int type = transaction_type(transaction->transaction, pakfire_package_id(pkg),
54 SOLVER_TRANSACTION_SHOW_ACTIVE|SOLVER_TRANSACTION_CHANGE_IS_REINSTALL);
55
56 // Translate solver types into our own types
57 switch (type) {
58 case SOLVER_TRANSACTION_INSTALL:
59 case SOLVER_TRANSACTION_MULTIINSTALL:
60 return PAKFIRE_STEP_INSTALL;
61
62 case SOLVER_TRANSACTION_REINSTALL:
63 case SOLVER_TRANSACTION_MULTIREINSTALL:
64 return PAKFIRE_STEP_REINSTALL;
65
66 case SOLVER_TRANSACTION_ERASE:
67 return PAKFIRE_STEP_ERASE;
68
69 case SOLVER_TRANSACTION_DOWNGRADE:
70 return PAKFIRE_STEP_DOWNGRADE;
71
72 case SOLVER_TRANSACTION_UPGRADE:
73 return PAKFIRE_STEP_UPGRADE;
74
75 case SOLVER_TRANSACTION_OBSOLETES:
76 return PAKFIRE_STEP_OBSOLETE;
77
78 // Anything we don't care about
79 case SOLVER_TRANSACTION_IGNORE:
80 case SOLVER_TRANSACTION_REINSTALLED:
81 case SOLVER_TRANSACTION_DOWNGRADED:
82 default:
83 return PAKFIRE_STEP_IGNORE;
84 }
85 }
86
87 static void pakfire_transaction_free_archives_and_packages(
88 struct pakfire_transaction* transaction) {
89 if (transaction->archives) {
90 for (unsigned int i = 0; i < transaction->num; i++)
91 if (transaction->archives[i])
92 pakfire_archive_unref(transaction->archives[i]);
93 free(transaction->archives);
94
95 transaction->archives = NULL;
96 }
97
98 if (transaction->packages) {
99 for (unsigned int i = 0; i < transaction->num; i++)
100 if (transaction->packages[i])
101 pakfire_package_unref(transaction->packages[i]);
102 free(transaction->packages);
103
104 transaction->packages = NULL;
105 }
106 }
107
108 static void pakfire_transaction_free(struct pakfire_transaction* transaction) {
109 pakfire_transaction_free_archives_and_packages(transaction);
110
111 transaction_free(transaction->transaction);
112
113 pakfire_unref(transaction->pakfire);
114 free(transaction);
115 }
116
117 static int pakfire_transaction_import_transaction(
118 struct pakfire_transaction* transaction, Transaction* t) {
119 // Free any previous content
120 pakfire_transaction_free_archives_and_packages(transaction);
121
122 // Order the transaction
123 transaction_order(t, 0);
124
125 // How many steps?
126 transaction->num = t->steps.count;
127
128 // Allocate space for packages
129 transaction->packages = calloc(transaction->num, sizeof(*transaction->packages));
130 if (!transaction->packages)
131 return 1;
132
133 // Allocate space for archives
134 transaction->archives = calloc(transaction->num, sizeof(*transaction->archives));
135 if (!transaction->archives)
136 return 1;
137
138 // Create all packages
139 for (unsigned int i = 0; i < transaction->num; i++) {
140 transaction->packages[i] = pakfire_package_create_from_solvable(
141 transaction->pakfire, t->steps.elements[i]);
142 }
143
144 return 0;
145 }
146
147 int pakfire_transaction_create(struct pakfire_transaction** transaction,
148 Pakfire pakfire, Transaction* trans) {
149 struct pakfire_transaction* t = calloc(1, sizeof(*t));
150 if (!t)
151 return ENOMEM;
152
153 // Store reference to Pakfire
154 t->pakfire = pakfire_ref(pakfire);
155
156 // Initialize the reference counter
157 t->nrefs = 1;
158
159 // Clone the transaction to keep a copy of it
160 t->transaction = transaction_create_clone(trans);
161 if (!t->transaction)
162 goto ERROR;
163
164 // Import transaction
165 int r = pakfire_transaction_import_transaction(t, t->transaction);
166 if (r)
167 goto ERROR;
168
169 *transaction = t;
170 return 0;
171
172 ERROR:
173 pakfire_transaction_free(t);
174
175 return 1;
176 }
177
178 PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_ref(
179 struct pakfire_transaction* transaction) {
180 transaction->nrefs++;
181
182 return transaction;
183 }
184
185 PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_unref(
186 struct pakfire_transaction* transaction) {
187 if (--transaction->nrefs > 0)
188 return transaction;
189
190 pakfire_transaction_free(transaction);
191 return NULL;
192 }
193
194 PAKFIRE_EXPORT size_t pakfire_transaction_count(struct pakfire_transaction* transaction) {
195 return transaction->num;
196 }
197
198 static ssize_t pakfire_transaction_installsizechange(struct pakfire_transaction* transaction) {
199 ssize_t sizechange = transaction_calc_installsizechange(transaction->transaction);
200
201 // Convert from kbytes to bytes
202 return sizechange * 1024;
203 }
204
205 PAKFIRE_EXPORT ssize_t pakfire_transaction_downloadsize(struct pakfire_transaction* transaction) {
206 ssize_t size = 0;
207
208 for (unsigned int i = 0; i < transaction->num; i++)
209 size += pakfire_package_get_downloadsize(transaction->packages[i]);
210
211 return size;
212 }
213
214 static void pakfire_transaction_add_headline(char** str, size_t width, const char* headline) {
215 asprintf(str, "%s%s\n", *str, headline);
216 }
217
218 static void pakfire_transaction_add_newline(char** str, size_t width) {
219 asprintf(str, "%s\n", *str);
220 }
221
222 static void pakfire_transaction_add_line(char** str, size_t width, const char* name,
223 const char* arch, const char* version, const char* repo, const char* size) {
224 // XXX need to adapt to size
225 asprintf(str, "%s %-21s %-8s %-21s %-18s %6s \n", *str, name, arch, version, repo, size);
226 }
227
228 static void pakfire_transaction_add_package(char** str, size_t width, PakfirePackage pkg) {
229 char size[128];
230
231 PakfireRepo repo = pakfire_package_get_repo(pkg);
232
233 // Format size
234 pakfire_format_size(size, sizeof(size) - 1, pakfire_package_get_size(pkg));
235
236 pakfire_transaction_add_line(str, width,
237 pakfire_package_get_name(pkg),
238 pakfire_package_get_arch(pkg),
239 pakfire_package_get_evr(pkg),
240 pakfire_repo_get_name(repo),
241 size
242 );
243
244 pakfire_repo_unref(repo);
245 }
246
247 static void pakfire_transaction_add_package_change(char** str, size_t width,
248 PakfirePackage old_pkg, PakfirePackage new_pkg) {
249 // Print the new package first
250 pakfire_transaction_add_package(str, width, new_pkg);
251
252 asprintf(str, "%s --> %s\n", *str, pakfire_package_get_nevra(old_pkg));
253 }
254
255 static void pakfire_transaction_add_separator(char** str, size_t width) {
256 while (width-- > 0)
257 asprintf(str, "%s=", *str);
258
259 // newline
260 asprintf(str, "%s\n", *str);
261 }
262
263 static void pakfire_transaction_add_usage_line(char** str, size_t width, const char* headline, ssize_t size) {
264 char buffer[128];
265 pakfire_format_size(buffer, sizeof(buffer) - 1, size);
266
267 asprintf(str, "%s%-21s: %s\n", *str, headline, buffer);
268 }
269
270 PAKFIRE_EXPORT char* pakfire_transaction_dump(struct pakfire_transaction* transaction, size_t width) {
271 char headline[1024];
272 char* string = "";
273
274 Pool* pool = transaction->transaction->pool;
275 const int mode =
276 SOLVER_TRANSACTION_SHOW_OBSOLETES |
277 SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
278
279 // Header
280 pakfire_transaction_add_separator(&string, width);
281 pakfire_transaction_add_line(&string, width,
282 _("Package"),
283 _("Arch"),
284 _("Version"),
285 _("Repository"),
286 _("Size")
287 );
288 pakfire_transaction_add_separator(&string, width);
289
290 Queue classes;
291 queue_init(&classes);
292
293 // Get all classes
294 transaction_classify(transaction->transaction, mode, &classes);
295
296 Queue pkgs;
297 queue_init(&pkgs);
298
299 /*
300 The classes queue now contains a list of all classes as a tuple of:
301 * The class type
302 * The number of packages in this class
303 * The from ID (for arch/vendor change)
304 * The to ID (for arch/vendor change)
305 */
306 for (int i = 0; i < classes.count; i += 4) {
307 Id class = classes.elements[i];
308 unsigned int count = classes.elements[i+1];
309
310 const char* from = pool_id2str(pool, classes.elements[i+2]);
311 const char* to = pool_id2str(pool, classes.elements[i+3]);
312
313 switch (class) {
314 case SOLVER_TRANSACTION_INSTALL:
315 if (count)
316 pakfire_string_format(headline, _("Installing %u packages:"), count);
317 else
318 pakfire_string_set(headline, _("Installing one package:"));
319 break;
320
321 case SOLVER_TRANSACTION_REINSTALLED:
322 if (count)
323 pakfire_string_format(headline, _("Reinstalling %u packages:"), count);
324 else
325 pakfire_string_set(headline, _("Reinstalling one package:"));
326 break;
327
328 case SOLVER_TRANSACTION_ERASE:
329 if (count)
330 pakfire_string_format(headline, _("Removing %u packages:"), count);
331 else
332 pakfire_string_set(headline, _("Removing one package:"));
333 break;
334
335 case SOLVER_TRANSACTION_UPGRADED:
336 if (count)
337 pakfire_string_format(headline, _("Updating %u packages:"), count);
338 else
339 pakfire_string_set(headline, _("Updating one package:"));
340 break;
341
342 case SOLVER_TRANSACTION_DOWNGRADED:
343 if (count)
344 pakfire_string_format(headline, _("Downgrading %u packages:"), count);
345 else
346 pakfire_string_set(headline, _("Downgrading one package:"));
347 break;
348
349 case SOLVER_TRANSACTION_CHANGED:
350 if (count)
351 pakfire_string_format(headline, _("Changing %u packages:"), count);
352 else
353 pakfire_string_set(headline, _("Changing one package:"));
354 break;
355
356 case SOLVER_TRANSACTION_ARCHCHANGE:
357 if (count)
358 pakfire_string_format(headline,
359 _("%u architecture changes from '%s' to '%s':"), count, from, to);
360 else
361 pakfire_string_format(headline,
362 _("One architecture change from '%s' to '%s':"), from, to);
363 break;
364
365 case SOLVER_TRANSACTION_VENDORCHANGE:
366 if (count)
367 pakfire_string_format(headline,
368 _("%u vendor changes from '%s' to '%s':"), count, from, to);
369 else
370 pakfire_string_format(headline,
371 _("One vendor change from '%s' to '%s':"), from, to);
372 break;
373
374 case SOLVER_TRANSACTION_IGNORE:
375 continue;
376 }
377
378 // Show what we are doing
379 pakfire_transaction_add_headline(&string, width, headline);
380
381 // Fetch packages in this class
382 transaction_classify_pkgs(transaction->transaction, mode, class,
383 classes.elements[i+2], classes.elements[i+3], &pkgs);
384
385 // List all packages
386 for (int j = 0; j < pkgs.count; j++) {
387 PakfirePackage old_pkg = pakfire_package_create_from_solvable(
388 transaction->pakfire, pkgs.elements[j]);
389 PakfirePackage new_pkg = NULL;
390
391 switch (class) {
392 case SOLVER_TRANSACTION_UPGRADED:
393 case SOLVER_TRANSACTION_DOWNGRADED:
394 new_pkg = pakfire_package_create_from_solvable(transaction->pakfire,
395 transaction_obs_pkg(transaction->transaction, pkgs.elements[j]));
396
397 pakfire_transaction_add_package_change(&string, width, old_pkg, new_pkg);
398 break;
399
400 default:
401 pakfire_transaction_add_package(&string, width, old_pkg);
402 break;
403 }
404
405 pakfire_package_unref(old_pkg);
406 if (new_pkg)
407 pakfire_package_unref(new_pkg);
408 }
409
410 // Newline
411 pakfire_transaction_add_newline(&string, width);
412 }
413
414 queue_free(&classes);
415 queue_free(&pkgs);
416
417 // Summary
418 pakfire_transaction_add_headline(&string, width, _("Transaction Summary"));
419 pakfire_transaction_add_separator(&string, width);
420
421 // How much do we need to download?
422 size_t downloadsize = pakfire_transaction_downloadsize(transaction);
423
424 if (downloadsize > 0)
425 pakfire_transaction_add_usage_line(&string, width,
426 _("Total Download Size"), downloadsize);
427
428 // How much more space do we need?
429 ssize_t sizechange = pakfire_transaction_installsizechange(transaction);
430 pakfire_transaction_add_usage_line(&string, width,
431 (sizechange >= 0) ? _("Installed Size") : _("Freed Size"), sizechange);
432
433 // Remove trailing newline
434 pakfire_remove_trailing_newline(string);
435
436 DEBUG(transaction->pakfire, "Transaction: %s\n", string);
437
438 return string;
439 }
440
441 static int pakfire_transaction_verify(struct pakfire_transaction* transaction,
442 PakfirePackage pkg, PakfireArchive archive) {
443 // Nothing to do if this step does not have an archive
444 if (!archive)
445 return 0;
446
447 // Verify the archive
448 pakfire_archive_verify_status_t status = pakfire_archive_verify(archive);
449
450 // Log error
451 if (status) {
452 const char* error = pakfire_archive_verify_strerror(status);
453 ERROR(transaction->pakfire, "Archive verification failed: %s\n", error);
454 }
455
456 return status;
457 }
458
459 static int pakfire_transaction_run_script(struct pakfire_transaction* transaction,
460 struct pakfire_db* db, pakfire_scriptlet_type type, PakfirePackage pkg, PakfireArchive archive) {
461 struct pakfire_scriptlet* scriptlet = NULL;
462
463 // Fetch scriptlet from archive if possible
464 if (archive)
465 scriptlet = pakfire_archive_get_scriptlet(archive, type);
466 else
467 scriptlet = pakfire_db_get_scriptlet(db, pkg, type);
468
469 // Nothing to do if there are no scriptlets
470 if (!scriptlet)
471 return 0;
472
473 // Found a script!
474 DEBUG(transaction->pakfire, "Found scriptlet:\n%.*s",
475 (int)scriptlet->size, (const char*)scriptlet->data);
476
477 // Detect what kind of script this is and run it
478 if (pakfire_scriptlet_is_shell_script(scriptlet)) {
479 pakfire_execute_script(transaction->pakfire, scriptlet->data, scriptlet->size,
480 NULL, 0, NULL, NULL);
481 } else {
482 ERROR(transaction->pakfire, "Scriptlet is of an unknown kind\n");
483 }
484
485 return 0;
486 }
487
488 static int pakfire_transaction_extract(struct pakfire_transaction* transaction,
489 PakfirePackage pkg, PakfireArchive archive) {
490 // Extract payload to the root of the Pakfire instance
491 int r = pakfire_archive_extract(archive, NULL);
492 if (r) {
493 ERROR(transaction->pakfire, "Could not extract package %s: %s\n",
494 pakfire_package_get_nevra(pkg), strerror(errno));
495 return r;
496 }
497
498 // Is it necessary to call ldconfig?
499 PakfireFilelist filelist = pakfire_archive_get_filelist(archive);
500 if (filelist) {
501 int need_ldconfig = pakfire_filelist_contains(filelist, "*/lib*.so.?");
502
503 // Update the runtime linker cache
504 if (need_ldconfig)
505 pakfire_execute_ldconfig(transaction->pakfire);
506
507 pakfire_filelist_unref(filelist);
508 }
509
510 return r;
511 }
512
513 static int pakfire_transaction_erase(struct pakfire_transaction* transaction,
514 PakfirePackage pkg, PakfireArchive archive) {
515 // Update the runtime linker cache after all files have been removed
516 pakfire_execute_ldconfig(transaction->pakfire);
517
518 return 0; // TODO
519 }
520
521 static const char* pakfire_action_type_string(pakfire_action_type_t type) {
522 switch (type) {
523 case PAKFIRE_ACTION_NOOP:
524 return "NOOP";
525
526 case PAKFIRE_ACTION_VERIFY:
527 return "VERIFY";
528
529 case PAKFIRE_ACTION_EXECUTE:
530 return "EXECUTE";
531
532 case PAKFIRE_ACTION_PRETRANS:
533 return "PRETRANS";
534
535 case PAKFIRE_ACTION_POSTTRANS:
536 return "POSTTRANS";
537 }
538
539 return NULL;
540 }
541
542 static int pakfire_transaction_run_step(struct pakfire_transaction* transaction,
543 struct pakfire_db* db, const pakfire_action_type_t action, PakfirePackage pkg, PakfireArchive archive) {
544 if (!pkg) {
545 errno = EINVAL;
546 return 1;
547 }
548
549 DEBUG(transaction->pakfire, "Running %s for %s\n",
550 pakfire_action_type_string(action), pakfire_package_get_nevra(pkg));
551
552 pakfire_step_type_t type = pakfire_transaction_get_step_type(transaction, pkg);
553
554 int r = 0;
555 switch (action) {
556 // Verify this step
557 case PAKFIRE_ACTION_VERIFY:
558 r = pakfire_transaction_verify(transaction, pkg, archive);
559 break;
560
561 // Run the pre-transaction scripts
562 case PAKFIRE_ACTION_PRETRANS:
563 switch (type) {
564 case PAKFIRE_STEP_INSTALL:
565 case PAKFIRE_STEP_REINSTALL:
566 r = pakfire_transaction_run_script(transaction, db,
567 PAKFIRE_SCRIPTLET_PRETRANSIN, pkg, archive);
568 break;
569
570 case PAKFIRE_STEP_UPGRADE:
571 case PAKFIRE_STEP_DOWNGRADE:
572 r = pakfire_transaction_run_script(transaction, db,
573 PAKFIRE_SCRIPTLET_PRETRANSUP, pkg, archive);
574 break;
575
576 case PAKFIRE_STEP_ERASE:
577 case PAKFIRE_STEP_OBSOLETE:
578 r = pakfire_transaction_run_script(transaction, db,
579 PAKFIRE_SCRIPTLET_PRETRANSUN, pkg, archive);
580 break;
581
582 case PAKFIRE_STEP_IGNORE:
583 break;
584 }
585 break;
586
587 // Run the post-transaction scripts
588 case PAKFIRE_ACTION_POSTTRANS:
589 switch (type) {
590 case PAKFIRE_STEP_INSTALL:
591 case PAKFIRE_STEP_REINSTALL:
592 r = pakfire_transaction_run_script(transaction, db,
593 PAKFIRE_SCRIPTLET_POSTTRANSIN, pkg, archive);
594 break;
595
596 case PAKFIRE_STEP_UPGRADE:
597 case PAKFIRE_STEP_DOWNGRADE:
598 r = pakfire_transaction_run_script(transaction, db,
599 PAKFIRE_SCRIPTLET_POSTTRANSUP, pkg, archive);
600 break;
601
602 case PAKFIRE_STEP_ERASE:
603 case PAKFIRE_STEP_OBSOLETE:
604 r = pakfire_transaction_run_script(transaction, db,
605 PAKFIRE_SCRIPTLET_POSTTRANSUN, pkg, archive);
606 break;
607
608 case PAKFIRE_STEP_IGNORE:
609 break;
610 }
611 break;
612
613 // Execute the action of this script
614 case PAKFIRE_ACTION_EXECUTE:
615 switch (type) {
616 case PAKFIRE_STEP_INSTALL:
617 case PAKFIRE_STEP_REINSTALL:
618 r = pakfire_transaction_run_script(transaction, db,
619 PAKFIRE_SCRIPTLET_PREIN, pkg, archive);
620 if (r)
621 break;
622
623 r = pakfire_transaction_extract(transaction, pkg, archive);
624 if (r)
625 break;
626
627 // Remove package metadata first when reinstalling
628 if (type == PAKFIRE_STEP_REINSTALL) {
629 r = pakfire_db_remove_package(db, pkg);
630 if (r)
631 break;
632 }
633
634 r = pakfire_db_add_package(db, pkg, archive);
635 if (r)
636 break;
637
638 r = pakfire_transaction_run_script(transaction, db,
639 PAKFIRE_SCRIPTLET_POSTIN, pkg, archive);
640 break;
641
642 case PAKFIRE_STEP_UPGRADE:
643 case PAKFIRE_STEP_DOWNGRADE:
644 r = pakfire_transaction_run_script(transaction, db,
645 PAKFIRE_SCRIPTLET_PREUP, pkg, archive);
646 if (r)
647 break;
648
649 r = pakfire_transaction_extract(transaction, pkg, archive);
650 if (r)
651 break;
652
653 r = pakfire_db_add_package(db, pkg, archive);
654 if (r)
655 break;
656
657 r = pakfire_transaction_run_script(transaction, db,
658 PAKFIRE_SCRIPTLET_POSTUP, pkg, archive);
659 break;
660
661 case PAKFIRE_STEP_ERASE:
662 case PAKFIRE_STEP_OBSOLETE:
663 r = pakfire_transaction_run_script(transaction, db,
664 PAKFIRE_SCRIPTLET_PREUN, pkg, archive);
665 if (r)
666 break;
667
668 r = pakfire_transaction_erase(transaction, pkg, archive);
669 if (r)
670 break;
671
672 r = pakfire_db_remove_package(db, pkg);
673 if (r)
674 break;
675
676 r = pakfire_transaction_run_script(transaction, db,
677 PAKFIRE_SCRIPTLET_POSTUN, pkg, archive);
678 break;
679
680 case PAKFIRE_STEP_IGNORE:
681 break;
682 }
683 break;
684
685 // Do nothing
686 case PAKFIRE_ACTION_NOOP:
687 break;
688 }
689
690 if (r)
691 ERROR(transaction->pakfire, "Step has failed: %s\n", strerror(r));
692
693 return r;
694 }
695
696 static int pakfire_transaction_run_steps(struct pakfire_transaction* transaction,
697 struct pakfire_db* db, const pakfire_action_type_t action) {
698 int r = 0;
699
700 // Walk through all steps
701 for (unsigned int i = 0; i < transaction->num; i++) {
702 r = pakfire_transaction_run_step(transaction, db, action,
703 transaction->packages[i], transaction->archives[i]);
704
705 // End loop if action was unsuccessful
706 if (r) {
707 DEBUG(transaction->pakfire, "Step %d failed: %s\n", i, strerror(errno));
708 break;
709 }
710 }
711
712 return r;
713 }
714
715 static int pakfire_transaction_open_archives(struct pakfire_transaction* transaction) {
716 for (unsigned int i = 0; i < transaction->num; i++) {
717 PakfirePackage pkg = transaction->packages[i];
718
719 // Fetch the type
720 pakfire_step_type_t type = pakfire_transaction_get_step_type(transaction, pkg);
721
722 // Do we need the archive?
723 switch (type) {
724 case PAKFIRE_STEP_INSTALL:
725 case PAKFIRE_STEP_REINSTALL:
726 case PAKFIRE_STEP_UPGRADE:
727 case PAKFIRE_STEP_DOWNGRADE:
728 case PAKFIRE_STEP_OBSOLETE:
729 break;
730
731 case PAKFIRE_STEP_ERASE:
732 case PAKFIRE_STEP_IGNORE:
733 continue;
734 }
735
736 transaction->archives[i] = pakfire_package_get_archive(pkg);
737 if (!transaction->archives[i]) {
738 ERROR(transaction->pakfire, "Could not open archive for %s: %s\n",
739 pakfire_package_get_nevra(pkg), strerror(errno));
740 return 1;
741 }
742 }
743
744 return 0;
745 }
746
747 PAKFIRE_EXPORT int pakfire_transaction_run(struct pakfire_transaction* transaction) {
748 PakfireRepo repo = NULL;
749 struct pakfire_db* db;
750 int r;
751
752 DEBUG(transaction->pakfire, "Running Transaction %p\n", transaction);
753
754 // Open all archives
755 r = pakfire_transaction_open_archives(transaction);
756 if (r)
757 return r;
758
759 // Open the database
760 r = pakfire_db_open(&db, transaction->pakfire, PAKFIRE_DB_READWRITE);
761 if (r) {
762 ERROR(transaction->pakfire, "Could not open the database\n");
763 return r;
764 }
765
766 // Verify steps
767 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_VERIFY);
768 if (r)
769 goto ERROR;
770
771 // Execute all pre transaction actions
772 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_PRETRANS);
773 if (r)
774 goto ERROR;
775
776 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_EXECUTE);
777 if (r)
778 goto ERROR;
779
780 // Execute all post transaction actions
781 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_POSTTRANS);
782 if (r)
783 goto ERROR;
784
785 DEBUG(transaction->pakfire, "The transaction has finished successfully\n");
786
787 // Reload database for next transaction
788
789 repo = pakfire_get_installed_repo(transaction->pakfire);
790 if (!repo)
791 goto ERROR;
792
793 // Reload the database
794 r = pakfire_db_load(db, repo);
795
796 ERROR:
797 if (repo)
798 pakfire_repo_unref(repo);
799 pakfire_db_unref(db);
800
801 return r;
802 }
803
804 static int pakfire_transaction_download_package(struct pakfire_transaction* transaction,
805 struct pakfire_downloader* downloader, PakfirePackage pkg) {
806 int r = 1;
807 PakfireRepo repo = NULL;
808 struct pakfire_mirrorlist* mirrorlist = NULL;
809
810 // Fetch the repository to download from
811 repo = pakfire_package_get_repo(pkg);
812 if (!repo)
813 goto ERROR;
814
815 // Fetch baseurl
816 const char* baseurl = pakfire_repo_get_baseurl(repo);
817
818 // Fetch mirrorlist
819 mirrorlist = pakfire_repo_get_mirrorlist(repo);
820
821 // Where to store the package?
822 const char* path = pakfire_package_get_path(pkg);
823 if (!path)
824 goto ERROR;
825
826 // What file to download?
827 const char* filename = pakfire_package_get_filename(pkg);
828 if (!filename)
829 goto ERROR;
830
831 const char* nevra = pakfire_package_get_nevra(pkg);
832 if (!nevra)
833 goto ERROR;
834
835 // Add transfer to downloader
836 r = pakfire_downloader_add_transfer(downloader, baseurl, mirrorlist,
837 nevra, filename, path, 0);
838
839 ERROR:
840 if (mirrorlist)
841 pakfire_mirrorlist_unref(mirrorlist);
842 if (repo)
843 pakfire_repo_unref(repo);
844
845 return r;
846 }
847
848 static int pakfire_transaction_package_needs_download(
849 struct pakfire_transaction* transaction, PakfirePackage pkg) {
850 pakfire_step_type_t type = pakfire_transaction_get_step_type(transaction, pkg);
851 switch (type) {
852 case PAKFIRE_STEP_INSTALL:
853 case PAKFIRE_STEP_REINSTALL:
854 case PAKFIRE_STEP_DOWNGRADE:
855 case PAKFIRE_STEP_UPGRADE:
856 break;
857
858 // No need to download for these steps
859 default:
860 return 0;
861 }
862
863 // No download required if this package is already installed
864 if (pakfire_package_is_installed(pkg))
865 return 0;
866
867 const char* path = pakfire_package_get_path(pkg);
868
869 // Does the file exist?
870 int r = access(path, R_OK);
871 if (r == 0)
872 return 0;
873
874 // This package needs to be downloaded
875 return 1;
876 }
877
878 PAKFIRE_EXPORT int pakfire_transaction_download(struct pakfire_transaction* transaction) {
879 struct pakfire_downloader* downloader;
880 int r;
881
882 // Initialize the downloader
883 r = pakfire_downloader_create(&downloader, transaction->pakfire);
884 if (r) {
885 ERROR(transaction->pakfire, "Could not initialize downloader: %s\n",
886 strerror(errno));
887 return 1;
888 }
889
890 // Add all packages that need to be downloaded
891 for (unsigned int i = 0; i < transaction->num; i++) {
892 PakfirePackage pkg = transaction->packages[i];
893
894 if (!pakfire_transaction_package_needs_download(transaction, pkg))
895 continue;
896
897 // Enqueue download
898 r = pakfire_transaction_download_package(transaction, downloader, pkg);
899 if (r)
900 goto ERROR;
901 }
902
903 // Run the downloader
904 r = pakfire_downloader_run(downloader);
905
906 ERROR:
907 pakfire_downloader_unref(downloader);
908
909 return r;
910 }