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