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>
29 #include <sys/mount.h>
31 #include <sys/types.h>
36 #include <archive_entry.h>
39 #include <solv/pool.h>
40 #include <solv/poolarch.h>
41 #include <solv/queue.h>
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>
64 #define KEYSTORE_DIR "/etc/pakfire/trusted.keys.d"
65 #define LOCK_PATH PAKFIRE_PRIVATE_DIR "/.lock"
71 char lock_path
[PATH_MAX
];
72 char cache_path
[PATH_MAX
];
74 char keystore_path
[PATH_MAX
];
81 // UID/GID of running user
86 struct pakfire_subid subuid
;
87 struct pakfire_subid subgid
;
93 struct pakfire_callbacks
{
95 pakfire_log_callback log
;
99 pakfire_confirm_callback confirm
;
106 struct pakfire_config
* config
;
108 struct pakfire_distro
{
109 char pretty_name
[256];
115 char version_codename
[32];
123 int destroy_on_free
:1;
129 This is a list of all features that are supported by this version of Pakfire
131 static const struct pakfire_feature
{
134 { "RichDependencies" },
137 { "PackageFormat-6" },
138 { "PackageFormat-5" },
141 { "Compress-Zstandard" },
151 int pakfire_on_root(struct pakfire
* pakfire
) {
152 return (strcmp(pakfire
->path
, "/") == 0);
155 const struct pakfire_subid
* pakfire_subuid(struct pakfire
* pakfire
) {
156 return &pakfire
->subuid
;
159 const struct pakfire_subid
* pakfire_subgid(struct pakfire
* pakfire
) {
160 return &pakfire
->subgid
;
164 Maps any UID/GIDs to the SUBUID/SUBGIDs so that we can transparently
165 copy files in and out of the jail environment.
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
))
174 unsigned int mapped_id
= subid
->id
+ id
;
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
;
182 DEBUG(pakfire
, "Mapping UID/GID %u to %u\n", id
, mapped_id
);
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
))
194 int unmapped_id
= id
- subid
->id
;
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
;
202 DEBUG(pakfire
, "Mapping UID/GID %d from %d\n", unmapped_id
, id
);
207 static int log_priority(const char* priority
) {
210 int prio
= strtol(priority
, &end
, 10);
211 if (*end
== '\0' || isspace(*end
))
214 if (strncmp(priority
, "error", strlen("error")) == 0)
217 if (strncmp(priority
, "info", strlen("info")) == 0)
220 if (strncmp(priority
, "debug", strlen("debug")) == 0)
226 static void pool_log(Pool
* pool
, void* data
, int type
, const char* s
) {
227 struct pakfire
* pakfire
= (struct pakfire
*)data
;
229 DEBUG(pakfire
, "pool: %s", s
);
232 static Id
pakfire_namespace_callback(Pool
* pool
, void* data
, Id ns
, Id id
) {
233 struct pakfire
* pakfire
= (struct pakfire
*)data
;
235 const char* namespace = pool_id2str(pool
, ns
);
236 const char* name
= pakfire_dep2str(pakfire
, id
);
238 DEBUG(pakfire
, "Namespace callback called for %s(%s)\n", namespace, name
);
240 // We only handle the pakfire namesapce
241 if (strcmp(namespace, "pakfire") != 0)
244 // Find all supported features
245 for (const struct pakfire_feature
* feature
= features
; feature
->name
; feature
++) {
246 if (strcmp(feature
->name
, name
) == 0)
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
;
261 // Initialize the pool
262 Pool
* pool
= pakfire
->pool
= pool_create();
263 pool_setdisttype(pool
, DISTTYPE_RPM
);
266 // Enable debug output
267 pool_setdebuglevel(pool
, 3);
270 // Set architecture of the pool
271 pool_setarch(pool
, pakfire
->arch
);
274 pool_set_rootdir(pool
, pakfire
->path
);
276 // Set debug callback
277 pool_setdebugcallback(pool
, pool_log
, pakfire
);
279 // Install namespace callback
280 pool_setnamespacecallback(pool
, pakfire_namespace_callback
, pakfire
);
282 // Open database in read-only mode and try to load all installed packages
283 r
= pakfire_db_open(&db
, pakfire
, PAKFIRE_DB_READWRITE
);
287 // Create a dummy repository
288 r
= pakfire_repo_create(&dummy
, pakfire
, PAKFIRE_REPO_DUMMY
);
292 // Disable the repository
293 pakfire_repo_set_enabled(dummy
, 0);
295 // Create the system repository
296 r
= pakfire_repo_create(&system
, pakfire
, PAKFIRE_REPO_SYSTEM
);
300 // Set this repository as the installed one
301 pool_set_installed(pool
, pakfire_repo_get_repo(system
));
303 // Create the command line repo
304 r
= pakfire_repo_create(&commandline
, pakfire
, PAKFIRE_REPO_COMMANDLINE
);
308 // Load database content
309 r
= pakfire_db_load(db
, system
);
315 pakfire_db_unref(db
);
317 pakfire_repo_unref(commandline
);
319 pakfire_repo_unref(dummy
);
321 pakfire_repo_unref(system
);
326 static void pakfire_free(struct pakfire
* pakfire
) {
327 struct pakfire_repo
* repo
= NULL
;
330 // Avoid recursive free
331 if (pakfire
->in_free
++)
334 // Destroy the commandline repository
335 repo
= pakfire_get_repo(pakfire
, PAKFIRE_REPO_COMMANDLINE
);
337 r
= pakfire_repo_clean(repo
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
339 ERROR(pakfire
, "Could not cleanup %s repository: %m\n", PAKFIRE_REPO_COMMANDLINE
);
341 pakfire_repo_unref(repo
);
344 // Release GPGME context
346 pakfire_keystore_destroy(pakfire
, &pakfire
->gpgctx
);
348 // Release lock (if not already done so)
349 pakfire_release_lock(pakfire
);
351 if (pakfire
->destroy_on_free
&& *pakfire
->path
) {
352 DEBUG(pakfire
, "Destroying %s\n", pakfire
->path
);
354 // Destroy the temporary directory
355 pakfire_rmtree(pakfire
->path
, 0);
358 pakfire_repo_free_all(pakfire
);
361 pool_free(pakfire
->pool
);
364 pakfire_config_unref(pakfire
->config
);
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
))
375 // We must be root in order to operate in /
377 ERROR(pakfire
, "Must be running as root on /\n");
382 if (strcmp(pakfire
->distro
.id
, "ipfire") != 0) {
383 ERROR(pakfire
, "Not an IPFire system\n");
391 static int pakfire_read_repo_config(struct pakfire
* pakfire
) {
394 int r
= pakfire_make_path(pakfire
, path
, PAKFIRE_CONFIG_DIR
"/repos");
398 DEBUG(pakfire
, "Reading repository configuration from %s\n", path
);
405 FTS
* d
= fts_open(paths
, FTS_NOCHDIR
|FTS_NOSTAT
, NULL
);
410 FTSENT
* fent
= fts_read(d
);
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"))
420 DEBUG(pakfire
, "Reading %s\n", fent
->fts_path
);
422 FILE* f
= fopen(fent
->fts_path
, "r");
426 // Parse the configuration file
427 r
= pakfire_config_read(pakfire
->config
, f
);
445 const char* pakfire_get_distro_name(struct pakfire
* pakfire
) {
446 if (*pakfire
->distro
.name
)
447 return pakfire
->distro
.name
;
452 const char* pakfire_get_distro_id(struct pakfire
* pakfire
) {
453 if (*pakfire
->distro
.id
)
454 return pakfire
->distro
.id
;
459 const char* pakfire_get_distro_vendor(struct pakfire
* pakfire
) {
460 if (*pakfire
->distro
.vendor
)
461 return pakfire
->distro
.vendor
;
466 const char* pakfire_get_distro_version(struct pakfire
* pakfire
) {
467 if (*pakfire
->distro
.version
)
468 return pakfire
->distro
.version
;
473 const char* pakfire_get_distro_version_id(struct pakfire
* pakfire
) {
474 if (*pakfire
->distro
.version_id
)
475 return pakfire
->distro
.version_id
;
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"))
486 const char* name
= pakfire_config_get(pakfire
->config
, "distro", "name", NULL
);
488 pakfire_string_set(pakfire
->distro
.name
, name
);
491 const char* id
= pakfire_config_get(pakfire
->config
, "distro", "id", NULL
);
493 pakfire_string_set(pakfire
->distro
.id
, id
);
496 const char* version_id
= pakfire_config_get(pakfire
->config
, "distro", "version_id", NULL
);
498 pakfire_string_set(pakfire
->distro
.version_id
, version_id
);
501 const char* codename
= pakfire_config_get(pakfire
->config
, "distro", "codename", NULL
);
503 pakfire_string_set(pakfire
->distro
.version_codename
, codename
);
506 if (*pakfire
->distro
.version_codename
)
507 pakfire_string_format(pakfire
->distro
.version
, "%s (%s)",
508 pakfire
->distro
.version_id
, pakfire
->distro
.version_codename
);
510 pakfire_string_set(pakfire
->distro
.version
, pakfire
->distro
.version_id
);
512 // Fill in pretty name
513 pakfire_string_format(pakfire
->distro
.pretty_name
, "%s %s",
514 pakfire
->distro
.name
, pakfire
->distro
.version
);
517 const char* vendor
= pakfire_config_get(pakfire
->config
, "distro", "vendor", NULL
);
519 pakfire_string_set(pakfire
->distro
.vendor
, vendor
);
522 const char* slogan
= pakfire_config_get(pakfire
->config
, "distro", "slogan", NULL
);
524 pakfire_string_set(pakfire
->distro
.slogan
, slogan
);
529 static int pakfire_read_config(struct pakfire
* pakfire
, const char* path
) {
530 char default_path
[PATH_MAX
];
532 // Use default path if none set
534 int r
= pakfire_make_path(pakfire
, default_path
, PAKFIRE_CONFIG_DIR
"/general.conf");
541 DEBUG(pakfire
, "Reading configuration from %s\n", path
);
543 FILE* f
= fopen(path
, "r");
545 // Silently ignore when there is no default configuration file
546 if (*default_path
&& errno
== ENOENT
)
549 ERROR(pakfire
, "Could not open configuration file %s: %m\n", path
);
553 // Read configuration from file
554 int r
= pakfire_config_read(pakfire
->config
, f
);
556 ERROR(pakfire
, "Could not parse configuration file %s: %m\n", path
);
560 // Import distro configuration
561 r
= pakfire_config_import_distro(pakfire
);
565 // Read repository configuration
566 r
= pakfire_read_repo_config(pakfire
);
576 static int pakfire_read_os_release(struct pakfire
* pakfire
) {
581 int r
= pakfire_make_path(pakfire
, path
, "/etc/os-release");
587 FILE* f
= fopen(path
, "r");
589 // Ignore when the file does not exist
590 if (errno
== ENOENT
) {
595 ERROR(pakfire
, "Could not open %s: %m\n", path
);
600 ssize_t bytes_read
= getline(&line
, &l
, f
);
604 // Remove trailing newline
605 pakfire_remove_trailing_newline(line
);
608 char* delim
= strchr(line
, '=');
615 // Set key and val to the start of the strings
617 char* val
= delim
+ 1;
620 val
= pakfire_unquote_in_place(val
);
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
);
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";
660 // Reset pakfire pointer
663 // Default to the native architecture
665 arch
= pakfire_arch_native();
667 // Check if the architecture is supported
668 if (!pakfire_arch_supported(arch
)) {
673 // Path must be absolute
674 if (path
&& !pakfire_string_startswith(path
, "/")) {
679 struct pakfire
* p
= calloc(1, sizeof(*p
));
686 // Store the UID/GID we are running as
691 pakfire_string_set(p
->arch
, arch
);
695 pakfire_set_log_callback(p
, log_callback
, log_data
);
697 pakfire_set_log_callback(p
, pakfire_log_syslog
, NULL
);
701 pakfire_log_set_priority(p
, loglevel
);
703 const char* env
= secure_getenv("PAKFIRE_LOG");
705 pakfire_log_set_priority(p
, log_priority(env
));
708 // Setup confirm callback
709 pakfire_set_confirm_callback(p
, pakfire_ui_confirm
, NULL
);
711 // Initialise configuration
712 r
= pakfire_config_create(&p
->config
);
716 // Generate a random path if none is set
718 path
= pakfire_mkdtemp(tempdir
);
724 // Destroy everything when done
725 p
->destroy_on_free
= 1;
729 pakfire_string_set(p
->path
, path
);
731 // Read /etc/os-release
732 r
= pakfire_read_os_release(p
);
733 if (r
&& errno
!= ENOENT
)
736 // Bump RLIMIT_NOFILE to maximum
737 r
= pakfire_rlimit_set(p
, PAKFIRE_RLIMIT_NOFILE_MAX
);
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
));
745 // Fetch sub UID/GIDs
746 if (!pakfire_on_root(p
)) {
748 r
= pakfire_getsubuid(p
, p
->uid
, &p
->subuid
);
750 ERROR(p
, "Could not fetch subuid: %m\n");
755 r
= pakfire_getsubgid(p
, p
->gid
, &p
->subgid
);
757 ERROR(p
, "Could not fetch subgid: %m\n");
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
);
766 // Perform some safety checks
767 r
= pakfire_safety_checks(p
);
771 // Read configuration file
772 r
= pakfire_read_config(p
, conf
);
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
);
790 r
= pakfire_make_path(p
, p
->lock_path
, LOCK_PATH
);
792 ERROR(p
, "Could not set lock path: %m\n");
798 const char* home
= pakfire_get_home(p
, p
->uid
);
800 ERROR(p
, "Could not find home directory\n");
805 pakfire_string_format(p
->cache_path
, "%s/.pakfire/cache/%s/%s/%s",
806 home
, p
->distro
.id
, p
->distro
.version_id
, p
->arch
);
808 pakfire_string_format(p
->cache_path
, "%s/%s/%s/%s",
809 PAKFIRE_CACHE_DIR
, p
->distro
.id
, p
->distro
.version_id
, p
->arch
);
813 r
= pakfire_make_path(p
, p
->keystore_path
, KEYSTORE_DIR
);
815 ERROR(p
, "Could not set keystore path: %m\n");
819 // Make path for private files
820 char private_dir
[PATH_MAX
];
821 r
= pakfire_make_path(p
, private_dir
, PAKFIRE_PRIVATE_DIR
);
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
);
834 // Initialize keystore
835 r
= pakfire_keystore_init(p
, &p
->gpgctx
);
840 r
= pakfire_populate_pool(p
);
844 // Create repositories
845 r
= pakfire_repo_import(p
, p
->config
);
859 PAKFIRE_EXPORT
struct pakfire
* pakfire_ref(struct pakfire
* pakfire
) {
865 PAKFIRE_EXPORT
struct pakfire
* pakfire_unref(struct pakfire
* pakfire
) {
866 if (--pakfire
->nrefs
> 0)
869 pakfire_free(pakfire
);
874 int pakfire_has_flag(struct pakfire
* pakfire
, int flag
) {
875 return pakfire
->flags
& flag
;
878 struct pakfire_config
* pakfire_get_config(struct pakfire
* pakfire
) {
879 if (!pakfire
->config
)
882 return pakfire_config_ref(pakfire
->config
);
885 PAKFIRE_EXPORT
const char* pakfire_get_path(struct pakfire
* pakfire
) {
886 return pakfire
->path
;
889 int pakfire_acquire_lock(struct pakfire
* pakfire
) {
892 // Check if the lock is already held
894 ERROR(pakfire
, "Lock is already been acquired by this process\n");
899 DEBUG(pakfire
, "Acquire lock...\n");
901 // Ensure the parent directory exists
902 pakfire_mkparentdir(pakfire
->lock_path
, 0755);
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
);
911 // Attempt to lock the file exclusively
913 r
= flock(fileno(pakfire
->lock
), LOCK_EX
|LOCK_NB
);
919 DEBUG(pakfire
, "Could not acquire lock %s: %m\n", pakfire
->lock_path
);
921 // Wait 500ms until the next attempt
926 DEBUG(pakfire
, "Lock acquired\n");
931 void pakfire_release_lock(struct pakfire
* pakfire
) {
935 DEBUG(pakfire
, "Releasing lock\n");
937 fclose(pakfire
->lock
);
938 pakfire
->lock
= NULL
;
940 // Attempt to unlink the lock file
941 unlink(pakfire
->lock_path
);
944 const char* pakfire_get_keystore_path(struct pakfire
* pakfire
) {
945 return pakfire
->keystore_path
;
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
== '/')
953 return __pakfire_path_join(dst
, length
, pakfire
->path
, path
);
956 const char* pakfire_relpath(struct pakfire
* pakfire
, const char* path
) {
957 return pakfire_path_relpath(pakfire
->path
, path
);
960 gpgme_ctx_t
pakfire_get_gpgctx(struct pakfire
* pakfire
) {
961 return pakfire
->gpgctx
;
964 PAKFIRE_EXPORT
int pakfire_list_keys(struct pakfire
* pakfire
, struct pakfire_key
*** keys
) {
968 // Fetch GPGME context
969 gpgme_ctx_t gpgctx
= pakfire_get_gpgctx(pakfire
);
973 struct pakfire_key
* key
= NULL
;
974 gpgme_key_t gpgkey
= NULL
;
978 // Iterate over all keys and import them to the list
979 gpgme_error_t e
= gpgme_op_keylist_start(gpgctx
, NULL
, 0);
984 e
= gpgme_op_keylist_next(gpgctx
, &gpgkey
);
989 r
= pakfire_key_create(&key
, pakfire
, gpgkey
);
990 gpgme_key_unref(gpgkey
);
995 *keys
= reallocarray(*keys
, length
+ 2, sizeof(**keys
));
1001 // Store key in array
1002 (*keys
)[length
++] = key
;
1004 // Terminate the array
1005 (*keys
)[length
] = NULL
;
1013 for (struct pakfire_key
** _key
= *keys
; *_key
; _key
++)
1014 pakfire_key_unref(*_key
);
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
;
1030 Pool
* pool
= pakfire
->pool
;
1032 // Run func for every repository
1033 FOR_REPOS(i
, solv_repo
) {
1034 repo
= pakfire_repo_create_from_repo(pakfire
, solv_repo
);
1039 r
= func(repo
, flags
);
1040 pakfire_repo_unref(repo
);
1050 PAKFIRE_EXPORT
int pakfire_clean(struct pakfire
* pakfire
, int flags
) {
1053 // Clean all repositories
1054 r
= pakfire_foreach_repo(pakfire
, pakfire_repo_clean
, flags
);
1058 // Clean build environments
1059 r
= pakfire_build_clean(pakfire
, flags
);
1064 return pakfire_rmtree(PAKFIRE_CACHE_DIR
, 0);
1067 PAKFIRE_EXPORT
int pakfire_refresh(struct pakfire
* pakfire
, int flags
) {
1068 return pakfire_foreach_repo(pakfire
, pakfire_repo_refresh
, flags
);
1071 enum pakfire_copy_direction
{
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
;
1084 DEBUG(pakfire
, "Copying %s to %s\n", src
, dst
);
1086 // Open the source file
1087 f
= fopen(src
, "r");
1089 ERROR(pakfire
, "Could not open %s: %m\n", src
);
1094 reader
= pakfire_make_archive_disk_reader(pakfire
, (direction
== PAKFIRE_COPY_OUT
));
1099 writer
= pakfire_make_archive_disk_writer(pakfire
, (direction
== PAKFIRE_COPY_IN
));
1103 // Create a new entry
1104 entry
= archive_entry_new();
1108 // Set the source path
1109 archive_entry_copy_sourcepath(entry
, src
);
1111 // Set the destination path
1112 archive_entry_set_pathname(entry
, dst
);
1114 // Read everything from source file
1115 r
= archive_read_disk_entry_from_file(reader
, entry
, fileno(f
), NULL
);
1117 ERROR(pakfire
, "Could not read from %s: %m\n", src
);
1121 // Write file to destination
1122 r
= archive_write_header(writer
, entry
);
1124 ERROR(pakfire
, "Could not write %s: %m\n", dst
);
1129 if (archive_entry_filetype(entry
) == AE_IFREG
) {
1130 r
= pakfire_archive_copy_data_from_file(pakfire
, writer
, f
);
1139 archive_entry_free(entry
);
1141 archive_read_free(reader
);
1143 archive_write_free(writer
);
1148 PAKFIRE_EXPORT
int pakfire_copy_in(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1149 if (pakfire_on_root(pakfire
)) {
1154 char path
[PATH_MAX
];
1155 int r
= pakfire_make_path(pakfire
, path
, dst
);
1159 return pakfire_copy(pakfire
, src
, path
, PAKFIRE_COPY_IN
);
1162 PAKFIRE_EXPORT
int pakfire_copy_out(struct pakfire
* pakfire
, const char* src
, const char* dst
) {
1163 if (pakfire_on_root(pakfire
)) {
1168 char path
[PATH_MAX
];
1169 int r
= pakfire_make_path(pakfire
, path
, src
);
1173 return pakfire_copy(pakfire
, path
, dst
, PAKFIRE_COPY_OUT
);
1176 PAKFIRE_EXPORT
const char* pakfire_get_arch(struct pakfire
* pakfire
) {
1177 return pakfire
->arch
;
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
);
1184 Pool
* pakfire_get_solv_pool(struct pakfire
* pakfire
) {
1185 return pakfire
->pool
;
1188 void pakfire_pool_has_changed(struct pakfire
* pakfire
) {
1189 pakfire
->pool_ready
= 0;
1192 void pakfire_pool_internalize(struct pakfire
* pakfire
) {
1193 // Nothing to do if the pool is ready
1194 if (pakfire
->pool_ready
)
1197 // Internalize all repositories
1198 pakfire_foreach_repo(pakfire
, pakfire_repo_internalize
, 0);
1200 // Create fileprovides
1201 pool_addfileprovides(pakfire
->pool
);
1203 // Create whatprovides index
1204 pool_createwhatprovides(pakfire
->pool
);
1206 // Mark the pool as ready
1207 pakfire
->pool_ready
= 1;
1210 PAKFIRE_EXPORT
struct pakfire_repolist
* pakfire_get_repos(struct pakfire
* pakfire
) {
1211 struct pakfire_repolist
* list
;
1213 int r
= pakfire_repolist_create(&list
);
1217 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
1221 FOR_REPOS(i
, solv_repo
) {
1222 // Skip the dummy repository
1223 if (strcmp(solv_repo
->name
, PAKFIRE_REPO_DUMMY
) == 0)
1226 struct pakfire_repo
* repo
= pakfire_repo_create_from_repo(pakfire
, solv_repo
);
1232 r
= pakfire_repolist_append(list
, repo
);
1234 pakfire_repo_unref(repo
);
1238 pakfire_repo_unref(repo
);
1244 pakfire_repolist_unref(list
);
1248 PAKFIRE_EXPORT
struct pakfire_repo
* pakfire_get_repo(struct pakfire
* pakfire
, const char* name
) {
1249 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
1256 FOR_REPOS(i
, repo
) {
1257 if (strcmp(repo
->name
, name
) == 0)
1258 return pakfire_repo_create_from_repo(pakfire
, repo
);
1265 struct pakfire_repo
* pakfire_get_installed_repo(struct pakfire
* pakfire
) {
1266 if (!pakfire
->pool
->installed
)
1269 return pakfire_repo_create_from_repo(pakfire
, pakfire
->pool
->installed
);
1272 static int pakfire_search_dep(struct pakfire
* pakfire
, Id type
, const char* what
, int flags
,
1273 struct pakfire_packagelist
** list
) {
1276 // Get the pool ready
1277 pakfire_pool_internalize(pakfire
);
1279 // Translate dependency to ID
1280 Id dep
= pakfire_str2dep(pakfire
, what
);
1290 queue_init(&matches
);
1292 // Search for anything that matches
1293 pool_whatmatchesdep(pakfire
->pool
, type
, dep
, &matches
, 0);
1295 // Create a packagelist
1296 r
= pakfire_packagelist_create_from_queue(list
, pakfire
, &matches
);
1301 pakfire_packagelist_sort(*list
);
1304 queue_free(&matches
);
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
);
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
);
1319 PAKFIRE_EXPORT
int pakfire_search(struct pakfire
* pakfire
, const char* what
, int flags
,
1320 struct pakfire_packagelist
** list
) {
1326 // Get the pool ready
1327 pakfire_pool_internalize(pakfire
);
1329 // Initialize the result queue
1330 queue_init(&matches
);
1332 if (flags
& PAKFIRE_SEARCH_NAME_ONLY
)
1333 dflags
= SEARCH_STRING
|SEARCH_GLOB
;
1335 dflags
= SEARCH_SUBSTRING
|SEARCH_NOCASE
|SEARCH_GLOB
;
1337 // Setup the data interator
1338 dataiterator_init(&di
, pakfire
->pool
, 0, 0, 0, what
, dflags
);
1343 SOLVABLE_DESCRIPTION
,
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);
1352 while (dataiterator_step(&di
))
1353 queue_pushunique(&matches
, di
.solvid
);
1356 if (flags
& PAKFIRE_SEARCH_NAME_ONLY
)
1360 // Convert matches to package list
1361 r
= pakfire_packagelist_create_from_queue(list
, pakfire
, &matches
);
1366 pakfire_packagelist_sort(*list
);
1369 dataiterator_free(&di
);
1370 queue_free(&matches
);
1377 int __pakfire_make_cache_path(struct pakfire
* pakfire
, char* path
, size_t length
,
1378 const char* format
, ...) {
1382 ssize_t l
= snprintf(path
, length
- 1, "%s/", pakfire
->cache_path
);
1386 // We have run out of space
1387 if ((size_t)l
>= length
)
1390 // Append everything after the format string
1393 va_start(args
, format
);
1394 vsnprintf(path
, length
- l
- 1, format
, args
);
1402 PAKFIRE_EXPORT
int pakfire_log_get_priority(struct pakfire
* pakfire
) {
1403 return pakfire
->log_priority
;
1406 PAKFIRE_EXPORT
void pakfire_log_set_priority(struct pakfire
* pakfire
, int priority
) {
1407 pakfire
->log_priority
= priority
;
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
;
1416 void pakfire_log(struct pakfire
* pakfire
, int priority
, const char* file
, int line
,
1417 const char* fn
, const char* format
, ...) {
1420 // Do not do anything if callback isn't set
1421 if (!pakfire
->callbacks
.log
)
1425 int saved_errno
= errno
;
1427 va_start(args
, format
);
1428 pakfire
->callbacks
.log(pakfire
->callbacks
.log_data
,
1429 priority
, file
, line
, fn
, format
, args
);
1433 errno
= saved_errno
;
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
;
1444 int pakfire_confirm(struct pakfire
* pakfire
, const char* message
, const char* question
) {
1445 // No callback configured
1446 if (!pakfire
->callbacks
.confirm
)
1449 // Skip this, if running in non-interactive mode
1451 if (!pakfire_has_flag(pakfire
, PAKFIRE_FLAGS_INTERACTIVE
))
1456 return pakfire
->callbacks
.confirm(
1457 pakfire
, pakfire
->callbacks
.confirm_data
, message
, question
);
1460 static const char* pakfire_user_lookup(void* data
, la_int64_t uid
) {
1461 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1463 DEBUG(pakfire
, "Looking up name for UID %ld\n", uid
);
1465 // Unmap the UID first
1466 uid
= pakfire_unmap_id(pakfire
, &pakfire
->subuid
, uid
);
1468 // Fast path for "root"
1472 // Find a matching entry in /etc/passwd
1473 struct passwd
* entry
= pakfire_getpwuid(pakfire
, uid
);
1475 ERROR(pakfire
, "Could not retrieve uname for %ld: %m\n", uid
);
1479 DEBUG(pakfire
, "Mapping UID %ld to %s\n", uid
, entry
->pw_name
);
1481 return entry
->pw_name
;
1484 static const char* pakfire_group_lookup(void* data
, la_int64_t gid
) {
1485 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1487 DEBUG(pakfire
, "Looking up name for GID %ld\n", gid
);
1489 // Unmap the GID first
1490 gid
= pakfire_unmap_id(pakfire
, &pakfire
->subgid
, gid
);
1492 // Fast path for "root"
1496 // Find a matching entry in /etc/group
1497 struct group
* entry
= pakfire_getgrgid(pakfire
, gid
);
1499 ERROR(pakfire
, "Could not retrieve gname for %ld: %m\n", gid
);
1503 DEBUG(pakfire
, "Mapping GID %ld to %s\n", gid
, entry
->gr_name
);
1505 return entry
->gr_name
;
1508 struct archive
* pakfire_make_archive_disk_reader(struct pakfire
* pakfire
, int internal
) {
1509 struct archive
* archive
= archive_read_disk_new();
1513 // Do not read fflags
1514 int r
= archive_read_disk_set_behavior(archive
, ARCHIVE_READDISK_NO_FFLAGS
);
1516 ERROR(pakfire
, "Could not change behavior of reader: %s\n",
1517 archive_error_string(archive
));
1518 archive_read_free(archive
);
1522 // Install user/group lookups
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
);
1527 archive_read_disk_set_standard_lookup(archive
);
1533 static la_int64_t
pakfire_uid_lookup(void* data
, const char* name
, la_int64_t uid
) {
1534 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1536 DEBUG(pakfire
, "Looking up UID for '%s' (%ld)\n", name
, uid
);
1538 // Fast path for "root"
1539 if (strcmp(name
, "root") == 0)
1540 return pakfire_map_id(pakfire
, &pakfire
->subuid
, 0);
1542 // Find a matching entry in /etc/passwd
1543 struct passwd
* entry
= pakfire_getpwnam(pakfire
, name
);
1545 ERROR(pakfire
, "Could not retrieve UID for '%s': %m\n", name
);
1546 return pakfire_map_id(pakfire
, &pakfire
->subuid
, 0);
1549 DEBUG(pakfire
, "Mapping %s to UID %d\n", name
, entry
->pw_uid
);
1551 return pakfire_map_id(pakfire
, &pakfire
->subuid
, entry
->pw_uid
);
1554 static la_int64_t
pakfire_gid_lookup(void* data
, const char* name
, la_int64_t gid
) {
1555 struct pakfire
* pakfire
= (struct pakfire
*)data
;
1557 DEBUG(pakfire
, "Looking up GID for '%s' (%ld)\n", name
, gid
);
1559 // Fast path for "root"
1560 if (strcmp(name
, "root") == 0)
1561 return pakfire_map_id(pakfire
, &pakfire
->subgid
, 0);
1563 // Find a matching entry in /etc/group
1564 struct group
* entry
= pakfire_getgrnam(pakfire
, name
);
1566 ERROR(pakfire
, "Could not retrieve GID for '%s': %m\n", name
);
1567 return pakfire_map_id(pakfire
, &pakfire
->subgid
, 0);
1570 DEBUG(pakfire
, "Mapping %s to GID %d\n", name
, entry
->gr_gid
);
1572 return pakfire_map_id(pakfire
, &pakfire
->subgid
, entry
->gr_gid
);
1575 struct archive
* pakfire_make_archive_disk_writer(struct pakfire
* pakfire
, int internal
) {
1576 struct archive
* archive
= archive_write_disk_new();
1580 // Set flags for extracting files
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
;
1590 archive_write_disk_set_options(archive
, flags
);
1592 // Install our own routine for user/group lookups
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
);
1597 archive_write_disk_set_standard_lookup(archive
);
1603 // Convenience functions to install/erase/update packages
1605 static int pakfire_perform_transaction(
1606 struct pakfire
* pakfire
,
1607 int transaction_flags
,
1609 int (*action
)(struct pakfire_request
* request
, const char* what
, int flags
),
1610 const char** packages
,
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
;
1621 // Packages cannot be NULL
1628 r
= pakfire_acquire_lock(pakfire
);
1632 // Create a new request
1633 r
= pakfire_request_create(&request
, pakfire
, solver_flags
);
1637 // Lock anything that should be locked
1639 for (const char** lock
= locks
; *lock
; lock
++) {
1640 r
= pakfire_request_lock(request
, *lock
);
1642 ERROR(pakfire
, "Could not lock '%s': %m\n", *lock
);
1648 // Perform action on all packages
1649 for (const char** package
= packages
; *package
; package
++) {
1650 r
= action(request
, *package
, job_flags
);
1652 ERROR(pakfire
, "Could not find '%s': %m\n", *package
);
1659 // Solve the request
1661 r
= pakfire_request_solve(request
, &transaction
, &problems
);
1672 // Let the user choose a problem
1673 r
= pakfire_ui_pick_solution(pakfire
, request
, problems
);
1678 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1679 pakfire_problem_unref(*problem
);
1683 // Another error occured
1689 // Set how many packages have been changed
1691 *changed
= pakfire_transaction_count(transaction
);
1693 // Set status callback
1694 if (status_callback
)
1695 pakfire_transaction_set_status_callback(
1696 transaction
, status_callback
, status_callback_data
);
1698 // Run the transaction
1699 r
= pakfire_transaction_run(transaction
, transaction_flags
);
1708 pakfire_release_lock(pakfire
);
1712 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1713 pakfire_problem_unref(*problem
);
1717 pakfire_transaction_unref(transaction
);
1719 pakfire_request_unref(request
);
1724 PAKFIRE_EXPORT
int pakfire_install(
1725 struct pakfire
* pakfire
,
1726 int transaction_flags
,
1728 const char** packages
,
1732 pakfire_status_callback status_callback
,
1733 void* status_callback_data
) {
1734 return pakfire_perform_transaction(
1738 pakfire_request_install
,
1744 status_callback_data
);
1747 PAKFIRE_EXPORT
int pakfire_erase(
1748 struct pakfire
* pakfire
,
1749 int transaction_flags
,
1751 const char** packages
,
1755 pakfire_status_callback status_callback
,
1756 void* status_callback_data
) {
1757 return pakfire_perform_transaction(
1761 pakfire_request_erase
,
1767 status_callback_data
);
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
;
1780 r
= pakfire_acquire_lock(pakfire
);
1784 // Create a new request
1785 r
= pakfire_request_create(&request
, pakfire
, solver_flags
);
1790 r
= action(request
, job_flags
);
1796 // Solve the request
1798 r
= pakfire_request_solve(request
, &transaction
, &problems
);
1809 // Let the user choose a problem
1810 r
= pakfire_ui_pick_solution(pakfire
, request
, problems
);
1815 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1816 pakfire_problem_unref(*problem
);
1820 // Another error occured
1826 // Set how many packages have been changed
1828 *changed
= pakfire_transaction_count(transaction
);
1830 // Set status callback
1831 if (status_callback
)
1832 pakfire_transaction_set_status_callback(
1833 transaction
, status_callback
, status_callback_data
);
1835 // Run the transaction
1836 r
= pakfire_transaction_run(transaction
, 0);
1845 pakfire_release_lock(pakfire
);
1848 for (struct pakfire_problem
** problem
= problems
; *problem
; problem
++)
1849 pakfire_problem_unref(*problem
);
1853 pakfire_transaction_unref(transaction
);
1855 pakfire_request_unref(request
);
1860 PAKFIRE_EXPORT
int pakfire_update(
1861 struct pakfire
* pakfire
,
1862 int transaction_flags
,
1864 const char** packages
,
1868 pakfire_status_callback status_callback
,
1869 void* status_callback_data
) {
1870 // If no packages are being passed, we will try to update everything
1873 return pakfire_perform_transaction_simple(
1874 pakfire
, solver_flags
, pakfire_request_update_all
, flags
, changed
,
1875 status_callback
, status_callback_data
);
1877 return pakfire_perform_transaction(pakfire
, transaction_flags
, solver_flags
,
1878 pakfire_request_update
, packages
, locks
, flags
, changed
,
1879 status_callback
, status_callback_data
);
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
);
1887 PAKFIRE_EXPORT
int pakfire_check(struct pakfire
* pakfire
) {
1888 struct pakfire_db
* db
= NULL
;
1891 // Open database in read-only mode and try to load all installed packages
1892 r
= pakfire_db_open(&db
, pakfire
, PAKFIRE_DB_READWRITE
);
1896 // Perform a database integrity check
1897 r
= pakfire_db_check(db
);
1901 // Check if all dependencies are intact
1902 r
= pakfire_verify(pakfire
, NULL
);
1908 pakfire_db_unref(db
);
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
);