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