1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2021 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 #############################################################################*/
23 #include <sys/mount.h>
25 #include <uuid/uuid.h>
27 #define PCRE2_CODE_UNIT_WIDTH 8
30 #include <pakfire/build.h>
31 #include <pakfire/cgroup.h>
32 #include <pakfire/dependencies.h>
33 #include <pakfire/dist.h>
34 #include <pakfire/file.h>
35 #include <pakfire/i18n.h>
36 #include <pakfire/jail.h>
37 #include <pakfire/logging.h>
38 #include <pakfire/mount.h>
39 #include <pakfire/package.h>
40 #include <pakfire/packager.h>
41 #include <pakfire/parser.h>
42 #include <pakfire/private.h>
43 #include <pakfire/problem.h>
44 #include <pakfire/repo.h>
45 #include <pakfire/request.h>
46 #include <pakfire/scriptlet.h>
47 #include <pakfire/snapshot.h>
48 #include <pakfire/solution.h>
49 #include <pakfire/string.h>
50 #include <pakfire/util.h>
52 #define CCACHE_DIR "/var/cache/ccache"
54 // We guarantee 2 GiB of memory to every build container
55 #define PAKFIRE_BUILD_MEMORY_GUARANTEED (size_t)2 * 1024 * 1024 * 1024
57 // We allow only up to 2048 processes/threads for every build container
58 #define PAKFIRE_BUILD_PID_LIMIT (size_t)2048
60 struct pakfire_build
{
61 struct pakfire
* pakfire
;
69 char _id
[UUID_STR_LEN
];
71 char target
[PATH_MAX
];
74 struct pakfire_cgroup
* cgroup
;
77 struct pakfire_jail
* jail
;
79 // The build repository
80 struct pakfire_repo
* repo
;
82 // A list of all built packages
83 struct pakfire_packagelist
* packages
;
86 char buildroot
[PATH_MAX
];
93 "#!/bin/bash --login\n" \
102 static int pakfire_build_has_flag(struct pakfire_build
* build
, int flag
) {
103 return build
->flags
& flag
;
106 static int __pakfire_build_setup_repo(struct pakfire
* pakfire
,
107 struct pakfire_repo
* repo
, void* p
) {
112 struct pakfire_build
* build
= (struct pakfire_build
*)p
;
114 // Skip processing the installed repository
115 if (pakfire_repo_is_installed_repo(repo
))
118 // Skip processing any other internal repositories
119 if (pakfire_repo_is_internal(repo
))
122 const char* name
= pakfire_repo_get_name(repo
);
124 DEBUG(pakfire
, "Exporting repository configuration for '%s'\n", name
);
126 // Make path for configuration file
127 r
= pakfire_path(build
->pakfire
, path
, PAKFIRE_CONFIG_DIR
"/repos/%s.repo", name
);
129 ERROR(pakfire
, "Could not make repository configuration path for %s: %m\n", name
);
133 // Create the parent directory
134 r
= pakfire_mkparentdir(path
, 0755);
138 // Open the repository configuration
139 f
= fopen(path
, "w");
141 ERROR(pakfire
, "Could not open %s for writing: %m\n", path
);
145 // Write repository configuration
146 r
= pakfire_repo_write_config(repo
, f
);
148 ERROR(pakfire
, "Could not write repository configuration for %s: %m\n", name
);
152 // Bind-mount any local repositories
153 if (pakfire_repo_is_local(repo
)) {
154 const char* _path
= pakfire_repo_get_path(repo
);
156 // Bind-mount the repository data read-only
157 r
= pakfire_jail_bind(build
->jail
, _path
, _path
, MS_RDONLY
);
159 ERROR(pakfire
, "Could not bind-mount the repository at %s: %m\n", _path
);
172 This function enables the local repository so that it can be accessed by
173 a pakfire instance running inside the chroot.
175 static int pakfire_build_enable_repos(struct pakfire_build
* build
) {
176 return pakfire_repo_walk(build
->pakfire
, __pakfire_build_setup_repo
, build
);
180 Drops the user into a shell
182 static int pakfire_build_shell(struct pakfire_build
* build
) {
185 // Export local repository if running in interactive mode
186 r
= pakfire_build_enable_repos(build
);
191 return pakfire_jail_shell(build
->jail
);
194 static int pakfire_build_read_script(struct pakfire_build
* build
,
195 const char* filename
, char** buffer
, size_t* length
) {
200 // Compose the source path
201 r
= pakfire_path_join(path
, PAKFIRE_SCRIPTS_DIR
, filename
);
203 ERROR(build
->pakfire
, "Could not compose path for script '%s': %m\n", filename
);
207 DEBUG(build
->pakfire
, "Reading script from %s...\n", path
);
210 f
= fopen(path
, "r");
212 ERROR(build
->pakfire
, "Could not open script %s: %m\n", path
);
216 // Read the file into a the buffer
217 r
= pakfire_read_file_into_buffer(f
, buffer
, length
);
219 ERROR(build
->pakfire
, "Could not read script: %m\n");
230 static int pakfire_build_run_script(
231 struct pakfire_build
* build
,
232 const char* filename
,
234 pakfire_jail_communicate_in communicate_in
,
235 pakfire_jail_communicate_out communicate_out
,
242 DEBUG(build
->pakfire
, "Running build script '%s'...\n", filename
);
245 r
= pakfire_build_read_script(build
, filename
, &script
, &length
);
247 ERROR(build
->pakfire
, "Could not read script %s: %m\n", filename
);
251 // Execute the script
252 r
= pakfire_jail_exec_script(build
->jail
, script
, length
, args
,
253 communicate_in
, communicate_out
, data
);
255 ERROR(build
->pakfire
, "Script '%s' failed with status %d\n", filename
, r
);
264 struct pakfire_find_deps_ctx
{
265 struct pakfire_package
* pkg
;
267 struct pakfire_scriptlet
* scriptlet
;
269 const pcre2_code
* filter
;
271 struct pakfire_filelist
* filelist
;
275 static int pakfire_build_make_filter(struct pakfire_build
* build
, pcre2_code
** regex
,
276 struct pakfire_parser
* makefile
, const char* namespace, const char* filter
) {
277 char* pattern
= NULL
;
281 pattern
= pakfire_parser_get(makefile
, namespace, filter
);
283 // Nothing if to if there is no or an empty pattern
284 if (!pattern
|| !*pattern
)
287 DEBUG(build
->pakfire
, "Found filter for %s: %s\n", filter
, pattern
);
289 // Compile the regular expression
290 r
= pakfire_compile_regex(build
->pakfire
, regex
, pattern
);
301 static int pakfire_build_send_filelist(struct pakfire
* pakfire
, void* data
, int fd
) {
302 struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
303 struct pakfire_file
* file
= NULL
;
306 const size_t length
= pakfire_filelist_size(ctx
->filelist
);
308 // Check if we have reached the end of the filelist
309 if (ctx
->i
>= length
)
312 // Fetch the next file
313 file
= pakfire_filelist_get(ctx
->filelist
, ctx
->i
);
315 DEBUG(pakfire
, "Could not fetch file %d: %m\n", ctx
->i
);
320 // Fetch the path of the file
321 const char* path
= pakfire_file_get_path(file
);
323 ERROR(pakfire
, "Received a file with an empty path\n");
328 // Skip files that don't match what we are looking for
329 if (ctx
->class && !pakfire_file_matches_class(file
, ctx
->class))
332 // Write path to stdin
333 r
= dprintf(fd
, "%s\n", path
);
338 // Move on to the next file
346 pakfire_file_unref(file
);
351 static int pakfire_build_process_deps(struct pakfire
* pakfire
,
352 void* data
, int priority
, const char* buffer
, const size_t length
) {
353 const struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
355 pcre2_match_data
* match
= NULL
;
358 // Nothing to do for an empty buffer
359 if (!buffer
|| !*buffer
)
363 // Add every dependency that we have received
365 // Copy the dependency to the stack (and remove the trailing newline)
366 r
= pakfire_string_format(dep
, "%.*s", (int)length
- 1, buffer
);
370 DEBUG(pakfire
, "Processing dependency: %s\n", dep
);
372 // Filter out any dependencies that are provided by this package
373 if (ctx
->dep
== PAKFIRE_PKG_REQUIRES
) {
374 // If this is a file, we check if it is on the filelist
375 if (pakfire_filelist_contains(ctx
->filelist
, dep
))
378 // Otherwise check if this dependency is provided by this package
379 else if (pakfire_package_matches_dep(ctx
->pkg
, PAKFIRE_PKG_PROVIDES
, dep
))
383 // Check if this dependency should be filtered
385 match
= pcre2_match_data_create_from_pattern(ctx
->filter
, NULL
);
387 ERROR(pakfire
, "Could not allocate PCRE match data: %m\n");
392 r
= pcre2_jit_match(ctx
->filter
, (PCRE2_SPTR
)dep
, length
- 1,
396 if (r
== PCRE2_ERROR_NOMATCH
) {
403 // Fetch the error message
404 r
= pcre2_get_error_message(r
, (PCRE2_UCHAR
*)error
, sizeof(error
));
406 ERROR(pakfire
, "Could not fetch PCRE error message: %m\n");
411 ERROR(pakfire
, "Could not match the filter: %s\n", error
);
417 DEBUG(pakfire
, "Skipping dependency that has been filtered: %s\n", dep
);
424 r
= pakfire_package_add_dep(ctx
->pkg
, ctx
->dep
, buffer
);
426 ERROR(pakfire
, "Could not process dependency '%s': %m\n", buffer
);
431 // Send everything else to the default logger
433 ERROR(pakfire
, "%s\n", buffer
);
440 DEBUG(pakfire
, "Skipping dependency that is provided by the package itself: %s\n", dep
);
444 pcre2_match_data_free(match
);
450 This function is a special way to run a script.
452 It will pipe the filelist into the standard input of the called script
453 and will read any dependencies from the standard output.
455 static int pakfire_build_find_deps(struct pakfire_build
* build
,
456 struct pakfire_package
* pkg
, int dep
, const char* script
,
457 struct pakfire_filelist
* filelist
, int class, const pcre2_code
* filter
) {
458 // Construct the context
459 struct pakfire_find_deps_ctx ctx
= {
466 .filelist
= filelist
,
471 // Skip calling the script if class doesn't match
472 if (class && !pakfire_filelist_matches_class(filelist
, class)) {
473 DEBUG(build
->pakfire
, "Skipping calling %s as class does not match\n", script
);
477 // Pass the buildroot as first argument
478 const char* args
[] = {
479 pakfire_relpath(build
->pakfire
, build
->buildroot
),
484 r
= pakfire_build_run_script(build
, script
, args
,
485 pakfire_build_send_filelist
, pakfire_build_process_deps
, &ctx
);
487 ERROR(build
->pakfire
, "%s returned with error %d\n", script
, r
);
492 static int pakfire_build_find_dependencies(struct pakfire_build
* build
,
493 struct pakfire_parser
* makefile
, const char* namespace,
494 struct pakfire_package
* pkg
, struct pakfire_filelist
* filelist
) {
495 pcre2_code
* filter_provides
= NULL
;
496 pcre2_code
* filter_requires
= NULL
;
499 // Fetch the provides filter
500 r
= pakfire_build_make_filter(build
, &filter_provides
,
501 makefile
, namespace, "filter_provides");
503 ERROR(build
->pakfire
, "Provides filter is broken: %m\n");
507 // Fetch the requires filter
508 r
= pakfire_build_make_filter(build
, &filter_requires
,
509 makefile
, namespace, "filter_requires");
511 ERROR(build
->pakfire
, "Requires filter is broken: %m\n");
516 r
= pakfire_build_find_deps(build
, pkg
,
517 PAKFIRE_PKG_PROVIDES
, "find-provides", filelist
, 0, filter_provides
);
521 // Find all Perl provides
522 r
= pakfire_build_find_deps(build
, pkg
,
523 PAKFIRE_PKG_PROVIDES
, "perl.prov", filelist
, PAKFIRE_FILE_PERL
, filter_provides
);
528 r
= pakfire_build_find_deps(build
, pkg
,
529 PAKFIRE_PKG_REQUIRES
, "find-requires", filelist
, 0, filter_requires
);
533 // Find all Perl requires
534 r
= pakfire_build_find_deps(build
, pkg
,
535 PAKFIRE_PKG_REQUIRES
, "perl.req", filelist
, PAKFIRE_FILE_PERL
, filter_requires
);
541 pcre2_code_free(filter_provides
);
543 pcre2_code_free(filter_requires
);
548 static int append_to_array(char*** array
, const char* s
) {
549 unsigned int length
= 0;
551 // Determine the length of the existing array
553 for (char** element
= *array
; *element
; element
++)
558 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
562 // Copy the string to the heap
567 // Append p and terminate the array
568 (*array
)[length
] = p
;
569 (*array
)[length
+ 1] = NULL
;
574 static int pakfire_build_package_add_files(struct pakfire_build
* build
,
575 struct pakfire_parser
* makefile
, const char* buildroot
, const char* namespace,
576 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
577 struct pakfire_filelist
* filelist
= NULL
;
580 char** includes
= NULL
;
581 char** excludes
= NULL
;
584 // Fetch filelist from makefile
585 char* files
= pakfire_parser_get(makefile
, namespace, "files");
587 // No files to package?
591 const char* file
= strtok_r(files
, " \n", &p
);
593 // Split into includes and excludes
596 r
= append_to_array(&excludes
, file
+ 1);
598 r
= append_to_array(&includes
, file
);
602 // Move on to the next token
603 file
= strtok_r(NULL
, " \n", &p
);
606 // Allocate a new filelist
607 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
612 r
= pakfire_filelist_scan(filelist
, build
->buildroot
,
613 (const char**)includes
, (const char**)excludes
);
617 const size_t length
= pakfire_filelist_size(filelist
);
618 DEBUG(build
->pakfire
, "%zu file(s) found\n", length
);
620 // Nothing to do if the filelist is empty
625 pakfire_filelist_dump(filelist
, 1);
628 r
= pakfire_build_find_dependencies(build
, makefile
, namespace, pkg
, filelist
);
630 ERROR(build
->pakfire
, "Finding dependencies failed: %m\n");
634 // Add all files to the package
635 r
= pakfire_packager_add_files(packager
, filelist
);
641 pakfire_filelist_unref(filelist
);
645 for (char** include
= includes
; *include
; include
++)
650 for (char** exclude
= excludes
; *exclude
; exclude
++)
658 static int pakfire_build_send_scriptlet(struct pakfire
* pakfire
, void* data
, int fd
) {
659 const struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
662 // Fetch the scriptlet
663 const char* p
= pakfire_scriptlet_get_data(ctx
->scriptlet
, &length
);
665 ERROR(pakfire
, "Could not fetch scriptlet: %m\n");
669 // Write it into the pipe
670 ssize_t bytes_written
= write(fd
, p
, length
);
671 if (bytes_written
< 0) {
672 ERROR(pakfire
, "Could not send scriptlet: %m\n");
679 static int pakfire_build_add_scriptlet_requires(struct pakfire_build
* build
,
680 struct pakfire_package
* pkg
, struct pakfire_scriptlet
* scriptlet
) {
683 struct pakfire_find_deps_ctx ctx
= {
685 .dep
= PAKFIRE_PKG_PREREQUIRES
,
686 .scriptlet
= scriptlet
,
689 // Find all pre-requires
690 r
= pakfire_build_run_script(build
, "find-prerequires", NULL
,
691 pakfire_build_send_scriptlet
, pakfire_build_process_deps
, &ctx
);
699 static int pakfire_build_package_add_scriptlet(struct pakfire_build
* build
,
700 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
,
701 const char* type
, const char* data
) {
702 struct pakfire_scriptlet
* scriptlet
= NULL
;
706 // Wrap scriptlet into a shell script
707 r
= asprintf(&shell
, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data
);
711 // Create a scriptlet
712 r
= pakfire_scriptlet_create(&scriptlet
, build
->pakfire
, type
, shell
, 0);
716 // Add it to the package
717 r
= pakfire_packager_add_scriptlet(packager
, scriptlet
);
719 ERROR(build
->pakfire
, "Could not add scriptlet %s\n", type
);
723 // Add scriptlet requirements
724 r
= pakfire_build_add_scriptlet_requires(build
, pkg
, scriptlet
);
726 ERROR(build
->pakfire
, "Could not add scriptlet requirements: %m\n");
735 pakfire_scriptlet_unref(scriptlet
);
742 static int pakfire_build_package_add_scriptlets(struct pakfire_build
* build
,
743 struct pakfire_parser
* makefile
, const char* namespace,
744 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
748 for (const char** type
= pakfire_scriptlet_types
; *type
; type
++) {
749 r
= pakfire_string_format(name
, "scriptlet:%s", *type
);
753 // Fetch the scriptlet
754 char* data
= pakfire_parser_get(makefile
, namespace, name
);
758 // Add it to the package
759 r
= pakfire_build_package_add_scriptlet(build
, pkg
, packager
, *type
, data
);
771 static int pakfire_build_package(struct pakfire_build
* build
, struct pakfire_parser
* makefile
,
772 const char* buildroot
, const char* namespace) {
773 struct pakfire_package
* pkg
= NULL
;
774 struct pakfire_packager
* packager
= NULL
;
778 // Expand the handle into the package name
779 char* name
= pakfire_parser_expand(makefile
, "packages", namespace);
781 ERROR(build
->pakfire
, "Could not get package name: %m\n");
785 INFO(build
->pakfire
, "Building package '%s'...\n", name
);
786 DEBUG(build
->pakfire
, " buildroot = %s\n", buildroot
);
788 // Fetch build architecture
789 const char* arch
= pakfire_get_arch(build
->pakfire
);
793 // Fetch package from makefile
794 r
= pakfire_parser_create_package(makefile
, &pkg
, NULL
, namespace, arch
);
796 ERROR(build
->pakfire
, "Could not create package from makefile: %m\n");
801 const char* distribution
= pakfire_parser_get(makefile
, NULL
, "DISTRO_NAME");
803 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_DISTRO
, distribution
);
809 pakfire_package_set_uuid(pkg
, PAKFIRE_PKG_BUILD_ID
, build
->id
);
811 // Set source package
812 const char* source_name
= pakfire_parser_get(makefile
, NULL
, "name");
814 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_NAME
, source_name
);
820 const char* source_evr
= pakfire_parser_get(makefile
, NULL
, "evr");
822 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_EVR
, source_evr
);
828 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_ARCH
, "src");
833 r
= pakfire_packager_create(&packager
, build
->pakfire
, pkg
);
838 r
= pakfire_build_package_add_files(build
, makefile
, buildroot
, namespace,
844 r
= pakfire_build_package_add_scriptlets(build
, makefile
, namespace,
849 const char* path
= pakfire_repo_get_path(build
->repo
);
851 // Write the finished package
852 r
= pakfire_packager_finish_to_directory(packager
, path
, NULL
);
854 ERROR(build
->pakfire
, "pakfire_packager_finish() failed: %m\n");
858 // Cleanup all packaged files
859 r
= pakfire_packager_cleanup(packager
);
868 pakfire_packager_unref(packager
);
870 pakfire_package_unref(pkg
);
877 static int pakfire_build_package_dump(struct pakfire
* pakfire
,
878 struct pakfire_package
* pkg
, void* p
) {
879 char* dump
= pakfire_package_dump(pkg
, PAKFIRE_PKG_DUMP_LONG
);
883 INFO(pakfire
, "%s\n", dump
);
889 static int pakfire_build_packages(struct pakfire_build
* build
,
890 struct pakfire_parser
* makefile
) {
891 DEBUG(build
->pakfire
, "Creating packages...");
894 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
896 // Fetch a list all all packages
897 char** packages
= pakfire_parser_list_namespaces(makefile
, "packages.package:*");
899 ERROR(build
->pakfire
, "Could not find any packages: %m\n");
903 unsigned int num_packages
= 0;
905 // Count how many packages we have
906 for (char** package
= packages
; *package
; package
++)
909 DEBUG(build
->pakfire
, "Found %d package(s)\n", num_packages
);
911 // Build packages in reverse order
912 for (int i
= num_packages
- 1; i
>= 0; i
--) {
913 r
= pakfire_build_package(build
, makefile
, buildroot
, packages
[i
]);
918 // Rescan the build repository to import all packages again
919 r
= pakfire_repo_scan(build
->repo
, 0);
923 // Fetch all packages
924 r
= pakfire_repo_create_packagelist(build
->repo
, &build
->packages
);
929 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_package_dump
, NULL
);
943 static int pakfire_build_stage(struct pakfire_build
* build
,
944 struct pakfire_parser
* makefile
, const char* stage
) {
947 // Prepare template for this stage
948 int r
= pakfire_string_format(template, TEMPLATE
, stage
);
952 // Fetch the environment
953 char** envp
= pakfire_parser_make_environ(makefile
);
955 // Create the build script
956 char* script
= pakfire_parser_expand(makefile
, "build", template);
958 ERROR(build
->pakfire
, "Could not generate the build script for stage '%s': %m\n",
963 INFO(build
->pakfire
, "Running build stage '%s'\n", stage
);
965 // Import environment
966 // XXX is this a good idea?
967 r
= pakfire_jail_import_env(build
->jail
, (const char**)envp
);
969 ERROR(build
->pakfire
, "Could not import environment: %m\n");
974 r
= pakfire_jail_exec_script(build
->jail
, script
, strlen(script
), NULL
, NULL
, NULL
, NULL
);
976 ERROR(build
->pakfire
, "Build stage '%s' failed with status %d\n", stage
, r
);
981 for (char** e
= envp
; *e
; e
++)
992 This helper function takes a callback which is expected to add any files
993 to the given filelist which will be all removed after.
995 static int pakfire_build_post_remove_files(struct pakfire_build
* build
,
996 struct pakfire_filelist
* filelist
, const char* description
,
997 int (*callback
)(struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
)) {
998 struct pakfire_filelist
* removees
= NULL
;
1001 // Create a filelist with objects that need to be removed
1002 r
= pakfire_filelist_create(&removees
, build
->pakfire
);
1006 // Find all files that need to be removed
1007 r
= pakfire_filelist_walk(filelist
, callback
, removees
);
1011 if (!pakfire_filelist_is_empty(removees
)) {
1013 INFO(build
->pakfire
, "%s\n", description
);
1015 // Show all files which will be removed
1016 pakfire_filelist_dump(removees
, 0);
1018 // Remove all files on the removee list
1019 r
= pakfire_filelist_cleanup(removees
);
1023 // Remove all files from the filelist
1024 r
= pakfire_filelist_remove_all(filelist
, removees
);
1031 pakfire_filelist_unref(removees
);
1036 static int __pakfire_build_remove_static_libraries(
1037 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1038 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1040 // Find all static libraries
1041 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_STATIC_LIBRARY
))
1042 return pakfire_filelist_append(removees
, file
);
1047 static int pakfire_build_post_remove_static_libraries(
1048 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1049 return pakfire_build_post_remove_files(build
, filelist
,
1050 "Removing static libaries...", __pakfire_build_remove_static_libraries
);
1053 static int __pakfire_build_remove_libtool_archives(
1054 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1055 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1057 // Find all libtool archive files
1058 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_LIBTOOL_ARCHIVE
))
1059 return pakfire_filelist_append(removees
, file
);
1064 static int pakfire_build_post_remove_libtool_archives(
1065 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1066 return pakfire_build_post_remove_files(build
, filelist
,
1067 "Removing libtool archives...", __pakfire_build_remove_libtool_archives
);
1070 static int pakfire_build_run_post_build_checks(struct pakfire_build
* build
) {
1071 struct pakfire_filelist
* filelist
= NULL
;
1074 // Create a filelist of all files in the build
1075 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1077 ERROR(build
->pakfire
, "Could not create filelist: %m\n");
1081 // Scan for all files in BUILDROOT
1082 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
);
1086 const size_t length
= pakfire_filelist_size(filelist
);
1088 // If the filelist is empty, we can are done
1090 DEBUG(build
->pakfire
, "Empty BUILDROOT. Skipping post build checks...\n");
1095 // Remove any static libraries
1096 r
= pakfire_build_post_remove_static_libraries(build
, filelist
);
1100 // Remove any libtool archives
1101 r
= pakfire_build_post_remove_libtool_archives(build
, filelist
);
1107 pakfire_filelist_unref(filelist
);
1112 static const char* post_build_scripts
[] = {
1114 "check-unsafe-files",
1120 "check-interpreters",
1122 "compress-man-pages",
1127 static int pakfire_build_run_post_build_scripts(struct pakfire_build
* build
) {
1129 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1131 // Set default arguments for build scripts
1132 const char* args
[] = {
1136 // Run them one by one
1137 for (const char** script
= post_build_scripts
; *script
; script
++) {
1138 int r
= pakfire_build_run_script(build
, *script
, args
, NULL
, NULL
, NULL
);
1146 static void pakfire_build_free(struct pakfire_build
* build
) {
1147 if (build
->packages
)
1148 pakfire_packagelist_unref(build
->packages
);
1151 pakfire_repo_clean(build
->repo
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
1152 pakfire_repo_unref(build
->repo
);
1156 pakfire_jail_unref(build
->jail
);
1158 if (build
->cgroup
) {
1159 // Destroy the cgroup
1160 pakfire_cgroup_destroy(build
->cgroup
);
1163 pakfire_cgroup_unref(build
->cgroup
);
1166 pakfire_unref(build
->pakfire
);
1170 static int pakfire_build_parse_id(struct pakfire_build
* build
, const char* id
) {
1173 // Try parsing the Build ID
1175 r
= uuid_parse(id
, build
->id
);
1177 ERROR(build
->pakfire
, "Could not parse build ID '%s'\n", id
);
1182 // Otherwise initialize the Build ID with something random
1184 uuid_generate_random(build
->id
);
1187 // Store the ID as string, too
1188 uuid_unparse_lower(build
->id
, build
->_id
);
1194 Sets up a new cgroup for this build
1196 static int pakfire_build_setup_cgroup(struct pakfire_build
* build
) {
1197 struct pakfire_config
* config
= NULL
;
1198 char path
[PATH_MAX
];
1202 r
= pakfire_string_format(path
, "pakfire/build-%s", build
->_id
);
1204 ERROR(build
->pakfire
, "Could not compose path for cgroup: %m\n");
1208 // Create a new cgroup
1209 r
= pakfire_cgroup_open(&build
->cgroup
, build
->pakfire
, path
,
1210 PAKFIRE_CGROUP_ENABLE_ACCOUNTING
);
1212 ERROR(build
->pakfire
, "Could not create cgroup for build %s: %m\n", build
->_id
);
1217 config
= pakfire_get_config(build
->pakfire
);
1221 // Guarantee some minimum memory
1222 size_t memory_guaranteed
= pakfire_config_get_bytes(config
, "build",
1223 "memory_guaranteed", PAKFIRE_BUILD_MEMORY_GUARANTEED
);
1224 if (memory_guaranteed
) {
1225 r
= pakfire_cgroup_set_guaranteed_memory(build
->cgroup
, memory_guaranteed
);
1231 size_t memory_limit
= pakfire_config_get_bytes(config
, "build", "memory_limit", 0);
1233 r
= pakfire_cgroup_set_memory_limit(build
->cgroup
, memory_limit
);
1239 size_t pid_limit
= pakfire_config_get_int(config
, "build",
1240 "pid_limit", PAKFIRE_BUILD_PID_LIMIT
);
1242 r
= pakfire_cgroup_set_pid_limit(build
->cgroup
, pid_limit
);
1249 pakfire_config_unref(config
);
1255 Sets up a new jail for this build
1257 static int pakfire_build_setup_jail(struct pakfire_build
* build
) {
1260 // Create a new jail
1261 r
= pakfire_jail_create(&build
->jail
, build
->pakfire
, 0);
1263 ERROR(build
->pakfire
, "Could not create jail for build %s: %m\n", build
->_id
);
1267 // Connect the jail to our cgroup
1268 r
= pakfire_jail_set_cgroup(build
->jail
, build
->cgroup
);
1270 ERROR(build
->pakfire
, "Could not set cgroup for jail: %m\n");
1279 Sets up the ccache for this build
1281 static int pakfire_build_setup_ccache(struct pakfire_build
* build
) {
1282 char path
[PATH_MAX
];
1285 // Check if we want a ccache
1286 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
)) {
1287 DEBUG(build
->pakfire
, "ccache usage has been disabled for this build\n");
1289 // Set CCACHE_DISABLE=1 so that if ccache is installed, it will disable itself
1290 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_DISABLE", "1");
1292 ERROR(build
->pakfire
, "Could not disable ccache: %m\n");
1300 r
= pakfire_cache_path(build
->pakfire
, path
, "%s", "ccache");
1302 ERROR(build
->pakfire
, "Could not compose ccache path: %m\n");
1306 DEBUG(build
->pakfire
, "Mounting ccache from %s\n", path
);
1308 // Ensure path exists
1309 r
= pakfire_mkdir(path
, 0755);
1310 if (r
&& errno
!= EEXIST
) {
1311 ERROR(build
->pakfire
, "Could not create ccache directory %s: %m\n", path
);
1315 // Bind-mount the directory
1316 r
= pakfire_jail_bind(build
->jail
, path
, CCACHE_DIR
, MS_NOSUID
|MS_NOEXEC
|MS_NODEV
);
1318 ERROR(build
->pakfire
, "Could not mount ccache: %m\n");
1325 static int pakfire_build_setup_repo(struct pakfire_build
* build
) {
1326 char path
[PATH_MAX
] = PAKFIRE_TMP_DIR
"/pakfire-build-repo.XXXXXX";
1330 // Create a new repository
1331 r
= pakfire_repo_create(&build
->repo
, build
->pakfire
, PAKFIRE_REPO_RESULT
);
1333 ERROR(build
->pakfire
, "Could not create repository %s: %m", PAKFIRE_REPO_RESULT
);
1338 pakfire_repo_set_description(build
->repo
, _("Build Repository"));
1340 // Create a temporary directory
1341 const char* p
= pakfire_mkdtemp(path
);
1343 ERROR(build
->pakfire
, "Could not create a the build repository: %m\n");
1348 r
= pakfire_string_format(url
, "file://%s", path
);
1353 pakfire_repo_set_baseurl(build
->repo
, url
);
1358 PAKFIRE_EXPORT
int pakfire_build_create(struct pakfire_build
** build
,
1359 struct pakfire
* pakfire
, const char* id
, int flags
) {
1362 // Allocate build object
1363 struct pakfire_build
* b
= calloc(1, sizeof(*b
));
1367 // Reference pakfire
1368 b
->pakfire
= pakfire_ref(pakfire
);
1370 // Initialize reference counter
1377 r
= pakfire_build_parse_id(b
, id
);
1382 r
= pakfire_build_setup_repo(b
);
1387 r
= pakfire_build_setup_cgroup(b
);
1392 r
= pakfire_build_setup_jail(b
);
1397 r
= pakfire_build_setup_ccache(b
);
1405 pakfire_build_free(b
);
1409 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_ref(struct pakfire_build
* build
) {
1415 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_unref(struct pakfire_build
* build
) {
1416 if (--build
->nrefs
> 0)
1419 pakfire_build_free(build
);
1423 PAKFIRE_EXPORT
int pakfire_build_set_target(
1424 struct pakfire_build
* build
, const char* target
) {
1425 return pakfire_string_set(build
->target
, target
);
1428 static int pakfire_build_install_packages(struct pakfire_build
* build
,
1429 int* snapshot_needs_update
) {
1432 const char* packages
[] = {
1439 // Install everything
1440 r
= pakfire_install(build
->pakfire
, 0, 0, packages
, NULL
, 0,
1441 &changed
, NULL
, NULL
);
1443 ERROR(build
->pakfire
, "Could not install build dependencies: %m\n");
1447 // Mark snapshot as changed if new packages were installed
1449 *snapshot_needs_update
= 1;
1451 // Update everything
1452 r
= pakfire_sync(build
->pakfire
, 0, 0, &changed
, NULL
, NULL
);
1454 ERROR(build
->pakfire
, "Could not update packages: %m\n");
1458 // Has anything changed?
1460 *snapshot_needs_update
= 1;
1466 Initializes the build environment
1468 static int pakfire_build_init(struct pakfire_build
* build
) {
1469 char path
[PATH_MAX
];
1472 // Don't do it again
1474 DEBUG(build
->pakfire
, "Build environment has already been initialized\n");
1478 // Compose path for snapshot
1479 r
= pakfire_cache_path(build
->pakfire
, path
, "%s", "snapshot.tar.zst");
1481 ERROR(build
->pakfire
, "Could not compose snapshot path: %m\n");
1485 // Tells us whether we need to (re-)create the snapshot
1486 int snapshot_needs_update
= 0;
1489 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_SNAPSHOT
)) {
1490 // Try restoring the snapshot
1491 r
= pakfire_snapshot_restore(build
->pakfire
, path
);
1492 if (r
&& errno
!= ENOENT
)
1496 // Install or update any build dependencies
1497 r
= pakfire_build_install_packages(build
, &snapshot_needs_update
);
1501 // Update the snapshot if there were changes
1502 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_SNAPSHOT
) && snapshot_needs_update
) {
1503 // Create a new snapshot
1504 r
= pakfire_snapshot_create(build
->pakfire
, path
);
1509 // Mark as initialized
1515 static int pakfire_build_read_makefile(struct pakfire_build
* build
,
1516 struct pakfire_parser
** parser
, struct pakfire_package
* package
) {
1517 char path
[PATH_MAX
];
1520 struct pakfire_parser_error
* error
= NULL
;
1522 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
1523 const char* name
= pakfire_package_get_string(package
, PAKFIRE_PKG_NAME
);
1525 // Compose path to makefile
1526 r
= pakfire_path(build
->pakfire
, path
, "/usr/src/packages/%s/%s.nm", nevra
, name
);
1531 r
= pakfire_read_makefile(parser
, build
->pakfire
, path
, &error
);
1534 ERROR(build
->pakfire
, "Could not parse makefile %s: %s\n", path
,
1535 pakfire_parser_error_get_message(error
));
1537 ERROR(build
->pakfire
, "Could not parse makefile %s: %m\n", path
);
1544 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1546 pakfire_parser_set(*parser
, NULL
, "BUILDROOT", buildroot
, 0);
1550 pakfire_parser_error_unref(error
);
1555 static int pakfire_build_perform(struct pakfire_build
* build
,
1556 struct pakfire_parser
* makefile
) {
1559 // Prepare the build
1560 r
= pakfire_build_stage(build
, makefile
, "prepare");
1564 // Perform the build
1565 r
= pakfire_build_stage(build
, makefile
, "build");
1570 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_TESTS
)) {
1571 r
= pakfire_build_stage(build
, makefile
, "test");
1576 // Install everything
1577 r
= pakfire_build_stage(build
, makefile
, "install");
1581 // Run post build checks
1582 r
= pakfire_build_run_post_build_checks(build
);
1586 // Run post build scripts
1587 r
= pakfire_build_run_post_build_scripts(build
);
1595 // Drop to a shell for debugging
1596 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_INTERACTIVE
))
1597 pakfire_build_shell(build
);
1602 static int __pakfire_build_unpackaged_file(struct pakfire
* pakfire
,
1603 struct pakfire_file
* file
, void* p
) {
1604 char* s
= pakfire_file_dump(file
);
1606 ERROR(pakfire
, "%s\n", s
);
1613 static int pakfire_build_check_unpackaged_files(struct pakfire_build
* build
) {
1614 struct pakfire_filelist
* filelist
= NULL
;
1617 // Create a new filelist
1618 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1622 // Scan for all files in BUILDROOT
1623 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
);
1627 const size_t length
= pakfire_filelist_size(filelist
);
1630 ERROR(build
->pakfire
, "Unpackaged files found:\n");
1632 r
= pakfire_filelist_walk(filelist
, __pakfire_build_unpackaged_file
, NULL
);
1642 pakfire_filelist_unref(filelist
);
1647 static int pakfire_build_install_package(struct pakfire
* pakfire
,
1648 struct pakfire_package
* pkg
, void* p
) {
1649 struct pakfire_request
* request
= (struct pakfire_request
*)p
;
1651 return pakfire_request_add_package(request
, PAKFIRE_REQ_INSTALL
, pkg
,
1652 PAKFIRE_REQUEST_ESSENTIAL
);
1655 static int pakfire_build_install_test(struct pakfire_build
* build
) {
1656 struct pakfire_request
* request
= NULL
;
1657 struct pakfire_problem
* problem
= NULL
;
1658 struct pakfire_solution
* solution
= NULL
;
1659 const char* s
= NULL
;
1662 // Create a new request
1663 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
1668 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_install_package
, request
);
1670 // Solve the request
1671 r
= pakfire_request_solve(request
);
1679 ERROR(build
->pakfire
, "Install test failed:\n");
1681 // Walk through all problems
1683 r
= pakfire_request_next_problem(request
, &problem
);
1687 // There are no more problems
1691 // Format the problem into something human-readable
1692 s
= pakfire_problem_to_string(problem
);
1696 ERROR(build
->pakfire
, " * %s\n", s
);
1698 // Walk through all solutions
1700 r
= pakfire_problem_next_solution(problem
, &solution
);
1704 // There are no more solutions
1708 // Format the solution into something human-readable
1709 s
= pakfire_solution_to_string(solution
);
1713 ERROR(build
->pakfire
, " * %s\n", s
);
1726 ERROR(build
->pakfire
, "Install test failed: %m\n");
1728 pakfire_request_unref(request
);
1730 pakfire_problem_unref(problem
);
1732 pakfire_solution_unref(solution
);
1737 static int pakfire_build_post_check(struct pakfire_build
* build
) {
1740 // Check for unpackaged files
1741 r
= pakfire_build_check_unpackaged_files(build
);
1745 // Perform install test
1746 r
= pakfire_build_install_test(build
);
1753 static int pakfire_build_copy_package(struct pakfire
* pakfire
,
1754 struct pakfire_package
* pkg
, void* p
) {
1755 struct pakfire_archive
* archive
= NULL
;
1756 char path
[PATH_MAX
];
1759 const char* target
= (const char*)p
;
1766 // Fetch the package filename
1767 const char* filename
= pakfire_package_get_string(pkg
, PAKFIRE_PKG_FILENAME
);
1773 // Format the destination path
1774 r
= pakfire_string_format(path
, "%s/%s", target
, filename
);
1779 archive
= pakfire_package_get_archive(pkg
);
1785 // Copy it to its destination
1786 r
= pakfire_archive_copy(archive
, path
);
1792 pakfire_archive_unref(archive
);
1797 static int pakfire_build_copy_packages(struct pakfire_build
* build
) {
1798 struct pakfire_repo
* local
= NULL
;
1801 DEBUG(build
->pakfire
, "Copying built packages\n");
1803 // Fetch local repository
1804 local
= pakfire_get_repo(build
->pakfire
, PAKFIRE_REPO_LOCAL
);
1806 // Copy all packages to the target path
1807 if (*build
->target
) {
1808 r
= pakfire_packagelist_walk(build
->packages
,
1809 pakfire_build_copy_package
, build
->target
);
1814 // If we have a local repository, we copy all packages to it
1816 const char* path
= pakfire_repo_get_path(local
);
1818 r
= pakfire_packagelist_walk(build
->packages
,
1819 pakfire_build_copy_package
, (void*)path
);
1827 pakfire_repo_unref(local
);
1832 static int pakfire_build_install_source_package(
1833 struct pakfire_build
* build
, struct pakfire_package
* package
) {
1834 struct pakfire_request
* request
= NULL
;
1835 struct pakfire_transaction
* transaction
= NULL
;
1838 // Create a new request
1839 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
1844 r
= pakfire_request_add_package(request
, PAKFIRE_REQ_INSTALL
, package
,
1845 PAKFIRE_REQUEST_ESSENTIAL
);
1849 // Solve the request
1850 r
= pakfire_request_solve(request
);
1854 // Fetch the transaction
1855 r
= pakfire_request_get_transaction(request
, &transaction
);
1859 // Set how many packages have been changed
1860 const size_t changes
= pakfire_transaction_count(transaction
);
1862 // Sanity check to see if we actually try to install anything
1864 ERROR(build
->pakfire
, "The source package did not get installed\n");
1869 // Run the transaction
1870 r
= pakfire_transaction_run(transaction
, 0);
1876 pakfire_transaction_unref(transaction
);
1878 pakfire_request_unref(request
);
1883 PAKFIRE_EXPORT
int pakfire_build_exec(struct pakfire_build
* build
, const char* path
) {
1884 struct pakfire_package
* package
= NULL
;
1885 struct pakfire_parser
* makefile
= NULL
;
1886 char* buildroot
= NULL
;
1890 r
= pakfire_path(build
->pakfire
, build
->buildroot
, "%s",
1891 PAKFIRE_TMP_DIR
"/pakfire-buildroot.XXXXXX");
1895 // Open the source package
1896 r
= pakfire_commandline_add(build
->pakfire
, path
, &package
);
1900 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
1902 INFO(build
->pakfire
, "Building %s...\n", nevra
);
1904 // Initialize the build environment
1905 r
= pakfire_build_init(build
);
1909 // Install the source package
1910 r
= pakfire_build_install_source_package(build
, package
);
1912 ERROR(build
->pakfire
, "Could not install the source package: %m\n");
1917 buildroot
= pakfire_mkdtemp(build
->buildroot
);
1919 ERROR(build
->pakfire
, "Could not create BUILDROOT: %m\n");
1923 // Open the makefile
1924 r
= pakfire_build_read_makefile(build
, &makefile
, package
);
1928 // Perform the actual build
1929 r
= pakfire_build_perform(build
, makefile
);
1933 // Create the packages
1934 r
= pakfire_build_packages(build
, makefile
);
1936 ERROR(build
->pakfire
, "Could not create packages: %m\n");
1940 // Perform post build checks
1941 r
= pakfire_build_post_check(build
);
1945 // Copy packages to their destination
1946 r
= pakfire_build_copy_packages(build
);
1952 pakfire_parser_unref(makefile
);
1954 pakfire_package_unref(package
);
1956 // Cleanup buildroot
1958 pakfire_rmtree(buildroot
, 0);
1964 Compatibility function to keep the legacy API.
1966 PAKFIRE_EXPORT
int pakfire_build(struct pakfire
* pakfire
, const char* path
,
1967 const char* target
, const char* id
, int flags
) {
1968 struct pakfire_build
* build
= NULL
;
1971 // Check if path is set
1977 // Create a new build environment
1978 r
= pakfire_build_create(&build
, pakfire
, id
, flags
);
1984 r
= pakfire_build_set_target(build
, target
);
1990 r
= pakfire_build_exec(build
, path
);
1994 pakfire_build_unref(build
);
1999 int pakfire_build_clean(struct pakfire
* pakfire
, int flags
) {
2000 struct pakfire_repo
* local
= NULL
;
2003 // Fetch local repository
2004 local
= pakfire_get_repo(pakfire
, PAKFIRE_REPO_LOCAL
);
2006 ERROR(pakfire
, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL
);
2010 // Destroy everything in it
2011 r
= pakfire_repo_clean(local
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
2017 pakfire_repo_unref(local
);
2023 This is a convenience function that sets up a build environment and
2024 then drops the user into an interactive shell.
2026 PAKFIRE_EXPORT
int pakfire_shell(struct pakfire
* pakfire
, const char** packages
, int flags
) {
2027 struct pakfire_build
* build
= NULL
;
2030 // Shells are always interactive
2031 flags
|= PAKFIRE_BUILD_INTERACTIVE
;
2033 // Create a new build environment
2034 r
= pakfire_build_create(&build
, pakfire
, NULL
, flags
);
2036 ERROR(pakfire
, "Could not create build: %m\n");
2040 // Initialize the build environment
2041 r
= pakfire_build_init(build
);
2045 // Install any additional packages
2047 r
= pakfire_install(build
->pakfire
, 0, 0, packages
, NULL
, 0, NULL
, NULL
, NULL
);
2053 r
= pakfire_build_shell(build
);
2057 pakfire_build_unref(build
);