]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/transaction.c
compress: Create a unified extraction function
[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 <openssl/crypto.h>
25 #include <openssl/evp.h>
26
27 #include <solv/pool_fileconflicts.h>
28 #include <solv/transaction.h>
29
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>
45
46 struct pakfire_transaction {
47 struct pakfire* pakfire;
48 int nrefs;
49
50 Transaction* transaction;
51 char** userinstalled;
52
53 struct pakfire_archive** archives;
54 struct pakfire_package** packages;
55 size_t num;
56 size_t progress;
57
58 // Callbacks
59 struct pakfire_transaction_callbacks {
60 // Status
61 pakfire_status_callback status;
62 void* status_data;
63 } callbacks;
64 };
65
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,
72 };
73
74 enum pakfire_steps {
75 PAKFIRE_STEP_IGNORE = 0,
76 PAKFIRE_STEP_INSTALL,
77 PAKFIRE_STEP_REINSTALL,
78 PAKFIRE_STEP_ERASE,
79 PAKFIRE_STEP_UPGRADE,
80 PAKFIRE_STEP_DOWNGRADE,
81 PAKFIRE_STEP_OBSOLETE,
82 };
83
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);
88
89 // Translate solver types into our own types
90 switch (type) {
91 case SOLVER_TRANSACTION_INSTALL:
92 case SOLVER_TRANSACTION_MULTIINSTALL:
93 return PAKFIRE_STEP_INSTALL;
94
95 case SOLVER_TRANSACTION_REINSTALL:
96 case SOLVER_TRANSACTION_MULTIREINSTALL:
97 return PAKFIRE_STEP_REINSTALL;
98
99 case SOLVER_TRANSACTION_ERASE:
100 return PAKFIRE_STEP_ERASE;
101
102 case SOLVER_TRANSACTION_DOWNGRADE:
103 return PAKFIRE_STEP_DOWNGRADE;
104
105 case SOLVER_TRANSACTION_UPGRADE:
106 return PAKFIRE_STEP_UPGRADE;
107
108 case SOLVER_TRANSACTION_OBSOLETES:
109 return PAKFIRE_STEP_OBSOLETE;
110
111 // Anything we don't care about
112 case SOLVER_TRANSACTION_IGNORE:
113 case SOLVER_TRANSACTION_REINSTALLED:
114 case SOLVER_TRANSACTION_DOWNGRADED:
115 default:
116 return PAKFIRE_STEP_IGNORE;
117 }
118 }
119
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);
127
128 transaction->archives = NULL;
129 }
130
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);
136
137 transaction->packages = NULL;
138 }
139 }
140
141 static void pakfire_transaction_free(struct pakfire_transaction* transaction) {
142 pakfire_transaction_free_archives_and_packages(transaction);
143
144 if (transaction->userinstalled) {
145 for (char** userinstalled = transaction->userinstalled; *userinstalled; userinstalled++)
146 free(*userinstalled);
147 free(transaction->userinstalled);
148 }
149 transaction_free(transaction->transaction);
150
151 pakfire_unref(transaction->pakfire);
152 free(transaction);
153 }
154
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);
159 if (!t)
160 return 1;
161
162 transaction->transaction = t;
163
164 // Order the transaction
165 transaction_order(t, 0);
166
167 // Free any previous content
168 pakfire_transaction_free_archives_and_packages(transaction);
169
170 // How many steps?
171 transaction->num = t->steps.count;
172
173 // Allocate space for packages
174 transaction->packages = calloc(transaction->num, sizeof(*transaction->packages));
175 if (!transaction->packages)
176 return 1;
177
178 // Allocate space for archives
179 transaction->archives = calloc(transaction->num, sizeof(*transaction->archives));
180 if (!transaction->archives)
181 return 1;
182
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]);
187 }
188
189 return 0;
190 }
191
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;
197 }
198
199 Queue userinstalled;
200 queue_init(&userinstalled);
201
202 // Fetch a list of all packages that are installed by the user
203 solver_get_userinstalled(solver, &userinstalled, GET_USERINSTALLED_NAMES);
204
205 // Skip everything if the queue is empty
206 if (!userinstalled.count)
207 return 0;
208
209 t->userinstalled = calloc(userinstalled.count + 1, sizeof(*t->userinstalled));
210 if (!t->userinstalled) {
211 ERROR(t->pakfire, "Could not allocate userinstalled\n");
212 return 1;
213 }
214
215 Pool* pool = pakfire_get_solv_pool(t->pakfire);
216
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);
221 }
222
223 return 0;
224 }
225
226 int pakfire_transaction_create(struct pakfire_transaction** transaction,
227 struct pakfire* pakfire, Solver* solver) {
228 struct pakfire_transaction* t = calloc(1, sizeof(*t));
229 if (!t)
230 return ENOMEM;
231
232 // Store reference to Pakfire
233 t->pakfire = pakfire_ref(pakfire);
234
235 // Initialize the reference counter
236 t->nrefs = 1;
237
238 // Import transaction
239 int r = pakfire_transaction_import_transaction(t, solver);
240 if (r)
241 goto ERROR;
242
243 // Import userinstalled
244 r = pakfire_transaction_import_userinstalled(t, solver);
245 if (r)
246 goto ERROR;
247
248 *transaction = t;
249 return 0;
250
251 ERROR:
252 pakfire_transaction_free(t);
253 return 1;
254 }
255
256 PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_ref(
257 struct pakfire_transaction* transaction) {
258 transaction->nrefs++;
259
260 return transaction;
261 }
262
263 PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_unref(
264 struct pakfire_transaction* transaction) {
265 if (--transaction->nrefs > 0)
266 return transaction;
267
268 pakfire_transaction_free(transaction);
269 return NULL;
270 }
271
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;
276 }
277
278 static int pakfire_transaction_get_progress(struct pakfire_transaction* transaction) {
279 return transaction->progress * 100 / transaction->num;
280 }
281
282 static void pakfire_transaction_status(struct pakfire_transaction* transaction,
283 const char* message, ...) {
284 char* buffer = NULL;
285 va_list args;
286 int r;
287
288 // Do nothing if callback isn't set
289 if (!transaction->callbacks.status)
290 return;
291
292 // Format the message
293 if (message) {
294 va_start(args, message);
295 r = vasprintf(&buffer, message, args);
296 va_end(args);
297
298 if (r < 0)
299 return;
300 }
301
302 // Fetch progress
303 const int progress = pakfire_transaction_get_progress(transaction);
304
305 // Call the callback
306 transaction->callbacks.status(transaction->pakfire,
307 transaction->callbacks.status_data, progress, buffer);
308
309 // Cleanup
310 if (buffer)
311 free(buffer);
312 }
313
314 PAKFIRE_EXPORT size_t pakfire_transaction_count(struct pakfire_transaction* transaction) {
315 return transaction->num;
316 }
317
318 static ssize_t pakfire_transaction_installsizechange(struct pakfire_transaction* transaction) {
319 ssize_t sizechange = transaction_calc_installsizechange(transaction->transaction);
320
321 // Convert from kbytes to bytes
322 return sizechange * 1024;
323 }
324
325 static ssize_t pakfire_transaction_downloadsize(struct pakfire_transaction* transaction) {
326 ssize_t size = 0;
327
328 for (unsigned int i = 0; i < transaction->num; i++)
329 size += pakfire_package_get_downloadsize(transaction->packages[i]);
330
331 return size;
332 }
333
334 static void pakfire_transaction_append_line(char*** lines, const char* format, ...) {
335 if (!lines)
336 return;
337
338 char* buffer = NULL;
339 va_list args;
340 int r;
341
342 va_start(args, format);
343 r = vasprintf(&buffer, format, args);
344 va_end(args);
345
346 if (r < 0)
347 return;
348
349 // Count lines
350 unsigned int count = 0;
351 if (*lines) {
352 for (char** l = *lines; *l; l++)
353 count++;
354 }
355
356 // Increase size of array
357 *lines = reallocarray(*lines, count + 2, sizeof(**lines));
358 if (!*lines)
359 return;
360
361 // Append line and terminate lines
362 (*lines)[count] = buffer;
363 (*lines)[count + 1] = NULL;
364 }
365
366 static void pakfire_transaction_add_headline(char*** lines, size_t width, const char* headline) {
367 pakfire_transaction_append_line(lines, "%s\n", headline);
368 }
369
370 static void pakfire_transaction_add_newline(char*** lines, size_t width) {
371 pakfire_transaction_append_line(lines, "\n");
372 }
373
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);
378 }
379
380 static void pakfire_transaction_add_package(char*** lines, size_t width, struct pakfire_package* pkg) {
381 char size[128];
382
383 struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
384
385 // Format size
386 int r = pakfire_format_size(size, pakfire_package_get_size(pkg));
387 if (r < 0)
388 return;
389
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),
395 size
396 );
397
398 pakfire_repo_unref(repo);
399 }
400
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);
405
406 pakfire_transaction_append_line(lines,
407 " --> %s\n", pakfire_package_get_nevra(old_pkg));
408 }
409
410 static void pakfire_transaction_add_separator(char*** lines, size_t width) {
411 char* separator = alloca(width + 1);
412
413 for (unsigned int i = 0; i < width; i++)
414 separator[i] = '=';
415 separator[width] = '\0';
416
417 pakfire_transaction_append_line(lines, "%s\n", separator);
418 }
419
420 static void pakfire_transaction_add_usage_line(char*** lines, size_t width,
421 const char* headline, ssize_t size) {
422 char buffer[128];
423
424 int r = pakfire_format_size(buffer, size);
425 if (r < 0)
426 return;
427
428 pakfire_transaction_append_line(lines, "%-21s: %s\n", headline, buffer);
429 }
430
431 static char* pakfire_transaction_join_lines(char** lines) {
432 if (!lines)
433 return NULL;
434
435 size_t size = 0;
436
437 // Determine total length
438 for (char** line = lines; *line; line++)
439 size += strlen(*line);
440
441 // Allocate memory large enough to hold the result
442 char* s = calloc(1, size + 1);
443 if (!s)
444 return s;
445
446 char* p = s;
447
448 for (char** line = lines; *line; line++) {
449 p += snprintf(p, s - p - 1, "%s", *line);
450 }
451
452 return s;
453 }
454
455 PAKFIRE_EXPORT char* pakfire_transaction_dump(struct pakfire_transaction* transaction, size_t width) {
456 char headline[1024];
457
458 Pool* pool = transaction->transaction->pool;
459 const int mode =
460 SOLVER_TRANSACTION_SHOW_OBSOLETES |
461 SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
462
463 char** lines = NULL;
464
465 // Header
466 pakfire_transaction_add_separator(&lines, width);
467 pakfire_transaction_add_line(&lines, width,
468 _("Package"),
469 _("Arch"),
470 _("Version"),
471 _("Repository"),
472 _("Size")
473 );
474 pakfire_transaction_add_separator(&lines, width);
475
476 Queue classes;
477 queue_init(&classes);
478
479 // Get all classes
480 transaction_classify(transaction->transaction, mode, &classes);
481
482 Queue pkgs;
483 queue_init(&pkgs);
484
485 /*
486 The classes queue now contains a list of all classes as a tuple of:
487 * The class type
488 * The number of packages in this class
489 * The from ID (for arch/vendor change)
490 * The to ID (for arch/vendor change)
491 */
492 for (int i = 0; i < classes.count; i += 4) {
493 Id class = classes.elements[i];
494 unsigned int count = classes.elements[i+1];
495
496 const char* from = pool_id2str(pool, classes.elements[i+2]);
497 const char* to = pool_id2str(pool, classes.elements[i+3]);
498
499 switch (class) {
500 case SOLVER_TRANSACTION_INSTALL:
501 if (count)
502 pakfire_string_format(headline, _("Installing %u packages:"), count);
503 else
504 pakfire_string_set(headline, _("Installing one package:"));
505 break;
506
507 case SOLVER_TRANSACTION_REINSTALLED:
508 if (count)
509 pakfire_string_format(headline, _("Reinstalling %u packages:"), count);
510 else
511 pakfire_string_set(headline, _("Reinstalling one package:"));
512 break;
513
514 case SOLVER_TRANSACTION_ERASE:
515 if (count)
516 pakfire_string_format(headline, _("Removing %u packages:"), count);
517 else
518 pakfire_string_set(headline, _("Removing one package:"));
519 break;
520
521 case SOLVER_TRANSACTION_UPGRADED:
522 if (count)
523 pakfire_string_format(headline, _("Updating %u packages:"), count);
524 else
525 pakfire_string_set(headline, _("Updating one package:"));
526 break;
527
528 case SOLVER_TRANSACTION_DOWNGRADED:
529 if (count)
530 pakfire_string_format(headline, _("Downgrading %u packages:"), count);
531 else
532 pakfire_string_set(headline, _("Downgrading one package:"));
533 break;
534
535 case SOLVER_TRANSACTION_CHANGED:
536 if (count)
537 pakfire_string_format(headline, _("Changing %u packages:"), count);
538 else
539 pakfire_string_set(headline, _("Changing one package:"));
540 break;
541
542 case SOLVER_TRANSACTION_ARCHCHANGE:
543 if (count)
544 pakfire_string_format(headline,
545 _("%u architecture changes from '%s' to '%s':"), count, from, to);
546 else
547 pakfire_string_format(headline,
548 _("One architecture change from '%s' to '%s':"), from, to);
549 break;
550
551 case SOLVER_TRANSACTION_VENDORCHANGE:
552 if (count)
553 pakfire_string_format(headline,
554 _("%u vendor changes from '%s' to '%s':"), count, from, to);
555 else
556 pakfire_string_format(headline,
557 _("One vendor change from '%s' to '%s':"), from, to);
558 break;
559
560 case SOLVER_TRANSACTION_IGNORE:
561 continue;
562 }
563
564 // Show what we are doing
565 pakfire_transaction_add_headline(&lines, width, headline);
566
567 // Fetch packages in this class
568 transaction_classify_pkgs(transaction->transaction, mode, class,
569 classes.elements[i+2], classes.elements[i+3], &pkgs);
570
571 // List all packages
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;
576
577 switch (class) {
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]));
582
583 pakfire_transaction_add_package_change(&lines, width, old_pkg, new_pkg);
584 break;
585
586 default:
587 pakfire_transaction_add_package(&lines, width, old_pkg);
588 break;
589 }
590
591 pakfire_package_unref(old_pkg);
592 if (new_pkg)
593 pakfire_package_unref(new_pkg);
594 }
595
596 // Newline
597 pakfire_transaction_add_newline(&lines, width);
598 }
599
600 queue_free(&classes);
601 queue_free(&pkgs);
602
603 // Summary
604 pakfire_transaction_add_headline(&lines, width, _("Transaction Summary"));
605 pakfire_transaction_add_separator(&lines, width);
606
607 // How much do we need to download?
608 size_t downloadsize = pakfire_transaction_downloadsize(transaction);
609
610 if (downloadsize > 0)
611 pakfire_transaction_add_usage_line(&lines, width,
612 _("Total Download Size"), downloadsize);
613
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);
618
619 // Join all lines together
620 char* string = pakfire_transaction_join_lines(lines);
621
622 DEBUG(transaction->pakfire, "Transaction: %s\n", string);
623
624 // Free lines
625 if (lines) {
626 for (char** line = lines; *line; line++)
627 free(*line);
628 free(lines);
629 }
630
631 return string;
632 }
633
634 static void* pakfire_transaction_fileconflict_callback(
635 Pool* pool, Id p, void* data) {
636 return NULL;
637 }
638
639 static int pakfire_transaction_check_fileconflicts(
640 struct pakfire_transaction* transaction) {
641 Pool* pool = pakfire_get_solv_pool(transaction->pakfire);
642
643 const int flags =
644 FINDFILECONFLICTS_USE_SOLVABLEFILELIST |
645 FINDFILECONFLICTS_CHECK_DIRALIASING |
646 FINDFILECONFLICTS_USE_ROOTDIR;
647
648 Queue pkgs;
649 queue_init(&pkgs);
650
651 Queue conflicts;
652 queue_init(&conflicts);
653
654 // Fetch all installed packages
655 int newpkgs = transaction_installedresult(transaction->transaction, &pkgs);
656
657 // Perform check
658 int count = pool_findfileconflicts(pool, &pkgs, newpkgs, &conflicts, flags,
659 pakfire_transaction_fileconflict_callback, NULL);
660
661 DEBUG(transaction->pakfire, "Found %d file conflict(s)\n", count);
662
663 // Free everything
664 queue_free(&pkgs);
665 queue_free(&conflicts);
666
667 return (count > 0);
668 }
669
670 static int pakfire_transaction_check(struct pakfire_transaction* transaction) {
671 int r;
672
673 // Check for any file conflicts
674 r = pakfire_transaction_check_fileconflicts(transaction);
675 if (r)
676 return r;
677
678 return 0;
679 }
680
681 static int pakfire_transaction_verify(struct pakfire_transaction* transaction,
682 struct pakfire_package* pkg, struct pakfire_archive* archive) {
683 int r;
684
685 const char* nevra = pakfire_package_get_nevra(pkg);
686
687 // Nothing to do if this step does not have an archive
688 if (!archive) {
689 DEBUG(transaction->pakfire, "Package %s requires no archive\n", nevra);
690 return 0;
691 }
692
693 enum pakfire_digests digest_type = PAKFIRE_DIGEST_NONE;
694
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);
699 return 0;
700 }
701
702 unsigned char computed_digest[EVP_MAX_MD_SIZE];
703 size_t digest_length = 0;
704
705 // Compute digest of the archive
706 r = pakfire_archive_digest(archive, digest_type, computed_digest, &digest_length);
707 if (r) {
708 ERROR(transaction->pakfire, "Could not compute digest for %s: %m\n", nevra);
709 return r;
710 }
711
712 // Compare digests
713 r = CRYPTO_memcmp(computed_digest, expected_digest, digest_length);
714 if (r) {
715 ERROR(transaction->pakfire, "Digests of %s do not match\n", nevra);
716 return 1;
717 }
718
719 return 0;
720 }
721
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;
725
726 // Fetch scriptlet from archive if possible
727 if (archive)
728 scriptlet = pakfire_archive_get_scriptlet(archive, type);
729 else
730 scriptlet = pakfire_db_get_scriptlet(db, pkg, type);
731
732 // Nothing to do if there are no scriptlets
733 if (!scriptlet)
734 return 0;
735
736 // Execute the scriptlet
737 pakfire_scriptlet_execute(scriptlet);
738
739 pakfire_scriptlet_unref(scriptlet);
740
741 return 0;
742 }
743
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);
747
748 // Update status
749 pakfire_transaction_status(transaction, _("Installing %s..."), nevra);
750
751 // Extract payload
752 int r = pakfire_archive_extract(archive);
753 if (r) {
754 ERROR(transaction->pakfire, "Could not extract package %s: %m\n",
755 nevra);
756 return r;
757 }
758
759 // Is it necessary to call ldconfig?
760 struct pakfire_filelist* filelist = pakfire_archive_get_filelist(archive);
761 if (filelist) {
762 int need_ldconfig = pakfire_filelist_contains(filelist, "*/lib*.so.?");
763
764 // Update the runtime linker cache
765 if (need_ldconfig)
766 pakfire_jail_ldconfig(transaction->pakfire);
767
768 pakfire_filelist_unref(filelist);
769 }
770
771 return r;
772 }
773
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;
777 int r;
778
779 // Fetch filelist
780 r = pakfire_db_package_filelist(db, &filelist, pkg);
781 if (r)
782 goto ERROR;
783
784 const size_t length = pakfire_filelist_size(filelist);
785
786 // Delete all files
787 for (unsigned int i = 0; i < length; i++) {
788 struct pakfire_file* file = pakfire_filelist_get(filelist, i);
789
790 // Remove the file
791 r = pakfire_file_remove(file);
792 pakfire_file_unref(file);
793
794 // Break on any errors
795 if (r)
796 goto ERROR;
797 }
798
799 // Update the runtime linker cache after all files have been removed
800 pakfire_jail_ldconfig(transaction->pakfire);
801
802 ERROR:
803 if (filelist)
804 pakfire_filelist_unref(filelist);
805
806 return r;
807 }
808
809 static const char* pakfire_action_type_string(enum pakfire_actions type) {
810 switch (type) {
811 case PAKFIRE_ACTION_NOOP:
812 return "NOOP";
813
814 case PAKFIRE_ACTION_VERIFY:
815 return "VERIFY";
816
817 case PAKFIRE_ACTION_EXECUTE:
818 return "EXECUTE";
819
820 case PAKFIRE_ACTION_PRETRANS:
821 return "PRETRANS";
822
823 case PAKFIRE_ACTION_POSTTRANS:
824 return "POSTTRANS";
825 }
826
827 return NULL;
828 }
829
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)
834 return 0;
835
836 const char* name = pakfire_package_get_name(pkg);
837
838 // Check if the package is on the list
839 for (char** elem = transaction->userinstalled; *elem; elem++) {
840 if (strcmp(name, *elem) == 0)
841 return 1;
842 }
843
844 // Not found
845 return 0;
846 }
847
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) {
850 if (!pkg) {
851 errno = EINVAL;
852 return 1;
853 }
854
855 DEBUG(transaction->pakfire, "Running %s for %s\n",
856 pakfire_action_type_string(action), pakfire_package_get_nevra(pkg));
857
858 enum pakfire_steps type = pakfire_transaction_get_step_type(transaction, pkg);
859
860 int r = 0;
861 switch (action) {
862 // Verify this step
863 case PAKFIRE_ACTION_VERIFY:
864 r = pakfire_transaction_verify(transaction, pkg, archive);
865 break;
866
867 // Run the pre-transaction scripts
868 case PAKFIRE_ACTION_PRETRANS:
869 switch (type) {
870 case PAKFIRE_STEP_INSTALL:
871 case PAKFIRE_STEP_REINSTALL:
872 r = pakfire_transaction_run_script(transaction, db,
873 "pretransin", pkg, archive);
874 break;
875
876 case PAKFIRE_STEP_UPGRADE:
877 case PAKFIRE_STEP_DOWNGRADE:
878 r = pakfire_transaction_run_script(transaction, db,
879 "pretransup", pkg, archive);
880 break;
881
882 case PAKFIRE_STEP_ERASE:
883 case PAKFIRE_STEP_OBSOLETE:
884 r = pakfire_transaction_run_script(transaction, db,
885 "pretransun", pkg, archive);
886 break;
887
888 case PAKFIRE_STEP_IGNORE:
889 break;
890 }
891 break;
892
893 // Run the post-transaction scripts
894 case PAKFIRE_ACTION_POSTTRANS:
895 switch (type) {
896 case PAKFIRE_STEP_INSTALL:
897 case PAKFIRE_STEP_REINSTALL:
898 r = pakfire_transaction_run_script(transaction, db,
899 "posttransin", pkg, archive);
900 break;
901
902 case PAKFIRE_STEP_UPGRADE:
903 case PAKFIRE_STEP_DOWNGRADE:
904 r = pakfire_transaction_run_script(transaction, db,
905 "posttransup", pkg, archive);
906 break;
907
908 case PAKFIRE_STEP_ERASE:
909 case PAKFIRE_STEP_OBSOLETE:
910 r = pakfire_transaction_run_script(transaction, db,
911 "posttransun", pkg, archive);
912 break;
913
914 case PAKFIRE_STEP_IGNORE:
915 break;
916 }
917 break;
918
919 // Execute the action of this script
920 case PAKFIRE_ACTION_EXECUTE:
921 // Increment progress
922 transaction->progress++;
923
924 // Update progress callback
925 pakfire_transaction_status(transaction, NULL);
926
927 switch (type) {
928 case PAKFIRE_STEP_INSTALL:
929 case PAKFIRE_STEP_REINSTALL:
930 r = pakfire_transaction_run_script(transaction, db,
931 "prein", pkg, archive);
932 if (r)
933 break;
934
935 r = pakfire_transaction_extract(transaction, pkg, archive);
936 if (r)
937 break;
938
939 // Remove package metadata first when reinstalling
940 if (type == PAKFIRE_STEP_REINSTALL) {
941 r = pakfire_db_remove_package(db, pkg);
942 if (r)
943 break;
944 }
945
946 r = pakfire_db_add_package(db, pkg, archive,
947 pakfire_transaction_package_is_userinstalled(transaction, pkg));
948 if (r)
949 break;
950
951 r = pakfire_transaction_run_script(transaction, db,
952 "postin", pkg, archive);
953 break;
954
955 case PAKFIRE_STEP_UPGRADE:
956 case PAKFIRE_STEP_DOWNGRADE:
957 r = pakfire_transaction_run_script(transaction, db,
958 "preup", pkg, archive);
959 if (r)
960 break;
961
962 r = pakfire_transaction_extract(transaction, pkg, archive);
963 if (r)
964 break;
965
966 r = pakfire_db_add_package(db, pkg, archive,
967 pakfire_transaction_package_is_userinstalled(transaction, pkg));
968 if (r)
969 break;
970
971 r = pakfire_transaction_run_script(transaction, db,
972 "postup", pkg, archive);
973 break;
974
975 case PAKFIRE_STEP_ERASE:
976 case PAKFIRE_STEP_OBSOLETE:
977 r = pakfire_transaction_run_script(transaction, db,
978 "preun", pkg, archive);
979 if (r)
980 break;
981
982 r = pakfire_transaction_erase(transaction, db, pkg);
983 if (r)
984 break;
985
986 r = pakfire_db_remove_package(db, pkg);
987 if (r)
988 break;
989
990 r = pakfire_transaction_run_script(transaction, db,
991 "postun", pkg, archive);
992 break;
993
994 case PAKFIRE_STEP_IGNORE:
995 break;
996 }
997 break;
998
999 // Do nothing
1000 case PAKFIRE_ACTION_NOOP:
1001 break;
1002 }
1003
1004 if (r)
1005 ERROR(transaction->pakfire, "Step has failed: %s\n", strerror(r));
1006
1007 return r;
1008 }
1009
1010 static int pakfire_transaction_run_steps(struct pakfire_transaction* transaction,
1011 struct pakfire_db* db, enum pakfire_actions action) {
1012 int r = 0;
1013
1014 // Update status
1015 switch (action) {
1016 case PAKFIRE_ACTION_VERIFY:
1017 pakfire_transaction_status(transaction, _("Verifying packages..."));
1018 break;
1019
1020 case PAKFIRE_ACTION_PRETRANS:
1021 pakfire_transaction_status(transaction, _("Preparing installation..."));
1022 break;
1023
1024 case PAKFIRE_ACTION_POSTTRANS:
1025 pakfire_transaction_status(transaction, _("Finishing up..."));
1026 break;
1027
1028 default:
1029 break;
1030 }
1031
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]);
1036
1037 // End loop if action was unsuccessful
1038 if (r) {
1039 DEBUG(transaction->pakfire, "Step %d failed: %m\n", i);
1040 break;
1041 }
1042 }
1043
1044 return r;
1045 }
1046
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];
1050
1051 // Fetch the type
1052 enum pakfire_steps type = pakfire_transaction_get_step_type(transaction, pkg);
1053
1054 // Do we need the archive?
1055 switch (type) {
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:
1061 break;
1062
1063 case PAKFIRE_STEP_ERASE:
1064 case PAKFIRE_STEP_IGNORE:
1065 continue;
1066 }
1067
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));
1072 return 1;
1073 }
1074 }
1075
1076 return 0;
1077 }
1078
1079 static int pakfire_transaction_perform(struct pakfire_transaction* transaction) {
1080 struct pakfire_repo* repo = NULL;
1081 struct pakfire_db* db;
1082 int r;
1083
1084 DEBUG(transaction->pakfire, "Running Transaction %p\n", transaction);
1085
1086 // Open all archives
1087 r = pakfire_transaction_open_archives(transaction);
1088 if (r)
1089 return r;
1090
1091 // Open the database
1092 r = pakfire_db_open(&db, transaction->pakfire, PAKFIRE_DB_READWRITE);
1093 if (r) {
1094 ERROR(transaction->pakfire, "Could not open the database\n");
1095 return r;
1096 }
1097
1098 // Verify steps
1099 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_VERIFY);
1100 if (r)
1101 goto ERROR;
1102
1103 // Execute all pre transaction actions
1104 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_PRETRANS);
1105 if (r)
1106 goto ERROR;
1107
1108 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_EXECUTE);
1109 if (r)
1110 goto ERROR;
1111
1112 // Execute all post transaction actions
1113 r = pakfire_transaction_run_steps(transaction, db, PAKFIRE_ACTION_POSTTRANS);
1114 if (r)
1115 goto ERROR;
1116
1117 DEBUG(transaction->pakfire, "The transaction has finished successfully\n");
1118
1119 // Reload database for next transaction
1120
1121 repo = pakfire_get_installed_repo(transaction->pakfire);
1122 if (!repo)
1123 goto ERROR;
1124
1125 // Reload the database
1126 r = pakfire_db_load(db, repo);
1127
1128 ERROR:
1129 if (repo)
1130 pakfire_repo_unref(repo);
1131 pakfire_db_unref(db);
1132
1133 return r;
1134 }
1135
1136 static int pakfire_transaction_download_package(struct pakfire_transaction* transaction,
1137 struct pakfire_downloader* downloader, struct pakfire_package* pkg) {
1138 int r = 1;
1139 struct pakfire_repo* repo = NULL;
1140 struct pakfire_mirrorlist* mirrorlist = NULL;
1141
1142 // Fetch the repository to download from
1143 repo = pakfire_package_get_repo(pkg);
1144 if (!repo)
1145 goto ERROR;
1146
1147 // Fetch baseurl
1148 const char* baseurl = pakfire_repo_get_baseurl(repo);
1149
1150 // Fetch mirrorlist
1151 mirrorlist = pakfire_repo_get_mirrorlist(repo);
1152
1153 const char* nevra = pakfire_package_get_nevra(pkg);
1154 if (!nevra)
1155 goto ERROR;
1156
1157 // Where to store the package?
1158 const char* path = pakfire_package_get_path(pkg);
1159 if (!path) {
1160 ERROR(transaction->pakfire, "Could not retrieve package path for %s: %m\n", nevra);
1161 goto ERROR;
1162 }
1163
1164 // What file to download?
1165 const char* filename = pakfire_package_get_filename(pkg);
1166 if (!filename) {
1167 ERROR(transaction->pakfire, "Could not retrieve filename for package %s: %m\n", nevra);
1168 goto ERROR;
1169 }
1170
1171 enum pakfire_digests digest_type = PAKFIRE_DIGEST_NONE;
1172
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);
1176
1177 // Add transfer to downloader
1178 r = pakfire_downloader_add_transfer(downloader, baseurl, mirrorlist,
1179 nevra, filename, path, digest_type, digest, digest_length, 0);
1180
1181 ERROR:
1182 if (mirrorlist)
1183 pakfire_mirrorlist_unref(mirrorlist);
1184 if (repo)
1185 pakfire_repo_unref(repo);
1186
1187 return r;
1188 }
1189
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);
1193 switch (type) {
1194 case PAKFIRE_STEP_INSTALL:
1195 case PAKFIRE_STEP_REINSTALL:
1196 case PAKFIRE_STEP_DOWNGRADE:
1197 case PAKFIRE_STEP_UPGRADE:
1198 break;
1199
1200 // No need to download for these steps
1201 default:
1202 return 0;
1203 }
1204
1205 // No download required if this package is already installed
1206 if (pakfire_package_is_installed(pkg))
1207 return 0;
1208
1209 const char* path = pakfire_package_get_path(pkg);
1210
1211 // Does the file exist?
1212 int r = access(path, R_OK);
1213 if (r == 0)
1214 return 0;
1215
1216 // This package needs to be downloaded
1217 return 1;
1218 }
1219
1220 PAKFIRE_EXPORT int pakfire_transaction_download(struct pakfire_transaction* transaction) {
1221 struct pakfire_downloader* downloader;
1222 int r;
1223
1224 // Initialize the downloader
1225 r = pakfire_downloader_create(&downloader, transaction->pakfire);
1226 if (r) {
1227 ERROR(transaction->pakfire, "Could not initialize downloader: %m\n");
1228 return 1;
1229 }
1230
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];
1234
1235 if (!pakfire_transaction_package_needs_download(transaction, pkg))
1236 continue;
1237
1238 // Enqueue download
1239 r = pakfire_transaction_download_package(transaction, downloader, pkg);
1240 if (r) {
1241 const char* nevra = pakfire_package_get_nevra(pkg);
1242
1243 ERROR(transaction->pakfire, "Could not add download to queue: %s: %m\n", nevra);
1244 goto ERROR;
1245 }
1246 }
1247
1248 // Run the downloader
1249 r = pakfire_downloader_run(downloader);
1250
1251 ERROR:
1252 pakfire_downloader_unref(downloader);
1253
1254 return r;
1255 }
1256
1257 PAKFIRE_EXPORT int pakfire_transaction_run(
1258 struct pakfire_transaction* transaction, int flags) {
1259 int r;
1260
1261 // Skip running an empty transaction
1262 if (!transaction->num) {
1263 DEBUG(transaction->pakfire, "Empty transaction. Skipping...\n");
1264 return 0;
1265 }
1266
1267 // Show what would be done
1268 char* dump = pakfire_transaction_dump(transaction, 80);
1269
1270 // Check if we should continue
1271 r = pakfire_confirm(transaction->pakfire, dump, _("Is this okay? [y/N]"));
1272 if (r) {
1273 ERROR(transaction->pakfire, "Transaction aborted upon user request\n");
1274 goto ERROR;
1275 }
1276
1277 // Write transaction dump to log
1278 INFO(transaction->pakfire, "%s\n", dump);
1279
1280 // Perform a check if this can actually be run
1281 r = pakfire_transaction_check(transaction);
1282 if (r)
1283 goto ERROR;
1284
1285 // End here for a dry run
1286 if (flags & PAKFIRE_TRANSACTION_DRY_RUN)
1287 goto ERROR;
1288
1289 // Download what we need
1290 r = pakfire_transaction_download(transaction);
1291 if (r)
1292 goto ERROR;
1293
1294 // Perform all steps
1295 r = pakfire_transaction_perform(transaction);
1296 if (r)
1297 goto ERROR;
1298
1299 ERROR:
1300 // Cleanup
1301 free(dump);
1302
1303 return r;
1304 }