]> git.ipfire.org Git - pakfire.git/blob - src/libpakfire/pakfire.c
dependencies: Add support for arch() namespace
[pakfire.git] / src / libpakfire / pakfire.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2017 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 <ctype.h>
22 #include <errno.h>
23 #include <fts.h>
24 #include <linux/limits.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/file.h>
29 #include <sys/mount.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <syslog.h>
33 #include <unistd.h>
34
35 #include <archive.h>
36 #include <archive_entry.h>
37 #include <gpgme.h>
38 #include <magic.h>
39 #include <solv/evr.h>
40 #include <solv/pool.h>
41 #include <solv/poolarch.h>
42 #include <solv/queue.h>
43
44 #include <pakfire/arch.h>
45 #include <pakfire/build.h>
46 #include <pakfire/config.h>
47 #include <pakfire/constants.h>
48 #include <pakfire/db.h>
49 #include <pakfire/dependencies.h>
50 #include <pakfire/keystore.h>
51 #include <pakfire/logging.h>
52 #include <pakfire/mount.h>
53 #include <pakfire/package.h>
54 #include <pakfire/packagelist.h>
55 #include <pakfire/pakfire.h>
56 #include <pakfire/parser.h>
57 #include <pakfire/private.h>
58 #include <pakfire/pwd.h>
59 #include <pakfire/repo.h>
60 #include <pakfire/request.h>
61 #include <pakfire/string.h>
62 #include <pakfire/transaction.h>
63 #include <pakfire/ui.h>
64 #include <pakfire/util.h>
65
66 #define KEYSTORE_DIR "/etc/pakfire/trusted.keys.d"
67 #define LOCK_PATH PAKFIRE_PRIVATE_DIR "/.lock"
68
69 struct pakfire {
70 int nrefs;
71
72 char path[PATH_MAX];
73 char lock_path[PATH_MAX];
74 char cache_path[PATH_MAX];
75 char arch[ARCH_MAX];
76 char keystore_path[PATH_MAX];
77
78 int flags;
79
80 // Lock
81 FILE* lock;
82
83 // UID/GID of running user
84 uid_t uid;
85 gid_t gid;
86
87 // Mapped UID/GID
88 struct pakfire_subid subuid;
89 struct pakfire_subid subgid;
90
91 // Pool
92 Pool* pool;
93
94 // Callbacks
95 struct pakfire_callbacks {
96 // Logging
97 pakfire_log_callback log;
98 void* log_data;
99
100 // Confirm
101 pakfire_confirm_callback confirm;
102 void* confirm_data;
103 } callbacks;
104
105 // Logging
106 int log_priority;
107
108 struct pakfire_config* config;
109
110 struct pakfire_distro {
111 char pretty_name[256];
112 char name[64];
113 char id[32];
114 char slogan[256];
115 char vendor[64];
116 char version[64];
117 char version_codename[32];
118 char version_id[8];
119 char tag[40];
120 } distro;
121
122 // GPG Context
123 gpgme_ctx_t gpgctx;
124
125 // Magic Context
126 magic_t magic;
127
128 // States
129 int destroy_on_free:1;
130 int pool_ready:1;
131 int in_free:1;
132 };
133
134 /*
135 This is a list of all features that are supported by this version of Pakfire
136 */
137 static const struct pakfire_feature {
138 const char* name;
139 } features[] = {
140 { "RichDependencies" },
141
142 // Package Formats
143 { "PackageFormat-6" },
144 { "PackageFormat-5" },
145
146 // Compression
147 { "Compress-XZ" },
148 { "Compress-Zstandard" },
149
150 // Digests
151 { "Digest-BLAKE2b512" },
152 { "Digest-BLAKE2s256" },
153 { "Digest-SHA3-512" },
154 { "Digest-SHA3-256" },
155 { "Digest-SHA2-512" },
156 { "Digest-SHA2-256" },
157
158 // The end
159 { NULL },
160 };
161
162 int pakfire_on_root(struct pakfire* pakfire) {
163 return (strcmp(pakfire->path, "/") == 0);
164 }
165
166 uid_t pakfire_uid(struct pakfire* pakfire) {
167 return pakfire->uid;
168 }
169
170 gid_t pakfire_gid(struct pakfire* pakfire) {
171 return pakfire->gid;
172 }
173
174 const struct pakfire_subid* pakfire_subuid(struct pakfire* pakfire) {
175 return &pakfire->subuid;
176 }
177
178 const struct pakfire_subid* pakfire_subgid(struct pakfire* pakfire) {
179 return &pakfire->subgid;
180 }
181
182 /*
183 Maps any UID/GIDs to the SUBUID/SUBGIDs so that we can transparently
184 copy files in and out of the jail environment.
185 */
186 static unsigned int pakfire_map_id(struct pakfire* pakfire,
187 const struct pakfire_subid* subid, const unsigned int id) {
188 // Nothing to do if we are running on root
189 if (pakfire_on_root(pakfire))
190 return id;
191
192 // Map the ID
193 unsigned int mapped_id = subid->id + id;
194
195 // Check if the ID is in range
196 if (id > subid->length) {
197 ERROR(pakfire, "Mapped ID is out of range. Setting to %u\n", subid->id);
198 mapped_id = subid->id;
199 }
200
201 DEBUG(pakfire, "Mapping UID/GID %u to %u\n", id, mapped_id);
202
203 return mapped_id;
204 }
205
206 static unsigned int pakfire_unmap_id(struct pakfire* pakfire,
207 const struct pakfire_subid* subid, const unsigned int id) {
208 // Nothing to do if we are running on root
209 if (pakfire_on_root(pakfire))
210 return id;
211
212 // Unmap the ID
213 int unmapped_id = id - subid->id;
214
215 // Check if the ID is in range
216 if (unmapped_id < 0) {
217 ERROR(pakfire, "Mapped ID is out of range. Setting to %d\n", subid->id);
218 unmapped_id = subid->id;
219 }
220
221 DEBUG(pakfire, "Mapping UID/GID %d from %d\n", unmapped_id, id);
222
223 return unmapped_id;
224 }
225
226 static int log_priority(const char* priority) {
227 char* end;
228
229 int prio = strtol(priority, &end, 10);
230 if (*end == '\0' || isspace(*end))
231 return prio;
232
233 if (strncmp(priority, "error", strlen("error")) == 0)
234 return LOG_ERR;
235
236 if (strncmp(priority, "info", strlen("info")) == 0)
237 return LOG_INFO;
238
239 if (strncmp(priority, "debug", strlen("debug")) == 0)
240 return LOG_DEBUG;
241
242 return 0;
243 }
244
245 static void pool_log(Pool* pool, void* data, int type, const char* s) {
246 struct pakfire* pakfire = (struct pakfire*)data;
247
248 DEBUG(pakfire, "pool: %s", s);
249 }
250
251 static Id pakfire_handle_ns_pakfire(struct pakfire* pakfire, const char* name) {
252 // Find all supported features
253 for (const struct pakfire_feature* feature = features; feature->name; feature++) {
254 if (strcmp(feature->name, name) == 0)
255 return 1;
256 }
257
258 // Not supported
259 return 0;
260 }
261
262 static Id pakfire_handle_ns_arch(struct pakfire* pakfire, const char* name) {
263 const char* arch = pakfire_get_arch(pakfire);
264
265 return strcmp(arch, name) == 0;
266 }
267
268 static Id pakfire_namespace_callback(Pool* pool, void* data, Id ns, Id id) {
269 struct pakfire* pakfire = (struct pakfire*)data;
270
271 const char* namespace = pool_id2str(pool, ns);
272 const char* name = pakfire_dep2str(pakfire, id);
273
274 DEBUG(pakfire, "Namespace callback called for %s(%s)\n", namespace, name);
275
276 // Handle the pakfire() namespace
277 if (strcmp(namespace, "pakfire") == 0)
278 return pakfire_handle_ns_pakfire(pakfire, name);
279
280 // Handle the arch() namespace
281 else if (strcmp(namespace, "arch") == 0)
282 return pakfire_handle_ns_arch(pakfire, name);
283
284 // Not handled here
285 else
286 return 0;
287 }
288
289 static int pakfire_populate_pool(struct pakfire* pakfire) {
290 struct pakfire_db* db = NULL;
291 struct pakfire_repo* commandline = NULL;
292 struct pakfire_repo* dummy = NULL;
293 struct pakfire_repo* system = NULL;
294 int r;
295
296 // Initialize the pool
297 Pool* pool = pakfire->pool = pool_create();
298 pool_setdisttype(pool, DISTTYPE_RPM);
299
300 #ifdef ENABLE_DEBUG
301 // Enable debug output
302 pool_setdebuglevel(pool, 3);
303 #endif
304
305 // Set architecture of the pool
306 pool_setarch(pool, pakfire->arch);
307
308 // Set path
309 pool_set_rootdir(pool, pakfire->path);
310
311 // Set debug callback
312 pool_setdebugcallback(pool, pool_log, pakfire);
313
314 // Install namespace callback
315 pool_setnamespacecallback(pool, pakfire_namespace_callback, pakfire);
316
317 // Open database in read-only mode and try to load all installed packages
318 r = pakfire_db_open(&db, pakfire, PAKFIRE_DB_READWRITE);
319 if (r)
320 goto ERROR;
321
322 // Create a dummy repository
323 r = pakfire_repo_create(&dummy, pakfire, PAKFIRE_REPO_DUMMY);
324 if (r)
325 goto ERROR;
326
327 // Disable the repository
328 pakfire_repo_set_enabled(dummy, 0);
329
330 // Create the system repository
331 r = pakfire_repo_create(&system, pakfire, PAKFIRE_REPO_SYSTEM);
332 if (r)
333 goto ERROR;
334
335 // Set this repository as the installed one
336 pool_set_installed(pool, pakfire_repo_get_repo(system));
337
338 // Create the command line repo
339 r = pakfire_repo_create(&commandline, pakfire, PAKFIRE_REPO_COMMANDLINE);
340 if (r)
341 goto ERROR;
342
343 // Load database content
344 r = pakfire_db_load(db, system);
345 if (r)
346 goto ERROR;
347
348 ERROR:
349 if (db)
350 pakfire_db_unref(db);
351 if (commandline)
352 pakfire_repo_unref(commandline);
353 if (dummy)
354 pakfire_repo_unref(dummy);
355 if (system)
356 pakfire_repo_unref(system);
357
358 return r;
359 }
360
361 static void pakfire_free(struct pakfire* pakfire) {
362 struct pakfire_repo* repo = NULL;
363 int r;
364
365 // Avoid recursive free
366 if (pakfire->in_free++)
367 return;
368
369 // Destroy the commandline repository
370 repo = pakfire_get_repo(pakfire, PAKFIRE_REPO_COMMANDLINE);
371 if (repo) {
372 r = pakfire_repo_clean(repo, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY);
373 if (r)
374 ERROR(pakfire, "Could not cleanup %s repository: %m\n", PAKFIRE_REPO_COMMANDLINE);
375
376 pakfire_repo_unref(repo);
377 }
378
379 // Release Magic Context
380 if (pakfire->magic)
381 magic_close(pakfire->magic);
382
383 // Release GPGME context
384 if (pakfire->gpgctx)
385 pakfire_keystore_destroy(pakfire, &pakfire->gpgctx);
386
387 // Release lock (if not already done so)
388 pakfire_release_lock(pakfire);
389
390 if (pakfire->destroy_on_free && *pakfire->path) {
391 DEBUG(pakfire, "Destroying %s\n", pakfire->path);
392
393 // Destroy the temporary directory
394 pakfire_rmtree(pakfire->path, 0);
395 }
396
397 pakfire_repo_free_all(pakfire);
398
399 if (pakfire->pool)
400 pool_free(pakfire->pool);
401
402 if (pakfire->config)
403 pakfire_config_unref(pakfire->config);
404
405 free(pakfire);
406 }
407
408 // Safety check in case this is being launched on the host system
409 static int pakfire_safety_checks(struct pakfire* pakfire) {
410 // Nothing to do if we are not working on root
411 if (!pakfire_on_root(pakfire))
412 return 0;
413
414 // We must be root in order to operate in /
415 if (pakfire->uid) {
416 ERROR(pakfire, "Must be running as root on /\n");
417 errno = EPERM;
418 return 1;
419 }
420
421 if (strcmp(pakfire->distro.id, "ipfire") != 0) {
422 ERROR(pakfire, "Not an IPFire system\n");
423 errno = EPERM;
424 return 1;
425 }
426
427 return 0;
428 }
429
430 static int pakfire_read_repo_config(struct pakfire* pakfire) {
431 char path[PATH_MAX];
432 int r;
433
434 // Make path absolute
435 r = pakfire_path(pakfire, path, "%s", PAKFIRE_CONFIG_DIR "/repos");
436 if (r)
437 return r;
438
439 DEBUG(pakfire, "Reading repository configuration from %s\n", path);
440
441 char* paths[2] = {
442 path, NULL,
443 };
444 r = 1;
445
446 FTS* d = fts_open(paths, FTS_NOCHDIR|FTS_NOSTAT, NULL);
447 if (!d)
448 goto ERROR;
449
450 for (;;) {
451 FTSENT* fent = fts_read(d);
452 if (!fent)
453 break;
454
455 // Only handle files
456 if (fent->fts_info & FTS_F) {
457 // Skip everything that doesn't end in .repo
458 if (!pakfire_string_endswith(fent->fts_name, ".repo"))
459 continue;
460
461 DEBUG(pakfire, "Reading %s\n", fent->fts_path);
462
463 FILE* f = fopen(fent->fts_path, "r");
464 if (!f)
465 goto ERROR;
466
467 // Parse the configuration file
468 r = pakfire_config_read(pakfire->config, f);
469 fclose(f);
470
471 if (r)
472 goto ERROR;
473 }
474 }
475
476 // Success
477 r = 0;
478
479 ERROR:
480 if (d)
481 fts_close(d);
482
483 return r;
484 }
485
486 const char* pakfire_get_distro_name(struct pakfire* pakfire) {
487 if (*pakfire->distro.name)
488 return pakfire->distro.name;
489
490 return NULL;
491 }
492
493 const char* pakfire_get_distro_id(struct pakfire* pakfire) {
494 if (*pakfire->distro.id)
495 return pakfire->distro.id;
496
497 return NULL;
498 }
499
500 const char* pakfire_get_distro_vendor(struct pakfire* pakfire) {
501 if (*pakfire->distro.vendor)
502 return pakfire->distro.vendor;
503
504 return NULL;
505 }
506
507 const char* pakfire_get_distro_version(struct pakfire* pakfire) {
508 if (*pakfire->distro.version)
509 return pakfire->distro.version;
510
511 return NULL;
512 }
513
514 const char* pakfire_get_distro_version_id(struct pakfire* pakfire) {
515 if (*pakfire->distro.version_id)
516 return pakfire->distro.version_id;
517
518 return NULL;
519 }
520
521 const char* pakfire_get_distro_tag(struct pakfire* pakfire) {
522 int r;
523
524 if (*pakfire->distro.tag)
525 return pakfire->distro.tag;
526
527 const char* id = pakfire_get_distro_id(pakfire);
528 const char* version_id = pakfire_get_distro_version_id(pakfire);
529
530 // Break if the configuration is incomplete
531 if (!id || !version_id) {
532 errno = EINVAL;
533 return NULL;
534 }
535
536 // Format string
537 r = pakfire_string_format(pakfire->distro.tag, "%s%s", id, version_id);
538 if (r)
539 return NULL;
540
541 // Return the tag
542 return pakfire->distro.tag;
543 }
544
545 static int pakfire_config_import_distro(struct pakfire* pakfire) {
546 // Nothing to do if there is no distro section
547 if (!pakfire_config_has_section(pakfire->config, "distro"))
548 return 0;
549
550 // Name
551 const char* name = pakfire_config_get(pakfire->config, "distro", "name", NULL);
552 if (name)
553 pakfire_string_set(pakfire->distro.name, name);
554
555 // ID
556 const char* id = pakfire_config_get(pakfire->config, "distro", "id", NULL);
557 if (id)
558 pakfire_string_set(pakfire->distro.id, id);
559
560 // Version ID
561 const char* version_id = pakfire_config_get(pakfire->config, "distro", "version_id", NULL);
562 if (version_id)
563 pakfire_string_set(pakfire->distro.version_id, version_id);
564
565 // Codename
566 const char* codename = pakfire_config_get(pakfire->config, "distro", "codename", NULL);
567 if (codename)
568 pakfire_string_set(pakfire->distro.version_codename, codename);
569
570 // Fill in version
571 if (*pakfire->distro.version_codename)
572 pakfire_string_format(pakfire->distro.version, "%s (%s)",
573 pakfire->distro.version_id, pakfire->distro.version_codename);
574 else
575 pakfire_string_set(pakfire->distro.version, pakfire->distro.version_id);
576
577 // Fill in pretty name
578 pakfire_string_format(pakfire->distro.pretty_name, "%s %s",
579 pakfire->distro.name, pakfire->distro.version);
580
581 // Vendor
582 const char* vendor = pakfire_config_get(pakfire->config, "distro", "vendor", NULL);
583 if (vendor)
584 pakfire_string_set(pakfire->distro.vendor, vendor);
585
586 // Slogan
587 const char* slogan = pakfire_config_get(pakfire->config, "distro", "slogan", NULL);
588 if (slogan)
589 pakfire_string_set(pakfire->distro.slogan, slogan);
590
591 return 0;
592 }
593
594 static int pakfire_read_config(struct pakfire* pakfire, const char* path) {
595 char default_path[PATH_MAX];
596 int r;
597
598 // Use default path if none set
599 if (!path) {
600 r = pakfire_path(pakfire, default_path, "%s", PAKFIRE_CONFIG_DIR "/general.conf");
601 if (r)
602 return r;
603
604 path = default_path;
605 }
606
607 DEBUG(pakfire, "Reading configuration from %s\n", path);
608
609 FILE* f = fopen(path, "r");
610 if (!f) {
611 // Silently ignore when there is no default configuration file
612 if (*default_path && errno == ENOENT)
613 return 0;
614
615 ERROR(pakfire, "Could not open configuration file %s: %m\n", path);
616 return 1;
617 }
618
619 // Read configuration from file
620 r = pakfire_config_read(pakfire->config, f);
621 if (r) {
622 ERROR(pakfire, "Could not parse configuration file %s: %m\n", path);
623 goto ERROR;
624 }
625
626 // Import distro configuration
627 r = pakfire_config_import_distro(pakfire);
628 if (r)
629 goto ERROR;
630
631 // Read repository configuration
632 r = pakfire_read_repo_config(pakfire);
633 if (r)
634 goto ERROR;
635
636 ERROR:
637 fclose(f);
638
639 return r;
640 }
641
642 static int pakfire_read_os_release(struct pakfire* pakfire) {
643 char path[PATH_MAX];
644 char* line = NULL;
645 size_t l = 0;
646
647 int r = pakfire_path(pakfire, path, "%s", "/etc/os-release");
648 if (r)
649 return r;
650
651 r = 1;
652
653 FILE* f = fopen(path, "r");
654 if (!f) {
655 // Ignore when the file does not exist
656 if (errno == ENOENT) {
657 r = 0;
658 goto ERROR;
659 }
660
661 ERROR(pakfire, "Could not open %s: %m\n", path);
662 goto ERROR;
663 }
664
665 while (1) {
666 ssize_t bytes_read = getline(&line, &l, f);
667 if (bytes_read < 0)
668 break;
669
670 // Remove trailing newline
671 pakfire_remove_trailing_newline(line);
672
673 // Find =
674 char* delim = strchr(line, '=');
675 if (!delim)
676 continue;
677
678 // Replace = by NULL
679 *delim = '\0';
680
681 // Set key and val to the start of the strings
682 char* key = line;
683 char* val = delim + 1;
684
685 // Unquote val
686 val = pakfire_unquote_in_place(val);
687
688 if (strcmp(key, "PRETTY_NAME") == 0)
689 r = pakfire_string_set(pakfire->distro.pretty_name, val);
690 else if (strcmp(key, "NAME") == 0)
691 r = pakfire_string_set(pakfire->distro.name, val);
692 else if (strcmp(key, "ID") == 0)
693 r = pakfire_string_set(pakfire->distro.id, val);
694 else if (strcmp(key, "VERSION") == 0)
695 r = pakfire_string_set(pakfire->distro.version, val);
696 else if (strcmp(key, "VERSION_CODENAME") == 0)
697 r = pakfire_string_set(pakfire->distro.version_codename, val);
698 else if (strcmp(key, "VERSION_ID") == 0)
699 r = pakfire_string_set(pakfire->distro.version_id, val);
700 else
701 continue;
702
703 // Catch any errors
704 if (r)
705 goto ERROR;
706 }
707
708 // Success
709 r = 0;
710
711 ERROR:
712 if (f)
713 fclose(f);
714 if (line)
715 free(line);
716
717 return r;
718 }
719
720 PAKFIRE_EXPORT int pakfire_create(struct pakfire** pakfire, const char* path,
721 const char* arch, const char* conf, int flags,
722 int loglevel, pakfire_log_callback log_callback, void* log_data) {
723 char tempdir[PATH_MAX] = PAKFIRE_TMP_DIR "/pakfire-root-XXXXXX";
724 char private_dir[PATH_MAX];
725 int r = 1;
726
727 // Reset pakfire pointer
728 *pakfire = NULL;
729
730 // Default to the native architecture
731 if (!arch)
732 arch = pakfire_arch_native();
733
734 // Check if the architecture is supported
735 if (!pakfire_arch_supported(arch)) {
736 errno = EINVAL;
737 return 1;
738 }
739
740 // Path must be absolute
741 if (path && !pakfire_string_startswith(path, "/")) {
742 errno = EINVAL;
743 return 1;
744 }
745
746 struct pakfire* p = calloc(1, sizeof(*p));
747 if (!p)
748 return 1;
749
750 p->nrefs = 1;
751 p->flags = flags;
752
753 // Store the UID/GID we are running as
754 p->uid = geteuid();
755 p->gid = getegid();
756
757 // Set architecture
758 pakfire_string_set(p->arch, arch);
759
760 // Setup logging
761 if (log_callback)
762 pakfire_set_log_callback(p, log_callback, log_data);
763 else
764 pakfire_set_log_callback(p, pakfire_log_syslog, NULL);
765
766 // Set log level
767 if (loglevel) {
768 pakfire_log_set_priority(p, loglevel);
769 } else {
770 const char* env = secure_getenv("PAKFIRE_LOG");
771 if (env)
772 pakfire_log_set_priority(p, log_priority(env));
773 }
774
775 // Initialise configuration
776 r = pakfire_config_create(&p->config);
777 if (r)
778 goto ERROR;
779
780 // Generate a random path if none is set
781 if (!path) {
782 path = pakfire_mkdtemp(tempdir);
783 if (!path) {
784 r = 1;
785 goto ERROR;
786 }
787
788 // Destroy everything when done
789 p->destroy_on_free = 1;
790 }
791
792 // Set path
793 pakfire_string_set(p->path, path);
794
795 // Read /etc/os-release
796 r = pakfire_read_os_release(p);
797 if (r && errno != ENOENT)
798 goto ERROR;
799
800 // Bump RLIMIT_NOFILE to maximum
801 r = pakfire_rlimit_set(p, PAKFIRE_RLIMIT_NOFILE_MAX);
802 if (r)
803 goto ERROR;
804
805 DEBUG(p, "Pakfire initialized at %p\n", p);
806 DEBUG(p, " arch = %s\n", pakfire_get_arch(p));
807 DEBUG(p, " path = %s\n", pakfire_get_path(p));
808
809 // Fetch sub UID/GIDs
810 if (!pakfire_on_root(p)) {
811 // UID
812 r = pakfire_getsubid(p, "/etc/subuid", p->uid, &p->subuid);
813 if (r) {
814 ERROR(p, "Could not fetch subuid: %m\n");
815 goto ERROR;
816 }
817
818 // GID
819 r = pakfire_getsubid(p, "/etc/subgid", p->uid, &p->subgid);
820 if (r) {
821 ERROR(p, "Could not fetch subgid: %m\n");
822 goto ERROR;
823 }
824
825 // Log
826 DEBUG(p, " subuid = %u - %zu\n", p->subuid.id, p->subuid.id + p->subuid.length);
827 DEBUG(p, " subgid = %u - %zu\n", p->subgid.id, p->subgid.id + p->subgid.length);
828 }
829
830 // Perform some safety checks
831 r = pakfire_safety_checks(p);
832 if (r)
833 goto ERROR;
834
835 // Read configuration file
836 r = pakfire_read_config(p, conf);
837 if (r)
838 goto ERROR;
839
840 // Dump distribution configuration
841 DEBUG(p, " Distribution: %s\n", p->distro.pretty_name);
842 DEBUG(p, " name = %s\n", p->distro.name);
843 DEBUG(p, " id = %s\n", p->distro.id);
844 DEBUG(p, " version = %s\n", p->distro.version);
845 DEBUG(p, " version_id = %s\n", p->distro.version_id);
846 if (*p->distro.version_codename)
847 DEBUG(p, " codename = %s\n", p->distro.version_codename);
848 if (*p->distro.vendor)
849 DEBUG(p, " vendor = %s\n", p->distro.vendor);
850 if (*p->distro.slogan)
851 DEBUG(p, " slogan = %s\n", p->distro.slogan);
852
853 // Set lock path
854 r = pakfire_path(p, p->lock_path, "%s", LOCK_PATH);
855 if (r) {
856 ERROR(p, "Could not set lock path: %m\n");
857 goto ERROR;
858 }
859
860 // Set cache path
861 if (p->uid) {
862 const char* home = pakfire_get_home(p, p->uid);
863 if (!home) {
864 ERROR(p, "Could not find home directory\n");
865 errno = ENOENT;
866 goto ERROR;
867 }
868
869 pakfire_string_format(p->cache_path, "%s/.pakfire/cache/%s/%s/%s",
870 home, p->distro.id, p->distro.version_id, p->arch);
871 } else {
872 pakfire_string_format(p->cache_path, "%s/%s/%s/%s",
873 PAKFIRE_CACHE_DIR, p->distro.id, p->distro.version_id, p->arch);
874 }
875
876 // Set keystore path
877 r = pakfire_path(p, p->keystore_path, "%s", KEYSTORE_DIR);
878 if (r) {
879 ERROR(p, "Could not set keystore path: %m\n");
880 goto ERROR;
881 }
882
883 // Make path for private files
884 r = pakfire_path(p, private_dir, "%s", PAKFIRE_PRIVATE_DIR);
885 if (r)
886 goto ERROR;
887
888 // Make sure that our private directory exists
889 r = pakfire_mkdir(private_dir, 0755);
890 if (r) {
891 ERROR(p, "Could not create private directory %s: %m\n", private_dir);
892 goto ERROR;
893 }
894
895 // Initialize keystore
896 r = pakfire_keystore_init(p, &p->gpgctx);
897 if (r)
898 goto ERROR;
899
900 // Populate pool
901 r = pakfire_populate_pool(p);
902 if (r)
903 goto ERROR;
904
905 // Create repositories
906 r = pakfire_repo_import(p, p->config);
907 if (r)
908 goto ERROR;
909
910 *pakfire = p;
911
912 return 0;
913
914 ERROR:
915 pakfire_free(p);
916
917 return r;
918 }
919
920 PAKFIRE_EXPORT struct pakfire* pakfire_ref(struct pakfire* pakfire) {
921 ++pakfire->nrefs;
922
923 return pakfire;
924 }
925
926 PAKFIRE_EXPORT struct pakfire* pakfire_unref(struct pakfire* pakfire) {
927 if (--pakfire->nrefs > 0)
928 return pakfire;
929
930 pakfire_free(pakfire);
931
932 return NULL;
933 }
934
935 int pakfire_has_flag(struct pakfire* pakfire, int flag) {
936 return pakfire->flags & flag;
937 }
938
939 struct pakfire_config* pakfire_get_config(struct pakfire* pakfire) {
940 if (!pakfire->config)
941 return NULL;
942
943 return pakfire_config_ref(pakfire->config);
944 }
945
946 PAKFIRE_EXPORT const char* pakfire_get_path(struct pakfire* pakfire) {
947 return pakfire->path;
948 }
949
950 int pakfire_acquire_lock(struct pakfire* pakfire) {
951 int r;
952
953 // Check if the lock is already held
954 if (pakfire->lock) {
955 ERROR(pakfire, "Lock is already been acquired by this process\n");
956 errno = ENOLCK;
957 return 1;
958 }
959
960 DEBUG(pakfire, "Acquire lock...\n");
961
962 // Ensure the parent directory exists
963 pakfire_mkparentdir(pakfire->lock_path, 0755);
964
965 // Open the lock file
966 pakfire->lock = fopen(pakfire->lock_path, "w");
967 if (!pakfire->lock) {
968 ERROR(pakfire, "Could not open lock file %s: %m\n", pakfire->lock_path);
969 return 1;
970 }
971
972 // Attempt to lock the file exclusively
973 while (1) {
974 r = flock(fileno(pakfire->lock), LOCK_EX|LOCK_NB);
975
976 // Success!
977 if (r == 0)
978 goto SUCCESS;
979
980 DEBUG(pakfire, "Could not acquire lock %s: %m\n", pakfire->lock_path);
981
982 // Wait 500ms until the next attempt
983 usleep(500000);
984 }
985
986 SUCCESS:
987 DEBUG(pakfire, "Lock acquired\n");
988
989 return 0;
990 }
991
992 void pakfire_release_lock(struct pakfire* pakfire) {
993 if (!pakfire->lock)
994 return;
995
996 DEBUG(pakfire, "Releasing lock\n");
997
998 fclose(pakfire->lock);
999 pakfire->lock = NULL;
1000
1001 // Attempt to unlink the lock file
1002 unlink(pakfire->lock_path);
1003 }
1004
1005 const char* pakfire_get_keystore_path(struct pakfire* pakfire) {
1006 return pakfire->keystore_path;
1007 }
1008
1009 int __pakfire_path(struct pakfire* pakfire, char* path, const size_t length,
1010 const char* format, ...) {
1011 char buffer[PATH_MAX];
1012 va_list args;
1013 int r;
1014
1015 // Format input into buffer
1016 va_start(args, format);
1017 r = __pakfire_string_vformat(buffer, sizeof(buffer), format, args);
1018 va_end(args);
1019
1020 // Break on any errors
1021 if (r)
1022 return r;
1023
1024 // Join paths together
1025 return __pakfire_path_join(path, length, pakfire->path, buffer);
1026 }
1027
1028 const char* pakfire_relpath(struct pakfire* pakfire, const char* path) {
1029 return pakfire_path_relpath(pakfire->path, path);
1030 }
1031
1032 int __pakfire_cache_path(struct pakfire* pakfire, char* path, size_t length,
1033 const char* format, ...) {
1034 char buffer[PATH_MAX];
1035 va_list args;
1036 int r;
1037
1038 // Format input into buffer
1039 va_start(args, format);
1040 r = __pakfire_string_vformat(buffer, sizeof(buffer), format, args);
1041 va_end(args);
1042
1043 // Break on any errors
1044 if (r)
1045 return r;
1046
1047 // Join paths together
1048 return __pakfire_path_join(path, length, pakfire->cache_path, buffer);
1049 }
1050
1051 gpgme_ctx_t pakfire_get_gpgctx(struct pakfire* pakfire) {
1052 return pakfire->gpgctx;
1053 }
1054
1055 magic_t pakfire_get_magic(struct pakfire* pakfire) {
1056 int r;
1057
1058 // Initialize the context if not already done
1059 if (!pakfire->magic) {
1060 // Allocate a new context
1061 pakfire->magic = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR | MAGIC_NO_CHECK_TOKENS);
1062 if (!pakfire->magic) {
1063 ERROR(pakfire, "Could not allocate magic context: %m\n");
1064 return NULL;
1065 }
1066
1067 // Load the database
1068 r = magic_load(pakfire->magic, NULL);
1069 if (r) {
1070 ERROR(pakfire, "Could not open the magic database: %s\n",
1071 magic_error(pakfire->magic));
1072 goto ERROR;
1073 }
1074 }
1075
1076 return pakfire->magic;
1077
1078 ERROR:
1079 if (pakfire->magic)
1080 magic_close(pakfire->magic);
1081
1082 // Reset the pointer
1083 pakfire->magic = NULL;
1084
1085 return NULL;
1086 }
1087
1088 PAKFIRE_EXPORT int pakfire_list_keys(struct pakfire* pakfire, struct pakfire_key*** keys) {
1089 // Reset keys
1090 *keys = NULL;
1091
1092 // Fetch GPGME context
1093 gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire);
1094 if (!gpgctx)
1095 return 1;
1096
1097 struct pakfire_key* key = NULL;
1098 gpgme_key_t gpgkey = NULL;
1099 size_t length = 0;
1100 int r = 1;
1101
1102 // Iterate over all keys and import them to the list
1103 gpgme_error_t e = gpgme_op_keylist_start(gpgctx, NULL, 0);
1104 if (e)
1105 goto ERROR;
1106
1107 while (!e) {
1108 e = gpgme_op_keylist_next(gpgctx, &gpgkey);
1109 if (e)
1110 break;
1111
1112 // Create key
1113 r = pakfire_key_create(&key, pakfire, gpgkey);
1114 gpgme_key_unref(gpgkey);
1115 if (r)
1116 goto ERROR;
1117
1118 // Append to keys
1119 *keys = reallocarray(*keys, length + 2, sizeof(**keys));
1120 if (!*keys) {
1121 r = 1;
1122 goto ERROR;
1123 }
1124
1125 // Store key in array
1126 (*keys)[length++] = key;
1127
1128 // Terminate the array
1129 (*keys)[length] = NULL;
1130 }
1131
1132 // Done
1133 return 0;
1134
1135 ERROR:
1136 if (*keys) {
1137 for (struct pakfire_key** _key = *keys; *_key; _key++)
1138 pakfire_key_unref(*_key);
1139 free(*keys);
1140 keys = NULL;
1141 }
1142
1143 return r;
1144 }
1145
1146 int pakfire_repo_walk(struct pakfire* pakfire,
1147 pakfire_repo_walk_callback callback, void* p) {
1148 struct pakfire_repo* repo = NULL;
1149 Repo* solv_repo = NULL;
1150 int i = 0;
1151 int r;
1152
1153 Pool* pool = pakfire->pool;
1154
1155 // Run func for every repository
1156 FOR_REPOS(i, solv_repo) {
1157 repo = pakfire_repo_create_from_repo(pakfire, solv_repo);
1158 if (!repo)
1159 return 1;
1160
1161 // Run callback
1162 r = callback(pakfire, repo, p);
1163 pakfire_repo_unref(repo);
1164
1165 // Raise any errors
1166 if (r)
1167 break;
1168 }
1169
1170 return r;
1171 }
1172
1173 static int __pakfire_repo_clean(struct pakfire* pakfire, struct pakfire_repo* repo,
1174 void* p) {
1175 int flags = *(int*)p;
1176
1177 return pakfire_repo_clean(repo, flags);
1178 }
1179
1180 PAKFIRE_EXPORT int pakfire_clean(struct pakfire* pakfire, int flags) {
1181 int r;
1182
1183 // Clean all repositories
1184 r = pakfire_repo_walk(pakfire, __pakfire_repo_clean, &flags);
1185 if (r)
1186 return r;
1187
1188 // Clean build environments
1189 r = pakfire_build_clean(pakfire, flags);
1190 if (r)
1191 return r;
1192
1193 // Remove the cache
1194 return pakfire_rmtree(PAKFIRE_CACHE_DIR, 0);
1195 }
1196
1197 static int __pakfire_repo_refresh(struct pakfire* pakfire, struct pakfire_repo* repo,
1198 void* p) {
1199 int flags = *(int*)p;
1200
1201 return pakfire_repo_refresh(repo, flags);
1202 }
1203
1204 PAKFIRE_EXPORT int pakfire_refresh(struct pakfire* pakfire, int flags) {
1205 return pakfire_repo_walk(pakfire, __pakfire_repo_refresh, &flags);
1206 }
1207
1208 enum pakfire_copy_direction {
1209 PAKFIRE_COPY_IN,
1210 PAKFIRE_COPY_OUT,
1211 };
1212
1213 static int pakfire_copy(struct pakfire* pakfire, const char* src, const char* dst,
1214 enum pakfire_copy_direction direction) {
1215 struct archive* reader = NULL;
1216 struct archive* writer = NULL;
1217 struct archive_entry* entry = NULL;
1218 FILE* f = NULL;
1219 int r = 1;
1220
1221 DEBUG(pakfire, "Copying %s to %s\n", src, dst);
1222
1223 // Open the source file
1224 f = fopen(src, "r");
1225 if (!f) {
1226 ERROR(pakfire, "Could not open %s: %m\n", src);
1227 goto ERROR;
1228 }
1229
1230 // Allocate reader
1231 reader = pakfire_make_archive_disk_reader(pakfire, (direction == PAKFIRE_COPY_OUT));
1232 if (!reader)
1233 goto ERROR;
1234
1235 // Allocate writer
1236 writer = pakfire_make_archive_disk_writer(pakfire, (direction == PAKFIRE_COPY_IN));
1237 if (!writer)
1238 goto ERROR;
1239
1240 // Create a new entry
1241 entry = archive_entry_new();
1242 if (!entry)
1243 goto ERROR;
1244
1245 // Set the source path
1246 archive_entry_copy_sourcepath(entry, src);
1247
1248 // Set the destination path
1249 archive_entry_set_pathname(entry, dst);
1250
1251 // Read everything from source file
1252 r = archive_read_disk_entry_from_file(reader, entry, fileno(f), NULL);
1253 if (r) {
1254 ERROR(pakfire, "Could not read from %s: %m\n", src);
1255 goto ERROR;
1256 }
1257
1258 // Write file to destination
1259 r = archive_write_header(writer, entry);
1260 if (r) {
1261 ERROR(pakfire, "Could not write %s: %m\n", dst);
1262 goto ERROR;
1263 }
1264
1265 // Copy payload
1266 if (archive_entry_filetype(entry) == AE_IFREG) {
1267 r = pakfire_archive_copy_data_from_file(pakfire, writer, f);
1268 if (r)
1269 goto ERROR;
1270 }
1271
1272 ERROR:
1273 if (f)
1274 fclose(f);
1275 if (entry)
1276 archive_entry_free(entry);
1277 if (reader)
1278 archive_read_free(reader);
1279 if (writer)
1280 archive_write_free(writer);
1281
1282 return r;
1283 }
1284
1285 PAKFIRE_EXPORT int pakfire_copy_in(struct pakfire* pakfire, const char* src, const char* dst) {
1286 char path[PATH_MAX];
1287 int r;
1288
1289 if (pakfire_on_root(pakfire)) {
1290 errno = ENOTSUP;
1291 return 1;
1292 }
1293
1294 r = pakfire_path(pakfire, path, "%s", dst);
1295 if (r)
1296 return r;
1297
1298 return pakfire_copy(pakfire, src, path, PAKFIRE_COPY_IN);
1299 }
1300
1301 PAKFIRE_EXPORT int pakfire_copy_out(struct pakfire* pakfire, const char* src, const char* dst) {
1302 char path[PATH_MAX];
1303 int r;
1304
1305 if (pakfire_on_root(pakfire)) {
1306 errno = ENOTSUP;
1307 return 1;
1308 }
1309
1310 r = pakfire_path(pakfire, path, "%s", src);
1311 if (r)
1312 return r;
1313
1314 return pakfire_copy(pakfire, path, dst, PAKFIRE_COPY_OUT);
1315 }
1316
1317 PAKFIRE_EXPORT const char* pakfire_get_arch(struct pakfire* pakfire) {
1318 return pakfire->arch;
1319 }
1320
1321 PAKFIRE_EXPORT int pakfire_version_compare(struct pakfire* pakfire, const char* evr1, const char* evr2) {
1322 return pool_evrcmp_str(pakfire->pool, evr1, evr2, EVRCMP_COMPARE);
1323 }
1324
1325 Pool* pakfire_get_solv_pool(struct pakfire* pakfire) {
1326 return pakfire->pool;
1327 }
1328
1329 void pakfire_pool_has_changed(struct pakfire* pakfire) {
1330 pakfire->pool_ready = 0;
1331 }
1332
1333 static int __pakfire_repo_internalize(struct pakfire* pakfire, struct pakfire_repo* repo,
1334 void* p) {
1335 int flags = *(int*)p;
1336
1337 return pakfire_repo_internalize(repo, flags);
1338 }
1339
1340 void pakfire_pool_internalize(struct pakfire* pakfire) {
1341 int flags = 0;
1342
1343 // Nothing to do if the pool is ready
1344 if (pakfire->pool_ready)
1345 return;
1346
1347 // Internalize all repositories
1348 pakfire_repo_walk(pakfire, __pakfire_repo_internalize, &flags);
1349
1350 // Create fileprovides
1351 pool_addfileprovides(pakfire->pool);
1352
1353 // Create whatprovides index
1354 pool_createwhatprovides(pakfire->pool);
1355
1356 // Mark the pool as ready
1357 pakfire->pool_ready = 1;
1358 }
1359
1360 PAKFIRE_EXPORT struct pakfire_repolist* pakfire_get_repos(struct pakfire* pakfire) {
1361 struct pakfire_repolist* list;
1362
1363 int r = pakfire_repolist_create(&list);
1364 if (r)
1365 return NULL;
1366
1367 Pool* pool = pakfire_get_solv_pool(pakfire);
1368 Repo* solv_repo;
1369 int i;
1370
1371 FOR_REPOS(i, solv_repo) {
1372 // Skip the dummy repository
1373 if (strcmp(solv_repo->name, PAKFIRE_REPO_DUMMY) == 0)
1374 continue;
1375
1376 struct pakfire_repo* repo = pakfire_repo_create_from_repo(pakfire, solv_repo);
1377 if (!repo) {
1378 r = 1;
1379 goto ERROR;
1380 }
1381
1382 r = pakfire_repolist_append(list, repo);
1383 if (r) {
1384 pakfire_repo_unref(repo);
1385 goto ERROR;
1386 }
1387
1388 pakfire_repo_unref(repo);
1389 }
1390
1391 return list;
1392
1393 ERROR:
1394 pakfire_repolist_unref(list);
1395 return NULL;
1396 }
1397
1398 PAKFIRE_EXPORT struct pakfire_repo* pakfire_get_repo(struct pakfire* pakfire, const char* name) {
1399 Pool* pool = pakfire_get_solv_pool(pakfire);
1400 if (!pool)
1401 return NULL;
1402
1403 Repo* repo;
1404 int i;
1405
1406 FOR_REPOS(i, repo) {
1407 if (strcmp(repo->name, name) == 0)
1408 return pakfire_repo_create_from_repo(pakfire, repo);
1409 }
1410
1411 // Nothing found
1412 return NULL;
1413 }
1414
1415 struct pakfire_repo* pakfire_get_installed_repo(struct pakfire* pakfire) {
1416 if (!pakfire->pool->installed)
1417 return NULL;
1418
1419 return pakfire_repo_create_from_repo(pakfire, pakfire->pool->installed);
1420 }
1421
1422 /*
1423 Convenience function to add a package to the @commandline repository
1424 */
1425 int pakfire_commandline_add(struct pakfire* pakfire, const char* path,
1426 struct pakfire_package** package) {
1427 struct pakfire_repo* repo = NULL;
1428 int r;
1429
1430 // Find the commandline repository
1431 repo = pakfire_get_repo(pakfire, PAKFIRE_REPO_COMMANDLINE);
1432 if (!repo) {
1433 ERROR(pakfire, "Could not find the commandline repository: %m\n");
1434 return 1;
1435 }
1436
1437 // Add the package
1438 r = pakfire_repo_add(repo, path, package);
1439 if (r)
1440 goto ERROR;
1441
1442 ERROR:
1443 if (repo)
1444 pakfire_repo_unref(repo);
1445
1446 return r;
1447 }
1448
1449 static int pakfire_search_dep(struct pakfire* pakfire, Id type, const char* what, int flags,
1450 struct pakfire_packagelist** list) {
1451 int r;
1452
1453 // Get the pool ready
1454 pakfire_pool_internalize(pakfire);
1455
1456 // Translate dependency to ID
1457 Id dep = pakfire_str2dep(pakfire, what);
1458 if (!dep) {
1459 errno = EINVAL;
1460 return 1;
1461 }
1462
1463 // Reset pointer
1464 *list = NULL;
1465
1466 Queue matches;
1467 queue_init(&matches);
1468
1469 // Search for anything that matches
1470 pool_whatmatchesdep(pakfire->pool, type, dep, &matches, 0);
1471
1472 // Create a packagelist
1473 r = pakfire_packagelist_create_from_queue(list, pakfire, &matches);
1474 if (r)
1475 goto ERROR;
1476
1477 // Sort the list
1478 pakfire_packagelist_sort(*list);
1479
1480 ERROR:
1481 queue_free(&matches);
1482
1483 return r;
1484 }
1485
1486 PAKFIRE_EXPORT int pakfire_whatprovides(struct pakfire* pakfire, const char* what, int flags,
1487 struct pakfire_packagelist** list) {
1488 return pakfire_search_dep(pakfire, SOLVABLE_PROVIDES, what, flags, list);
1489 }
1490
1491 PAKFIRE_EXPORT int pakfire_whatrequires(struct pakfire* pakfire, const char* what, int flags,
1492 struct pakfire_packagelist** list) {
1493 return pakfire_search_dep(pakfire, SOLVABLE_REQUIRES, what, flags, list);
1494 }
1495
1496 PAKFIRE_EXPORT int pakfire_search(struct pakfire* pakfire, const char* what, int flags,
1497 struct pakfire_packagelist** list) {
1498 Queue matches;
1499 Dataiterator di;
1500 int r;
1501
1502 // Get the pool ready
1503 pakfire_pool_internalize(pakfire);
1504
1505 // Initialize the result queue
1506 queue_init(&matches);
1507
1508 // Setup the data interator
1509 dataiterator_init(&di, pakfire->pool, 0, 0, 0, what, SEARCH_SUBSTRING|SEARCH_NOCASE);
1510
1511 const Id keys[] = {
1512 SOLVABLE_NAME,
1513 SOLVABLE_SUMMARY,
1514 SOLVABLE_DESCRIPTION,
1515 ID_NULL
1516 };
1517
1518 // Search through these keys and add matches to the queue
1519 for (const Id* key = keys; *key; key++) {
1520 dataiterator_set_keyname(&di, *key);
1521 dataiterator_set_search(&di, 0, 0);
1522
1523 while (dataiterator_step(&di))
1524 queue_pushunique(&matches, di.solvid);
1525
1526 // Stop after name
1527 if (flags & PAKFIRE_SEARCH_NAME_ONLY)
1528 break;
1529 }
1530
1531 // Convert matches to package list
1532 r = pakfire_packagelist_create_from_queue(list, pakfire, &matches);
1533 if (r)
1534 goto ERROR;
1535
1536 // Sort the result
1537 pakfire_packagelist_sort(*list);
1538
1539 ERROR:
1540 dataiterator_free(&di);
1541 queue_free(&matches);
1542
1543 return r;
1544 }
1545
1546 // Logging
1547
1548 PAKFIRE_EXPORT int pakfire_log_get_priority(struct pakfire* pakfire) {
1549 return pakfire->log_priority;
1550 }
1551
1552 PAKFIRE_EXPORT void pakfire_log_set_priority(struct pakfire* pakfire, int priority) {
1553 pakfire->log_priority = priority;
1554 }
1555
1556 PAKFIRE_EXPORT void pakfire_set_log_callback(struct pakfire* pakfire,
1557 pakfire_log_callback callback, void* data) {
1558 pakfire->callbacks.log = callback;
1559 pakfire->callbacks.log_data = data;
1560 }
1561
1562 void pakfire_log(struct pakfire* pakfire, int priority, const char* file, int line,
1563 const char* fn, const char* format, ...) {
1564 va_list args;
1565
1566 // Do not do anything if callback isn't set
1567 if (!pakfire->callbacks.log)
1568 return;
1569
1570 // Save errno
1571 int saved_errno = errno;
1572
1573 va_start(args, format);
1574 pakfire->callbacks.log(pakfire->callbacks.log_data,
1575 priority, file, line, fn, format, args);
1576 va_end(args);
1577
1578 // Restore errno
1579 errno = saved_errno;
1580 }
1581
1582 // UI
1583
1584 PAKFIRE_EXPORT void pakfire_set_confirm_callback(struct pakfire* pakfire,
1585 pakfire_confirm_callback callback, void* data) {
1586 pakfire->callbacks.confirm = callback;
1587 pakfire->callbacks.confirm_data = data;
1588 }
1589
1590 int pakfire_confirm(struct pakfire* pakfire, const char* message, const char* question) {
1591 // Run callback
1592 if (pakfire->callbacks.confirm)
1593 return pakfire->callbacks.confirm(
1594 pakfire, pakfire->callbacks.confirm_data, message, question);
1595
1596 // If no callback is set, we just log the message
1597 INFO(pakfire, "%s\n", message);
1598
1599 return 0;
1600 }
1601
1602 static const char* pakfire_user_lookup(void* data, la_int64_t uid) {
1603 struct pakfire* pakfire = (struct pakfire*)data;
1604
1605 DEBUG(pakfire, "Looking up name for UID %ld\n", uid);
1606
1607 // Unmap the UID first
1608 uid = pakfire_unmap_id(pakfire, &pakfire->subuid, uid);
1609
1610 // Fast path for "root"
1611 if (uid == 0)
1612 return "root";
1613
1614 // Find a matching entry in /etc/passwd
1615 struct passwd* entry = pakfire_getpwuid(pakfire, uid);
1616 if (!entry) {
1617 ERROR(pakfire, "Could not retrieve uname for %ld: %m\n", uid);
1618 return 0;
1619 }
1620
1621 DEBUG(pakfire, "Mapping UID %ld to %s\n", uid, entry->pw_name);
1622
1623 return entry->pw_name;
1624 }
1625
1626 static const char* pakfire_group_lookup(void* data, la_int64_t gid) {
1627 struct pakfire* pakfire = (struct pakfire*)data;
1628
1629 DEBUG(pakfire, "Looking up name for GID %ld\n", gid);
1630
1631 // Unmap the GID first
1632 gid = pakfire_unmap_id(pakfire, &pakfire->subgid, gid);
1633
1634 // Fast path for "root"
1635 if (gid == 0)
1636 return "root";
1637
1638 // Find a matching entry in /etc/group
1639 struct group* entry = pakfire_getgrgid(pakfire, gid);
1640 if (!entry) {
1641 ERROR(pakfire, "Could not retrieve gname for %ld: %m\n", gid);
1642 return 0;
1643 }
1644
1645 DEBUG(pakfire, "Mapping GID %ld to %s\n", gid, entry->gr_name);
1646
1647 return entry->gr_name;
1648 }
1649
1650 struct archive* pakfire_make_archive_disk_reader(struct pakfire* pakfire, int internal) {
1651 struct archive* archive = archive_read_disk_new();
1652 if (!archive)
1653 return NULL;
1654
1655 // Do not read fflags
1656 int r = archive_read_disk_set_behavior(archive, ARCHIVE_READDISK_NO_FFLAGS);
1657 if (r) {
1658 ERROR(pakfire, "Could not change behavior of reader: %s\n",
1659 archive_error_string(archive));
1660 archive_read_free(archive);
1661 return NULL;
1662 }
1663
1664 // Install user/group lookups
1665 if (internal) {
1666 archive_read_disk_set_uname_lookup(archive, pakfire, pakfire_user_lookup, NULL);
1667 archive_read_disk_set_gname_lookup(archive, pakfire, pakfire_group_lookup, NULL);
1668 } else {
1669 archive_read_disk_set_standard_lookup(archive);
1670 }
1671
1672 return archive;
1673 }
1674
1675 static la_int64_t pakfire_uid_lookup(void* data, const char* name, la_int64_t uid) {
1676 struct pakfire* pakfire = (struct pakfire*)data;
1677
1678 DEBUG(pakfire, "Looking up UID for '%s' (%ld)\n", name, uid);
1679
1680 // Fast path for "root"
1681 if (strcmp(name, "root") == 0)
1682 return pakfire_map_id(pakfire, &pakfire->subuid, 0);
1683
1684 // Find a matching entry in /etc/passwd
1685 struct passwd* entry = pakfire_getpwnam(pakfire, name);
1686 if (!entry) {
1687 ERROR(pakfire, "Could not retrieve UID for '%s': %m\n", name);
1688 return pakfire_map_id(pakfire, &pakfire->subuid, 0);
1689 }
1690
1691 DEBUG(pakfire, "Mapping %s to UID %d\n", name, entry->pw_uid);
1692
1693 return pakfire_map_id(pakfire, &pakfire->subuid, entry->pw_uid);
1694 }
1695
1696 static la_int64_t pakfire_gid_lookup(void* data, const char* name, la_int64_t gid) {
1697 struct pakfire* pakfire = (struct pakfire*)data;
1698
1699 DEBUG(pakfire, "Looking up GID for '%s' (%ld)\n", name, gid);
1700
1701 // Fast path for "root"
1702 if (strcmp(name, "root") == 0)
1703 return pakfire_map_id(pakfire, &pakfire->subgid, 0);
1704
1705 // Find a matching entry in /etc/group
1706 struct group* entry = pakfire_getgrnam(pakfire, name);
1707 if (!entry) {
1708 ERROR(pakfire, "Could not retrieve GID for '%s': %m\n", name);
1709 return pakfire_map_id(pakfire, &pakfire->subgid, 0);
1710 }
1711
1712 DEBUG(pakfire, "Mapping %s to GID %d\n", name, entry->gr_gid);
1713
1714 return pakfire_map_id(pakfire, &pakfire->subgid, entry->gr_gid);
1715 }
1716
1717 struct archive* pakfire_make_archive_disk_writer(struct pakfire* pakfire, int internal) {
1718 struct archive* archive = archive_write_disk_new();
1719 if (!archive)
1720 return NULL;
1721
1722 // Set flags for extracting files
1723 const int flags =
1724 ARCHIVE_EXTRACT_ACL |
1725 ARCHIVE_EXTRACT_OWNER |
1726 ARCHIVE_EXTRACT_PERM |
1727 ARCHIVE_EXTRACT_TIME |
1728 ARCHIVE_EXTRACT_UNLINK |
1729 ARCHIVE_EXTRACT_XATTR;
1730
1731 archive_write_disk_set_options(archive, flags);
1732
1733 // Install our own routine for user/group lookups
1734 if (internal) {
1735 archive_write_disk_set_user_lookup(archive, pakfire, pakfire_uid_lookup, NULL);
1736 archive_write_disk_set_group_lookup(archive, pakfire, pakfire_gid_lookup, NULL);
1737 } else {
1738 archive_write_disk_set_standard_lookup(archive);
1739 }
1740
1741 return archive;
1742 }
1743
1744 // Convenience functions to install/erase/update packages
1745
1746 static int pakfire_perform_transaction(
1747 struct pakfire* pakfire,
1748 int transaction_flags,
1749 int solver_flags,
1750 const enum pakfire_request_action action,
1751 const char** packages,
1752 const char** locks,
1753 int job_flags,
1754 int* changed,
1755 pakfire_status_callback status_callback,
1756 void* status_callback_data) {
1757 struct pakfire_request* request = NULL;
1758 struct pakfire_transaction* transaction = NULL;
1759 int r = 1;
1760
1761 // Packages cannot be NULL
1762 if (!packages) {
1763 errno = EINVAL;
1764 return 1;
1765 }
1766
1767 // Acquire lock
1768 r = pakfire_acquire_lock(pakfire);
1769 if (r)
1770 goto ERROR;
1771
1772 // Create a new request
1773 r = pakfire_request_create(&request, pakfire, solver_flags);
1774 if (r)
1775 goto ERROR;
1776
1777 // Lock anything that should be locked
1778 if (locks) {
1779 for (const char** lock = locks; *lock; lock++) {
1780 r = pakfire_request_add(request, PAKFIRE_REQ_LOCK, *lock, 0);
1781 if (r) {
1782 ERROR(pakfire, "Could not lock '%s': %m\n", *lock);
1783 goto ERROR;
1784 }
1785 }
1786 }
1787
1788 // Perform action on all packages
1789 for (const char** package = packages; *package; package++) {
1790 r = pakfire_request_add(request, action, *package, job_flags);
1791 if (r) {
1792 ERROR(pakfire, "Could not find '%s': %m\n", *package);
1793 goto ERROR;
1794 }
1795 }
1796
1797 // Solve the request
1798 r = pakfire_request_solve(request);
1799 if (r)
1800 goto ERROR;
1801
1802 // Fetch the transaction
1803 r = pakfire_request_get_transaction(request, &transaction);
1804 if (r)
1805 goto ERROR;
1806
1807 // Set how many packages have been changed
1808 if (changed)
1809 *changed = pakfire_transaction_count(transaction);
1810
1811 // Set status callback
1812 if (status_callback)
1813 pakfire_transaction_set_status_callback(
1814 transaction, status_callback, status_callback_data);
1815
1816 // Run the transaction
1817 r = pakfire_transaction_run(transaction, transaction_flags);
1818 if (r)
1819 goto ERROR;
1820
1821 // Success
1822 r = 0;
1823
1824 ERROR:
1825 // Release lock
1826 pakfire_release_lock(pakfire);
1827
1828 if (transaction)
1829 pakfire_transaction_unref(transaction);
1830 if (request)
1831 pakfire_request_unref(request);
1832
1833 return r;
1834 }
1835
1836 PAKFIRE_EXPORT int pakfire_install(
1837 struct pakfire* pakfire,
1838 int transaction_flags,
1839 int solver_flags,
1840 const char** packages,
1841 const char** locks,
1842 int flags,
1843 int* changed,
1844 pakfire_status_callback status_callback,
1845 void* status_callback_data) {
1846 return pakfire_perform_transaction(
1847 pakfire,
1848 transaction_flags,
1849 solver_flags,
1850 PAKFIRE_REQ_INSTALL,
1851 packages,
1852 locks,
1853 flags,
1854 changed,
1855 status_callback,
1856 status_callback_data);
1857 }
1858
1859 PAKFIRE_EXPORT int pakfire_erase(
1860 struct pakfire* pakfire,
1861 int transaction_flags,
1862 int solver_flags,
1863 const char** packages,
1864 const char** locks,
1865 int flags,
1866 int* changed,
1867 pakfire_status_callback status_callback,
1868 void* status_callback_data) {
1869 return pakfire_perform_transaction(
1870 pakfire,
1871 transaction_flags,
1872 solver_flags,
1873 PAKFIRE_REQ_ERASE,
1874 packages,
1875 locks,
1876 flags,
1877 changed,
1878 status_callback,
1879 status_callback_data);
1880 }
1881
1882 static int pakfire_perform_transaction_simple(struct pakfire* pakfire, int solver_flags,
1883 const enum pakfire_request_action action, int job_flags, int* changed,
1884 pakfire_status_callback status_callback, void* status_callback_data) {
1885 struct pakfire_request* request = NULL;
1886 struct pakfire_transaction* transaction = NULL;
1887 int r = 1;
1888
1889 // Acquire lock
1890 r = pakfire_acquire_lock(pakfire);
1891 if (r)
1892 goto ERROR;
1893
1894 // Create a new request
1895 r = pakfire_request_create(&request, pakfire, solver_flags);
1896 if (r)
1897 goto ERROR;
1898
1899 // Perform action
1900 r = pakfire_request_add(request, action, NULL, job_flags);
1901 if (r)
1902 goto ERROR;
1903
1904 // Solve the request
1905 r = pakfire_request_solve(request);
1906 if (r)
1907 goto ERROR;
1908
1909 // Fetch the transaction
1910 r = pakfire_request_get_transaction(request, &transaction);
1911 if (r)
1912 goto ERROR;
1913
1914 // Set how many packages have been changed
1915 if (changed)
1916 *changed = pakfire_transaction_count(transaction);
1917
1918 // Set status callback
1919 if (status_callback)
1920 pakfire_transaction_set_status_callback(
1921 transaction, status_callback, status_callback_data);
1922
1923 // Run the transaction
1924 r = pakfire_transaction_run(transaction, 0);
1925 if (r)
1926 goto ERROR;
1927
1928 // Success
1929 r = 0;
1930
1931 ERROR:
1932 // Release lock
1933 pakfire_release_lock(pakfire);
1934
1935 if (transaction)
1936 pakfire_transaction_unref(transaction);
1937 if (request)
1938 pakfire_request_unref(request);
1939
1940 return r;
1941 }
1942
1943 PAKFIRE_EXPORT int pakfire_update(
1944 struct pakfire* pakfire,
1945 int transaction_flags,
1946 int solver_flags,
1947 const char** packages,
1948 const char** locks,
1949 int flags,
1950 int* changed,
1951 pakfire_status_callback status_callback,
1952 void* status_callback_data) {
1953 // If no packages are being passed, we will try to update everything
1954 // XXX add locks
1955 if (!packages)
1956 return pakfire_perform_transaction_simple(
1957 pakfire, solver_flags, PAKFIRE_REQ_UPDATE_ALL, flags, changed,
1958 status_callback, status_callback_data);
1959
1960 return pakfire_perform_transaction(pakfire, transaction_flags, solver_flags,
1961 PAKFIRE_REQ_UPDATE, packages, locks, flags, changed,
1962 status_callback, status_callback_data);
1963 }
1964
1965 static int pakfire_verify(struct pakfire* pakfire, int *changed) {
1966 return pakfire_perform_transaction_simple(pakfire, 0, PAKFIRE_REQ_VERIFY,
1967 0, changed, NULL, NULL);
1968 }
1969
1970 static int pakfire_check_files(struct pakfire* pakfire,
1971 struct pakfire_db* db, struct pakfire_filelist* errors) {
1972 struct pakfire_filelist* filelist = NULL;
1973 int r;
1974
1975 // Fetch the filelist
1976 r = pakfire_db_filelist(db, &filelist);
1977 if (r)
1978 goto ERROR;
1979
1980 // Verify the filelist
1981 r = pakfire_filelist_verify(filelist, errors);
1982
1983 ERROR:
1984 if (filelist)
1985 pakfire_filelist_unref(filelist);
1986
1987 return r;
1988 }
1989
1990 PAKFIRE_EXPORT int pakfire_check(struct pakfire* pakfire, struct pakfire_filelist* errors) {
1991 struct pakfire_db* db = NULL;
1992 int r;
1993
1994 // Open database in read-only mode and try to load all installed packages
1995 r = pakfire_db_open(&db, pakfire, PAKFIRE_DB_READWRITE);
1996 if (r)
1997 goto ERROR;
1998
1999 // Perform a database integrity check
2000 r = pakfire_db_check(db);
2001 if (r)
2002 goto ERROR;
2003
2004 // Check if all dependencies are intact
2005 r = pakfire_verify(pakfire, NULL);
2006 if (r)
2007 goto ERROR;
2008
2009 // Check files
2010 r = pakfire_check_files(pakfire, db, errors);
2011 if (r)
2012 goto ERROR;
2013
2014 ERROR:
2015 if (db)
2016 pakfire_db_unref(db);
2017
2018 return r;
2019 }
2020
2021 PAKFIRE_EXPORT int pakfire_sync(struct pakfire* pakfire, int solver_flags, int flags,
2022 int* changed, pakfire_status_callback status_callback, void* status_callback_data) {
2023 return pakfire_perform_transaction_simple(pakfire, solver_flags,
2024 PAKFIRE_REQ_SYNC, flags, changed, status_callback, status_callback_data);
2025 }