]>
Commit | Line | Data |
---|---|---|
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 | 71 | struct 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 | */ | |
126 | static 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 | 155 | int pakfire_on_root(struct pakfire* pakfire) { |
028ed535 MT |
156 | return (strcmp(pakfire->path, "/") == 0); |
157 | } | |
158 | ||
0e2c206e | 159 | uid_t pakfire_uid(struct pakfire* pakfire) { |
1931780a | 160 | return pakfire->user.uid; |
0e2c206e MT |
161 | } |
162 | ||
163 | gid_t pakfire_gid(struct pakfire* pakfire) { | |
1931780a | 164 | return pakfire->group.gid; |
0e2c206e MT |
165 | } |
166 | ||
a1ff2863 | 167 | const struct pakfire_subid* pakfire_subuid(struct pakfire* pakfire) { |
9b50d885 | 168 | return &pakfire->user.subuids; |
705541ab MT |
169 | } |
170 | ||
a1ff2863 | 171 | const 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 | */ | |
179 | static 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 | ||
197 | static 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 | 215 | static 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 |
221 | static 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 | ||
232 | static 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 | 238 | static 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 |
259 | static 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 | 284 | static 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 | 367 | ERROR: |
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 | 380 | static 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 | 438 | static 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 |
459 | static 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 | 483 | static 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 | 530 | ERROR: |
dc6afe5c MT |
531 | if (dir) |
532 | closedir(dir); | |
5d1e84df MT |
533 | |
534 | return r; | |
535 | } | |
536 | ||
ac4c607b | 537 | const 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 | 544 | const 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 | 551 | const 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 | 558 | const 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 | 565 | const 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 |
572 | const 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 | 596 | static 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 | 645 | static 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 | 672 | static 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 | 684 | static 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 |
693 | static 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 |
776 | ERROR: |
777 | return r; | |
778 | } | |
779 | ||
f2a8f4f2 | 780 | PAKFIRE_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 | |
937 | ERROR: | |
938 | pakfire_free(p); | |
939 | ||
940 | return r; | |
6e46b18e MT |
941 | } |
942 | ||
ac4c607b | 943 | PAKFIRE_EXPORT struct pakfire* pakfire_ref(struct pakfire* pakfire) { |
af2ad1e0 | 944 | ++pakfire->nrefs; |
6e46b18e | 945 | |
af2ad1e0 | 946 | return pakfire; |
6e46b18e MT |
947 | } |
948 | ||
ac4c607b | 949 | PAKFIRE_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 |
958 | struct pakfire_ctx* pakfire_ctx(struct pakfire* pakfire) { |
959 | return pakfire_ctx_ref(pakfire->ctx); | |
960 | } | |
961 | ||
715e8dd5 | 962 | PAKFIRE_EXPORT int pakfire_has_flag(struct pakfire* pakfire, const int flag) { |
457feacb MT |
963 | return pakfire->flags & flag; |
964 | } | |
965 | ||
ac4c607b | 966 | struct 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 | 973 | PAKFIRE_EXPORT const char* pakfire_get_path(struct pakfire* pakfire) { |
af2ad1e0 | 974 | return pakfire->path; |
6e46b18e MT |
975 | } |
976 | ||
b5cc6424 MT |
977 | int 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 | ||
1012 | SUCCESS: | |
1013 | DEBUG(pakfire, "Lock acquired\n"); | |
1014 | ||
1015 | return 0; | |
1016 | } | |
1017 | ||
1018 | void 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 |
1031 | int __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 |
1050 | const char* pakfire_relpath(struct pakfire* pakfire, const char* path) { |
1051 | return pakfire_path_relpath(pakfire->path, path); | |
1052 | } | |
1053 | ||
df1409ef MT |
1054 | int __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 |
1073 | magic_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 | ||
1096 | ERROR: | |
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 |
1106 | int 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 | ||
1133 | static 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 | 1140 | PAKFIRE_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 |
1157 | static 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 | 1164 | PAKFIRE_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 | 1168 | PAKFIRE_EXPORT const char* pakfire_get_arch(struct pakfire* pakfire) { |
652f2a99 MT |
1169 | return pakfire->arches.nominal; |
1170 | } | |
1171 | ||
1172 | const char* pakfire_get_effective_arch(struct pakfire* pakfire) { | |
1173 | return pakfire->arches.effective; | |
af2ad1e0 MT |
1174 | } |
1175 | ||
ac4c607b | 1176 | PAKFIRE_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 | 1180 | Pool* pakfire_get_solv_pool(struct pakfire* pakfire) { |
f989dacd MT |
1181 | return pakfire->pool; |
1182 | } | |
1183 | ||
ac4c607b | 1184 | void pakfire_pool_has_changed(struct pakfire* pakfire) { |
f989dacd MT |
1185 | pakfire->pool_ready = 0; |
1186 | } | |
1187 | ||
7d22968f MT |
1188 | static 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 | 1195 | void 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 | 1215 | PAKFIRE_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 | ||
1248 | ERROR: | |
1249 | pakfire_repolist_unref(list); | |
1250 | return NULL; | |
1251 | } | |
1252 | ||
ac4c607b | 1253 | PAKFIRE_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 | 1270 | struct 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 | */ | |
1280 | static 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 | ||
1295 | ERROR: | |
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 | */ | |
1305 | int 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 | |
1328 | ERROR: | |
1329 | if (repo) | |
1330 | pakfire_repo_unref(repo); | |
1331 | ||
1332 | return r; | |
1333 | } | |
1334 | ||
644d2660 MT |
1335 | static 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 | ||
1364 | ERROR: | |
1365 | dataiterator_free(&di); | |
1366 | queue_free(&matches); | |
1367 | ||
1368 | return r; | |
1369 | } | |
1370 | ||
1371 | static 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 | 1381 | static 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 |
1406 | ERROR: |
1407 | queue_free(&matches); | |
8201cef2 | 1408 | |
b055ddf1 | 1409 | return r; |
8201cef2 MT |
1410 | } |
1411 | ||
ac4c607b | 1412 | PAKFIRE_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 | 1437 | static 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 | 1443 | PAKFIRE_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 | ||
1473 | ERROR: | |
1474 | if (packages) | |
1475 | pakfire_packagelist_unref(packages); | |
1476 | ||
1477 | return r; | |
54334355 MT |
1478 | } |
1479 | ||
ac4c607b | 1480 | PAKFIRE_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 |
1504 | void 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 | |
1528 | static 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 | ||
1552 | static 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 | 1576 | struct 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 | |
1601 | static 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 | 1622 | static 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 | 1643 | struct 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 | 1672 | static 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 |
1681 | static 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 | ||
1694 | ERROR: | |
1695 | if (filelist) | |
1696 | pakfire_filelist_unref(filelist); | |
1697 | ||
1698 | return r; | |
1699 | } | |
1700 | ||
1701 | PAKFIRE_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 |
1725 | ERROR: |
1726 | if (db) | |
1727 | pakfire_db_unref(db); | |
1728 | ||
1729 | return r; | |
1730 | } |