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
{
122 { "RichDependencies" },
125 { "PackageFormat-6" },
126 { "PackageFormat-5" },
129 { "Compress-Zstandard" },
138 int pakfire_on_root(struct pakfire
* pakfire
) {
139 return (strcmp(pakfire
->path
, "/") == 0);
142 static const struct pakfire_mountpoint
{
149 { "pakfire_root", "", "tmpfs", 0, NULL
},
151 { "pakfire_proc", "proc", "proc", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, NULL
},
153 // Bind mount /proc/sys as read-only with the following exceptions:
155 { "/proc/sys", "proc/sys", NULL
, MS_BIND
, NULL
},
156 { "/proc/sys/net", "proc/sys/net", NULL
, MS_BIND
, NULL
},
157 { "/proc/sys", "proc/sys", NULL
, MS_BIND
|MS_RDONLY
|MS_REMOUNT
, NULL
},
159 // Bind mount /sys as read-only
160 { "/sys", "sys", NULL
, MS_BIND
, NULL
},
161 { "/sys", "sys", NULL
, MS_BIND
|MS_RDONLY
|MS_REMOUNT
, NULL
},
164 { "pakfire_dev", "dev", "tmpfs", MS_NOSUID
|MS_NOEXEC
,
165 "mode=755,size=4m,nr_inodes=64k" },
166 { "/dev/pts", "dev/pts", NULL
, MS_BIND
, NULL
},
169 { "pakfire_tmpfs", "run", "tmpfs", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
,
170 "mode=755,size=4m,nr_inodes=1k" },
173 { "pakfire_tmpfs", "tmp", "tmpfs", MS_NOSUID
|MS_NODEV
,
180 static int __mount(struct pakfire
* pakfire
, const char* source
, const char* target
,
181 const char* filesystemtype
, unsigned long mountflags
, const void* data
) {
182 int r
= mount(source
, target
, filesystemtype
, mountflags
, data
);
186 // Skip if the mountpoint is already on the list
187 if (pakfire_is_mountpoint(pakfire
, target
))
190 // If not, add the mountpoint to the list so that we can umount it later
191 struct mountpoint
* mp
= calloc(1, sizeof(*mp
));
195 pakfire_string_set(mp
->path
, target
);
197 STAILQ_INSERT_HEAD(&pakfire
->mountpoints
, mp
, nodes
);
202 static int pakfire_mount(struct pakfire
* pakfire
) {
203 char target
[PATH_MAX
];
206 for (const struct pakfire_mountpoint
* mp
= mountpoints
; mp
->source
; mp
++) {
207 // Skip mounting root when a directory has been passed
208 if (!*mp
->target
&& !pakfire
->mount_tmpfs
)
211 DEBUG(pakfire
, "Mounting /%s\n", mp
->target
);
213 r
= pakfire_path_join(target
, pakfire
->path
, mp
->target
);
219 r
= __mount(pakfire
, mp
->source
, target
, mp
->fstype
, mp
->flags
, mp
->options
);
221 // If the target directory does not exist, we will create it
222 if (errno
== ENOENT
) {
223 r
= pakfire_mkdir(target
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
225 ERROR(pakfire
, "Could not create %s\n", target
);
232 ERROR(pakfire
, "Could not mount /%s: %m\n", mp
->target
);
240 static int pakfire_umount(struct pakfire
* pakfire
) {
241 struct mountpoint
* mp
;
245 while (!STAILQ_EMPTY(&pakfire
->mountpoints
)) {
246 // Take the first element from the list
247 mp
= STAILQ_FIRST(&pakfire
->mountpoints
);
249 // Remove first element
250 STAILQ_REMOVE_HEAD(&pakfire
->mountpoints
, nodes
);
252 DEBUG(pakfire
, "Umounting %s\n", mp
->path
);
259 r
= umount2(mp
->path
, flags
);
262 // Attempt a lazy umount when busy
263 if (errno
== EBUSY
) {
268 ERROR(pakfire
, "Could not umount %s: %m\n", mp
->path
);
277 int pakfire_is_mountpoint(struct pakfire
* pakfire
, const char* path
) {
278 struct mountpoint
* mp
;
280 // Check if path is on this list
281 STAILQ_FOREACH(mp
, &pakfire
->mountpoints
, nodes
) {
282 if (strcmp(mp
->path
, path
) == 0)
289 static const struct pakfire_devnode
{
295 { "/dev/null", 1, 3, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
296 { "/dev/zero", 1, 5, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
297 { "/dev/full", 1, 7, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
298 { "/dev/random", 1, 8, S_IFCHR
|S_IRUSR
|S_IRGRP
|S_IROTH
, },
299 { "/dev/urandom", 1, 9, S_IFCHR
|S_IRUSR
|S_IRGRP
|S_IROTH
, },
300 { "/dev/kmsg", 1, 11, S_IFCHR
|S_IRUSR
|S_IRGRP
|S_IROTH
, },
301 { "/dev/tty", 5, 0, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
302 { "/dev/console", 5, 1, S_IFCHR
|S_IRUSR
|S_IWUSR
, },
303 { "/dev/ptmx", 5, 2, S_IFCHR
|S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
, },
304 { "/dev/rtc0", 252, 0, S_IFCHR
|S_IRUSR
|S_IWUSR
, },
308 static const struct pakfire_symlink
{
312 { "/proc/self/fd", "/dev/fd", },
313 { "/proc/self/fd/0", "/dev/stdin" },
314 { "/proc/self/fd/1", "/dev/stdout" },
315 { "/proc/self/fd/2", "/dev/stderr" },
316 { "/proc/kcore", "/dev/core" },
320 static int pakfire_populate_dev(struct pakfire
* pakfire
) {
323 // Create device nodes
324 for (const struct pakfire_devnode
* devnode
= devnodes
; devnode
->path
; devnode
++) {
325 DEBUG(pakfire
, "Creating device node %s\n", devnode
->path
);
327 int r
= pakfire_make_path(pakfire
, path
, devnode
->path
);
331 dev_t dev
= makedev(devnode
->major
, devnode
->minor
);
333 r
= mknod(path
, devnode
->mode
, dev
);
335 ERROR(pakfire
, "Could not create %s: %m\n", devnode
->path
);
341 for (const struct pakfire_symlink
* s
= symlinks
; s
->target
; s
++) {
342 DEBUG(pakfire
, "Creating symlink %s -> %s\n", s
->path
, s
->target
);
344 int r
= pakfire_make_path(pakfire
, path
, s
->path
);
348 r
= symlink(s
->target
, path
);
350 ERROR(pakfire
, "Could not create symlink %s: %m\n", s
->path
);
358 static void pakfire_log_set_function(struct pakfire
* pakfire
,
359 pakfire_log_function_t log_function
, void* data
) {
360 pakfire
->log_function
= log_function
;
361 pakfire
->log_data
= data
;
364 static int log_priority(const char* priority
) {
367 int prio
= strtol(priority
, &end
, 10);
368 if (*end
== '\0' || isspace(*end
))
371 if (strncmp(priority
, "error", strlen("error")) == 0)
374 if (strncmp(priority
, "info", strlen("info")) == 0)
377 if (strncmp(priority
, "debug", strlen("debug")) == 0)
383 static void pool_log(Pool
* pool
, void* data
, int type
, const char* s
) {
384 struct pakfire
* pakfire
= (struct pakfire
*)data
;
386 DEBUG(pakfire
, "pool: %s", s
);
389 static Id
pakfire_namespace_callback(Pool
* pool
, void* data
, Id ns
, Id id
) {
390 struct pakfire
* pakfire
= (struct pakfire
*)data
;
392 const char* namespace = pool_id2str(pool
, ns
);
393 const char* name
= pakfire_dep2str(pakfire
, id
);
395 DEBUG(pakfire
, "Namespace callback called for %s(%s)\n", namespace, name
);
397 // We only handle the pakfire namesapce
398 if (strcmp(namespace, "pakfire") != 0)
401 // Find all supported features
402 for (const struct pakfire_feature
* feature
= features
; feature
->name
; feature
++) {
403 if (strcmp(feature
->name
, name
) == 0)
411 static int pakfire_populate_pool(struct pakfire
* pakfire
) {
412 struct pakfire_db
* db
;
413 struct pakfire_repo
* commandline
= NULL
;
414 struct pakfire_repo
* dummy
= NULL
;
415 struct pakfire_repo
* system
= NULL
;
418 // Initialize the pool
419 Pool
* pool
= pakfire
->pool
= pool_create();
420 pool_setdisttype(pool
, DISTTYPE_RPM
);
423 // Enable debug output
424 pool_setdebuglevel(pool
, 2);
427 // Set architecture of the pool
428 pool_setarch(pool
, pakfire
->arch
);
431 pool_set_rootdir(pool
, pakfire
->path
);
433 // Set debug callback
434 pool_setdebugcallback(pool
, pool_log
, pakfire
);
436 // Install namespace callback
437 pool_setnamespacecallback(pool
, pakfire_namespace_callback
, pakfire
);
439 // Open database in read-only mode and try to load all installed packages
440 r
= pakfire_db_open(&db
, pakfire
, PAKFIRE_DB_READWRITE
);
444 // Create a dummy repository
445 r
= pakfire_repo_create(&dummy
, pakfire
, PAKFIRE_REPO_DUMMY
);
449 // Disable the repository
450 pakfire_repo_set_enabled(dummy
, 0);
452 // Create the system repository
453 r
= pakfire_repo_create(&system
, pakfire
, PAKFIRE_REPO_SYSTEM
);
457 // Set this repository as the installed one
458 pool_set_installed(pool
, pakfire_repo_get_repo(system
));
460 // Create the command line repo
461 r
= pakfire_repo_create(&commandline
, pakfire
, PAKFIRE_REPO_COMMANDLINE
);
465 // Load database content
466 r
= pakfire_db_load(db
, system
);
472 pakfire_db_unref(db
);
474 pakfire_repo_unref(commandline
);
476 pakfire_repo_unref(dummy
);
478 pakfire_repo_unref(system
);
483 static int pakfire_mount_interpreter(struct pakfire
* pakfire
) {
484 char target
[PATH_MAX
];
486 // Can we emulate this architecture?
487 char* interpreter
= pakfire_arch_find_interpreter(pakfire
->arch
);
489 // No interpreter required
493 DEBUG(pakfire
, "Mounting interpreter %s for %s\n", interpreter
, pakfire
->arch
);
495 // Where to mount this?
496 int r
= pakfire_make_path(pakfire
, target
, interpreter
);
501 r
= pakfire_mkparentdir(target
, 0);
505 // Create an empty file
506 FILE* f
= fopen(target
, "w");
511 r
= __mount(pakfire
, interpreter
, target
, NULL
, MS_BIND
|MS_RDONLY
, NULL
);
513 ERROR(pakfire
, "Could not mount interpreter %s to %s: %m\n", interpreter
, target
);
518 static void pakfire_free(struct pakfire
* pakfire
) {
519 struct pakfire_repo
* repo
= NULL
;
522 // Avoid recursive free
523 if (pakfire
->in_free
++)
526 // Destroy the commandline repository
527 repo
= pakfire_get_repo(pakfire
, PAKFIRE_REPO_COMMANDLINE
);
529 r
= pakfire_repo_clean(repo
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
531 ERROR(pakfire
, "Could not cleanup %s repository: %m\n", PAKFIRE_REPO_COMMANDLINE
);
533 pakfire_repo_unref(repo
);
536 // Release GPGME context
538 pakfire_keystore_destroy(pakfire
, &pakfire
->gpgctx
);
541 pakfire_umount(pakfire
);
543 if (pakfire
->destroy_on_free
&& *pakfire
->path
) {
544 DEBUG(pakfire
, "Destroying %s\n", pakfire
->path
);
546 // Destroy the temporary directory
547 pakfire_rmtree(pakfire
->path
, 0);
550 pakfire_repo_free_all(pakfire
);
553 pool_free(pakfire
->pool
);
556 pakfire_config_unref(pakfire
->config
);
561 // Safety check in case this is being launched on the host system
562 static int pakfire_safety_checks(struct pakfire
* pakfire
) {
563 // Nothing to do if we are not working on root
564 if (!pakfire_on_root(pakfire
))
567 if (strcmp(pakfire
->distro
.id
, "ipfire") != 0) {
568 ERROR(pakfire
, "Not an IPFire system\n");
576 static int pakfire_read_repo_config(struct pakfire
* pakfire
) {
579 int r
= pakfire_make_path(pakfire
, path
, PAKFIRE_CONFIG_DIR
"/repos");
583 DEBUG(pakfire
, "Reading repository configuration from %s\n", path
);
590 FTS
* d
= fts_open(paths
, FTS_NOCHDIR
|FTS_NOSTAT
, NULL
);
595 FTSENT
* fent
= fts_read(d
);
600 if (fent
->fts_info
& FTS_F
) {
601 // Skip everything that doesn't end in .repo
602 if (!pakfire_string_endswith(fent
->fts_name
, ".repo"))
605 DEBUG(pakfire
, "Reading %s\n", fent
->fts_path
);
607 FILE* f
= fopen(fent
->fts_path
, "r");
611 // Parse the configuration file
612 r
= pakfire_config_read(pakfire
->config
, f
);
630 const char* pakfire_get_distro_name(struct pakfire
* pakfire
) {
631 if (*pakfire
->distro
.name
)
632 return pakfire
->distro
.name
;
637 const char* pakfire_get_distro_id(struct pakfire
* pakfire
) {
638 if (*pakfire
->distro
.id
)
639 return pakfire
->distro
.id
;
644 const char* pakfire_get_distro_vendor(struct pakfire
* pakfire
) {
645 if (*pakfire
->distro
.vendor
)
646 return pakfire
->distro
.vendor
;
651 const char* pakfire_get_distro_version(struct pakfire
* pakfire
) {
652 if (*pakfire
->distro
.version
)
653 return pakfire
->distro
.version
;
658 const char* pakfire_get_distro_version_id(struct pakfire
* pakfire
) {
659 if (*pakfire
->distro
.version_id
)
660 return pakfire
->distro
.version_id
;
665 static int pakfire_config_import_distro(struct pakfire
* pakfire
) {
666 // Nothing to do if there is no distro section
667 if (!pakfire_config_has_section(pakfire
->config
, "distro"))
671 const char* name
= pakfire_config_get(pakfire
->config
, "distro", "name", NULL
);
673 pakfire_string_set(pakfire
->distro
.name
, name
);
676 const char* id
= pakfire_config_get(pakfire
->config
, "distro", "id", NULL
);
678 pakfire_string_set(pakfire
->distro
.id
, id
);
681 const char* version_id
= pakfire_config_get(pakfire
->config
, "distro", "version_id", NULL
);
683 pakfire_string_set(pakfire
->distro
.version_id
, version_id
);
686 const char* codename
= pakfire_config_get(pakfire
->config
, "distro", "codename", NULL
);
688 pakfire_string_set(pakfire
->distro
.version_codename
, codename
);
691 if (*pakfire
->distro
.version_codename
)
692 pakfire_string_format(pakfire
->distro
.version
, "%s (%s)",
693 pakfire
->distro
.version_id
, pakfire
->distro
.version_codename
);
695 pakfire_string_set(pakfire
->distro
.version
, pakfire
->distro
.version_id
);
697 // Fill in pretty name
698 pakfire_string_format(pakfire
->distro
.pretty_name
, "%s %s",
699 pakfire
->distro
.name
, pakfire
->distro
.version
);
702 const char* vendor
= pakfire_config_get(pakfire
->config
, "distro", "vendor", NULL
);
704 pakfire_string_set(pakfire
->distro
.vendor
, vendor
);
707 const char* slogan
= pakfire_config_get(pakfire
->config
, "distro", "slogan", NULL
);
709 pakfire_string_set(pakfire
->distro
.slogan
, slogan
);
714 static int pakfire_read_config(struct pakfire
* pakfire
, const char* path
) {
715 char default_path
[PATH_MAX
];
717 // Use default path if none set
719 int r
= pakfire_make_path(pakfire
, default_path
, PAKFIRE_CONFIG_DIR
"/general.conf");
726 DEBUG(pakfire
, "Reading configuration from %s\n", path
);
728 FILE* f
= fopen(path
, "r");
730 // Silently ignore when there is no default configuration file
731 if (*default_path
&& errno
== ENOENT
)
734 ERROR(pakfire
, "Could not open configuration file %s: %m\n", path
);
738 // Read configuration from file
739 int r
= pakfire_config_read(pakfire
->config
, f
);
741 ERROR(pakfire
, "Could not parse configuration file %s: %m\n", path
);
745 // Import distro configuration
746 r
= pakfire_config_import_distro(pakfire
);
750 // Read repository configuration
751 r
= pakfire_read_repo_config(pakfire
);
761 static int pakfire_read_os_release(struct pakfire
* pakfire
) {
766 int r
= pakfire_make_path(pakfire
, path
, "/etc/os-release");
772 FILE* f
= fopen(path
, "r");
774 // Ignore when the file does not exist
775 if (errno
== ENOENT
) {
780 ERROR(pakfire
, "Could not open %s: %m\n", path
);
785 ssize_t bytes_read
= getline(&line
, &l
, f
);
789 // Remove trailing newline
790 pakfire_remove_trailing_newline(line
);
793 char* delim
= strchr(line
, '=');
800 // Set key and val to the start of the strings
802 char* val
= delim
+ 1;
805 val
= pakfire_unquote_in_place(val
);
807 if (strcmp(key
, "PRETTY_NAME") == 0)
808 r
= pakfire_string_set(pakfire
->distro
.pretty_name
, val
);
809 else if (strcmp(key
, "NAME") == 0)
810 r
= pakfire_string_set(pakfire
->distro
.name
, val
);
811 else if (strcmp(key
, "ID") == 0)
812 r
= pakfire_string_set(pakfire
->distro
.id
, val
);
813 else if (strcmp(key
, "VERSION") == 0)
814 r
= pakfire_string_set(pakfire
->distro
.version
, val
);
815 else if (strcmp(key
, "VERSION_CODENAME") == 0)
816 r
= pakfire_string_set(pakfire
->distro
.version_codename
, val
);
817 else if (strcmp(key
, "VERSION_ID") == 0)
818 r
= pakfire_string_set(pakfire
->distro
.version_id
, val
);
839 PAKFIRE_EXPORT
int pakfire_create(struct pakfire
** pakfire
, const char* path
,
840 const char* arch
, const char* conf
, int flags
, pakfire_log_function_t log
,
842 char tempdir
[PATH_MAX
] = PAKFIRE_TMP_DIR
"/XXXXXX";
845 // Reset pakfire pointer
848 // Default to the native architecture
850 arch
= pakfire_arch_native();
852 // Check if the architecture is supported
853 if (!pakfire_arch_supported(arch
)) {
858 // Path must be absolute
859 if (path
&& !pakfire_string_startswith(path
, "/")) {
864 // Check if we are running as root
865 uid_t uid
= getuid();
871 struct pakfire
* p
= calloc(1, sizeof(*p
));
879 pakfire_string_set(p
->arch
, arch
);
883 pakfire_log_set_function(p
, log
, data
);
885 pakfire_log_set_function(p
, pakfire_log_syslog
, NULL
);
887 const char* env
= secure_getenv("PAKFIRE_LOG");
889 pakfire_log_set_priority(p
, log_priority(env
));
891 // Initialise configuration
892 r
= pakfire_config_create(&p
->config
);
896 // Generate a random path if none is set
898 path
= pakfire_mkdtemp(tempdir
);
902 // Mount this as tmpfs
903 p
->mount_tmpfs
= !pakfire_has_flag(p
, PAKFIRE_FLAGS_DISABLE_RAMDISK
);
905 // Destroy everything when done
906 p
->destroy_on_free
= 1;
910 pakfire_string_set(p
->path
, path
);
912 // Read /etc/os-release
913 r
= pakfire_read_os_release(p
);
914 if (r
&& errno
!= ENOENT
)
917 // Bump RLIMIT_NOFILE to maximum
918 r
= pakfire_rlimit_set(p
, PAKFIRE_RLIMIT_NOFILE_MAX
);
922 DEBUG(p
, "Pakfire initialized at %p\n", p
);
923 DEBUG(p
, " arch = %s\n", pakfire_get_arch(p
));
924 DEBUG(p
, " path = %s\n", pakfire_get_path(p
));
926 // Automatically disable interactive mode
927 if (!pakfire_has_flag(p
, PAKFIRE_FLAGS_NON_INTERACTIVE
)) {
928 if (pakfire_tty_is_noninteractive()) {
929 DEBUG(p
, "Interactive mode disabled\n");
931 flags
|= PAKFIRE_FLAGS_NON_INTERACTIVE
;
935 // Perform some safety checks
936 r
= pakfire_safety_checks(p
);
940 // Read configuration file
941 r
= pakfire_read_config(p
, conf
);
945 // Dump distribution configuration
946 DEBUG(p
, " Distribution: %s\n", p
->distro
.pretty_name
);
947 DEBUG(p
, " name = %s\n", p
->distro
.name
);
948 DEBUG(p
, " id = %s\n", p
->distro
.id
);
949 DEBUG(p
, " version = %s\n", p
->distro
.version
);
950 DEBUG(p
, " version_id = %s\n", p
->distro
.version_id
);
951 if (*p
->distro
.version_codename
)
952 DEBUG(p
, " codename = %s\n", p
->distro
.version_codename
);
953 if (*p
->distro
.vendor
)
954 DEBUG(p
, " vendor = %s\n", p
->distro
.vendor
);
955 if (*p
->distro
.slogan
)
956 DEBUG(p
, " slogan = %s\n", p
->distro
.slogan
);
959 pakfire_string_format(p
->cache_path
, "%s/%s/%s/%s",
960 PAKFIRE_CACHE_DIR
, p
->distro
.id
, p
->distro
.version_id
, p
->arch
);
963 r
= pakfire_make_path(p
, p
->keystore_path
, KEYSTORE_DIR
);
965 ERROR(p
, "Could not set keystore path: %m\n");
970 r
= pakfire_mount(p
);
975 r
= pakfire_populate_dev(p
);
979 // Mount the interpreter (if needed)
980 r
= pakfire_mount_interpreter(p
);
984 // Make path for private files
985 char private_dir
[PATH_MAX
];
986 r
= pakfire_make_path(p
, private_dir
, PAKFIRE_PRIVATE_DIR
);
990 // Make sure that our private directory exists
991 r
= pakfire_mkdir(private_dir
, 0);
992 if (r
&& errno
!= EEXIST
) {
993 ERROR(p
, "Could not create private directory %s: %m\n", private_dir
);
997 // Initialize keystore
998 r
= pakfire_keystore_init(p
, &p
->gpgctx
);
1003 r
= pakfire_populate_pool(p
);
1007 // Create repositories
1008 r
= pakfire_repo_import(p
, p
->config
);
1012 // Setup build stuff
1013 if (pakfire_has_flag(p
, PAKFIRE_FLAGS_BUILD
)) {
1014 // Builds are never interactive
1015 p
->flags
|= PAKFIRE_FLAGS_NON_INTERACTIVE
;
1028 PAKFIRE_EXPORT
struct pakfire
* pakfire_ref(struct pakfire
* pakfire
) {
1034 PAKFIRE_EXPORT
struct pakfire
* pakfire_unref(struct pakfire
* pakfire
) {
1035 if (--pakfire
->nrefs
> 0)
1038 pakfire_free(pakfire
);
1043 int pakfire_has_flag(struct pakfire
* pakfire
, int flag
) {
1044 return pakfire
->flags
& flag
;
1047 struct pakfire_config
* pakfire_get_config(struct pakfire
* pakfire
) {
1048 if (!pakfire
->config
)
1051 return pakfire_config_ref(pakfire
->config
);
1054 PAKFIRE_EXPORT
const char* pakfire_get_path(struct pakfire
* pakfire
) {
1055 return pakfire
->path
;
1058 const char* pakfire_get_keystore_path(struct pakfire
* pakfire
) {
1059 return pakfire
->keystore_path
;
1062 int __pakfire_make_path(struct pakfire
* pakfire
, char* dst
, size_t length
, const char* path
) {
1063 // Make sure that path never starts with /
1064 while (path
&& *path
== '/')
1067 return __pakfire_path_join(dst
, length
, pakfire
->path
, path
);
1070 PAKFIRE_EXPORT
int pakfire_bind(struct pakfire
* pakfire
, const char* src
, const char* dst
, int flags
) {
1072 char mountpoint
[PATH_MAX
];
1077 int r
= pakfire_make_path(pakfire
, mountpoint
, dst
);
1081 DEBUG(pakfire
, "Mounting %s to %s\n", src
, mountpoint
);
1085 ERROR(pakfire
, "Could not stat %s: %m\n", src
);
1089 // Make sure the mountpoint exists
1090 switch (st
.st_mode
& S_IFMT
) {
1092 r
= pakfire_mkdir(mountpoint
, 0);
1093 if (r
&& errno
!= EEXIST
)
1099 // Make parent directory
1100 r
= pakfire_mkparentdir(mountpoint
, 0);
1105 FILE* f
= fopen(mountpoint
, "w");
1117 return __mount(pakfire
, src
, mountpoint
, NULL
, flags
|MS_BIND
, NULL
);
1120 gpgme_ctx_t
pakfire_get_gpgctx(struct pakfire
* pakfire
) {
1121 return pakfire
->gpgctx
;
1124 PAKFIRE_EXPORT
int pakfire_list_keys(struct pakfire
* pakfire
, struct pakfire_key
*** keys
) {
1128 // Fetch GPGME context
1129 gpgme_ctx_t gpgctx
= pakfire_get_gpgctx(pakfire
);
1133 struct pakfire_key
* key
= NULL
;
1134 gpgme_key_t gpgkey
= NULL
;
1138 // Iterate over all keys and import them to the list
1139 gpgme_error_t e
= gpgme_op_keylist_start(gpgctx
, NULL
, 0);
1144 e
= gpgme_op_keylist_next(gpgctx
, &gpgkey
);
1149 r
= pakfire_key_create(&key
, pakfire
, gpgkey
);
1150 gpgme_key_unref(gpgkey
);
1155 *keys
= reallocarray(*keys
, length
+ 2, sizeof(**keys
));
1161 // Store key in array
1162 (*keys
)[length
++] = key
;
1164 // Terminate the array
1165 (*keys
)[length
] = NULL
;
1173 for (struct pakfire_key
** key
= *keys
; *key
; key
++)
1174 pakfire_key_unref(*key
);
1182 static int pakfire_foreach_repo(struct pakfire
* pakfire
,
1183 int (*func
)(struct pakfire_repo
* repo
, int flags
), int flags
) {
1184 struct pakfire_repo
* repo
;
1190 Pool
* pool
= pakfire
->pool
;
1192 // Run func for every repository
1193 FOR_REPOS(i
, solv_repo
) {
1194 repo
= pakfire_repo_create_from_repo(pakfire
, solv_repo
);
1199 r
= func(repo
, flags
);
1200 pakfire_repo_unref(repo
);
1210 PAKFIRE_EXPORT
int pakfire_clean(struct pakfire
* pakfire
, int flags
) {
1213 // Clean all repositories
1214 r
= pakfire_foreach_repo(pakfire
, pakfire_repo_clean
, flags
);
1218 // Clean build environments
1219 // Nothing to do if we are not in build mode
1220 if (pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_BUILD
)) {
1221 r
= pakfire_build_clean(pakfire
, flags
);
1227 return pakfire_rmtree(PAKFIRE_CACHE_DIR
, 0);
1230 PAKFIRE_EXPORT
int pakfire_refresh(struct pakfire
* pakfire
, int flags
) {
1231 return pakfire_foreach_repo(pakfire
, pakfire_repo_refresh
, flags
);
1234 static int pakfire_copy(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1235 char buffer
[512 * 1024];
1236 struct archive
* reader
= NULL
;
1237 struct archive
* writer
= NULL
;
1238 struct archive_entry
* entry
= NULL
;
1243 reader
= archive_read_disk_new();
1248 writer
= archive_write_disk_new();
1252 // Create a new entry
1253 entry
= archive_entry_new();
1257 // Set the source path
1258 archive_entry_copy_sourcepath(entry
, src
);
1260 // Read everything from source file
1261 r
= archive_read_disk_entry_from_file(reader
, entry
, -1, NULL
);
1263 ERROR(pakfire
, "Could not read from %s: %m", src
);
1267 // Set the destination path
1268 archive_entry_set_pathname(entry
, dst
);
1270 // Write file to destination
1271 r
= archive_write_header(writer
, entry
);
1273 ERROR(pakfire
, "Could not write %s: %m\n", dst
);
1278 if (archive_entry_filetype(entry
) == AE_IFREG
) {
1279 f
= fopen(src
, "r");
1284 size_t bytes_read
= fread(buffer
, 1, sizeof(buffer
), f
);
1286 // Check if any error occured
1288 ERROR(pakfire
, "Error reading from file: %m\n");
1292 ssize_t bytes_written
= archive_write_data(writer
, buffer
, bytes_read
);
1293 if (bytes_written
< 0) {
1294 ERROR(pakfire
, "Error writing data: %s\n", archive_error_string(writer
));
1304 archive_entry_free(entry
);
1306 archive_read_free(reader
);
1308 archive_write_free(writer
);
1313 PAKFIRE_EXPORT
int pakfire_copy_in(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1314 if (pakfire_on_root(pakfire
)) {
1319 char path
[PATH_MAX
];
1320 int r
= pakfire_make_path(pakfire
, path
, dst
);
1324 return pakfire_copy(pakfire
, src
, path
);
1327 PAKFIRE_EXPORT
int pakfire_copy_out(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1328 if (pakfire_on_root(pakfire
)) {
1333 char path
[PATH_MAX
];
1334 int r
= pakfire_make_path(pakfire
, path
, src
);
1338 return pakfire_copy(pakfire
, path
, dst
);
1341 PAKFIRE_EXPORT
const char* pakfire_get_arch(struct pakfire
* pakfire
) {
1342 return pakfire
->arch
;
1345 PAKFIRE_EXPORT
int pakfire_version_compare(struct pakfire
* pakfire
, const char* evr1
, const char* evr2
) {
1346 return pool_evrcmp_str(pakfire
->pool
, evr1
, evr2
, EVRCMP_COMPARE
);
1349 Pool
* pakfire_get_solv_pool(struct pakfire
* pakfire
) {
1350 return pakfire
->pool
;
1353 void pakfire_pool_has_changed(struct pakfire
* pakfire
) {
1354 pakfire
->pool_ready
= 0;
1357 void pakfire_pool_internalize(struct pakfire
* pakfire
) {
1358 // Nothing to do if the pool is ready
1359 if (pakfire
->pool_ready
)
1362 // Internalize all repositories
1363 pakfire_foreach_repo(pakfire
, pakfire_repo_internalize
, 0);
1365 // Create fileprovides
1366 pool_addfileprovides(pakfire
->pool
);
1368 // Create whatprovides index
1369 pool_createwhatprovides(pakfire
->pool
);
1371 // Mark the pool as ready
1372 pakfire
->pool_ready
= 1;
1375 PAKFIRE_EXPORT
struct pakfire_repolist
* pakfire_get_repos(struct pakfire
* pakfire
) {
1376 struct pakfire_repolist
* list
;
1378 int r
= pakfire_repolist_create(&list
);
1382 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
1386 FOR_REPOS(i
, solv_repo
) {
1387 // Skip the dummy repository
1388 if (strcmp(solv_repo
->name
, PAKFIRE_REPO_DUMMY
) == 0)
1391 struct pakfire_repo
* repo
= pakfire_repo_create_from_repo(pakfire
, solv_repo
);
1397 r
= pakfire_repolist_append(list
, repo
);
1399 pakfire_repo_unref(repo
);
1403 pakfire_repo_unref(repo
);
1409 pakfire_repolist_unref(list
);
1413 PAKFIRE_EXPORT
struct pakfire_repo
* pakfire_get_repo(struct pakfire
* pakfire
, const char* name
) {
1414 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
1421 FOR_REPOS(i
, repo
) {
1422 if (strcmp(repo
->name
, name
) == 0)
1423 return pakfire_repo_create_from_repo(pakfire
, repo
);
1430 struct pakfire_repo
* pakfire_get_installed_repo(struct pakfire
* pakfire
) {
1431 if (!pakfire
->pool
->installed
)
1434 return pakfire_repo_create_from_repo(pakfire
, pakfire
->pool
->installed
);
1437 static int pakfire_search_dep(struct pakfire
* pakfire
, Id type
, const char* what
, int flags
,
1438 struct pakfire_packagelist
** list
) {
1441 // Get the pool ready
1442 pakfire_pool_internalize(pakfire
);
1444 // Translate dependency to ID
1445 Id dep
= pakfire_str2dep(pakfire
, what
);
1455 queue_init(&matches
);
1457 // Search for anything that matches
1458 pool_whatmatchesdep(pakfire
->pool
, type
, dep
, &matches
, 0);
1460 // Create a packagelist
1461 r
= pakfire_packagelist_create_from_queue(list
, pakfire
, &matches
);
1466 pakfire_packagelist_sort(*list
);
1469 queue_free(&matches
);
1474 PAKFIRE_EXPORT
int pakfire_whatprovides(struct pakfire
* pakfire
, const char* what
, int flags
,
1475 struct pakfire_packagelist
** list
) {
1476 return pakfire_search_dep(pakfire
, SOLVABLE_PROVIDES
, what
, flags
, list
);
1479 PAKFIRE_EXPORT
int pakfire_whatrequires(struct pakfire
* pakfire
, const char* what
, int flags
,
1480 struct pakfire_packagelist
** list
) {
1481 return pakfire_search_dep(pakfire
, SOLVABLE_REQUIRES
, what
, flags
, list
);
1484 PAKFIRE_EXPORT
int pakfire_search(struct pakfire
* pakfire
, const char* what
, int flags
,
1485 struct pakfire_packagelist
** list
) {
1491 // Get the pool ready
1492 pakfire_pool_internalize(pakfire
);
1494 // Initialize the result queue
1495 queue_init(&matches
);
1497 if (flags
& PAKFIRE_SEARCH_NAME_ONLY
)
1498 dflags
= SEARCH_STRING
|SEARCH_GLOB
;
1500 dflags
= SEARCH_SUBSTRING
|SEARCH_NOCASE
|SEARCH_GLOB
;
1502 // Setup the data interator
1503 dataiterator_init(&di
, pakfire
->pool
, 0, 0, 0, what
, dflags
);
1508 SOLVABLE_DESCRIPTION
,
1512 // Search through these keys and add matches to the queue
1513 for (const Id
* key
= keys
; *key
; key
++) {
1514 dataiterator_set_keyname(&di
, *key
);
1515 dataiterator_set_search(&di
, 0, 0);
1517 while (dataiterator_step(&di
))
1518 queue_pushunique(&matches
, di
.solvid
);
1521 if (flags
& PAKFIRE_SEARCH_NAME_ONLY
)
1525 // Convert matches to package list
1526 r
= pakfire_packagelist_create_from_queue(list
, pakfire
, &matches
);
1531 pakfire_packagelist_sort(*list
);
1534 dataiterator_free(&di
);
1535 queue_free(&matches
);
1542 int __pakfire_make_cache_path(struct pakfire
* pakfire
, char* path
, size_t length
,
1543 const char* format
, ...) {
1547 ssize_t l
= snprintf(path
, length
- 1, "%s/", pakfire
->cache_path
);
1551 // We have run out of space
1552 if ((size_t)l
>= length
)
1555 // Append everything after the format string
1558 va_start(args
, format
);
1559 vsnprintf(path
, length
- l
- 1, format
, args
);
1565 PAKFIRE_EXPORT
int pakfire_log_get_priority(struct pakfire
* pakfire
) {
1566 return pakfire
->log_priority
;
1569 PAKFIRE_EXPORT
void pakfire_log_set_priority(struct pakfire
* pakfire
, int priority
) {
1570 pakfire
->log_priority
= priority
;
1573 void pakfire_log(struct pakfire
* pakfire
, int priority
, const char* file
, int line
,
1574 const char* fn
, const char* format
, ...) {
1578 int saved_errno
= errno
;
1580 va_start(args
, format
);
1581 pakfire
->log_function(pakfire
->log_data
, priority
, file
, line
, fn
, format
, args
);
1585 errno
= saved_errno
;
1588 static const char* pakfire_user_lookup(void* data
, la_int64_t uid
) {
1589 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1591 // Fast path for "root"
1595 // Find a matching entry in /etc/passwd
1596 struct passwd
* entry
= pakfire_getpwuid(pakfire
, uid
);
1598 ERROR(pakfire
, "Could not retrieve uname for %ld: %m\n", uid
);
1602 DEBUG(pakfire
, "Mapping UID %ld to %s\n", uid
, entry
->pw_name
);
1604 return entry
->pw_name
;
1607 static const char* pakfire_group_lookup(void* data
, la_int64_t gid
) {
1608 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1610 // Fast path for "root"
1614 // Find a matching entry in /etc/group
1615 struct group
* entry
= pakfire_getgrgid(pakfire
, gid
);
1617 ERROR(pakfire
, "Could not retrieve gname for %ld: %m\n", gid
);
1621 DEBUG(pakfire
, "Mapping GID %ld to %s\n", gid
, entry
->gr_name
);
1623 return entry
->gr_name
;
1626 struct archive
* pakfire_make_archive_disk_reader(struct pakfire
* pakfire
, int internal
) {
1627 struct archive
* archive
= archive_read_disk_new();
1631 // Do not read fflags
1632 int r
= archive_read_disk_set_behavior(archive
, ARCHIVE_READDISK_NO_FFLAGS
);
1634 ERROR(pakfire
, "Could not change behavior of reader: %s\n",
1635 archive_error_string(archive
));
1636 archive_read_free(archive
);
1640 // Install user/group lookups
1642 archive_read_disk_set_uname_lookup(archive
, pakfire
, pakfire_user_lookup
, NULL
);
1643 archive_read_disk_set_gname_lookup(archive
, pakfire
, pakfire_group_lookup
, NULL
);
1645 archive_read_disk_set_standard_lookup(archive
);
1651 static la_int64_t
pakfire_uid_lookup(void* data
, const char* name
, la_int64_t uid
) {
1652 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1654 // Fast path for "root"
1655 if (strcmp(name
, "root") == 0)
1658 // Find a matching entry in /etc/passwd
1659 struct passwd
* entry
= pakfire_getpwnam(pakfire
, name
);
1661 ERROR(pakfire
, "Could not retrieve UID for '%s': %m\n", name
);
1665 DEBUG(pakfire
, "Mapping %s to UID %d\n", name
, entry
->pw_uid
);
1667 return entry
->pw_uid
;
1670 static la_int64_t
pakfire_gid_lookup(void* data
, const char* name
, la_int64_t uid
) {
1671 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1673 // Fast path for "root"
1674 if (strcmp(name
, "root") == 0)
1677 // Find a matching entry in /etc/group
1678 struct group
* entry
= pakfire_getgrnam(pakfire
, name
);
1680 ERROR(pakfire
, "Could not retrieve GID for '%s': %m\n", name
);
1684 DEBUG(pakfire
, "Mapping %s to GID %d\n", name
, entry
->gr_gid
);
1686 return entry
->gr_gid
;
1689 struct archive
* pakfire_make_archive_disk_writer(struct pakfire
* pakfire
) {
1690 struct archive
* archive
= archive_write_disk_new();
1694 // Set flags for extracting files
1696 ARCHIVE_EXTRACT_ACL
|
1697 ARCHIVE_EXTRACT_OWNER
|
1698 ARCHIVE_EXTRACT_PERM
|
1699 ARCHIVE_EXTRACT_TIME
|
1700 ARCHIVE_EXTRACT_UNLINK
|
1701 ARCHIVE_EXTRACT_XATTR
|
1702 ARCHIVE_EXTRACT_SECURE_SYMLINKS
;
1704 archive_write_disk_set_options(archive
, flags
);
1706 // Install our own routine for user/group lookups
1707 archive_write_disk_set_user_lookup(archive
, pakfire
, pakfire_uid_lookup
, NULL
);
1708 archive_write_disk_set_group_lookup(archive
, pakfire
, pakfire_gid_lookup
, NULL
);
1713 // Convenience functions to install/erase/update packages
1715 static int pakfire_perform_transaction(struct pakfire
* pakfire
, int solver_flags
,
1716 int (*action
)(struct pakfire_request
* request
, const char* what
, int flags
),
1717 const char** packages
, const char** locks
, int job_flags
, int* changed
) {
1718 struct pakfire_request
* request
= NULL
;
1719 struct pakfire_transaction
* transaction
= NULL
;
1720 struct pakfire_problem
** problems
= NULL
;
1723 // Packages cannot be NULL
1729 // Create a new request
1730 r
= pakfire_request_create(&request
, pakfire
, solver_flags
);
1734 // Lock anything that should be locked
1736 for (const char** lock
= locks
; *lock
; lock
++) {
1737 r
= pakfire_request_lock(request
, *lock
);
1739 ERROR(pakfire
, "Could not lock '%s': %m\n", *lock
);
1745 // Perform action on all packages
1746 for (const char** package
= packages
; *package
; package
++) {
1747 r
= action(request
, *package
, job_flags
);
1749 ERROR(pakfire
, "Could not find '%s': %m\n", *package
);
1756 // Solve the request
1758 r
= pakfire_request_solve(request
, &transaction
, &problems
);
1769 // Let the user choose a problem
1770 r
= pakfire_ui_pick_solution(pakfire
, request
, problems
);
1775 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1776 pakfire_problem_unref(*problem
);
1780 // Another error occured
1786 // Set how many packages have been changed
1788 *changed
= pakfire_transaction_count(transaction
);
1790 // Run the transaction
1791 r
= pakfire_transaction_run(transaction
);
1800 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1801 pakfire_problem_unref(*problem
);
1805 pakfire_transaction_unref(transaction
);
1807 pakfire_request_unref(request
);
1812 PAKFIRE_EXPORT
int pakfire_install(struct pakfire
* pakfire
, int solver_flags
,
1813 const char** packages
, const char** locks
, int flags
, int* changed
) {
1814 return pakfire_perform_transaction(pakfire
, solver_flags
, pakfire_request_install
,
1815 packages
, locks
, flags
, changed
);
1818 PAKFIRE_EXPORT
int pakfire_erase(struct pakfire
* pakfire
, int solver_flags
,
1819 const char** packages
, const char** locks
, int flags
, int* changed
) {
1820 return pakfire_perform_transaction(pakfire
, solver_flags
, pakfire_request_erase
,
1821 packages
, locks
, flags
, changed
);
1824 static int pakfire_perform_transaction_simple(struct pakfire
* pakfire
, int solver_flags
,
1825 int (*action
)(struct pakfire_request
* request
, int flags
),
1826 int job_flags
, int* changed
) {
1827 struct pakfire_request
* request
= NULL
;
1828 struct pakfire_transaction
* transaction
= NULL
;
1829 struct pakfire_problem
** problems
= NULL
;
1832 // Create a new request
1833 r
= pakfire_request_create(&request
, pakfire
, solver_flags
);
1838 r
= action(request
, job_flags
);
1844 // Solve the request
1846 r
= pakfire_request_solve(request
, &transaction
, &problems
);
1857 // Let the user choose a problem
1858 r
= pakfire_ui_pick_solution(pakfire
, request
, problems
);
1863 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1864 pakfire_problem_unref(*problem
);
1868 // Another error occured
1874 // Set how many packages have been changed
1876 *changed
= pakfire_transaction_count(transaction
);
1878 // Run the transaction
1879 r
= pakfire_transaction_run(transaction
);
1888 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1889 pakfire_problem_unref(*problem
);
1893 pakfire_transaction_unref(transaction
);
1895 pakfire_request_unref(request
);
1900 PAKFIRE_EXPORT
int pakfire_update(struct pakfire
* pakfire
, int solver_flags
,
1901 const char** packages
, const char** locks
, int flags
, int* changed
) {
1902 // If no packages are being passed, we will try to update everything
1905 return pakfire_perform_transaction_simple(
1906 pakfire
, solver_flags
, pakfire_request_update_all
, flags
, changed
);
1908 return pakfire_perform_transaction(pakfire
, solver_flags
, pakfire_request_update
,
1909 packages
, locks
, flags
, changed
);
1912 static int pakfire_verify(struct pakfire
* pakfire
, int *changed
) {
1913 return pakfire_perform_transaction_simple(pakfire
, 0, pakfire_request_verify
, 0, changed
);
1916 PAKFIRE_EXPORT
int pakfire_check(struct pakfire
* pakfire
) {
1917 struct pakfire_db
* db
= NULL
;
1920 // Open database in read-only mode and try to load all installed packages
1921 r
= pakfire_db_open(&db
, pakfire
, PAKFIRE_DB_READWRITE
);
1925 // Perform a database integrity check
1926 r
= pakfire_db_check(db
);
1930 // Check if all dependencies are intact
1931 r
= pakfire_verify(pakfire
, NULL
);
1937 pakfire_db_unref(db
);
1942 PAKFIRE_EXPORT
int pakfire_sync(struct pakfire
* pakfire
, int solver_flags
, int flags
, int* changed
) {
1943 return pakfire_perform_transaction_simple(pakfire
, solver_flags
,
1944 pakfire_request_sync
, flags
, changed
);
1949 static int pakfire_build_install_packages(struct pakfire
* pakfire
, int* snapshot_needs_update
) {
1950 char** packages
= NULL
;
1953 // Fetch build environment
1954 const char* requires
= pakfire_config_get(pakfire
->config
, "build", "requires", NULL
);
1956 ERROR(pakfire
, "No build requirements have been defined\n");
1960 // Split requirements into packages
1961 packages
= pakfire_split_string(requires
, ',');
1967 // Install everything
1968 r
= pakfire_install(pakfire
, 0, (const char**)packages
, NULL
, 0, &changed
);
1970 ERROR(pakfire
, "Could not install build dependencies: %m\n");
1974 // Mark snapshot as changed if new packages were installed
1976 *snapshot_needs_update
= 1;
1978 // Update everything
1979 r
= pakfire_sync(pakfire
, 0, 0, &changed
);
1981 ERROR(pakfire
, "Could not update packages: %m\n");
1985 // Has anything changed?
1987 *snapshot_needs_update
= 1;
1994 for (char** package
= packages
; *package
; package
++)
2002 int pakfire_build_setup(struct pakfire
* pakfire
) {
2003 // This function can only be called when in build mode
2004 if (!pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_BUILD
)) {
2009 // Do nothing if build environment has been set up
2010 if (pakfire
->build_setup
)
2013 char path
[PATH_MAX
];
2017 if (!pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_DISABLE_CCACHE
)) {
2018 r
= pakfire_make_cache_path(pakfire
, path
, "%s", "ccache");
2022 // Ensure path exists
2023 r
= pakfire_mkdir(path
, 0);
2024 if (r
&& errno
!= EEXIST
) {
2025 ERROR(pakfire
, "Could not create ccache directory %s: %m\n", path
);
2029 r
= pakfire_bind(pakfire
, path
, CCACHE_DIR
, MS_NOSUID
|MS_NOEXEC
|MS_NODEV
);
2031 ERROR(pakfire
, "Could not mount ccache: %m\n");
2037 if (!pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_DISABLE_SNAPSHOT
)) {
2038 r
= pakfire_make_cache_path(pakfire
, path
, "%s", "snapshot.tar.zst");
2042 // Open the snapshot
2043 FILE* f
= fopen(path
, "r");
2045 // Try restoring the snapshot
2047 r
= pakfire_snapshot_restore(pakfire
, f
);
2054 // Tells us whether we need to (re-)create the snapshot
2055 int snapshot_needs_update
= 0;
2057 // Install or update any build dependencies
2058 r
= pakfire_build_install_packages(pakfire
, &snapshot_needs_update
);
2062 if (snapshot_needs_update
) {
2063 // Open snapshot file for writing
2064 f
= fopen(path
, "w");
2066 ERROR(pakfire
, "Could not open snapshot file for writing: %m\n");
2070 // Create a new snapshot
2071 r
= pakfire_snapshot_create(pakfire
, f
);
2080 pakfire
->build_setup
= 1;