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