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