]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/libpakfire/pakfire.c
pakfire: Remove unused log priority variable
[people/ms/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 <dirent.h>
23 #include <errno.h>
24 #include <linux/limits.h>
25 #include <pwd.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/file.h>
30 #include <sys/mount.h>
31 #include <sys/stat.h>
32 #include <sys/utsname.h>
33 #include <sys/types.h>
34 #include <syslog.h>
35 #include <unistd.h>
36
37 #include <archive.h>
38 #include <archive_entry.h>
39 #include <magic.h>
40 #include <solv/evr.h>
41 #include <solv/pool.h>
42 #include <solv/poolarch.h>
43 #include <solv/queue.h>
44
45 #include <pakfire/arch.h>
46 #include <pakfire/build.h>
47 #include <pakfire/config.h>
48 #include <pakfire/constants.h>
49 #include <pakfire/ctx.h>
50 #include <pakfire/db.h>
51 #include <pakfire/dependencies.h>
52 #include <pakfire/dist.h>
53 #include <pakfire/logging.h>
54 #include <pakfire/mount.h>
55 #include <pakfire/os.h>
56 #include <pakfire/package.h>
57 #include <pakfire/packagelist.h>
58 #include <pakfire/pakfire.h>
59 #include <pakfire/parser.h>
60 #include <pakfire/path.h>
61 #include <pakfire/private.h>
62 #include <pakfire/pwd.h>
63 #include <pakfire/repo.h>
64 #include <pakfire/string.h>
65 #include <pakfire/transaction.h>
66 #include <pakfire/util.h>
67
68 #define LOCK_PATH PAKFIRE_PRIVATE_DIR "/.lock"
69
70 struct pakfire {
71 struct pakfire_ctx* ctx;
72 int nrefs;
73
74 char path[PATH_MAX];
75 char lock_path[PATH_MAX];
76 char cache_path[PATH_MAX];
77
78 struct pakfire_arches {
79 char nominal[ARCH_MAX];
80 const char* effective;
81 } arches;
82
83 int flags;
84
85 // Lock
86 FILE* lock;
87
88 // UID/GID of running user
89 struct pakfire_user {
90 uid_t uid;
91 char name[NAME_MAX];
92 char home[PATH_MAX];
93 struct pakfire_subid subuids;
94 } user;
95
96 struct pakfire_group {
97 gid_t gid;
98 char name[NAME_MAX];
99 struct pakfire_subid subgids;
100 } group;
101
102 // Pool
103 Pool* pool;
104
105 struct pakfire_config* config;
106
107 // Distro
108 struct pakfire_distro distro;
109
110 // Magic Context
111 magic_t magic;
112
113 // States
114 unsigned int destroy_on_free:1;
115 unsigned int pool_ready:1;
116 unsigned int in_free:1;
117 };
118
119 /*
120 This is a list of all features that are supported by this version of Pakfire
121 */
122 static const struct pakfire_feature {
123 const char* name;
124 } features[] = {
125 { "RichDependencies" },
126
127 // Package Formats
128 { "PackageFormat-6" },
129 { "PackageFormat-5" },
130
131 // Compression
132 { "Compress-XZ" },
133 { "Compress-Zstandard" },
134
135 // Digests
136 { "Digest-BLAKE2b512" },
137 { "Digest-BLAKE2s256" },
138 { "Digest-SHA3-512" },
139 { "Digest-SHA3-256" },
140 { "Digest-SHA2-512" },
141 { "Digest-SHA2-256" },
142
143 // Systemd
144 { "systemd-sysusers" },
145 { "systemd-tmpfiles" },
146
147 // The end
148 { NULL },
149 };
150
151 int pakfire_on_root(struct pakfire* pakfire) {
152 return (strcmp(pakfire->path, "/") == 0);
153 }
154
155 uid_t pakfire_uid(struct pakfire* pakfire) {
156 return pakfire->user.uid;
157 }
158
159 gid_t pakfire_gid(struct pakfire* pakfire) {
160 return pakfire->group.gid;
161 }
162
163 const struct pakfire_subid* pakfire_subuid(struct pakfire* pakfire) {
164 return &pakfire->user.subuids;
165 }
166
167 const struct pakfire_subid* pakfire_subgid(struct pakfire* pakfire) {
168 return &pakfire->group.subgids;
169 }
170
171 /*
172 Maps any UID/GIDs to the SUBUID/SUBGIDs so that we can transparently
173 copy files in and out of the jail environment.
174 */
175 static unsigned int pakfire_map_id(struct pakfire* pakfire,
176 const struct pakfire_subid* subid, const unsigned int id) {
177 // Nothing to do if we are running on root
178 if (pakfire_on_root(pakfire))
179 return id;
180
181 // Map the ID
182 unsigned int mapped_id = subid->id + id;
183
184 // Check if the ID is in range
185 if (id > subid->length) {
186 ERROR(pakfire, "Mapped ID is out of range. Setting to %u\n", subid->id);
187 mapped_id = subid->id;
188 }
189
190 return mapped_id;
191 }
192
193 static unsigned int pakfire_unmap_id(struct pakfire* pakfire,
194 const struct pakfire_subid* subid, const unsigned int id) {
195 // Nothing to do if we are running on root
196 if (pakfire_on_root(pakfire))
197 return id;
198
199 // Unmap the ID
200 int unmapped_id = id - subid->id;
201
202 // Check if the ID is in range
203 if (unmapped_id < 0) {
204 ERROR(pakfire, "Mapped ID is out of range. Setting to %u\n", subid->id);
205 unmapped_id = subid->id;
206 }
207
208 return unmapped_id;
209 }
210
211 static void pool_log(Pool* pool, void* data, int type, const char* s) {
212 struct pakfire* pakfire = (struct pakfire*)data;
213
214 DEBUG(pakfire, "pool: %s", s);
215 }
216
217 static Id pakfire_handle_ns_pakfire(struct pakfire* pakfire, const char* name) {
218 // Find all supported features
219 for (const struct pakfire_feature* feature = features; feature->name; feature++) {
220 if (strcmp(feature->name, name) == 0)
221 return 1;
222 }
223
224 // Not supported
225 return 0;
226 }
227
228 static Id pakfire_handle_ns_arch(struct pakfire* pakfire, const char* name) {
229 const char* arch = pakfire_get_arch(pakfire);
230
231 return strcmp(arch, name) == 0;
232 }
233
234 static Id pakfire_namespace_callback(Pool* pool, void* data, Id ns, Id id) {
235 struct pakfire* pakfire = (struct pakfire*)data;
236
237 const char* namespace = pool_id2str(pool, ns);
238 const char* name = pakfire_dep2str(pakfire, id);
239
240 DEBUG(pakfire, "Namespace callback called for %s(%s)\n", namespace, name);
241
242 // Handle the pakfire() namespace
243 if (strcmp(namespace, "pakfire") == 0)
244 return pakfire_handle_ns_pakfire(pakfire, name);
245
246 // Handle the arch() namespace
247 else if (strcmp(namespace, "arch") == 0)
248 return pakfire_handle_ns_arch(pakfire, name);
249
250 // Not handled here
251 else
252 return 0;
253 }
254
255 static int pakfire_lock_running_kernel(struct pakfire* pakfire) {
256 struct utsname utsname;
257 char buffer[NAME_MAX];
258
259 // Call uname()
260 int r = uname(&utsname);
261 if (r) {
262 ERROR(pakfire, "uname() failed: %m\n");
263 return r;
264 }
265
266 DEBUG(pakfire, "Locking running kernel %s\n", utsname.release);
267
268 r = pakfire_string_format(buffer, "kernel(%s)", utsname.release);
269 if (r)
270 return r;
271
272 // Add a locking pool job
273 Id id = pool_str2id(pakfire->pool, buffer, 1);
274 if (id)
275 queue_push2(&pakfire->pool->pooljobs, SOLVER_LOCK|SOLVER_SOLVABLE_PROVIDES, id);
276
277 return 0;
278 }
279
280 static int pakfire_populate_pool(struct pakfire* pakfire) {
281 struct pakfire_db* db = NULL;
282 struct pakfire_repo* commandline = NULL;
283 struct pakfire_repo* dummy = NULL;
284 struct pakfire_repo* system = NULL;
285 int r;
286
287 const char* arch = pakfire_get_effective_arch(pakfire);
288
289 // Initialize the pool
290 Pool* pool = pakfire->pool = pool_create();
291 pool_setdisttype(pool, DISTTYPE_RPM);
292
293 #ifdef ENABLE_DEBUG
294 // Enable debug output
295 pool_setdebuglevel(pool, 3);
296 #endif
297
298 // Set architecture of the pool
299 pool_setarch(pool, arch);
300
301 // Set path
302 pool_set_rootdir(pool, pakfire->path);
303
304 // Set debug callback
305 pool_setdebugcallback(pool, pool_log, pakfire);
306
307 // Install namespace callback
308 pool_setnamespacecallback(pool, pakfire_namespace_callback, pakfire);
309
310 // These packages can be installed multiple times simultaneously
311 static const char* pakfire_multiinstall_packages[] = {
312 "kernel",
313 "kernel-devel",
314 NULL,
315 };
316
317 for (const char** package = pakfire_multiinstall_packages; *package; package++) {
318 Id id = pakfire_str2dep(pakfire, *package);
319 if (!id)
320 continue;
321
322 queue_push2(&pool->pooljobs, SOLVER_SOLVABLE_PROVIDES|SOLVER_MULTIVERSION, id);
323 }
324
325 // Open database in read-only mode and try to load all installed packages
326 r = pakfire_db_open(&db, pakfire, PAKFIRE_DB_READWRITE);
327 if (r)
328 goto ERROR;
329
330 // Create a dummy repository
331 r = pakfire_repo_create(&dummy, pakfire, PAKFIRE_REPO_DUMMY);
332 if (r)
333 goto ERROR;
334
335 // Disable the repository
336 pakfire_repo_set_enabled(dummy, 0);
337
338 // Create the system repository
339 r = pakfire_repo_create(&system, pakfire, PAKFIRE_REPO_SYSTEM);
340 if (r)
341 goto ERROR;
342
343 // Set this repository as the installed one
344 pool_set_installed(pool, pakfire_repo_get_repo(system));
345
346 // Create the command line repo
347 r = pakfire_repo_create(&commandline, pakfire, PAKFIRE_REPO_COMMANDLINE);
348 if (r)
349 goto ERROR;
350
351 // Load database content
352 r = pakfire_db_load(db, system);
353 if (r)
354 goto ERROR;
355
356 // Lock the running kernel
357 if (pakfire_on_root(pakfire)) {
358 r = pakfire_lock_running_kernel(pakfire);
359 if (r)
360 goto ERROR;
361 }
362
363 ERROR:
364 if (db)
365 pakfire_db_unref(db);
366 if (commandline)
367 pakfire_repo_unref(commandline);
368 if (dummy)
369 pakfire_repo_unref(dummy);
370 if (system)
371 pakfire_repo_unref(system);
372
373 return r;
374 }
375
376 static void pakfire_free(struct pakfire* pakfire) {
377 struct pakfire_repo* repo = NULL;
378 int r;
379
380 // Avoid recursive free
381 if (pakfire->in_free)
382 return;
383
384 pakfire->in_free = 1;
385
386 // Destroy the commandline repository
387 repo = pakfire_get_repo(pakfire, PAKFIRE_REPO_COMMANDLINE);
388 if (repo) {
389 r = pakfire_repo_clean(repo, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY);
390 if (r)
391 ERROR(pakfire, "Could not cleanup %s repository: %m\n", PAKFIRE_REPO_COMMANDLINE);
392
393 pakfire_repo_unref(repo);
394 }
395
396 // Release Magic Context
397 if (pakfire->magic)
398 magic_close(pakfire->magic);
399
400 // Release lock (if not already done so)
401 pakfire_release_lock(pakfire);
402
403 if (pakfire->destroy_on_free && *pakfire->path) {
404 DEBUG(pakfire, "Destroying %s\n", pakfire->path);
405
406 // Umount the ramdisk
407 r = umount2(pakfire->path, MNT_DETACH);
408 if (r)
409 ERROR(pakfire, "Could not umount ramdisk at %s: %m\n", pakfire->path);
410
411 // Destroy the temporary directory
412 pakfire_rmtree(pakfire->path, 0);
413 }
414
415 pakfire_repo_free_all(pakfire);
416
417 if (pakfire->pool)
418 pool_free(pakfire->pool);
419
420 if (pakfire->config)
421 pakfire_config_unref(pakfire->config);
422
423 if (pakfire->ctx)
424 pakfire_ctx_unref(pakfire->ctx);
425
426 free(pakfire);
427 }
428
429 // Safety check in case this is being launched on the host system
430 static int pakfire_safety_checks(struct pakfire* pakfire) {
431 // Nothing to do if we are not working on root
432 if (!pakfire_on_root(pakfire))
433 return 0;
434
435 // We must be root in order to operate in /
436 if (pakfire->user.uid) {
437 ERROR(pakfire, "Must be running as root on /\n");
438 errno = EPERM;
439 return 1;
440 }
441
442 if (strcmp(pakfire->distro.id, "ipfire") != 0) {
443 ERROR(pakfire, "Not an IPFire system\n");
444 errno = EPERM;
445 return 1;
446 }
447
448 return 0;
449 }
450
451 static int pakfire_read_one_repo_config(struct pakfire* pakfire, DIR* dir, const char* path) {
452 FILE* f = NULL;
453 int fd = -1;
454 int r;
455
456 // Open the file
457 fd = openat(dirfd(dir), path, O_CLOEXEC);
458 if (fd < 0)
459 return -errno;
460
461 // Re-open as file handle
462 f = fdopen(fd, "r");
463 if (!f)
464 return -errno;
465
466 // Read the configuration
467 r = pakfire_config_read(pakfire->config, f);
468
469 // Cleanup
470 fclose(f);
471
472 return r;
473 }
474
475 static int pakfire_read_repo_config(struct pakfire* pakfire) {
476 struct dirent* entry = NULL;
477 char path[PATH_MAX];
478 int r;
479
480 // Make path absolute
481 r = pakfire_path(pakfire, path, "%s", PAKFIRE_CONFIG_DIR "/repos");
482 if (r)
483 return r;
484
485 DEBUG(pakfire, "Reading repository configuration from %s\n", path);
486
487 // Open path
488 DIR* dir = opendir(path);
489 if (!dir) {
490 switch (errno) {
491 case ENOENT:
492 return 0;
493
494 default:
495 ERROR(pakfire, "Could not open %s: %m\n", path);
496 return -errno;
497 }
498 }
499
500 for (;;) {
501 entry = readdir(dir);
502 if (!entry)
503 break;
504
505 // Skip anything that isn't a regular file
506 if (entry->d_type != DT_REG)
507 continue;
508
509 // Skip any files that don't end on .repo
510 if (!pakfire_path_match("*.repo", entry->d_name))
511 continue;
512
513 // Read the configuration
514 r = pakfire_read_one_repo_config(pakfire, dir, entry->d_name);
515 if (r)
516 goto ERROR;
517 }
518
519 // Success
520 r = 0;
521
522 ERROR:
523 if (dir)
524 closedir(dir);
525
526 return r;
527 }
528
529 const char* pakfire_get_distro_name(struct pakfire* pakfire) {
530 if (*pakfire->distro.name)
531 return pakfire->distro.name;
532
533 return NULL;
534 }
535
536 const char* pakfire_get_distro_id(struct pakfire* pakfire) {
537 if (*pakfire->distro.id)
538 return pakfire->distro.id;
539
540 return NULL;
541 }
542
543 const char* pakfire_get_distro_vendor(struct pakfire* pakfire) {
544 if (*pakfire->distro.vendor)
545 return pakfire->distro.vendor;
546
547 return NULL;
548 }
549
550 const char* pakfire_get_distro_version(struct pakfire* pakfire) {
551 if (*pakfire->distro.version)
552 return pakfire->distro.version;
553
554 return NULL;
555 }
556
557 const char* pakfire_get_distro_version_id(struct pakfire* pakfire) {
558 if (*pakfire->distro.version_id)
559 return pakfire->distro.version_id;
560
561 return NULL;
562 }
563
564 const char* pakfire_get_distro_tag(struct pakfire* pakfire) {
565 int r;
566
567 if (*pakfire->distro.tag)
568 return pakfire->distro.tag;
569
570 const char* id = pakfire_get_distro_id(pakfire);
571 const char* version_id = pakfire_get_distro_version_id(pakfire);
572
573 // Break if the configuration is incomplete
574 if (!id || !version_id) {
575 errno = EINVAL;
576 return NULL;
577 }
578
579 // Format string
580 r = pakfire_string_format(pakfire->distro.tag, "%s%s", id, version_id);
581 if (r)
582 return NULL;
583
584 // Return the tag
585 return pakfire->distro.tag;
586 }
587
588 static int pakfire_config_import_distro(struct pakfire* pakfire) {
589 // Nothing to do if there is no distro section
590 if (!pakfire_config_has_section(pakfire->config, "distro"))
591 return 0;
592
593 // Name
594 const char* name = pakfire_config_get(pakfire->config, "distro", "name", NULL);
595 if (name)
596 pakfire_string_set(pakfire->distro.name, name);
597
598 // ID
599 const char* id = pakfire_config_get(pakfire->config, "distro", "id", NULL);
600 if (id)
601 pakfire_string_set(pakfire->distro.id, id);
602
603 // Version ID
604 const char* version_id = pakfire_config_get(pakfire->config, "distro", "version_id", NULL);
605 if (version_id)
606 pakfire_string_set(pakfire->distro.version_id, version_id);
607
608 // Codename
609 const char* codename = pakfire_config_get(pakfire->config, "distro", "codename", NULL);
610 if (codename)
611 pakfire_string_set(pakfire->distro.version_codename, codename);
612
613 // Fill in version
614 if (*pakfire->distro.version_codename)
615 pakfire_string_format(pakfire->distro.version, "%s (%s)",
616 pakfire->distro.version_id, pakfire->distro.version_codename);
617 else
618 pakfire_string_set(pakfire->distro.version, pakfire->distro.version_id);
619
620 // Fill in pretty name
621 pakfire_string_format(pakfire->distro.pretty_name, "%s %s",
622 pakfire->distro.name, pakfire->distro.version);
623
624 // Vendor
625 const char* vendor = pakfire_config_get(pakfire->config, "distro", "vendor", NULL);
626 if (vendor)
627 pakfire_string_set(pakfire->distro.vendor, vendor);
628
629 // Slogan
630 const char* slogan = pakfire_config_get(pakfire->config, "distro", "slogan", NULL);
631 if (slogan)
632 pakfire_string_set(pakfire->distro.slogan, slogan);
633
634 return 0;
635 }
636
637 static int pakfire_read_config(struct pakfire* pakfire, FILE* f) {
638 int r;
639
640 DEBUG(pakfire, "Reading configuration\n");
641
642 // Read configuration from file
643 if (f) {
644 r = pakfire_config_read(pakfire->config, f);
645 if (r) {
646 ERROR(pakfire, "Could not parse configuration: %m\n");
647 return r;
648 }
649 }
650
651 // Import distro configuration
652 r = pakfire_config_import_distro(pakfire);
653 if (r)
654 return r;
655
656 // Read repository configuration
657 r = pakfire_read_repo_config(pakfire);
658 if (r)
659 return r;
660
661 return 0;
662 }
663
664 static int pakfire_read_os_release(struct pakfire* pakfire) {
665 char path[PATH_MAX];
666 int r;
667
668 // Compose path
669 r = pakfire_path(pakfire, path, "%s", "/etc/os-release");
670 if (r)
671 return r;
672
673 return pakfire_distro(&pakfire->distro, path);
674 }
675
676 static int pakfire_set_cache_path(struct pakfire* pakfire) {
677 const char* cache_path = pakfire_ctx_get_cache_path(pakfire->ctx);
678 const char* arch = pakfire_get_effective_arch(pakfire);
679
680 // Format the final path
681 return pakfire_string_format(pakfire->cache_path, "%s/%s/%s/%s",
682 cache_path, pakfire->distro.id, pakfire->distro.version_id, arch);
683 }
684
685 static int pakfire_setup_user(struct pakfire* pakfire) {
686 struct passwd user;
687 struct passwd* u = NULL;
688 struct group group;
689 struct group* g = NULL;
690 char buffer[1024];
691 int r;
692
693 // Fetch the UID/GID we are running as
694 const uid_t uid = geteuid();
695 const gid_t gid = getegid();
696
697 // Fetch all user information
698 r = getpwuid_r(uid, &user, buffer, sizeof(buffer), &u);
699 if (r)
700 goto ERROR;
701
702 // Store UID
703 pakfire->user.uid = pakfire->user.subuids.id = uid;
704
705 // Store username
706 r = pakfire_string_set(pakfire->user.name, user.pw_name);
707 if (r)
708 goto ERROR;
709
710 // Store home directory
711 r = pakfire_string_set(pakfire->user.home, user.pw_dir);
712 if (r)
713 goto ERROR;
714
715 // Fetch all group information
716 r = getgrgid_r(gid, &group, buffer, sizeof(buffer), &g);
717 if (r)
718 goto ERROR;
719
720 // Store GID
721 pakfire->group.gid = pakfire->group.subgids.id = gid;
722
723 // Store name
724 r = pakfire_string_set(pakfire->group.name, group.gr_name);
725 if (r)
726 goto ERROR;
727
728 /*
729 Set default ranges for SUBUID/SUBGID
730
731 For root, we set the entire range, but for unprivileged users,
732 we can only map our own UID/GID. This may later be overwritten
733 from /etc/sub{u,g}id.
734 */
735 if (uid == 0)
736 pakfire->user.subuids.length = pakfire->group.subgids.length = 0xffffffff - 1;
737 else
738 pakfire->user.subuids.length = pakfire->group.subgids.length = 1;
739
740 // Read SUBUID/SUBGIDs from file
741 if (!pakfire_on_root(pakfire)) {
742 // Fetch SUBUIDs
743 r = pakfire_getsubuid(pakfire, pakfire->user.name, &pakfire->user.subuids);
744 switch (r) {
745 case 0:
746 case 1:
747 break;
748
749 default:
750 goto ERROR;
751 }
752
753 // Fetch SUBGIDs
754 r = pakfire_getsubgid(pakfire, pakfire->user.name, &pakfire->group.subgids);
755 switch (r) {
756 case 0:
757 case 1:
758 break;
759
760 default:
761 goto ERROR;
762 }
763 }
764
765 // Success
766 r = 0;
767
768 ERROR:
769 return r;
770 }
771
772 PAKFIRE_EXPORT int pakfire_create(struct pakfire** pakfire, struct pakfire_ctx* ctx,
773 const char* path, const char* arch, FILE* conf, int flags) {
774 char tempdir[PATH_MAX] = PAKFIRE_TMP_DIR "/pakfire-root-XXXXXX";
775 char private_dir[PATH_MAX];
776 int r = 1;
777
778 // Reset pakfire pointer
779 *pakfire = NULL;
780
781 // Default to the native architecture
782 if (!arch)
783 arch = pakfire_arch_native();
784
785 struct pakfire* p = calloc(1, sizeof(*p));
786 if (!p)
787 return -errno;
788
789 // Reference the context
790 p->ctx = pakfire_ctx_ref(ctx);
791
792 p->nrefs = 1;
793 p->flags = flags;
794
795 // Store the nominal architecture
796 r = pakfire_string_set(p->arches.nominal, arch);
797 if (r)
798 goto ERROR;
799
800 // Determine the effective architecture
801 p->arches.effective = pakfire_arch_is_supported_by_host(arch);
802 if (!p->arches.effective) {
803 ERROR(p, "Unsupported architecture: %s\n", arch);
804 r = errno;
805 goto ERROR;
806 }
807
808 // Path must be absolute
809 if (path && !pakfire_string_startswith(path, "/")) {
810 ERROR(p, "Invalid path: %s\n", path);
811 r = -EINVAL;
812 goto ERROR;
813 }
814
815 // Create a ramdisk if no path was given
816 if (!path) {
817 r = pakfire_make_ramdisk(p, tempdir, NULL);
818 if (r)
819 goto ERROR;
820
821 // Use the ramdisk as path
822 path = tempdir;
823
824 // Destroy everything when done
825 p->destroy_on_free = 1;
826 }
827
828 // Set path
829 pakfire_string_set(p->path, path);
830
831 // Setup user/group
832 r = pakfire_setup_user(p);
833 if (r)
834 goto ERROR;
835
836 // Initialise configuration
837 r = pakfire_config_create(&p->config);
838 if (r)
839 goto ERROR;
840
841 // Read /etc/os-release
842 r = pakfire_read_os_release(p);
843 if (r && errno != ENOENT)
844 goto ERROR;
845
846 // Bump RLIMIT_NOFILE to maximum
847 r = pakfire_rlimit_set(p, PAKFIRE_RLIMIT_NOFILE_MAX);
848 if (r)
849 goto ERROR;
850
851 DEBUG(p, "Pakfire initialized at %p\n", p);
852 DEBUG(p, " user = %s (%u)\n", p->user.name, p->user.uid);
853 DEBUG(p, " group = %s (%u)\n", p->group.name, p->group.gid);
854 DEBUG(p, " arch = %s (%s)\n", pakfire_get_arch(p), pakfire_get_effective_arch(p));
855 DEBUG(p, " path = %s\n", pakfire_get_path(p));
856 if (p->user.subuids.id)
857 DEBUG(p, " subuid = %u (%zu)\n", p->user.subuids.id, p->user.subuids.length);
858 if (p->group.subgids.id)
859 DEBUG(p, " subgid = %u (%zu)\n", p->group.subgids.id, p->group.subgids.length);
860
861 // Perform some safety checks
862 r = pakfire_safety_checks(p);
863 if (r)
864 goto ERROR;
865
866 // Read configuration file
867 r = pakfire_read_config(p, conf);
868 if (r)
869 goto ERROR;
870
871 // Dump distribution configuration
872 DEBUG(p, " Distribution: %s\n", p->distro.pretty_name);
873 DEBUG(p, " name = %s\n", p->distro.name);
874 DEBUG(p, " id = %s\n", p->distro.id);
875 DEBUG(p, " version = %s\n", p->distro.version);
876 DEBUG(p, " version_id = %s\n", p->distro.version_id);
877 if (*p->distro.version_codename)
878 DEBUG(p, " codename = %s\n", p->distro.version_codename);
879 if (*p->distro.vendor)
880 DEBUG(p, " vendor = %s\n", p->distro.vendor);
881 if (*p->distro.slogan)
882 DEBUG(p, " slogan = %s\n", p->distro.slogan);
883
884 // Set lock path
885 r = pakfire_path(p, p->lock_path, "%s", LOCK_PATH);
886 if (r) {
887 ERROR(p, "Could not set lock path: %m\n");
888 goto ERROR;
889 }
890
891 // Set cache path
892 r = pakfire_set_cache_path(p);
893 if (r) {
894 ERROR(p, "Could not set cache path: %m\n");
895 goto ERROR;
896 }
897
898 // Make path for private files
899 r = pakfire_path(p, private_dir, "%s", PAKFIRE_PRIVATE_DIR);
900 if (r)
901 goto ERROR;
902
903 // Make sure that our private directory exists
904 r = pakfire_mkdir(private_dir, 0755);
905 if (r) {
906 ERROR(p, "Could not create private directory %s: %m\n", private_dir);
907 goto ERROR;
908 }
909
910 // Populate pool
911 r = pakfire_populate_pool(p);
912 if (r)
913 goto ERROR;
914
915 // Create repositories
916 r = pakfire_repo_import(p, p->config);
917 if (r)
918 goto ERROR;
919
920 *pakfire = p;
921
922 return 0;
923
924 ERROR:
925 pakfire_free(p);
926
927 return r;
928 }
929
930 PAKFIRE_EXPORT struct pakfire* pakfire_ref(struct pakfire* pakfire) {
931 ++pakfire->nrefs;
932
933 return pakfire;
934 }
935
936 PAKFIRE_EXPORT struct pakfire* pakfire_unref(struct pakfire* pakfire) {
937 if (--pakfire->nrefs > 0)
938 return pakfire;
939
940 pakfire_free(pakfire);
941
942 return NULL;
943 }
944
945 struct pakfire_ctx* pakfire_ctx(struct pakfire* pakfire) {
946 return pakfire_ctx_ref(pakfire->ctx);
947 }
948
949 PAKFIRE_EXPORT int pakfire_has_flag(struct pakfire* pakfire, const int flag) {
950 return pakfire->flags & flag;
951 }
952
953 struct pakfire_config* pakfire_get_config(struct pakfire* pakfire) {
954 if (!pakfire->config)
955 return NULL;
956
957 return pakfire_config_ref(pakfire->config);
958 }
959
960 PAKFIRE_EXPORT const char* pakfire_get_path(struct pakfire* pakfire) {
961 return pakfire->path;
962 }
963
964 int pakfire_acquire_lock(struct pakfire* pakfire) {
965 int r;
966
967 // Check if the lock is already held
968 if (pakfire->lock) {
969 ERROR(pakfire, "Lock is already been acquired by this process\n");
970 return -ENOLCK;
971 }
972
973 DEBUG(pakfire, "Acquire lock...\n");
974
975 // Ensure the parent directory exists
976 pakfire_mkparentdir(pakfire->lock_path, 0755);
977
978 // Open the lock file
979 pakfire->lock = fopen(pakfire->lock_path, "w");
980 if (!pakfire->lock) {
981 ERROR(pakfire, "Could not open lock file %s: %m\n", pakfire->lock_path);
982 return -errno;
983 }
984
985 // Attempt to lock the file exclusively
986 while (1) {
987 r = flock(fileno(pakfire->lock), LOCK_EX|LOCK_NB);
988
989 // Success!
990 if (r == 0)
991 goto SUCCESS;
992
993 DEBUG(pakfire, "Could not acquire lock %s: %m\n", pakfire->lock_path);
994
995 // Wait 500ms until the next attempt
996 usleep(500000);
997 }
998
999 SUCCESS:
1000 DEBUG(pakfire, "Lock acquired\n");
1001
1002 return 0;
1003 }
1004
1005 void pakfire_release_lock(struct pakfire* pakfire) {
1006 if (!pakfire->lock)
1007 return;
1008
1009 DEBUG(pakfire, "Releasing lock\n");
1010
1011 fclose(pakfire->lock);
1012 pakfire->lock = NULL;
1013
1014 // Attempt to unlink the lock file
1015 unlink(pakfire->lock_path);
1016 }
1017
1018 int __pakfire_path(struct pakfire* pakfire, char* path, const size_t length,
1019 const char* format, ...) {
1020 char buffer[PATH_MAX];
1021 va_list args;
1022 int r;
1023
1024 // Format input into buffer
1025 va_start(args, format);
1026 r = __pakfire_string_vformat(buffer, sizeof(buffer), format, args);
1027 va_end(args);
1028
1029 // Break on any errors
1030 if (r)
1031 return r;
1032
1033 // Join paths together
1034 return __pakfire_path_append(path, length, pakfire->path, buffer);
1035 }
1036
1037 const char* pakfire_relpath(struct pakfire* pakfire, const char* path) {
1038 return pakfire_path_relpath(pakfire->path, path);
1039 }
1040
1041 int __pakfire_cache_path(struct pakfire* pakfire, char* path, size_t length,
1042 const char* format, ...) {
1043 char buffer[PATH_MAX];
1044 va_list args;
1045 int r;
1046
1047 // Format input into buffer
1048 va_start(args, format);
1049 r = __pakfire_string_vformat(buffer, sizeof(buffer), format, args);
1050 va_end(args);
1051
1052 // Break on any errors
1053 if (r)
1054 return r;
1055
1056 // Join paths together
1057 return __pakfire_path_append(path, length, pakfire->cache_path, buffer);
1058 }
1059
1060 magic_t pakfire_get_magic(struct pakfire* pakfire) {
1061 int r;
1062
1063 // Initialize the context if not already done
1064 if (!pakfire->magic) {
1065 // Allocate a new context
1066 pakfire->magic = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR | MAGIC_NO_CHECK_TOKENS);
1067 if (!pakfire->magic) {
1068 ERROR(pakfire, "Could not allocate magic context: %m\n");
1069 return NULL;
1070 }
1071
1072 // Load the database
1073 r = magic_load(pakfire->magic, NULL);
1074 if (r) {
1075 ERROR(pakfire, "Could not open the magic database: %s\n",
1076 magic_error(pakfire->magic));
1077 goto ERROR;
1078 }
1079 }
1080
1081 return pakfire->magic;
1082
1083 ERROR:
1084 if (pakfire->magic)
1085 magic_close(pakfire->magic);
1086
1087 // Reset the pointer
1088 pakfire->magic = NULL;
1089
1090 return NULL;
1091 }
1092
1093 int pakfire_repo_walk(struct pakfire* pakfire,
1094 pakfire_repo_walk_callback callback, void* p) {
1095 struct pakfire_repo* repo = NULL;
1096 Repo* solv_repo = NULL;
1097 int i = 0;
1098 int r;
1099
1100 Pool* pool = pakfire->pool;
1101
1102 // Run func for every repository
1103 FOR_REPOS(i, solv_repo) {
1104 repo = pakfire_repo_create_from_repo(pakfire, solv_repo);
1105 if (!repo)
1106 return 1;
1107
1108 // Run callback
1109 r = callback(pakfire, repo, p);
1110 pakfire_repo_unref(repo);
1111
1112 // Raise any errors
1113 if (r)
1114 return r;
1115 }
1116
1117 return 0;
1118 }
1119
1120 static int __pakfire_repo_clean(struct pakfire* pakfire, struct pakfire_repo* repo,
1121 void* p) {
1122 int flags = *(int*)p;
1123
1124 return pakfire_repo_clean(repo, flags);
1125 }
1126
1127 PAKFIRE_EXPORT int pakfire_clean(struct pakfire* pakfire, int flags) {
1128 int r;
1129
1130 // Clean all repositories
1131 r = pakfire_repo_walk(pakfire, __pakfire_repo_clean, &flags);
1132 if (r)
1133 return r;
1134
1135 // Clean build environments
1136 r = pakfire_build_clean(pakfire, flags);
1137 if (r)
1138 return r;
1139
1140 // Remove the cache
1141 return pakfire_rmtree(PAKFIRE_CACHE_DIR, 0);
1142 }
1143
1144 static int __pakfire_repo_refresh(struct pakfire* pakfire, struct pakfire_repo* repo,
1145 void* p) {
1146 int flags = *(int*)p;
1147
1148 return pakfire_repo_refresh(repo, flags);
1149 }
1150
1151 PAKFIRE_EXPORT int pakfire_refresh(struct pakfire* pakfire, int flags) {
1152 return pakfire_repo_walk(pakfire, __pakfire_repo_refresh, &flags);
1153 }
1154
1155 PAKFIRE_EXPORT const char* pakfire_get_arch(struct pakfire* pakfire) {
1156 return pakfire->arches.nominal;
1157 }
1158
1159 const char* pakfire_get_effective_arch(struct pakfire* pakfire) {
1160 return pakfire->arches.effective;
1161 }
1162
1163 PAKFIRE_EXPORT int pakfire_version_compare(struct pakfire* pakfire, const char* evr1, const char* evr2) {
1164 return pool_evrcmp_str(pakfire->pool, evr1, evr2, EVRCMP_COMPARE);
1165 }
1166
1167 Pool* pakfire_get_solv_pool(struct pakfire* pakfire) {
1168 return pakfire->pool;
1169 }
1170
1171 void pakfire_pool_has_changed(struct pakfire* pakfire) {
1172 pakfire->pool_ready = 0;
1173 }
1174
1175 static int __pakfire_repo_internalize(struct pakfire* pakfire, struct pakfire_repo* repo,
1176 void* p) {
1177 int flags = *(int*)p;
1178
1179 return pakfire_repo_internalize(repo, flags);
1180 }
1181
1182 void pakfire_pool_internalize(struct pakfire* pakfire) {
1183 int flags = 0;
1184
1185 // Nothing to do if the pool is ready
1186 if (pakfire->pool_ready)
1187 return;
1188
1189 // Internalize all repositories
1190 pakfire_repo_walk(pakfire, __pakfire_repo_internalize, &flags);
1191
1192 // Create fileprovides
1193 pool_addfileprovides(pakfire->pool);
1194
1195 // Create whatprovides index
1196 pool_createwhatprovides(pakfire->pool);
1197
1198 // Mark the pool as ready
1199 pakfire->pool_ready = 1;
1200 }
1201
1202 PAKFIRE_EXPORT struct pakfire_repolist* pakfire_get_repos(struct pakfire* pakfire) {
1203 struct pakfire_repolist* list;
1204
1205 int r = pakfire_repolist_create(&list);
1206 if (r)
1207 return NULL;
1208
1209 Pool* pool = pakfire_get_solv_pool(pakfire);
1210 Repo* solv_repo;
1211 int i;
1212
1213 FOR_REPOS(i, solv_repo) {
1214 // Skip the dummy repository
1215 if (strcmp(solv_repo->name, PAKFIRE_REPO_DUMMY) == 0)
1216 continue;
1217
1218 struct pakfire_repo* repo = pakfire_repo_create_from_repo(pakfire, solv_repo);
1219 if (!repo) {
1220 r = 1;
1221 goto ERROR;
1222 }
1223
1224 r = pakfire_repolist_append(list, repo);
1225 if (r) {
1226 pakfire_repo_unref(repo);
1227 goto ERROR;
1228 }
1229
1230 pakfire_repo_unref(repo);
1231 }
1232
1233 return list;
1234
1235 ERROR:
1236 pakfire_repolist_unref(list);
1237 return NULL;
1238 }
1239
1240 PAKFIRE_EXPORT struct pakfire_repo* pakfire_get_repo(struct pakfire* pakfire, const char* name) {
1241 Pool* pool = pakfire_get_solv_pool(pakfire);
1242 if (!pool)
1243 return NULL;
1244
1245 Repo* repo;
1246 int i;
1247
1248 FOR_REPOS(i, repo) {
1249 if (strcmp(repo->name, name) == 0)
1250 return pakfire_repo_create_from_repo(pakfire, repo);
1251 }
1252
1253 // Nothing found
1254 return NULL;
1255 }
1256
1257 struct pakfire_repo* pakfire_get_installed_repo(struct pakfire* pakfire) {
1258 if (!pakfire->pool->installed)
1259 return NULL;
1260
1261 return pakfire_repo_create_from_repo(pakfire, pakfire->pool->installed);
1262 }
1263
1264 /*
1265 Convenience function to dist() a package on the fly
1266 */
1267 static int pakfire_commandline_dist(struct pakfire* pakfire, struct pakfire_repo* repo,
1268 const char* path, struct pakfire_package** package) {
1269 char* result = NULL;
1270 int r;
1271
1272 // XXX result is not unique!
1273
1274 // Run dist()
1275 r = pakfire_dist(pakfire, path, PAKFIRE_TMP_DIR, &result);
1276 if (r)
1277 goto ERROR;
1278
1279 // Try to add the package to the repository
1280 r = pakfire_repo_add(repo, result, package);
1281
1282 ERROR:
1283 if (result)
1284 free(result);
1285
1286 return r;
1287 }
1288
1289 /*
1290 Convenience function to add a package to the @commandline repository
1291 */
1292 int pakfire_commandline_add(struct pakfire* pakfire, const char* path,
1293 struct pakfire_package** package) {
1294 struct pakfire_repo* repo = NULL;
1295 int r;
1296
1297 // Find the commandline repository
1298 repo = pakfire_get_repo(pakfire, PAKFIRE_REPO_COMMANDLINE);
1299 if (!repo) {
1300 ERROR(pakfire, "Could not find the commandline repository: %m\n");
1301 return 1;
1302 }
1303
1304 // Add the package
1305 r = pakfire_repo_add(repo, path, package);
1306 switch (-r) {
1307 case ENOMSG:
1308 r = pakfire_commandline_dist(pakfire, repo, path, package);
1309 break;
1310
1311 default:
1312 goto ERROR;
1313 }
1314
1315 ERROR:
1316 if (repo)
1317 pakfire_repo_unref(repo);
1318
1319 return r;
1320 }
1321
1322 static int __pakfire_search(struct pakfire* pakfire, struct pakfire_packagelist* list,
1323 const Id* keys, const char* what, int flags) {
1324 Dataiterator di;
1325 Queue matches;
1326 int r;
1327
1328 // Get the pool ready
1329 pakfire_pool_internalize(pakfire);
1330
1331 // Initialize the result queue
1332 queue_init(&matches);
1333
1334 // Setup the data interator
1335 dataiterator_init(&di, pakfire->pool, 0, 0, 0, what, flags);
1336
1337 // Search through these keys and add matches to the queue
1338 for (const Id* key = keys; *key; key++) {
1339 dataiterator_set_keyname(&di, *key);
1340 dataiterator_set_search(&di, 0, 0);
1341
1342 while (dataiterator_step(&di))
1343 queue_pushunique(&matches, di.solvid);
1344 }
1345
1346 // Import matches into the package list
1347 r = pakfire_packagelist_import_solvables(list, pakfire, &matches);
1348 if (r)
1349 goto ERROR;
1350
1351 ERROR:
1352 dataiterator_free(&di);
1353 queue_free(&matches);
1354
1355 return r;
1356 }
1357
1358 static int pakfire_search_filelist(struct pakfire* pakfire, const char* what, int flags,
1359 struct pakfire_packagelist* list) {
1360 const Id keys[] = {
1361 SOLVABLE_FILELIST,
1362 ID_NULL,
1363 };
1364
1365 return __pakfire_search(pakfire, list, keys, what, SEARCH_FILES|SEARCH_GLOB);
1366 }
1367
1368 static int pakfire_search_dep(struct pakfire* pakfire, Id type, const char* what, int flags,
1369 struct pakfire_packagelist* list) {
1370 int r;
1371
1372 // Get the pool ready
1373 pakfire_pool_internalize(pakfire);
1374
1375 // Translate dependency to ID
1376 Id dep = pakfire_str2dep(pakfire, what);
1377 if (!dep) {
1378 errno = EINVAL;
1379 return 1;
1380 }
1381
1382 Queue matches;
1383 queue_init(&matches);
1384
1385 // Search for anything that matches
1386 pool_whatmatchesdep(pakfire->pool, type, dep, &matches, 0);
1387
1388 // Add the result to the packagelist
1389 r = pakfire_packagelist_import_solvables(list, pakfire, &matches);
1390 if (r)
1391 goto ERROR;
1392
1393 ERROR:
1394 queue_free(&matches);
1395
1396 return r;
1397 }
1398
1399 PAKFIRE_EXPORT int pakfire_whatprovides(struct pakfire* pakfire, const char* what, int flags,
1400 struct pakfire_packagelist* list) {
1401 int r;
1402
1403 // Check for valid input
1404 if (!what || !list) {
1405 errno = EINVAL;
1406 return 1;
1407 }
1408
1409 // Search for all packages that match this dependency
1410 r = pakfire_search_dep(pakfire, SOLVABLE_PROVIDES, what, flags, list);
1411 if (r)
1412 return r;
1413
1414 // Search the filelist
1415 if (*what == '/') {
1416 r = pakfire_search_filelist(pakfire, what, flags, list);
1417 if (r)
1418 return r;
1419 }
1420
1421 return 0;
1422 }
1423
1424 static int __pakfire_whatrequires(struct pakfire_ctx* ctx, struct pakfire_package* pkg, void* data) {
1425 struct pakfire_packagelist* list = (struct pakfire_packagelist*)data;
1426
1427 return pakfire_package_get_reverse_requires(pkg, list);
1428 }
1429
1430 PAKFIRE_EXPORT int pakfire_whatrequires(struct pakfire* pakfire, const char* what, int flags,
1431 struct pakfire_packagelist* list) {
1432 struct pakfire_packagelist* packages = NULL;
1433 int r;
1434
1435 const Id keys[] = {
1436 SOLVABLE_NAME,
1437 ID_NULL,
1438 };
1439
1440 // Create a new package list
1441 r = pakfire_packagelist_create(&packages, pakfire->ctx);
1442 if (r)
1443 goto ERROR;
1444
1445 // Find any packages that match the name
1446 r = __pakfire_search(pakfire, packages, keys, what, SEARCH_STRING);
1447 if (r)
1448 goto ERROR;
1449
1450 // Find everything for all packages
1451 r = pakfire_packagelist_walk(packages, __pakfire_whatrequires, list);
1452 if (r)
1453 goto ERROR;
1454
1455 // Append any simple dependencies
1456 r = pakfire_search_dep(pakfire, SOLVABLE_REQUIRES, what, flags, list);
1457 if (r)
1458 goto ERROR;
1459
1460 ERROR:
1461 if (packages)
1462 pakfire_packagelist_unref(packages);
1463
1464 return r;
1465 }
1466
1467 PAKFIRE_EXPORT int pakfire_search(struct pakfire* pakfire, const char* what, int flags,
1468 struct pakfire_packagelist* list) {
1469 const Id keys[] = {
1470 SOLVABLE_NAME,
1471 SOLVABLE_SUMMARY,
1472 SOLVABLE_DESCRIPTION,
1473 ID_NULL
1474 };
1475
1476 const Id keys_name_only[] = {
1477 SOLVABLE_NAME,
1478 ID_NULL
1479 };
1480
1481 return __pakfire_search(pakfire,
1482 list,
1483 (flags & PAKFIRE_SEARCH_NAME_ONLY) ? keys_name_only : keys,
1484 what,
1485 SEARCH_SUBSTRING|SEARCH_NOCASE);
1486 }
1487
1488 // Logging
1489
1490 // XXX This function is deprecated and needs to be removed
1491 void pakfire_log(struct pakfire* pakfire, int priority, int r,
1492 const char* file, int line, const char* fn, const char* format, ...) {
1493 char* buffer = NULL;
1494 va_list args;
1495
1496 // Save errno
1497 int saved_errno = errno;
1498 if (r)
1499 errno = r;
1500
1501 va_start(args, format);
1502 r = vasprintf(&buffer, format, args);
1503 va_end(args);
1504
1505 // Restore errno
1506 errno = saved_errno;
1507
1508 if (r < 0)
1509 return;
1510
1511 // Pass on to the context logger
1512 pakfire_ctx_log(pakfire->ctx, priority, file, line, fn, "%s", buffer);
1513 }
1514
1515 static const char* pakfire_user_lookup(void* data, la_int64_t uid) {
1516 struct pakfire* pakfire = (struct pakfire*)data;
1517
1518 // Unmap the UID first
1519 uid = pakfire_unmap_id(pakfire, &pakfire->user.subuids, uid);
1520
1521 // Fast path for "root"
1522 if (uid == 0)
1523 return "root";
1524
1525 DEBUG(pakfire, "Looking up name for UID %ld\n", uid);
1526
1527 // Find a matching entry in /etc/passwd
1528 struct passwd* entry = pakfire_getpwuid(pakfire, uid);
1529 if (!entry) {
1530 ERROR(pakfire, "Could not retrieve uname for %ld: %m\n", uid);
1531 return 0;
1532 }
1533
1534 DEBUG(pakfire, "Mapping UID %ld to %s\n", uid, entry->pw_name);
1535
1536 return entry->pw_name;
1537 }
1538
1539 static const char* pakfire_group_lookup(void* data, la_int64_t gid) {
1540 struct pakfire* pakfire = (struct pakfire*)data;
1541
1542 // Unmap the GID first
1543 gid = pakfire_unmap_id(pakfire, &pakfire->group.subgids, gid);
1544
1545 // Fast path for "root"
1546 if (gid == 0)
1547 return "root";
1548
1549 DEBUG(pakfire, "Looking up name for GID %ld\n", gid);
1550
1551 // Find a matching entry in /etc/group
1552 struct group* entry = pakfire_getgrgid(pakfire, gid);
1553 if (!entry) {
1554 ERROR(pakfire, "Could not retrieve gname for %ld: %m\n", gid);
1555 return 0;
1556 }
1557
1558 DEBUG(pakfire, "Mapping GID %ld to %s\n", gid, entry->gr_name);
1559
1560 return entry->gr_name;
1561 }
1562
1563 struct archive* pakfire_make_archive_disk_reader(struct pakfire* pakfire, int internal) {
1564 struct archive* archive = archive_read_disk_new();
1565 if (!archive)
1566 return NULL;
1567
1568 // Do not read fflags
1569 int r = archive_read_disk_set_behavior(archive, ARCHIVE_READDISK_NO_FFLAGS);
1570 if (r) {
1571 ERROR(pakfire, "Could not change behavior of reader: %s\n",
1572 archive_error_string(archive));
1573 archive_read_free(archive);
1574 return NULL;
1575 }
1576
1577 // Install user/group lookups
1578 if (internal) {
1579 archive_read_disk_set_uname_lookup(archive, pakfire, pakfire_user_lookup, NULL);
1580 archive_read_disk_set_gname_lookup(archive, pakfire, pakfire_group_lookup, NULL);
1581 } else {
1582 archive_read_disk_set_standard_lookup(archive);
1583 }
1584
1585 return archive;
1586 }
1587
1588 static la_int64_t pakfire_uid_lookup(void* data, const char* name, la_int64_t uid) {
1589 struct pakfire* pakfire = (struct pakfire*)data;
1590
1591 // Fast path for "root"
1592 if (strcmp(name, "root") == 0)
1593 return pakfire_map_id(pakfire, &pakfire->user.subuids, 0);
1594
1595 DEBUG(pakfire, "Looking up UID for '%s' (%ld)\n", name, uid);
1596
1597 // Find a matching entry in /etc/passwd
1598 struct passwd* entry = pakfire_getpwnam(pakfire, name);
1599 if (!entry) {
1600 ERROR(pakfire, "Could not retrieve UID for '%s': %m\n", name);
1601 return pakfire_map_id(pakfire, &pakfire->user.subuids, 0);
1602 }
1603
1604 DEBUG(pakfire, "Mapping %s to UID %u\n", name, entry->pw_uid);
1605
1606 return pakfire_map_id(pakfire, &pakfire->user.subuids, entry->pw_uid);
1607 }
1608
1609 static la_int64_t pakfire_gid_lookup(void* data, const char* name, la_int64_t gid) {
1610 struct pakfire* pakfire = (struct pakfire*)data;
1611
1612 // Fast path for "root"
1613 if (strcmp(name, "root") == 0)
1614 return pakfire_map_id(pakfire, &pakfire->group.subgids, 0);
1615
1616 DEBUG(pakfire, "Looking up GID for '%s' (%ld)\n", name, gid);
1617
1618 // Find a matching entry in /etc/group
1619 struct group* entry = pakfire_getgrnam(pakfire, name);
1620 if (!entry) {
1621 ERROR(pakfire, "Could not retrieve GID for '%s': %m\n", name);
1622 return pakfire_map_id(pakfire, &pakfire->group.subgids, 0);
1623 }
1624
1625 DEBUG(pakfire, "Mapping %s to GID %u\n", name, entry->gr_gid);
1626
1627 return pakfire_map_id(pakfire, &pakfire->group.subgids, entry->gr_gid);
1628 }
1629
1630 struct archive* pakfire_make_archive_disk_writer(struct pakfire* pakfire, int internal) {
1631 struct archive* archive = archive_write_disk_new();
1632 if (!archive)
1633 return NULL;
1634
1635 // Set flags for extracting files
1636 const int flags =
1637 ARCHIVE_EXTRACT_ACL |
1638 ARCHIVE_EXTRACT_OWNER |
1639 ARCHIVE_EXTRACT_PERM |
1640 ARCHIVE_EXTRACT_TIME |
1641 ARCHIVE_EXTRACT_UNLINK |
1642 ARCHIVE_EXTRACT_XATTR;
1643
1644 archive_write_disk_set_options(archive, flags);
1645
1646 // Install our own routine for user/group lookups
1647 if (internal) {
1648 archive_write_disk_set_user_lookup(archive, pakfire, pakfire_uid_lookup, NULL);
1649 archive_write_disk_set_group_lookup(archive, pakfire, pakfire_gid_lookup, NULL);
1650 } else {
1651 archive_write_disk_set_standard_lookup(archive);
1652 }
1653
1654 return archive;
1655 }
1656
1657 // Convenience functions to install/erase/update packages
1658
1659 static int pakfire_verify(struct pakfire* pakfire, int *changed) {
1660 #if 0
1661 return pakfire_perform_transaction_simple(pakfire, 0, PAKFIRE_JOB_VERIFY,
1662 0, changed, NULL, NULL);
1663 #endif
1664 #warning TODO
1665 return 0;
1666 }
1667
1668 static int pakfire_check_files(struct pakfire* pakfire,
1669 struct pakfire_db* db, struct pakfire_filelist* errors) {
1670 struct pakfire_filelist* filelist = NULL;
1671 int r;
1672
1673 // Fetch the filelist
1674 r = pakfire_db_filelist(db, &filelist);
1675 if (r)
1676 goto ERROR;
1677
1678 // Verify the filelist
1679 r = pakfire_filelist_verify(filelist, errors);
1680
1681 ERROR:
1682 if (filelist)
1683 pakfire_filelist_unref(filelist);
1684
1685 return r;
1686 }
1687
1688 PAKFIRE_EXPORT int pakfire_check(struct pakfire* pakfire, struct pakfire_filelist* errors) {
1689 struct pakfire_db* db = NULL;
1690 int r;
1691
1692 // Open database in read-only mode and try to load all installed packages
1693 r = pakfire_db_open(&db, pakfire, PAKFIRE_DB_READWRITE);
1694 if (r)
1695 goto ERROR;
1696
1697 // Perform a database integrity check
1698 r = pakfire_db_check(db);
1699 if (r)
1700 goto ERROR;
1701
1702 // Check if all dependencies are intact
1703 r = pakfire_verify(pakfire, NULL);
1704 if (r)
1705 goto ERROR;
1706
1707 // Check files
1708 r = pakfire_check_files(pakfire, db, errors);
1709 if (r)
1710 goto ERROR;
1711
1712 ERROR:
1713 if (db)
1714 pakfire_db_unref(db);
1715
1716 return r;
1717 }