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