1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2017 Pakfire development team #
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. #
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. #
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/>. #
19 #############################################################################*/
24 #include <linux/limits.h>
28 #include <sys/mount.h>
29 #include <sys/queue.h>
31 #include <sys/sysmacros.h>
32 #include <sys/types.h>
37 #include <archive_entry.h>
40 #include <solv/pool.h>
41 #include <solv/poolarch.h>
42 #include <solv/queue.h>
44 #include <pakfire/arch.h>
45 #include <pakfire/build.h>
46 #include <pakfire/config.h>
47 #include <pakfire/constants.h>
48 #include <pakfire/db.h>
49 #include <pakfire/keystore.h>
50 #include <pakfire/logging.h>
51 #include <pakfire/package.h>
52 #include <pakfire/packagelist.h>
53 #include <pakfire/pakfire.h>
54 #include <pakfire/parser.h>
55 #include <pakfire/private.h>
56 #include <pakfire/pwd.h>
57 #include <pakfire/repo.h>
58 #include <pakfire/request.h>
59 #include <pakfire/snapshot.h>
60 #include <pakfire/transaction.h>
61 #include <pakfire/ui.h>
62 #include <pakfire/util.h>
64 #define KEYSTORE_DIR "/etc/pakfire/trusted.keys.d"
65 #define CCACHE_DIR "/var/cache/ccache"
68 STAILQ_ENTRY(mountpoint
) nodes
;
74 char cache_path
[PATH_MAX
];
76 char keystore_path
[PATH_MAX
];
84 pakfire_log_function_t log_function
;
90 struct pakfire_config
* config
;
92 STAILQ_HEAD(mountpoints
, mountpoint
) mountpoints
;
94 struct pakfire_distro
{
95 char pretty_name
[256];
101 char version_codename
[32];
110 int destroy_on_free
:1;
117 This is a list of all features that are supported by this version of Pakfire
119 static const struct pakfire_feature
{
123 { "PackageFormat-6" },
124 { "PackageFormat-5" },
127 { "Compress-Zstandard" },
136 int pakfire_on_root(struct pakfire
* pakfire
) {
137 return (strcmp(pakfire
->path
, "/") == 0);
140 static const struct pakfire_mountpoint
{
147 { "pakfire_root", "", "tmpfs", 0, NULL
},
149 { "pakfire_proc", "proc", "proc", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, NULL
},
151 // Bind mount /proc/sys as read-only with the following exceptions:
153 { "/proc/sys", "proc/sys", NULL
, MS_BIND
, NULL
},
154 { "/proc/sys/net", "proc/sys/net", NULL
, MS_BIND
, NULL
},
155 { "/proc/sys", "proc/sys", NULL
, MS_BIND
|MS_RDONLY
|MS_REMOUNT
, NULL
},
157 // Bind mount /sys as read-only
158 { "/sys", "sys", NULL
, MS_BIND
, NULL
},
159 { "/sys", "sys", NULL
, MS_BIND
|MS_RDONLY
|MS_REMOUNT
, NULL
},
162 { "pakfire_dev", "dev", "tmpfs", MS_NOSUID
|MS_NOEXEC
,
163 "mode=755,size=4m,nr_inodes=64k" },
164 { "/dev/pts", "dev/pts", NULL
, MS_BIND
, NULL
},
167 { "pakfire_tmpfs", "run", "tmpfs", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
,
168 "mode=755,size=4m,nr_inodes=1k" },
171 { "pakfire_tmpfs", "tmp", "tmpfs", MS_NOSUID
|MS_NODEV
,
178 static int __mount(struct pakfire
* pakfire
, const char* source
, const char* target
,
179 const char* filesystemtype
, unsigned long mountflags
, const void* data
) {
180 int r
= mount(source
, target
, filesystemtype
, mountflags
, data
);
184 // Skip if the mountpoint is already on the list
185 if (pakfire_is_mountpoint(pakfire
, target
))
188 // If not, add the mountpoint to the list so that we can umount it later
189 struct mountpoint
* mp
= calloc(1, sizeof(*mp
));
193 pakfire_string_set(mp
->path
, target
);
195 STAILQ_INSERT_HEAD(&pakfire
->mountpoints
, mp
, nodes
);
200 static int pakfire_mount(struct pakfire
* pakfire
) {
201 char target
[PATH_MAX
];
204 for (const struct pakfire_mountpoint
* mp
= mountpoints
; mp
->source
; mp
++) {
205 // Skip mounting root when a directory has been passed
206 if (!*mp
->target
&& !pakfire
->mount_tmpfs
)
209 DEBUG(pakfire
, "Mounting /%s\n", mp
->target
);
211 r
= pakfire_path_join(target
, pakfire
->path
, mp
->target
);
217 r
= __mount(pakfire
, mp
->source
, target
, mp
->fstype
, mp
->flags
, mp
->options
);
219 // If the target directory does not exist, we will create it
220 if (errno
== ENOENT
) {
221 r
= pakfire_mkdir(target
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
223 ERROR(pakfire
, "Could not create %s\n", target
);
230 ERROR(pakfire
, "Could not mount /%s: %m\n", mp
->target
);
238 static int pakfire_umount(struct pakfire
* pakfire
) {
239 struct mountpoint
* mp
;
243 while (!STAILQ_EMPTY(&pakfire
->mountpoints
)) {
244 // Take the first element from the list
245 mp
= STAILQ_FIRST(&pakfire
->mountpoints
);
247 // Remove first element
248 STAILQ_REMOVE_HEAD(&pakfire
->mountpoints
, nodes
);
250 DEBUG(pakfire
, "Umounting %s\n", mp
->path
);
257 r
= umount2(mp
->path
, flags
);
260 // Attempt a lazy umount when busy
261 if (errno
== EBUSY
) {
266 ERROR(pakfire
, "Could not umount %s: %m\n", mp
->path
);
275 int pakfire_is_mountpoint(struct pakfire
* pakfire
, const char* path
) {
276 struct mountpoint
* mp
;
278 // Check if path is on this list
279 STAILQ_FOREACH(mp
, &pakfire
->mountpoints
, nodes
) {
280 if (strcmp(mp
->path
, path
) == 0)
287 static const struct pakfire_devnode
{
293 { "/dev/null", 1, 3, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
294 { "/dev/zero", 1, 5, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
295 { "/dev/full", 1, 7, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
296 { "/dev/random", 1, 8, S_IFCHR
|S_IRUSR
|S_IRGRP
|S_IROTH
, },
297 { "/dev/urandom", 1, 9, S_IFCHR
|S_IRUSR
|S_IRGRP
|S_IROTH
, },
298 { "/dev/kmsg", 1, 11, S_IFCHR
|S_IRUSR
|S_IRGRP
|S_IROTH
, },
299 { "/dev/tty", 5, 0, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
300 { "/dev/console", 5, 1, S_IFCHR
|S_IRUSR
|S_IWUSR
, },
301 { "/dev/ptmx", 5, 2, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
302 { "/dev/rtc0", 252, 0, S_IFCHR
|S_IRUSR
|S_IWUSR
, },
306 static const struct pakfire_symlink
{
310 { "/proc/self/fd", "/dev/fd", },
311 { "/proc/self/fd/0", "/dev/stdin" },
312 { "/proc/self/fd/1", "/dev/stdout" },
313 { "/proc/self/fd/2", "/dev/stderr" },
314 { "/proc/kcore", "/dev/core" },
318 static int pakfire_populate_dev(struct pakfire
* pakfire
) {
321 // Create device nodes
322 for (const struct pakfire_devnode
* devnode
= devnodes
; devnode
->path
; devnode
++) {
323 DEBUG(pakfire
, "Creating device node %s\n", devnode
->path
);
325 int r
= pakfire_make_path(pakfire
, path
, devnode
->path
);
329 dev_t dev
= makedev(devnode
->major
, devnode
->minor
);
331 r
= mknod(path
, devnode
->mode
, dev
);
333 ERROR(pakfire
, "Could not create %s: %m\n", devnode
->path
);
339 for (const struct pakfire_symlink
* s
= symlinks
; s
->target
; s
++) {
340 DEBUG(pakfire
, "Creating symlink %s -> %s\n", s
->path
, s
->target
);
342 int r
= pakfire_make_path(pakfire
, path
, s
->path
);
346 r
= symlink(s
->target
, path
);
348 ERROR(pakfire
, "Could not create symlink %s: %m\n", s
->path
);
356 static void pakfire_log_set_function(struct pakfire
* pakfire
,
357 pakfire_log_function_t log_function
, void* data
) {
358 pakfire
->log_function
= log_function
;
359 pakfire
->log_data
= data
;
362 static int log_priority(const char* priority
) {
365 int prio
= strtol(priority
, &end
, 10);
366 if (*end
== '\0' || isspace(*end
))
369 if (strncmp(priority
, "error", strlen("error")) == 0)
372 if (strncmp(priority
, "info", strlen("info")) == 0)
375 if (strncmp(priority
, "debug", strlen("debug")) == 0)
381 static void pool_log(Pool
* pool
, void* data
, int type
, const char* s
) {
382 struct pakfire
* pakfire
= (struct pakfire
*)data
;
384 DEBUG(pakfire
, "pool: %s", s
);
387 static Id
pakfire_namespace_callback(Pool
* pool
, void* data
, Id ns
, Id id
) {
388 struct pakfire
* pakfire
= (struct pakfire
*)data
;
390 const char* namespace = pool_id2str(pool
, ns
);
391 const char* name
= pakfire_dep2str(pakfire
, id
);
393 DEBUG(pakfire
, "Namespace callback called for %s(%s)\n", namespace, name
);
395 // We only handle the pakfire namesapce
396 if (strcmp(namespace, "pakfire") != 0)
399 // Find all supported features
400 for (const struct pakfire_feature
* feature
= features
; feature
->name
; feature
++) {
401 if (strcmp(feature
->name
, name
) == 0)
409 static int pakfire_populate_pool(struct pakfire
* pakfire
) {
410 struct pakfire_db
* db
;
411 struct pakfire_repo
* commandline
= NULL
;
412 struct pakfire_repo
* dummy
= NULL
;
413 struct pakfire_repo
* system
= NULL
;
416 // Initialize the pool
417 Pool
* pool
= pakfire
->pool
= pool_create();
418 pool_setdisttype(pool
, DISTTYPE_RPM
);
421 // Enable debug output
422 pool_setdebuglevel(pool
, 2);
425 // Set architecture of the pool
426 pool_setarch(pool
, pakfire
->arch
);
429 pool_set_rootdir(pool
, pakfire
->path
);
431 // Set debug callback
432 pool_setdebugcallback(pool
, pool_log
, pakfire
);
434 // Install namespace callback
435 pool_setnamespacecallback(pool
, pakfire_namespace_callback
, pakfire
);
437 // Open database in read-only mode and try to load all installed packages
438 r
= pakfire_db_open(&db
, pakfire
, PAKFIRE_DB_READWRITE
);
442 // Create a dummy repository
443 r
= pakfire_repo_create(&dummy
, pakfire
, PAKFIRE_REPO_DUMMY
);
447 // Disable the repository
448 pakfire_repo_set_enabled(dummy
, 0);
450 // Create the system repository
451 r
= pakfire_repo_create(&system
, pakfire
, PAKFIRE_REPO_SYSTEM
);
455 // Set this repository as the installed one
456 pool_set_installed(pool
, pakfire_repo_get_repo(system
));
458 // Create the command line repo
459 r
= pakfire_repo_create(&commandline
, pakfire
, PAKFIRE_REPO_COMMANDLINE
);
463 // Load database content
464 r
= pakfire_db_load(db
, system
);
470 pakfire_db_unref(db
);
472 pakfire_repo_unref(commandline
);
474 pakfire_repo_unref(dummy
);
476 pakfire_repo_unref(system
);
481 static int pakfire_mount_interpreter(struct pakfire
* pakfire
) {
482 char target
[PATH_MAX
];
484 // Can we emulate this architecture?
485 char* interpreter
= pakfire_arch_find_interpreter(pakfire
->arch
);
487 // No interpreter required
491 DEBUG(pakfire
, "Mounting interpreter %s for %s\n", interpreter
, pakfire
->arch
);
493 // Where to mount this?
494 int r
= pakfire_make_path(pakfire
, target
, interpreter
);
499 r
= pakfire_mkparentdir(target
, 0);
503 // Create an empty file
504 FILE* f
= fopen(target
, "w");
509 r
= __mount(pakfire
, interpreter
, target
, NULL
, MS_BIND
|MS_RDONLY
, NULL
);
511 ERROR(pakfire
, "Could not mount interpreter %s to %s: %m\n", interpreter
, target
);
516 static void pakfire_free(struct pakfire
* pakfire
) {
517 struct pakfire_repo
* repo
= NULL
;
520 // Avoid recursive free
521 if (pakfire
->in_free
++)
524 // Destroy the commandline repository
525 repo
= pakfire_get_repo(pakfire
, PAKFIRE_REPO_COMMANDLINE
);
527 r
= pakfire_repo_clean(repo
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
529 ERROR(pakfire
, "Could not cleanup %s repository: %m\n", PAKFIRE_REPO_COMMANDLINE
);
531 pakfire_repo_unref(repo
);
534 // Release GPGME context
536 pakfire_keystore_destroy(pakfire
, &pakfire
->gpgctx
);
539 pakfire_umount(pakfire
);
541 if (pakfire
->destroy_on_free
&& *pakfire
->path
) {
542 DEBUG(pakfire
, "Destroying %s\n", pakfire
->path
);
544 // Destroy the temporary directory
545 pakfire_rmtree(pakfire
->path
, 0);
548 pakfire_repo_free_all(pakfire
);
551 pool_free(pakfire
->pool
);
554 pakfire_config_unref(pakfire
->config
);
559 // Safety check in case this is being launched on the host system
560 static int pakfire_safety_checks(struct pakfire
* pakfire
) {
561 // Nothing to do if we are not working on root
562 if (!pakfire_on_root(pakfire
))
565 if (strcmp(pakfire
->distro
.id
, "ipfire") != 0) {
566 ERROR(pakfire
, "Not an IPFire system\n");
574 static int pakfire_read_repo_config(struct pakfire
* pakfire
) {
577 int r
= pakfire_make_path(pakfire
, path
, PAKFIRE_CONFIG_DIR
"/repos");
581 DEBUG(pakfire
, "Reading repository configuration from %s\n", path
);
588 FTS
* d
= fts_open(paths
, FTS_NOCHDIR
|FTS_NOSTAT
, NULL
);
593 FTSENT
* fent
= fts_read(d
);
598 if (fent
->fts_info
& FTS_F
) {
599 // Skip everything that doesn't end in .repo
600 if (!pakfire_string_endswith(fent
->fts_name
, ".repo"))
603 DEBUG(pakfire
, "Reading %s\n", fent
->fts_path
);
605 FILE* f
= fopen(fent
->fts_path
, "r");
609 // Parse the configuration file
610 r
= pakfire_config_read(pakfire
->config
, f
);
628 const char* pakfire_get_distro_name(struct pakfire
* pakfire
) {
629 if (*pakfire
->distro
.name
)
630 return pakfire
->distro
.name
;
635 const char* pakfire_get_distro_id(struct pakfire
* pakfire
) {
636 if (*pakfire
->distro
.id
)
637 return pakfire
->distro
.id
;
642 const char* pakfire_get_distro_vendor(struct pakfire
* pakfire
) {
643 if (*pakfire
->distro
.vendor
)
644 return pakfire
->distro
.vendor
;
649 const char* pakfire_get_distro_version(struct pakfire
* pakfire
) {
650 if (*pakfire
->distro
.version
)
651 return pakfire
->distro
.version
;
656 const char* pakfire_get_distro_version_id(struct pakfire
* pakfire
) {
657 if (*pakfire
->distro
.version_id
)
658 return pakfire
->distro
.version_id
;
663 static int pakfire_config_import_distro(struct pakfire
* pakfire
) {
664 // Nothing to do if there is no distro section
665 if (!pakfire_config_has_section(pakfire
->config
, "distro"))
669 const char* name
= pakfire_config_get(pakfire
->config
, "distro", "name", NULL
);
671 pakfire_string_set(pakfire
->distro
.name
, name
);
674 const char* id
= pakfire_config_get(pakfire
->config
, "distro", "id", NULL
);
676 pakfire_string_set(pakfire
->distro
.id
, id
);
679 const char* version_id
= pakfire_config_get(pakfire
->config
, "distro", "version_id", NULL
);
681 pakfire_string_set(pakfire
->distro
.version_id
, version_id
);
684 const char* codename
= pakfire_config_get(pakfire
->config
, "distro", "codename", NULL
);
686 pakfire_string_set(pakfire
->distro
.version_codename
, codename
);
689 if (*pakfire
->distro
.version_codename
)
690 pakfire_string_format(pakfire
->distro
.version
, "%s (%s)",
691 pakfire
->distro
.version_id
, pakfire
->distro
.version_codename
);
693 pakfire_string_set(pakfire
->distro
.version
, pakfire
->distro
.version_id
);
695 // Fill in pretty name
696 pakfire_string_format(pakfire
->distro
.pretty_name
, "%s %s",
697 pakfire
->distro
.name
, pakfire
->distro
.version
);
700 const char* vendor
= pakfire_config_get(pakfire
->config
, "distro", "vendor", NULL
);
702 pakfire_string_set(pakfire
->distro
.vendor
, vendor
);
705 const char* slogan
= pakfire_config_get(pakfire
->config
, "distro", "slogan", NULL
);
707 pakfire_string_set(pakfire
->distro
.slogan
, slogan
);
712 static int pakfire_read_config(struct pakfire
* pakfire
, const char* path
) {
713 char default_path
[PATH_MAX
];
715 // Use default path if none set
717 int r
= pakfire_make_path(pakfire
, default_path
, PAKFIRE_CONFIG_DIR
"/general.conf");
724 DEBUG(pakfire
, "Reading configuration from %s\n", path
);
726 FILE* f
= fopen(path
, "r");
728 // Silently ignore when there is no default configuration file
729 if (*default_path
&& errno
== ENOENT
)
732 ERROR(pakfire
, "Could not open configuration file %s: %m\n", path
);
736 // Read configuration from file
737 int r
= pakfire_config_read(pakfire
->config
, f
);
739 ERROR(pakfire
, "Could not parse configuration file %s: %m\n", path
);
743 // Import distro configuration
744 r
= pakfire_config_import_distro(pakfire
);
748 // Read repository configuration
749 r
= pakfire_read_repo_config(pakfire
);
759 static int pakfire_read_os_release(struct pakfire
* pakfire
) {
764 int r
= pakfire_make_path(pakfire
, path
, "/etc/os-release");
770 FILE* f
= fopen(path
, "r");
772 // Ignore when the file does not exist
773 if (errno
== ENOENT
) {
778 ERROR(pakfire
, "Could not open %s: %m\n", path
);
783 ssize_t bytes_read
= getline(&line
, &l
, f
);
787 // Remove trailing newline
788 pakfire_remove_trailing_newline(line
);
791 char* delim
= strchr(line
, '=');
798 // Set key and val to the start of the strings
800 char* val
= delim
+ 1;
803 val
= pakfire_unquote_in_place(val
);
805 if (strcmp(key
, "PRETTY_NAME") == 0)
806 r
= pakfire_string_set(pakfire
->distro
.pretty_name
, val
);
807 else if (strcmp(key
, "NAME") == 0)
808 r
= pakfire_string_set(pakfire
->distro
.name
, val
);
809 else if (strcmp(key
, "ID") == 0)
810 r
= pakfire_string_set(pakfire
->distro
.id
, val
);
811 else if (strcmp(key
, "VERSION") == 0)
812 r
= pakfire_string_set(pakfire
->distro
.version
, val
);
813 else if (strcmp(key
, "VERSION_CODENAME") == 0)
814 r
= pakfire_string_set(pakfire
->distro
.version_codename
, val
);
815 else if (strcmp(key
, "VERSION_ID") == 0)
816 r
= pakfire_string_set(pakfire
->distro
.version_id
, val
);
837 PAKFIRE_EXPORT
int pakfire_create(struct pakfire
** pakfire
, const char* path
,
838 const char* arch
, const char* conf
, int flags
, pakfire_log_function_t log
,
840 char tempdir
[PATH_MAX
] = PAKFIRE_TMP_DIR
"/XXXXXX";
843 // Default to the native architecture
845 arch
= pakfire_arch_native();
847 // Check if the architecture is supported
848 if (!pakfire_arch_supported(arch
)) {
853 // Path must be absolute
854 if (path
&& !pakfire_string_startswith(path
, "/")) {
859 // Check if we are running as root
860 uid_t uid
= getuid();
866 struct pakfire
* p
= calloc(1, sizeof(*p
));
874 pakfire_string_set(p
->arch
, arch
);
878 pakfire_log_set_function(p
, log
, data
);
880 pakfire_log_set_function(p
, pakfire_log_syslog
, NULL
);
882 const char* env
= secure_getenv("PAKFIRE_LOG");
884 pakfire_log_set_priority(p
, log_priority(env
));
886 // Initialise configuration
887 r
= pakfire_config_create(&p
->config
);
891 // Generate a random path if none is set
893 path
= pakfire_mkdtemp(tempdir
);
897 // Mount this as tmpfs
898 p
->mount_tmpfs
= !pakfire_has_flag(p
, PAKFIRE_FLAGS_DISABLE_RAMDISK
);
900 // Destroy everything when done
901 p
->destroy_on_free
= 1;
905 pakfire_string_set(p
->path
, path
);
907 // Read /etc/os-release
908 r
= pakfire_read_os_release(p
);
909 if (r
&& errno
!= ENOENT
)
912 // Bump RLIMIT_NOFILE to maximum
913 r
= pakfire_rlimit_set(p
, PAKFIRE_RLIMIT_NOFILE_MAX
);
917 DEBUG(p
, "Pakfire initialized at %p\n", p
);
918 DEBUG(p
, " arch = %s\n", pakfire_get_arch(p
));
919 DEBUG(p
, " path = %s\n", pakfire_get_path(p
));
921 // Automatically disable interactive mode
922 if (!pakfire_has_flag(p
, PAKFIRE_FLAGS_NON_INTERACTIVE
)) {
923 if (pakfire_tty_is_noninteractive()) {
924 DEBUG(p
, "Interactive mode disabled\n");
926 flags
|= PAKFIRE_FLAGS_NON_INTERACTIVE
;
930 // Perform some safety checks
931 r
= pakfire_safety_checks(p
);
935 // Read configuration file
936 r
= pakfire_read_config(p
, conf
);
940 // Dump distribution configuration
941 DEBUG(p
, " Distribution: %s\n", p
->distro
.pretty_name
);
942 DEBUG(p
, " name = %s\n", p
->distro
.name
);
943 DEBUG(p
, " id = %s\n", p
->distro
.id
);
944 DEBUG(p
, " version = %s\n", p
->distro
.version
);
945 DEBUG(p
, " version_id = %s\n", p
->distro
.version_id
);
946 if (*p
->distro
.version_codename
)
947 DEBUG(p
, " codename = %s\n", p
->distro
.version_codename
);
948 if (*p
->distro
.vendor
)
949 DEBUG(p
, " vendor = %s\n", p
->distro
.vendor
);
950 if (*p
->distro
.slogan
)
951 DEBUG(p
, " slogan = %s\n", p
->distro
.slogan
);
954 pakfire_string_format(p
->cache_path
, "%s/%s/%s/%s",
955 PAKFIRE_CACHE_DIR
, p
->distro
.id
, p
->distro
.version_id
, p
->arch
);
958 r
= pakfire_make_path(p
, p
->keystore_path
, KEYSTORE_DIR
);
960 ERROR(p
, "Could not set keystore path: %m\n");
965 r
= pakfire_mount(p
);
970 r
= pakfire_populate_dev(p
);
974 // Mount the interpreter (if needed)
975 r
= pakfire_mount_interpreter(p
);
979 // Make path for private files
980 char private_dir
[PATH_MAX
];
981 r
= pakfire_make_path(p
, private_dir
, PAKFIRE_PRIVATE_DIR
);
985 // Make sure that our private directory exists
986 r
= pakfire_mkdir(private_dir
, 0);
987 if (r
&& errno
!= EEXIST
) {
988 ERROR(p
, "Could not create private directory %s: %m\n", private_dir
);
992 // Initialize keystore
993 r
= pakfire_keystore_init(p
, &p
->gpgctx
);
998 r
= pakfire_populate_pool(p
);
1002 // Create repositories
1003 r
= pakfire_repo_import(p
, p
->config
);
1007 // Setup build stuff
1008 if (pakfire_has_flag(p
, PAKFIRE_FLAGS_BUILD
)) {
1009 // Builds are never interactive
1010 p
->flags
|= PAKFIRE_FLAGS_NON_INTERACTIVE
;
1023 PAKFIRE_EXPORT
struct pakfire
* pakfire_ref(struct pakfire
* pakfire
) {
1029 PAKFIRE_EXPORT
struct pakfire
* pakfire_unref(struct pakfire
* pakfire
) {
1030 if (--pakfire
->nrefs
> 0)
1033 pakfire_free(pakfire
);
1038 int pakfire_has_flag(struct pakfire
* pakfire
, int flag
) {
1039 return pakfire
->flags
& flag
;
1042 struct pakfire_config
* pakfire_get_config(struct pakfire
* pakfire
) {
1043 if (!pakfire
->config
)
1046 return pakfire_config_ref(pakfire
->config
);
1049 PAKFIRE_EXPORT
const char* pakfire_get_path(struct pakfire
* pakfire
) {
1050 return pakfire
->path
;
1053 const char* pakfire_get_keystore_path(struct pakfire
* pakfire
) {
1054 return pakfire
->keystore_path
;
1057 int __pakfire_make_path(struct pakfire
* pakfire
, char* dst
, size_t length
, const char* path
) {
1058 // Make sure that path never starts with /
1059 while (path
&& *path
== '/')
1062 return __pakfire_path_join(dst
, length
, pakfire
->path
, path
);
1065 PAKFIRE_EXPORT
int pakfire_bind(struct pakfire
* pakfire
, const char* src
, const char* dst
, int flags
) {
1067 char mountpoint
[PATH_MAX
];
1072 int r
= pakfire_make_path(pakfire
, mountpoint
, dst
);
1076 DEBUG(pakfire
, "Mounting %s to %s\n", src
, mountpoint
);
1080 ERROR(pakfire
, "Could not stat %s: %m\n", src
);
1084 // Make sure the mountpoint exists
1085 switch (st
.st_mode
& S_IFMT
) {
1087 r
= pakfire_mkdir(mountpoint
, 0);
1088 if (r
&& errno
!= EEXIST
)
1094 // Make parent directory
1095 r
= pakfire_mkparentdir(mountpoint
, 0);
1100 FILE* f
= fopen(mountpoint
, "w");
1112 return __mount(pakfire
, src
, mountpoint
, NULL
, flags
|MS_BIND
, NULL
);
1115 gpgme_ctx_t
pakfire_get_gpgctx(struct pakfire
* pakfire
) {
1116 return pakfire
->gpgctx
;
1119 PAKFIRE_EXPORT
int pakfire_list_keys(struct pakfire
* pakfire
, struct pakfire_key
*** keys
) {
1123 // Fetch GPGME context
1124 gpgme_ctx_t gpgctx
= pakfire_get_gpgctx(pakfire
);
1128 struct pakfire_key
* key
= NULL
;
1129 gpgme_key_t gpgkey
= NULL
;
1133 // Iterate over all keys and import them to the list
1134 gpgme_error_t e
= gpgme_op_keylist_start(gpgctx
, NULL
, 0);
1139 e
= gpgme_op_keylist_next(gpgctx
, &gpgkey
);
1144 r
= pakfire_key_create(&key
, pakfire
, gpgkey
);
1145 gpgme_key_unref(gpgkey
);
1150 *keys
= reallocarray(*keys
, length
+ 2, sizeof(**keys
));
1156 // Store key in array
1157 (*keys
)[length
++] = key
;
1159 // Terminate the array
1160 (*keys
)[length
] = NULL
;
1168 for (struct pakfire_key
** key
= *keys
; *key
; key
++)
1169 pakfire_key_unref(*key
);
1177 static int pakfire_foreach_repo(struct pakfire
* pakfire
,
1178 int (*func
)(struct pakfire_repo
* repo
, int flags
), int flags
) {
1179 struct pakfire_repo
* repo
;
1185 Pool
* pool
= pakfire
->pool
;
1187 // Run func for every repository
1188 FOR_REPOS(i
, solv_repo
) {
1189 repo
= pakfire_repo_create_from_repo(pakfire
, solv_repo
);
1194 r
= func(repo
, flags
);
1195 pakfire_repo_unref(repo
);
1205 PAKFIRE_EXPORT
int pakfire_clean(struct pakfire
* pakfire
, int flags
) {
1208 // Clean all repositories
1209 r
= pakfire_foreach_repo(pakfire
, pakfire_repo_clean
, flags
);
1213 // Clean build environments
1214 // Nothing to do if we are not in build mode
1215 if (pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_BUILD
)) {
1216 r
= pakfire_build_clean(pakfire
, flags
);
1222 return pakfire_rmtree(PAKFIRE_CACHE_DIR
, 0);
1225 PAKFIRE_EXPORT
int pakfire_refresh(struct pakfire
* pakfire
, int flags
) {
1226 return pakfire_foreach_repo(pakfire
, pakfire_repo_refresh
, flags
);
1229 static int pakfire_copy(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1230 char buffer
[512 * 1024];
1231 struct archive
* reader
= NULL
;
1232 struct archive
* writer
= NULL
;
1233 struct archive_entry
* entry
= NULL
;
1238 reader
= archive_read_disk_new();
1243 writer
= archive_write_disk_new();
1247 // Create a new entry
1248 entry
= archive_entry_new();
1252 // Set the source path
1253 archive_entry_copy_sourcepath(entry
, src
);
1255 // Read everything from source file
1256 r
= archive_read_disk_entry_from_file(reader
, entry
, -1, NULL
);
1258 ERROR(pakfire
, "Could not read from %s: %m", src
);
1262 // Set the destination path
1263 archive_entry_set_pathname(entry
, dst
);
1265 // Write file to destination
1266 r
= archive_write_header(writer
, entry
);
1268 ERROR(pakfire
, "Could not write %s: %m\n", dst
);
1273 if (archive_entry_filetype(entry
) == AE_IFREG
) {
1274 f
= fopen(src
, "r");
1279 size_t bytes_read
= fread(buffer
, 1, sizeof(buffer
), f
);
1281 // Check if any error occured
1283 ERROR(pakfire
, "Error reading from file: %m\n");
1287 ssize_t bytes_written
= archive_write_data(writer
, buffer
, bytes_read
);
1288 if (bytes_written
< 0) {
1289 ERROR(pakfire
, "Error writing data: %s\n", archive_error_string(writer
));
1299 archive_entry_free(entry
);
1301 archive_read_free(reader
);
1303 archive_write_free(writer
);
1308 PAKFIRE_EXPORT
int pakfire_copy_in(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1309 if (pakfire_on_root(pakfire
)) {
1314 char path
[PATH_MAX
];
1315 int r
= pakfire_make_path(pakfire
, path
, dst
);
1319 return pakfire_copy(pakfire
, src
, path
);
1322 PAKFIRE_EXPORT
int pakfire_copy_out(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1323 if (pakfire_on_root(pakfire
)) {
1328 char path
[PATH_MAX
];
1329 int r
= pakfire_make_path(pakfire
, path
, src
);
1333 return pakfire_copy(pakfire
, path
, dst
);
1336 PAKFIRE_EXPORT
const char* pakfire_get_arch(struct pakfire
* pakfire
) {
1337 return pakfire
->arch
;
1340 PAKFIRE_EXPORT
int pakfire_version_compare(struct pakfire
* pakfire
, const char* evr1
, const char* evr2
) {
1341 return pool_evrcmp_str(pakfire
->pool
, evr1
, evr2
, EVRCMP_COMPARE
);
1344 Pool
* pakfire_get_solv_pool(struct pakfire
* pakfire
) {
1345 return pakfire
->pool
;
1348 void pakfire_pool_has_changed(struct pakfire
* pakfire
) {
1349 pakfire
->pool_ready
= 0;
1352 void pakfire_pool_apply_changes(struct pakfire
* pakfire
) {
1353 if (!pakfire
->pool_ready
) {
1354 pool_addfileprovides(pakfire
->pool
);
1355 pool_createwhatprovides(pakfire
->pool
);
1356 pakfire
->pool_ready
= 1;
1360 PAKFIRE_EXPORT
struct pakfire_repolist
* pakfire_get_repos(struct pakfire
* pakfire
) {
1361 struct pakfire_repolist
* list
;
1363 int r
= pakfire_repolist_create(&list
);
1367 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
1371 FOR_REPOS(i
, solv_repo
) {
1372 // Skip the dummy repository
1373 if (strcmp(solv_repo
->name
, PAKFIRE_REPO_DUMMY
) == 0)
1376 struct pakfire_repo
* repo
= pakfire_repo_create_from_repo(pakfire
, solv_repo
);
1382 r
= pakfire_repolist_append(list
, repo
);
1384 pakfire_repo_unref(repo
);
1388 pakfire_repo_unref(repo
);
1394 pakfire_repolist_unref(list
);
1398 PAKFIRE_EXPORT
struct pakfire_repo
* pakfire_get_repo(struct pakfire
* pakfire
, const char* name
) {
1399 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
1406 FOR_REPOS(i
, repo
) {
1407 if (strcmp(repo
->name
, name
) == 0)
1408 return pakfire_repo_create_from_repo(pakfire
, repo
);
1415 struct pakfire_repo
* pakfire_get_installed_repo(struct pakfire
* pakfire
) {
1416 if (!pakfire
->pool
->installed
)
1419 return pakfire_repo_create_from_repo(pakfire
, pakfire
->pool
->installed
);
1422 static int pakfire_search_dep(struct pakfire
* pakfire
, Id type
, const char* what
, int flags
,
1423 struct pakfire_packagelist
** list
) {
1426 // Get the pool ready
1427 pakfire_pool_apply_changes(pakfire
);
1429 // Translate dependency to ID
1430 Id dep
= pakfire_parse_dep(pakfire
, what
);
1440 queue_init(&matches
);
1442 // Search for anything that matches
1443 pool_whatmatchesdep(pakfire
->pool
, type
, dep
, &matches
, 0);
1445 // Create a packagelist
1446 r
= pakfire_packagelist_create_from_queue(list
, pakfire
, &matches
);
1451 pakfire_packagelist_sort(*list
);
1454 queue_free(&matches
);
1459 PAKFIRE_EXPORT
int pakfire_whatprovides(struct pakfire
* pakfire
, const char* what
, int flags
,
1460 struct pakfire_packagelist
** list
) {
1461 return pakfire_search_dep(pakfire
, SOLVABLE_PROVIDES
, what
, flags
, list
);
1464 PAKFIRE_EXPORT
int pakfire_whatrequires(struct pakfire
* pakfire
, const char* what
, int flags
,
1465 struct pakfire_packagelist
** list
) {
1466 return pakfire_search_dep(pakfire
, SOLVABLE_REQUIRES
, what
, flags
, list
);
1469 PAKFIRE_EXPORT
int pakfire_search(struct pakfire
* pakfire
, const char* what
, int flags
,
1470 struct pakfire_packagelist
** list
) {
1476 // Get the pool ready
1477 pakfire_pool_apply_changes(pakfire
);
1479 // Initialize the result queue
1480 queue_init(&matches
);
1482 if (flags
& PAKFIRE_SEARCH_NAME_ONLY
)
1483 dflags
= SEARCH_STRING
|SEARCH_GLOB
;
1485 dflags
= SEARCH_SUBSTRING
|SEARCH_NOCASE
|SEARCH_GLOB
;
1487 // Setup the data interator
1488 dataiterator_init(&di
, pakfire
->pool
, 0, 0, 0, what
, dflags
);
1493 SOLVABLE_DESCRIPTION
,
1497 // Search through these keys and add matches to the queue
1498 for (const Id
* key
= keys
; *key
; key
++) {
1499 dataiterator_set_keyname(&di
, *key
);
1500 dataiterator_set_search(&di
, 0, 0);
1502 while (dataiterator_step(&di
))
1503 queue_pushunique(&matches
, di
.solvid
);
1506 if (flags
& PAKFIRE_SEARCH_NAME_ONLY
)
1510 // Convert matches to package list
1511 r
= pakfire_packagelist_create_from_queue(list
, pakfire
, &matches
);
1516 pakfire_packagelist_sort(*list
);
1519 dataiterator_free(&di
);
1520 queue_free(&matches
);
1527 int __pakfire_make_cache_path(struct pakfire
* pakfire
, char* path
, size_t length
,
1528 const char* format
, ...) {
1532 ssize_t l
= snprintf(path
, length
- 1, "%s/", pakfire
->cache_path
);
1536 // We have run out of space
1537 if ((size_t)l
>= length
)
1540 // Append everything after the format string
1543 va_start(args
, format
);
1544 vsnprintf(path
, length
- l
- 1, format
, args
);
1550 PAKFIRE_EXPORT
int pakfire_log_get_priority(struct pakfire
* pakfire
) {
1551 return pakfire
->log_priority
;
1554 PAKFIRE_EXPORT
void pakfire_log_set_priority(struct pakfire
* pakfire
, int priority
) {
1555 pakfire
->log_priority
= priority
;
1558 void pakfire_log(struct pakfire
* pakfire
, int priority
, const char* file
, int line
,
1559 const char* fn
, const char* format
, ...) {
1563 int saved_errno
= errno
;
1565 va_start(args
, format
);
1566 pakfire
->log_function(pakfire
->log_data
, priority
, file
, line
, fn
, format
, args
);
1570 errno
= saved_errno
;
1573 static const char* pakfire_user_lookup(void* data
, la_int64_t uid
) {
1574 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1576 // Fast path for "root"
1580 // Find a matching entry in /etc/passwd
1581 struct passwd
* entry
= pakfire_getpwuid(pakfire
, uid
);
1583 ERROR(pakfire
, "Could not retrieve uname for %ld: %m\n", uid
);
1587 DEBUG(pakfire
, "Mapping UID %ld to %s\n", uid
, entry
->pw_name
);
1589 return entry
->pw_name
;
1592 static const char* pakfire_group_lookup(void* data
, la_int64_t gid
) {
1593 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1595 // Fast path for "root"
1599 // Find a matching entry in /etc/group
1600 struct group
* entry
= pakfire_getgrgid(pakfire
, gid
);
1602 ERROR(pakfire
, "Could not retrieve gname for %ld: %m\n", gid
);
1606 DEBUG(pakfire
, "Mapping GID %ld to %s\n", gid
, entry
->gr_name
);
1608 return entry
->gr_name
;
1611 struct archive
* pakfire_make_archive_disk_reader(struct pakfire
* pakfire
, int internal
) {
1612 struct archive
* archive
= archive_read_disk_new();
1616 // Do not read fflags
1617 int r
= archive_read_disk_set_behavior(archive
, ARCHIVE_READDISK_NO_FFLAGS
);
1619 ERROR(pakfire
, "Could not change behavior of reader: %s\n",
1620 archive_error_string(archive
));
1621 archive_read_free(archive
);
1625 // Install user/group lookups
1627 archive_read_disk_set_uname_lookup(archive
, pakfire
, pakfire_user_lookup
, NULL
);
1628 archive_read_disk_set_gname_lookup(archive
, pakfire
, pakfire_group_lookup
, NULL
);
1630 archive_read_disk_set_standard_lookup(archive
);
1636 static la_int64_t
pakfire_uid_lookup(void* data
, const char* name
, la_int64_t uid
) {
1637 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1639 // Fast path for "root"
1640 if (strcmp(name
, "root") == 0)
1643 // Find a matching entry in /etc/passwd
1644 struct passwd
* entry
= pakfire_getpwnam(pakfire
, name
);
1646 ERROR(pakfire
, "Could not retrieve UID for '%s': %m\n", name
);
1650 DEBUG(pakfire
, "Mapping %s to UID %d\n", name
, entry
->pw_uid
);
1652 return entry
->pw_uid
;
1655 static la_int64_t
pakfire_gid_lookup(void* data
, const char* name
, la_int64_t uid
) {
1656 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1658 // Fast path for "root"
1659 if (strcmp(name
, "root") == 0)
1662 // Find a matching entry in /etc/group
1663 struct group
* entry
= pakfire_getgrnam(pakfire
, name
);
1665 ERROR(pakfire
, "Could not retrieve GID for '%s': %m\n", name
);
1669 DEBUG(pakfire
, "Mapping %s to GID %d\n", name
, entry
->gr_gid
);
1671 return entry
->gr_gid
;
1674 struct archive
* pakfire_make_archive_disk_writer(struct pakfire
* pakfire
) {
1675 struct archive
* archive
= archive_write_disk_new();
1679 // Set flags for extracting files
1681 ARCHIVE_EXTRACT_ACL
|
1682 ARCHIVE_EXTRACT_OWNER
|
1683 ARCHIVE_EXTRACT_PERM
|
1684 ARCHIVE_EXTRACT_TIME
|
1685 ARCHIVE_EXTRACT_UNLINK
|
1686 ARCHIVE_EXTRACT_XATTR
|
1687 ARCHIVE_EXTRACT_SECURE_SYMLINKS
;
1689 archive_write_disk_set_options(archive
, flags
);
1691 // Install our own routine for user/group lookups
1692 archive_write_disk_set_user_lookup(archive
, pakfire
, pakfire_uid_lookup
, NULL
);
1693 archive_write_disk_set_group_lookup(archive
, pakfire
, pakfire_gid_lookup
, NULL
);
1698 // Convenience functions to install/erase/update packages
1700 static int pakfire_perform_transaction(struct pakfire
* pakfire
, int solver_flags
,
1701 int (*action
)(struct pakfire_request
* request
, const char* what
, int flags
),
1702 const char** packages
, const char** locks
, int job_flags
, int* changed
) {
1703 struct pakfire_request
* request
= NULL
;
1704 struct pakfire_transaction
* transaction
= NULL
;
1705 struct pakfire_problem
** problems
= NULL
;
1708 // Packages cannot be NULL
1714 // Create a new request
1715 r
= pakfire_request_create(&request
, pakfire
, solver_flags
);
1719 // Lock anything that should be locked
1721 for (const char** lock
= locks
; *lock
; lock
++) {
1722 r
= pakfire_request_lock(request
, *lock
);
1724 ERROR(pakfire
, "Could not lock '%s': %m\n", *lock
);
1730 // Perform action on all packages
1731 for (const char** package
= packages
; *package
; package
++) {
1732 r
= action(request
, *package
, job_flags
);
1734 ERROR(pakfire
, "Could not find '%s': %m\n", *package
);
1741 // Solve the request
1743 r
= pakfire_request_solve(request
, &transaction
, &problems
);
1754 // Let the user choose a problem
1755 r
= pakfire_ui_pick_solution(pakfire
, request
, problems
);
1760 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1761 pakfire_problem_unref(*problem
);
1765 // Another error occured
1771 // Set how many packages have been changed
1773 *changed
= pakfire_transaction_count(transaction
);
1775 // Run the transaction
1776 r
= pakfire_transaction_run(transaction
);
1785 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1786 pakfire_problem_unref(*problem
);
1790 pakfire_transaction_unref(transaction
);
1792 pakfire_request_unref(request
);
1797 PAKFIRE_EXPORT
int pakfire_install(struct pakfire
* pakfire
, int solver_flags
,
1798 const char** packages
, const char** locks
, int flags
, int* changed
) {
1799 return pakfire_perform_transaction(pakfire
, solver_flags
, pakfire_request_install
,
1800 packages
, locks
, flags
, changed
);
1803 PAKFIRE_EXPORT
int pakfire_erase(struct pakfire
* pakfire
, int solver_flags
,
1804 const char** packages
, const char** locks
, int flags
, int* changed
) {
1805 return pakfire_perform_transaction(pakfire
, solver_flags
, pakfire_request_erase
,
1806 packages
, locks
, flags
, changed
);
1809 static int pakfire_perform_transaction_simple(struct pakfire
* pakfire
, int solver_flags
,
1810 int (*action
)(struct pakfire_request
* request
, int flags
),
1811 int job_flags
, int* changed
) {
1812 struct pakfire_request
* request
= NULL
;
1813 struct pakfire_transaction
* transaction
= NULL
;
1814 struct pakfire_problem
** problems
= NULL
;
1817 // Create a new request
1818 r
= pakfire_request_create(&request
, pakfire
, solver_flags
);
1823 r
= action(request
, job_flags
);
1829 // Solve the request
1831 r
= pakfire_request_solve(request
, &transaction
, &problems
);
1842 // Let the user choose a problem
1843 r
= pakfire_ui_pick_solution(pakfire
, request
, problems
);
1848 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1849 pakfire_problem_unref(*problem
);
1853 // Another error occured
1859 // Set how many packages have been changed
1861 *changed
= pakfire_transaction_count(transaction
);
1863 // Run the transaction
1864 r
= pakfire_transaction_run(transaction
);
1873 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1874 pakfire_problem_unref(*problem
);
1878 pakfire_transaction_unref(transaction
);
1880 pakfire_request_unref(request
);
1885 PAKFIRE_EXPORT
int pakfire_update(struct pakfire
* pakfire
, int solver_flags
,
1886 const char** packages
, const char** locks
, int flags
, int* changed
) {
1887 // If no packages are being passed, we will try to update everything
1890 return pakfire_perform_transaction_simple(
1891 pakfire
, solver_flags
, pakfire_request_update_all
, flags
, changed
);
1893 return pakfire_perform_transaction(pakfire
, solver_flags
, pakfire_request_update
,
1894 packages
, locks
, flags
, changed
);
1897 static int pakfire_verify(struct pakfire
* pakfire
, int *changed
) {
1898 return pakfire_perform_transaction_simple(pakfire
, 0, pakfire_request_verify
, 0, changed
);
1901 PAKFIRE_EXPORT
int pakfire_check(struct pakfire
* pakfire
) {
1902 struct pakfire_db
* db
= NULL
;
1905 // Open database in read-only mode and try to load all installed packages
1906 r
= pakfire_db_open(&db
, pakfire
, PAKFIRE_DB_READWRITE
);
1910 // Perform a database integrity check
1911 r
= pakfire_db_check(db
);
1915 // Check if all dependencies are intact
1916 r
= pakfire_verify(pakfire
, NULL
);
1922 pakfire_db_unref(db
);
1927 PAKFIRE_EXPORT
int pakfire_sync(struct pakfire
* pakfire
, int solver_flags
, int flags
, int* changed
) {
1928 return pakfire_perform_transaction_simple(pakfire
, solver_flags
,
1929 pakfire_request_sync
, flags
, changed
);
1934 static int pakfire_build_install_packages(struct pakfire
* pakfire
, int* snapshot_needs_update
) {
1935 char** packages
= NULL
;
1938 // Fetch build environment
1939 const char* requires
= pakfire_config_get(pakfire
->config
, "build", "requires", NULL
);
1941 ERROR(pakfire
, "No build requirements have been defined\n");
1945 // Split requirements into packages
1946 packages
= pakfire_split_string(requires
, ',');
1952 // Install everything
1953 r
= pakfire_install(pakfire
, 0, (const char**)packages
, NULL
, 0, &changed
);
1955 ERROR(pakfire
, "Could not install build dependencies: %m\n");
1959 // Mark snapshot as changed if new packages were installed
1961 *snapshot_needs_update
= 1;
1963 // Update everything
1964 r
= pakfire_sync(pakfire
, 0, 0, &changed
);
1966 ERROR(pakfire
, "Could not update packages: %m\n");
1970 // Has anything changed?
1972 *snapshot_needs_update
= 1;
1979 for (char** package
= packages
; *package
; package
++)
1987 int pakfire_build_setup(struct pakfire
* pakfire
) {
1988 // This function can only be called when in build mode
1989 if (!pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_BUILD
)) {
1994 // Do nothing if build environment has been set up
1995 if (pakfire
->build_setup
)
1998 char path
[PATH_MAX
];
2002 if (!pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_DISABLE_CCACHE
)) {
2003 r
= pakfire_make_cache_path(pakfire
, path
, "%s", "ccache");
2007 // Ensure path exists
2008 r
= pakfire_mkdir(path
, 0);
2009 if (r
&& errno
!= EEXIST
) {
2010 ERROR(pakfire
, "Could not create ccache directory %s: %m\n", path
);
2014 r
= pakfire_bind(pakfire
, path
, CCACHE_DIR
, MS_NOSUID
|MS_NOEXEC
|MS_NODEV
);
2016 ERROR(pakfire
, "Could not mount ccache: %m\n");
2022 if (!pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_DISABLE_SNAPSHOT
)) {
2023 r
= pakfire_make_cache_path(pakfire
, path
, "%s", "snapshot.tar.zst");
2027 // Open the snapshot
2028 FILE* f
= fopen(path
, "r");
2030 // Try restoring the snapshot
2032 r
= pakfire_snapshot_restore(pakfire
, f
);
2039 // Tells us whether we need to (re-)create the snapshot
2040 int snapshot_needs_update
= 0;
2042 // Install or update any build dependencies
2043 r
= pakfire_build_install_packages(pakfire
, &snapshot_needs_update
);
2047 if (snapshot_needs_update
) {
2048 // Open snapshot file for writing
2049 f
= fopen(path
, "w");
2051 ERROR(pakfire
, "Could not open snapshot file for writing: %m\n");
2055 // Create a new snapshot
2056 r
= pakfire_snapshot_create(pakfire
, f
);
2065 pakfire
->build_setup
= 1;