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