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