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>
26 #include <uuid/uuid.h>
28 #define PCRE2_CODE_UNIT_WIDTH 8
31 #include <pakfire/build.h>
32 #include <pakfire/cgroup.h>
33 #include <pakfire/dependencies.h>
34 #include <pakfire/dist.h>
35 #include <pakfire/fhs.h>
36 #include <pakfire/file.h>
37 #include <pakfire/i18n.h>
38 #include <pakfire/jail.h>
39 #include <pakfire/logging.h>
40 #include <pakfire/mount.h>
41 #include <pakfire/package.h>
42 #include <pakfire/packager.h>
43 #include <pakfire/parser.h>
44 #include <pakfire/private.h>
45 #include <pakfire/problem.h>
46 #include <pakfire/repo.h>
47 #include <pakfire/request.h>
48 #include <pakfire/scriptlet.h>
49 #include <pakfire/snapshot.h>
50 #include <pakfire/solution.h>
51 #include <pakfire/string.h>
52 #include <pakfire/util.h>
54 #define CCACHE_DIR "/var/cache/ccache"
56 // We guarantee 2 GiB of memory to every build container
57 #define PAKFIRE_BUILD_MEMORY_GUARANTEED (size_t)2 * 1024 * 1024 * 1024
59 // We allow only up to 2048 processes/threads for every build container
60 #define PAKFIRE_BUILD_PID_LIMIT (size_t)2048
62 struct pakfire_build
{
63 struct pakfire
* pakfire
;
71 char _id
[UUID_STR_LEN
];
73 char target
[PATH_MAX
];
79 struct pakfire_cgroup
* cgroup
;
82 struct pakfire_jail
* jail
;
84 // The build repository
85 struct pakfire_repo
* repo
;
87 // A list of all built packages
88 struct pakfire_packagelist
* packages
;
91 char buildroot
[PATH_MAX
];
98 "#!/bin/bash --login\n" \
107 static int pakfire_build_has_flag(struct pakfire_build
* build
, int flag
) {
108 return build
->flags
& flag
;
111 static time_t pakfire_build_duration(struct pakfire_build
* build
) {
112 // What time is it now?
113 time_t now
= time(NULL
);
119 return now
- build
->time_start
;
122 static int __pakfire_build_setup_repo(struct pakfire
* pakfire
,
123 struct pakfire_repo
* repo
, void* p
) {
128 struct pakfire_build
* build
= (struct pakfire_build
*)p
;
130 // Skip processing the installed repository
131 if (pakfire_repo_is_installed_repo(repo
))
134 // Skip processing any other internal repositories
135 if (pakfire_repo_is_internal(repo
))
138 const char* name
= pakfire_repo_get_name(repo
);
140 DEBUG(pakfire
, "Exporting repository configuration for '%s'\n", name
);
142 // Make path for configuration file
143 r
= pakfire_path(build
->pakfire
, path
, PAKFIRE_CONFIG_DIR
"/repos/%s.repo", name
);
145 ERROR(pakfire
, "Could not make repository configuration path for %s: %m\n", name
);
149 // Create the parent directory
150 r
= pakfire_mkparentdir(path
, 0755);
154 // Open the repository configuration
155 f
= fopen(path
, "w");
157 ERROR(pakfire
, "Could not open %s for writing: %m\n", path
);
161 // Write repository configuration
162 r
= pakfire_repo_write_config(repo
, f
);
164 ERROR(pakfire
, "Could not write repository configuration for %s: %m\n", name
);
168 // Bind-mount any local repositories
169 if (pakfire_repo_is_local(repo
)) {
170 const char* _path
= pakfire_repo_get_path(repo
);
172 // Bind-mount the repository data read-only
173 r
= pakfire_jail_bind(build
->jail
, _path
, _path
, MS_RDONLY
);
175 ERROR(pakfire
, "Could not bind-mount the repository at %s: %m\n", _path
);
188 This function enables the local repository so that it can be accessed by
189 a pakfire instance running inside the chroot.
191 static int pakfire_build_enable_repos(struct pakfire_build
* build
) {
192 return pakfire_repo_walk(build
->pakfire
, __pakfire_build_setup_repo
, build
);
196 Drops the user into a shell
198 static int pakfire_build_shell(struct pakfire_build
* build
) {
201 // Export local repository if running in interactive mode
202 r
= pakfire_build_enable_repos(build
);
207 return pakfire_jail_shell(build
->jail
);
210 static int pakfire_build_read_script(struct pakfire_build
* build
,
211 const char* filename
, char** buffer
, size_t* length
) {
216 // Compose the source path
217 r
= pakfire_path_join(path
, PAKFIRE_SCRIPTS_DIR
, filename
);
219 ERROR(build
->pakfire
, "Could not compose path for script '%s': %m\n", filename
);
223 DEBUG(build
->pakfire
, "Reading script from %s...\n", path
);
226 f
= fopen(path
, "r");
228 ERROR(build
->pakfire
, "Could not open script %s: %m\n", path
);
232 // Read the file into a the buffer
233 r
= pakfire_read_file_into_buffer(f
, buffer
, length
);
235 ERROR(build
->pakfire
, "Could not read script: %m\n");
246 static int pakfire_build_run_script(
247 struct pakfire_build
* build
,
248 const char* filename
,
250 pakfire_jail_communicate_in communicate_in
,
251 pakfire_jail_communicate_out communicate_out
,
258 DEBUG(build
->pakfire
, "Running build script '%s'...\n", filename
);
261 r
= pakfire_build_read_script(build
, filename
, &script
, &length
);
263 ERROR(build
->pakfire
, "Could not read script %s: %m\n", filename
);
267 // Execute the script
268 r
= pakfire_jail_exec_script(build
->jail
, script
, length
, args
,
269 communicate_in
, communicate_out
, data
);
271 ERROR(build
->pakfire
, "Script '%s' failed with status %d\n", filename
, r
);
280 struct pakfire_find_deps_ctx
{
281 struct pakfire_package
* pkg
;
283 struct pakfire_scriptlet
* scriptlet
;
285 const pcre2_code
* filter
;
287 struct pakfire_filelist
* filelist
;
291 static int pakfire_build_make_filter(struct pakfire_build
* build
, pcre2_code
** regex
,
292 struct pakfire_parser
* makefile
, const char* namespace, const char* filter
) {
293 char* pattern
= NULL
;
297 pattern
= pakfire_parser_get(makefile
, namespace, filter
);
299 // Nothing if to if there is no or an empty pattern
300 if (!pattern
|| !*pattern
)
303 DEBUG(build
->pakfire
, "Found filter for %s: %s\n", filter
, pattern
);
305 // Compile the regular expression
306 r
= pakfire_compile_regex(build
->pakfire
, regex
, pattern
);
317 static int pakfire_build_send_filelist(struct pakfire
* pakfire
, void* data
, int fd
) {
318 struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
319 struct pakfire_file
* file
= NULL
;
322 const size_t length
= pakfire_filelist_length(ctx
->filelist
);
324 // Check if we have reached the end of the filelist
325 if (ctx
->i
>= length
)
328 // Fetch the next file
329 file
= pakfire_filelist_get(ctx
->filelist
, ctx
->i
);
331 DEBUG(pakfire
, "Could not fetch file %d: %m\n", ctx
->i
);
336 // Fetch the path of the file
337 const char* path
= pakfire_file_get_path(file
);
339 ERROR(pakfire
, "Received a file with an empty path\n");
344 // Skip files that don't match what we are looking for
345 if (ctx
->class && !pakfire_file_matches_class(file
, ctx
->class))
348 // Write path to stdin
349 r
= dprintf(fd
, "%s\n", path
);
354 // Move on to the next file
362 pakfire_file_unref(file
);
367 static int pakfire_build_process_deps(struct pakfire
* pakfire
,
368 void* data
, int priority
, const char* buffer
, const size_t length
) {
369 const struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
371 pcre2_match_data
* match
= NULL
;
374 // Nothing to do for an empty buffer
375 if (!buffer
|| !*buffer
)
379 // Add every dependency that we have received
381 // Copy the dependency to the stack (and remove the trailing newline)
382 r
= pakfire_string_format(dep
, "%.*s", (int)length
- 1, buffer
);
386 DEBUG(pakfire
, "Processing dependency: %s\n", dep
);
388 // Filter out any dependencies that are provided by this package
389 if (ctx
->dep
== PAKFIRE_PKG_REQUIRES
) {
390 // If this is a file, we check if it is on the filelist
391 if (pakfire_filelist_contains(ctx
->filelist
, dep
))
394 // Otherwise check if this dependency is provided by this package
395 else if (pakfire_package_matches_dep(ctx
->pkg
, PAKFIRE_PKG_PROVIDES
, dep
))
399 // Check if this dependency should be filtered
401 match
= pcre2_match_data_create_from_pattern(ctx
->filter
, NULL
);
403 ERROR(pakfire
, "Could not allocate PCRE match data: %m\n");
408 r
= pcre2_jit_match(ctx
->filter
, (PCRE2_SPTR
)dep
, length
- 1,
412 if (r
== PCRE2_ERROR_NOMATCH
) {
419 // Fetch the error message
420 r
= pcre2_get_error_message(r
, (PCRE2_UCHAR
*)error
, sizeof(error
));
422 ERROR(pakfire
, "Could not fetch PCRE error message: %m\n");
427 ERROR(pakfire
, "Could not match the filter: %s\n", error
);
433 DEBUG(pakfire
, "Skipping dependency that has been filtered: %s\n", dep
);
440 r
= pakfire_package_add_dep(ctx
->pkg
, ctx
->dep
, buffer
);
442 ERROR(pakfire
, "Could not process dependency '%s': %m\n", buffer
);
447 // Send everything else to the default logger
449 ERROR(pakfire
, "%s\n", buffer
);
456 DEBUG(pakfire
, "Skipping dependency that is provided by the package itself: %s\n", dep
);
460 pcre2_match_data_free(match
);
466 This function is a special way to run a script.
468 It will pipe the filelist into the standard input of the called script
469 and will read any dependencies from the standard output.
471 static int pakfire_build_find_deps(struct pakfire_build
* build
,
472 struct pakfire_package
* pkg
, int dep
, const char* script
,
473 struct pakfire_filelist
* filelist
, int class, const pcre2_code
* filter
) {
474 // Construct the context
475 struct pakfire_find_deps_ctx ctx
= {
482 .filelist
= filelist
,
487 // Skip calling the script if class doesn't match
488 if (class && !pakfire_filelist_matches_class(filelist
, class)) {
489 DEBUG(build
->pakfire
, "Skipping calling %s as class does not match\n", script
);
493 // Pass the buildroot as first argument
494 const char* args
[] = {
495 pakfire_relpath(build
->pakfire
, build
->buildroot
),
500 r
= pakfire_build_run_script(build
, script
, args
,
501 pakfire_build_send_filelist
, pakfire_build_process_deps
, &ctx
);
503 ERROR(build
->pakfire
, "%s returned with error %d\n", script
, r
);
508 static int pakfire_build_find_dependencies(struct pakfire_build
* build
,
509 struct pakfire_parser
* makefile
, const char* namespace,
510 struct pakfire_package
* pkg
, struct pakfire_filelist
* filelist
) {
511 pcre2_code
* filter_provides
= NULL
;
512 pcre2_code
* filter_requires
= NULL
;
515 // Fetch the provides filter
516 r
= pakfire_build_make_filter(build
, &filter_provides
,
517 makefile
, namespace, "filter_provides");
519 ERROR(build
->pakfire
, "Provides filter is broken: %m\n");
523 // Fetch the requires filter
524 r
= pakfire_build_make_filter(build
, &filter_requires
,
525 makefile
, namespace, "filter_requires");
527 ERROR(build
->pakfire
, "Requires filter is broken: %m\n");
532 r
= pakfire_build_find_deps(build
, pkg
,
533 PAKFIRE_PKG_PROVIDES
, "find-provides", filelist
, 0, filter_provides
);
537 // Find all Perl provides
538 r
= pakfire_build_find_deps(build
, pkg
,
539 PAKFIRE_PKG_PROVIDES
, "perl.prov", filelist
, PAKFIRE_FILE_PERL
, filter_provides
);
544 r
= pakfire_build_find_deps(build
, pkg
,
545 PAKFIRE_PKG_REQUIRES
, "find-requires", filelist
, 0, filter_requires
);
549 // Find all Perl requires
550 r
= pakfire_build_find_deps(build
, pkg
,
551 PAKFIRE_PKG_REQUIRES
, "perl.req", filelist
, PAKFIRE_FILE_PERL
, filter_requires
);
557 pcre2_code_free(filter_provides
);
559 pcre2_code_free(filter_requires
);
564 static int __pakfire_build_package_mark_config_files(
565 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
566 char** configfiles
= (char**)data
;
569 // Skip anything that isn't a regular file
570 if (pakfire_file_get_type(file
) == S_IFREG
)
574 const char* path
= pakfire_file_get_path(file
);
576 // Check if any configfile entry matches against this
577 for (char** configfile
= configfiles
; *configfile
; configfile
++) {
578 if (pakfire_string_startswith(path
, *configfile
)) {
579 r
= pakfire_file_set_flags(file
, PAKFIRE_FILE_CONFIG
);
591 static int pakfire_build_package_mark_config_files(struct pakfire_build
* build
,
592 struct pakfire_filelist
* filelist
, struct pakfire_parser
* makefile
, const char* namespace) {
593 char** configfiles
= NULL
;
596 // Fetch configfiles from makefile
597 r
= pakfire_parser_get_filelist(makefile
, namespace, "configfiles", &configfiles
, NULL
);
599 // If configfiles is not set, there is nothing to do
603 r
= pakfire_filelist_walk(filelist
, __pakfire_build_package_mark_config_files
, configfiles
);
607 for (char** configfile
= configfiles
; *configfile
; configfile
++)
615 static int pakfire_build_package_add_files(struct pakfire_build
* build
,
616 struct pakfire_parser
* makefile
, const char* buildroot
, const char* namespace,
617 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
618 struct pakfire_filelist
* filelist
= NULL
;
619 char** includes
= NULL
;
620 char** excludes
= NULL
;
623 // Fetch filelist from makefile
624 r
= pakfire_parser_get_filelist(makefile
, namespace, "files", &includes
, &excludes
);
626 // No files to package?
627 if (!includes
&& !excludes
)
630 // Allocate a new filelist
631 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
636 r
= pakfire_filelist_scan(filelist
, build
->buildroot
,
637 (const char**)includes
, (const char**)excludes
);
641 DEBUG(build
->pakfire
, "%zu file(s) found\n", pakfire_filelist_length(filelist
));
643 // Nothing to do if the filelist is empty
644 if (pakfire_filelist_is_empty(filelist
))
648 pakfire_filelist_dump(filelist
, PAKFIRE_FILE_DUMP_FULL
);
651 r
= pakfire_build_find_dependencies(build
, makefile
, namespace, pkg
, filelist
);
653 ERROR(build
->pakfire
, "Finding dependencies failed: %m\n");
657 // Mark configuration files
658 r
= pakfire_build_package_mark_config_files(build
, filelist
, makefile
, namespace);
662 // Add all files to the package
663 r
= pakfire_packager_add_files(packager
, filelist
);
669 pakfire_filelist_unref(filelist
);
671 for (char** include
= includes
; *include
; include
++)
676 for (char** exclude
= excludes
; *exclude
; exclude
++)
684 static int pakfire_build_send_scriptlet(struct pakfire
* pakfire
, void* data
, int fd
) {
685 const struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
688 // Fetch the scriptlet
689 const char* p
= pakfire_scriptlet_get_data(ctx
->scriptlet
, &length
);
691 ERROR(pakfire
, "Could not fetch scriptlet: %m\n");
695 // Write it into the pipe
696 ssize_t bytes_written
= write(fd
, p
, length
);
697 if (bytes_written
< 0) {
698 ERROR(pakfire
, "Could not send scriptlet: %m\n");
705 static int pakfire_build_add_scriptlet_requires(struct pakfire_build
* build
,
706 struct pakfire_package
* pkg
, struct pakfire_scriptlet
* scriptlet
) {
709 struct pakfire_find_deps_ctx ctx
= {
711 .dep
= PAKFIRE_PKG_PREREQUIRES
,
712 .scriptlet
= scriptlet
,
715 // Find all pre-requires
716 r
= pakfire_build_run_script(build
, "find-prerequires", NULL
,
717 pakfire_build_send_scriptlet
, pakfire_build_process_deps
, &ctx
);
725 static int pakfire_build_package_add_scriptlet(struct pakfire_build
* build
,
726 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
,
727 const char* type
, const char* data
) {
728 struct pakfire_scriptlet
* scriptlet
= NULL
;
732 // Wrap scriptlet into a shell script
733 r
= asprintf(&shell
, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data
);
737 // Create a scriptlet
738 r
= pakfire_scriptlet_create(&scriptlet
, build
->pakfire
, type
, shell
, 0);
742 // Add it to the package
743 r
= pakfire_packager_add_scriptlet(packager
, scriptlet
);
745 ERROR(build
->pakfire
, "Could not add scriptlet %s\n", type
);
749 // Add scriptlet requirements
750 r
= pakfire_build_add_scriptlet_requires(build
, pkg
, scriptlet
);
752 ERROR(build
->pakfire
, "Could not add scriptlet requirements: %m\n");
761 pakfire_scriptlet_unref(scriptlet
);
768 static int pakfire_build_package_add_scriptlets(struct pakfire_build
* build
,
769 struct pakfire_parser
* makefile
, const char* namespace,
770 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
774 for (const char** type
= pakfire_scriptlet_types
; *type
; type
++) {
775 r
= pakfire_string_format(name
, "scriptlet:%s", *type
);
779 // Fetch the scriptlet
780 char* data
= pakfire_parser_get(makefile
, namespace, name
);
784 // Add it to the package
785 r
= pakfire_build_package_add_scriptlet(build
, pkg
, packager
, *type
, data
);
797 static int pakfire_build_package(struct pakfire_build
* build
, struct pakfire_parser
* makefile
,
798 const char* buildroot
, const char* namespace) {
799 struct pakfire_package
* pkg
= NULL
;
800 struct pakfire_packager
* packager
= NULL
;
804 // Expand the handle into the package name
805 char* name
= pakfire_parser_expand(makefile
, "packages", namespace);
807 ERROR(build
->pakfire
, "Could not get package name: %m\n");
811 INFO(build
->pakfire
, "Building package '%s'...\n", name
);
812 DEBUG(build
->pakfire
, " buildroot = %s\n", buildroot
);
814 // Fetch build architecture
815 const char* arch
= pakfire_get_arch(build
->pakfire
);
819 // Fetch package from makefile
820 r
= pakfire_parser_create_package(makefile
, &pkg
, NULL
, namespace, arch
);
822 ERROR(build
->pakfire
, "Could not create package from makefile: %m\n");
827 const char* distribution
= pakfire_parser_get(makefile
, NULL
, "DISTRO_NAME");
829 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_DISTRO
, distribution
);
835 pakfire_package_set_uuid(pkg
, PAKFIRE_PKG_BUILD_ID
, build
->id
);
837 // Set source package
838 const char* source_name
= pakfire_parser_get(makefile
, NULL
, "name");
840 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_NAME
, source_name
);
846 const char* source_evr
= pakfire_parser_get(makefile
, NULL
, "evr");
848 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_EVR
, source_evr
);
854 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_ARCH
, "src");
859 r
= pakfire_packager_create(&packager
, build
->pakfire
, pkg
);
864 r
= pakfire_build_package_add_files(build
, makefile
, buildroot
, namespace,
870 r
= pakfire_build_package_add_scriptlets(build
, makefile
, namespace,
875 const char* path
= pakfire_repo_get_path(build
->repo
);
877 // Write the finished package
878 r
= pakfire_packager_finish_to_directory(packager
, path
, NULL
);
880 ERROR(build
->pakfire
, "pakfire_packager_finish() failed: %m\n");
884 // Cleanup all packaged files
885 r
= pakfire_packager_cleanup(packager
);
894 pakfire_packager_unref(packager
);
896 pakfire_package_unref(pkg
);
903 static int pakfire_build_package_dump(struct pakfire
* pakfire
,
904 struct pakfire_package
* pkg
, void* p
) {
905 char* dump
= pakfire_package_dump(pkg
, PAKFIRE_PKG_DUMP_LONG
);
909 INFO(pakfire
, "%s\n", dump
);
915 static int pakfire_build_packages(struct pakfire_build
* build
,
916 struct pakfire_parser
* makefile
) {
917 DEBUG(build
->pakfire
, "Creating packages...");
920 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
922 // Fetch a list all all packages
923 char** packages
= pakfire_parser_list_namespaces(makefile
, "packages.package:*");
925 ERROR(build
->pakfire
, "Could not find any packages: %m\n");
929 unsigned int num_packages
= 0;
931 // Count how many packages we have
932 for (char** package
= packages
; *package
; package
++)
935 DEBUG(build
->pakfire
, "Found %d package(s)\n", num_packages
);
937 // Build packages in reverse order
938 for (int i
= num_packages
- 1; i
>= 0; i
--) {
939 r
= pakfire_build_package(build
, makefile
, buildroot
, packages
[i
]);
944 // Rescan the build repository to import all packages again
945 r
= pakfire_repo_scan(build
->repo
, 0);
949 // Create a new packagelist
950 r
= pakfire_packagelist_create(&build
->packages
, build
->pakfire
);
954 // Fetch all packages
955 r
= pakfire_repo_to_packagelist(build
->repo
, build
->packages
);
960 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_package_dump
, NULL
);
974 static int pakfire_build_stage(struct pakfire_build
* build
,
975 struct pakfire_parser
* makefile
, const char* stage
) {
978 // Prepare template for this stage
979 int r
= pakfire_string_format(template, TEMPLATE
, stage
);
983 // Fetch the environment
984 char** envp
= pakfire_parser_make_environ(makefile
);
986 // Create the build script
987 char* script
= pakfire_parser_expand(makefile
, "build", template);
989 ERROR(build
->pakfire
, "Could not generate the build script for stage '%s': %m\n",
994 INFO(build
->pakfire
, "Running build stage '%s'\n", stage
);
996 // Import environment
997 // XXX is this a good idea?
998 r
= pakfire_jail_import_env(build
->jail
, (const char**)envp
);
1000 ERROR(build
->pakfire
, "Could not import environment: %m\n");
1005 r
= pakfire_jail_exec_script(build
->jail
, script
, strlen(script
), NULL
, NULL
, NULL
, NULL
);
1007 ERROR(build
->pakfire
, "Build stage '%s' failed with status %d\n", stage
, r
);
1012 for (char** e
= envp
; *e
; e
++)
1023 PAKFIRE_BUILD_CLEANUP_FILES
= (1 << 0),
1024 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
= (1 << 1),
1028 This helper function takes a callback which is expected to add any files
1029 to the given filelist which will optionally be all removed after.
1031 static int pakfire_build_post_process_files(struct pakfire_build
* build
,
1032 struct pakfire_filelist
* filelist
, const char* description
,
1033 int (*callback
)(struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
),
1035 struct pakfire_filelist
* removees
= NULL
;
1038 // Create a filelist with objects that need to be removed
1039 r
= pakfire_filelist_create(&removees
, build
->pakfire
);
1043 // Find all files that need to be removed
1044 r
= pakfire_filelist_walk(filelist
, callback
, removees
);
1048 if (!pakfire_filelist_is_empty(removees
)) {
1050 INFO(build
->pakfire
, "%s\n", description
);
1052 // Show all files which will be removed
1053 pakfire_filelist_dump(removees
, PAKFIRE_FILE_DUMP_FULL
|PAKFIRE_FILE_DUMP_HARDENING
);
1055 // Remove all files on the removee list
1056 if (flags
& PAKFIRE_BUILD_CLEANUP_FILES
) {
1057 r
= pakfire_filelist_cleanup(removees
);
1061 // Remove all files from the filelist
1062 r
= pakfire_filelist_remove_all(filelist
, removees
);
1067 // Report an error if any files have been found
1068 if (flags
& PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
)
1074 pakfire_filelist_unref(removees
);
1079 static int __pakfire_build_remove_static_libraries(
1080 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1081 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1082 char path
[PATH_MAX
];
1085 // Find all static libraries
1086 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_STATIC_LIBRARY
)) {
1087 // Copy the filename
1088 r
= pakfire_string_set(path
, pakfire_file_get_abspath(file
));
1092 // Remove the extension
1093 r
= pakfire_path_replace_extension(path
, "so");
1097 // Only delete if there is a shared object with the same name
1098 if (pakfire_path_exists(path
))
1099 return pakfire_filelist_add(removees
, file
);
1105 static int pakfire_build_post_remove_static_libraries(
1106 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1107 return pakfire_build_post_process_files(build
, filelist
,
1108 "Removing static libaries...",
1109 __pakfire_build_remove_static_libraries
,
1110 PAKFIRE_BUILD_CLEANUP_FILES
);
1113 static int __pakfire_build_post_check_stripped(
1114 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1115 struct pakfire_filelist
* filelist
= (struct pakfire_filelist
*)data
;
1118 // Skip anything that isn't an ELF file
1119 if (!pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
))
1122 // Collect all stripped files
1123 if (pakfire_file_is_stripped(file
)) {
1124 r
= pakfire_filelist_add(filelist
, file
);
1126 ERROR(pakfire
, "Could not add file to filelist: %m\n");
1134 static int pakfire_build_post_check_stripped(
1135 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1136 return pakfire_build_post_process_files(build
, filelist
,
1137 "Files lacking debugging information:",
1138 __pakfire_build_post_check_stripped
,
1139 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
);
1142 static int __pakfire_build_remove_libtool_archives(
1143 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1144 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1146 // Find all libtool archive files
1147 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_LIBTOOL_ARCHIVE
))
1148 return pakfire_filelist_add(removees
, file
);
1153 static int pakfire_build_post_remove_libtool_archives(
1154 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1155 return pakfire_build_post_process_files(build
, filelist
,
1156 "Removing libtool archives...",
1157 __pakfire_build_remove_libtool_archives
,
1158 PAKFIRE_BUILD_CLEANUP_FILES
);
1161 static int __pakfire_build_check_broken_symlinks(
1162 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1163 struct pakfire_filelist
* broken
= (struct pakfire_filelist
*)data
;
1166 // Ignore anything that isn't a symlink
1167 switch (pakfire_file_get_type(file
)) {
1169 if (!pakfire_file_symlink_target_exists(file
)) {
1170 r
= pakfire_filelist_add(broken
, file
);
1177 // Ignore anything that isn't a symlink
1185 static int pakfire_build_post_check_broken_symlinks(
1186 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1187 return pakfire_build_post_process_files(build
, filelist
,
1188 "Broken symlinks have been found:",
1189 __pakfire_build_check_broken_symlinks
,
1190 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
);
1194 Filesystem Layout Check
1196 static int __pakfire_build_post_check_filesystem(
1197 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1198 struct pakfire_filelist
* illegal
= (struct pakfire_filelist
*)data
;
1201 // Perform FHS check
1202 r
= pakfire_fhs_check_file(pakfire
, file
);
1204 r
= pakfire_filelist_add(illegal
, file
);
1212 static int pakfire_build_post_check_filesystem(
1213 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1214 return pakfire_build_post_process_files(
1218 __pakfire_build_post_check_filesystem
,
1219 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
);
1226 static int __pakfire_build_post_check_hardening(
1227 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1228 struct pakfire_filelist
* broken
= (struct pakfire_filelist
*)data
;
1232 // Skip anything that isn't an ELF file
1233 if (!pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
))
1237 r
= pakfire_file_check_hardening(file
, &issues
);
1239 ERROR(pakfire
, "%s: Hardening Check failed: %m\n",
1240 pakfire_file_get_path(file
));
1244 // If any issues have been found, consider this file to be on the list
1246 r
= pakfire_filelist_add(broken
, file
);
1254 static int pakfire_build_post_check_hardening(
1255 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1256 return pakfire_build_post_process_files(
1259 "Hardening Issues:",
1260 __pakfire_build_post_check_hardening
,
1261 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
);
1264 static int pakfire_build_run_post_build_checks(struct pakfire_build
* build
) {
1265 struct pakfire_filelist
* filelist
= NULL
;
1268 // Create a filelist of all files in the build
1269 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1271 ERROR(build
->pakfire
, "Could not create filelist: %m\n");
1275 // Scan for all files in BUILDROOT
1276 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
);
1280 // If the filelist is empty, we can are done
1281 if (pakfire_filelist_is_empty(filelist
)) {
1282 DEBUG(build
->pakfire
, "Empty BUILDROOT. Skipping post build checks...\n");
1287 // Check if binaries have been stripped
1288 r
= pakfire_build_post_check_stripped(build
, filelist
);
1292 // Remove any static libraries
1293 r
= pakfire_build_post_remove_static_libraries(build
, filelist
);
1297 // Remove any libtool archives
1298 r
= pakfire_build_post_remove_libtool_archives(build
, filelist
);
1302 // Check for any broken symlinks
1303 r
= pakfire_build_post_check_broken_symlinks(build
, filelist
);
1307 // Check filesystem layout
1308 r
= pakfire_build_post_check_filesystem(build
, filelist
);
1313 r
= pakfire_build_post_check_hardening(build
, filelist
);
1319 pakfire_filelist_unref(filelist
);
1324 static const char* post_build_scripts
[] = {
1325 "check-unsafe-files",
1330 "check-interpreters",
1331 "compress-man-pages",
1336 static int pakfire_build_run_post_build_scripts(struct pakfire_build
* build
) {
1338 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1340 // Set default arguments for build scripts
1341 const char* args
[] = {
1345 // Run them one by one
1346 for (const char** script
= post_build_scripts
; *script
; script
++) {
1347 int r
= pakfire_build_run_script(build
, *script
, args
, NULL
, NULL
, NULL
);
1355 static void pakfire_build_free(struct pakfire_build
* build
) {
1356 if (build
->packages
)
1357 pakfire_packagelist_unref(build
->packages
);
1360 pakfire_repo_clean(build
->repo
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
1361 pakfire_repo_unref(build
->repo
);
1365 pakfire_jail_unref(build
->jail
);
1367 if (build
->cgroup
) {
1368 // Destroy the cgroup
1369 pakfire_cgroup_destroy(build
->cgroup
);
1372 pakfire_cgroup_unref(build
->cgroup
);
1375 pakfire_unref(build
->pakfire
);
1379 static int pakfire_build_parse_id(struct pakfire_build
* build
, const char* id
) {
1382 // Try parsing the Build ID
1384 r
= uuid_parse(id
, build
->id
);
1386 ERROR(build
->pakfire
, "Could not parse build ID '%s'\n", id
);
1391 // Otherwise initialize the Build ID with something random
1393 uuid_generate_random(build
->id
);
1396 // Store the ID as string, too
1397 uuid_unparse_lower(build
->id
, build
->_id
);
1403 Sets up a new cgroup for this build
1405 static int pakfire_build_setup_cgroup(struct pakfire_build
* build
) {
1406 struct pakfire_config
* config
= NULL
;
1407 char path
[PATH_MAX
];
1411 r
= pakfire_string_format(path
, "pakfire/build-%s", build
->_id
);
1413 ERROR(build
->pakfire
, "Could not compose path for cgroup: %m\n");
1417 // Create a new cgroup
1418 r
= pakfire_cgroup_open(&build
->cgroup
, build
->pakfire
, path
,
1419 PAKFIRE_CGROUP_ENABLE_ACCOUNTING
);
1421 ERROR(build
->pakfire
, "Could not create cgroup for build %s: %m\n", build
->_id
);
1426 config
= pakfire_get_config(build
->pakfire
);
1430 // Guarantee some minimum memory
1431 size_t memory_guaranteed
= pakfire_config_get_bytes(config
, "build",
1432 "memory_guaranteed", PAKFIRE_BUILD_MEMORY_GUARANTEED
);
1433 if (memory_guaranteed
) {
1434 r
= pakfire_cgroup_set_guaranteed_memory(build
->cgroup
, memory_guaranteed
);
1440 size_t memory_limit
= pakfire_config_get_bytes(config
, "build", "memory_limit", 0);
1442 r
= pakfire_cgroup_set_memory_limit(build
->cgroup
, memory_limit
);
1448 size_t pid_limit
= pakfire_config_get_int(config
, "build",
1449 "pid_limit", PAKFIRE_BUILD_PID_LIMIT
);
1451 r
= pakfire_cgroup_set_pid_limit(build
->cgroup
, pid_limit
);
1458 pakfire_config_unref(config
);
1464 Sets up a new jail for this build
1466 static int pakfire_build_setup_jail(struct pakfire_build
* build
) {
1469 // Create a new jail
1470 r
= pakfire_jail_create(&build
->jail
, build
->pakfire
, 0);
1472 ERROR(build
->pakfire
, "Could not create jail for build %s: %m\n", build
->_id
);
1476 // Connect the jail to our cgroup
1477 r
= pakfire_jail_set_cgroup(build
->jail
, build
->cgroup
);
1479 ERROR(build
->pakfire
, "Could not set cgroup for jail: %m\n");
1488 Sets up the ccache for this build
1490 static int pakfire_build_setup_ccache(struct pakfire_build
* build
) {
1491 char path
[PATH_MAX
];
1494 // Check if we want a ccache
1495 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
)) {
1496 DEBUG(build
->pakfire
, "ccache usage has been disabled for this build\n");
1498 // Set CCACHE_DISABLE=1 so that if ccache is installed, it will disable itself
1499 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_DISABLE", "1");
1501 ERROR(build
->pakfire
, "Could not disable ccache: %m\n");
1509 r
= pakfire_cache_path(build
->pakfire
, path
, "%s", "ccache");
1511 ERROR(build
->pakfire
, "Could not compose ccache path: %m\n");
1515 DEBUG(build
->pakfire
, "Mounting ccache from %s\n", path
);
1517 // Ensure path exists
1518 r
= pakfire_mkdir(path
, 0755);
1519 if (r
&& errno
!= EEXIST
) {
1520 ERROR(build
->pakfire
, "Could not create ccache directory %s: %m\n", path
);
1524 // Bind-mount the directory
1525 r
= pakfire_jail_bind(build
->jail
, path
, CCACHE_DIR
, MS_NOSUID
|MS_NOEXEC
|MS_NODEV
);
1527 ERROR(build
->pakfire
, "Could not mount ccache: %m\n");
1534 static int pakfire_build_setup_repo(struct pakfire_build
* build
) {
1535 char path
[PATH_MAX
] = PAKFIRE_TMP_DIR
"/pakfire-build-repo.XXXXXX";
1539 // Create a new repository
1540 r
= pakfire_repo_create(&build
->repo
, build
->pakfire
, PAKFIRE_REPO_RESULT
);
1542 ERROR(build
->pakfire
, "Could not create repository %s: %m", PAKFIRE_REPO_RESULT
);
1547 pakfire_repo_set_description(build
->repo
, _("Build Repository"));
1549 // Create a temporary directory
1550 const char* p
= pakfire_mkdtemp(path
);
1552 ERROR(build
->pakfire
, "Could not create a the build repository: %m\n");
1557 r
= pakfire_string_format(url
, "file://%s", path
);
1562 pakfire_repo_set_baseurl(build
->repo
, url
);
1567 static int pakfire_build_set_time_start(struct pakfire_build
* build
) {
1568 const time_t now
= time(NULL
);
1571 ERROR(build
->pakfire
, "Could not fetch start time: %m\n");
1575 build
->time_start
= now
;
1580 PAKFIRE_EXPORT
int pakfire_build_create(struct pakfire_build
** build
,
1581 struct pakfire
* pakfire
, const char* id
, int flags
) {
1584 // Allocate build object
1585 struct pakfire_build
* b
= calloc(1, sizeof(*b
));
1589 // Reference pakfire
1590 b
->pakfire
= pakfire_ref(pakfire
);
1592 // Initialize reference counter
1599 r
= pakfire_build_set_time_start(b
);
1604 r
= pakfire_build_parse_id(b
, id
);
1609 r
= pakfire_build_setup_repo(b
);
1614 r
= pakfire_build_setup_cgroup(b
);
1619 r
= pakfire_build_setup_jail(b
);
1624 r
= pakfire_build_setup_ccache(b
);
1632 pakfire_build_free(b
);
1636 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_ref(struct pakfire_build
* build
) {
1642 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_unref(struct pakfire_build
* build
) {
1643 if (--build
->nrefs
> 0)
1646 pakfire_build_free(build
);
1650 PAKFIRE_EXPORT
int pakfire_build_set_target(
1651 struct pakfire_build
* build
, const char* target
) {
1652 return pakfire_string_set(build
->target
, target
);
1655 static int pakfire_build_install_packages(struct pakfire_build
* build
,
1656 int* snapshot_needs_update
) {
1659 const char* packages
[] = {
1666 // Install everything
1667 r
= pakfire_install(build
->pakfire
, 0, 0, packages
, NULL
, 0,
1668 &changed
, NULL
, NULL
);
1670 ERROR(build
->pakfire
, "Could not install build dependencies: %m\n");
1674 // Mark snapshot as changed if new packages were installed
1676 *snapshot_needs_update
= 1;
1678 // Update everything
1679 r
= pakfire_sync(build
->pakfire
, 0, 0, &changed
, NULL
, NULL
);
1681 ERROR(build
->pakfire
, "Could not update packages: %m\n");
1685 // Has anything changed?
1687 *snapshot_needs_update
= 1;
1693 Initializes the build environment
1695 static int pakfire_build_init(struct pakfire_build
* build
) {
1698 // Don't do it again
1700 DEBUG(build
->pakfire
, "Build environment has already been initialized\n");
1704 // Tells us whether we need to (re-)create the snapshot
1705 int snapshot_needs_update
= 0;
1708 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_SNAPSHOT
)) {
1709 r
= pakfire_snapshot_restore(build
->pakfire
);
1714 // Install or update any build dependencies
1715 r
= pakfire_build_install_packages(build
, &snapshot_needs_update
);
1719 // Update the snapshot if there were changes
1720 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_SNAPSHOT
) && snapshot_needs_update
) {
1721 // Store the snapshot
1722 r
= pakfire_snapshot_store(build
->pakfire
);
1727 // Mark as initialized
1733 static int pakfire_build_read_makefile(struct pakfire_build
* build
,
1734 struct pakfire_parser
** parser
, struct pakfire_package
* package
) {
1735 char path
[PATH_MAX
];
1738 struct pakfire_parser_error
* error
= NULL
;
1740 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
1741 const char* name
= pakfire_package_get_string(package
, PAKFIRE_PKG_NAME
);
1743 // Compose path to makefile
1744 r
= pakfire_path(build
->pakfire
, path
, "/usr/src/packages/%s/%s.nm", nevra
, name
);
1749 r
= pakfire_read_makefile(parser
, build
->pakfire
, path
, &error
);
1752 ERROR(build
->pakfire
, "Could not parse makefile %s: %s\n", path
,
1753 pakfire_parser_error_get_message(error
));
1755 ERROR(build
->pakfire
, "Could not parse makefile %s: %m\n", path
);
1762 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1764 pakfire_parser_set(*parser
, NULL
, "BUILDROOT", buildroot
, 0);
1768 pakfire_parser_error_unref(error
);
1773 static int pakfire_build_perform(struct pakfire_build
* build
,
1774 struct pakfire_parser
* makefile
) {
1777 // Prepare the build
1778 r
= pakfire_build_stage(build
, makefile
, "prepare");
1782 // Perform the build
1783 r
= pakfire_build_stage(build
, makefile
, "build");
1788 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_TESTS
)) {
1789 r
= pakfire_build_stage(build
, makefile
, "test");
1794 // Install everything
1795 r
= pakfire_build_stage(build
, makefile
, "install");
1799 // Run post build checks
1800 r
= pakfire_build_run_post_build_checks(build
);
1802 ERROR(build
->pakfire
, "Post build checks failed\n");
1806 // Run post build scripts
1807 r
= pakfire_build_run_post_build_scripts(build
);
1815 // Drop to a shell for debugging
1816 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_INTERACTIVE
))
1817 pakfire_build_shell(build
);
1822 static int __pakfire_build_unpackaged_file(struct pakfire
* pakfire
,
1823 struct pakfire_file
* file
, void* p
) {
1824 char* s
= pakfire_file_dump(file
, PAKFIRE_FILE_DUMP_FULL
);
1826 ERROR(pakfire
, "%s\n", s
);
1833 static int pakfire_build_check_unpackaged_files(struct pakfire_build
* build
) {
1834 struct pakfire_filelist
* filelist
= NULL
;
1837 // Create a new filelist
1838 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1842 // Scan for all files in BUILDROOT
1843 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
);
1847 if (!pakfire_filelist_is_empty(filelist
)) {
1848 ERROR(build
->pakfire
, "Unpackaged files found:\n");
1850 r
= pakfire_filelist_walk(filelist
, __pakfire_build_unpackaged_file
, NULL
);
1860 pakfire_filelist_unref(filelist
);
1865 static int pakfire_build_install_package(struct pakfire
* pakfire
,
1866 struct pakfire_package
* pkg
, void* p
) {
1867 struct pakfire_request
* request
= (struct pakfire_request
*)p
;
1869 return pakfire_request_add_package(request
, PAKFIRE_REQ_INSTALL
, pkg
,
1870 PAKFIRE_REQUEST_ESSENTIAL
);
1873 static int pakfire_build_install_test(struct pakfire_build
* build
) {
1874 struct pakfire_request
* request
= NULL
;
1875 struct pakfire_problem
* problem
= NULL
;
1876 struct pakfire_solution
* solution
= NULL
;
1877 const char* s
= NULL
;
1880 // Create a new request
1881 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
1886 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_install_package
, request
);
1888 // Solve the request
1889 r
= pakfire_request_solve(request
);
1897 ERROR(build
->pakfire
, "Install test failed:\n");
1899 // Walk through all problems
1901 r
= pakfire_request_next_problem(request
, &problem
);
1905 // There are no more problems
1909 // Format the problem into something human-readable
1910 s
= pakfire_problem_to_string(problem
);
1914 ERROR(build
->pakfire
, " * %s\n", s
);
1916 // Walk through all solutions
1918 r
= pakfire_problem_next_solution(problem
, &solution
);
1922 // There are no more solutions
1926 // Format the solution into something human-readable
1927 s
= pakfire_solution_to_string(solution
);
1931 ERROR(build
->pakfire
, " * %s\n", s
);
1944 ERROR(build
->pakfire
, "Install test failed: %m\n");
1946 pakfire_request_unref(request
);
1948 pakfire_problem_unref(problem
);
1950 pakfire_solution_unref(solution
);
1955 static int pakfire_build_post_check(struct pakfire_build
* build
) {
1958 // Check for unpackaged files
1959 r
= pakfire_build_check_unpackaged_files(build
);
1963 // Perform install test
1964 r
= pakfire_build_install_test(build
);
1971 static int pakfire_build_copy_package(struct pakfire
* pakfire
,
1972 struct pakfire_package
* pkg
, void* p
) {
1973 struct pakfire_archive
* archive
= NULL
;
1974 char path
[PATH_MAX
];
1977 const char* target
= (const char*)p
;
1984 // Fetch the package filename
1985 const char* filename
= pakfire_package_get_string(pkg
, PAKFIRE_PKG_FILENAME
);
1991 // Format the destination path
1992 r
= pakfire_string_format(path
, "%s/%s", target
, filename
);
1997 archive
= pakfire_package_get_archive(pkg
);
2003 // Copy it to its destination
2004 r
= pakfire_archive_copy(archive
, path
);
2010 pakfire_archive_unref(archive
);
2015 static int pakfire_build_copy_packages(struct pakfire_build
* build
) {
2016 struct pakfire_repo
* local
= NULL
;
2019 DEBUG(build
->pakfire
, "Copying built packages\n");
2021 // Fetch local repository
2022 local
= pakfire_get_repo(build
->pakfire
, PAKFIRE_REPO_LOCAL
);
2024 // Copy all packages to the target path
2025 if (*build
->target
) {
2026 r
= pakfire_packagelist_walk(build
->packages
,
2027 pakfire_build_copy_package
, build
->target
);
2032 // If we have a local repository, we copy all packages to it
2034 const char* path
= pakfire_repo_get_path(local
);
2036 r
= pakfire_packagelist_walk(build
->packages
,
2037 pakfire_build_copy_package
, (void*)path
);
2045 pakfire_repo_unref(local
);
2050 static int pakfire_build_install_source_package(
2051 struct pakfire_build
* build
, struct pakfire_package
* package
) {
2052 struct pakfire_request
* request
= NULL
;
2053 struct pakfire_transaction
* transaction
= NULL
;
2056 // Create a new request
2057 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
2062 r
= pakfire_request_add_package(request
, PAKFIRE_REQ_INSTALL
, package
,
2063 PAKFIRE_REQUEST_ESSENTIAL
);
2067 // Solve the request
2068 r
= pakfire_request_solve(request
);
2072 // Fetch the transaction
2073 r
= pakfire_request_get_transaction(request
, &transaction
);
2077 // Set how many packages have been changed
2078 const size_t changes
= pakfire_transaction_count(transaction
);
2080 // Sanity check to see if we actually try to install anything
2082 ERROR(build
->pakfire
, "The source package did not get installed\n");
2087 // Run the transaction
2088 r
= pakfire_transaction_run(transaction
, 0);
2094 pakfire_transaction_unref(transaction
);
2096 pakfire_request_unref(request
);
2101 PAKFIRE_EXPORT
int pakfire_build_exec(struct pakfire_build
* build
, const char* path
) {
2102 struct pakfire_package
* package
= NULL
;
2103 struct pakfire_parser
* makefile
= NULL
;
2104 char* buildroot
= NULL
;
2105 char duration
[TIME_STRING_MAX
];
2109 r
= pakfire_path(build
->pakfire
, build
->buildroot
, "%s",
2110 PAKFIRE_TMP_DIR
"/pakfire-buildroot.XXXXXX");
2114 // Open the source package
2115 r
= pakfire_commandline_add(build
->pakfire
, path
, &package
);
2119 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
2121 INFO(build
->pakfire
, "Building %s...\n", nevra
);
2123 // Initialize the build environment
2124 r
= pakfire_build_init(build
);
2128 // Install the source package
2129 r
= pakfire_build_install_source_package(build
, package
);
2131 ERROR(build
->pakfire
, "Could not install the source package: %m\n");
2136 buildroot
= pakfire_mkdtemp(build
->buildroot
);
2138 ERROR(build
->pakfire
, "Could not create BUILDROOT: %m\n");
2142 // Open the makefile
2143 r
= pakfire_build_read_makefile(build
, &makefile
, package
);
2147 // Perform the actual build
2148 r
= pakfire_build_perform(build
, makefile
);
2152 // Create the packages
2153 r
= pakfire_build_packages(build
, makefile
);
2155 ERROR(build
->pakfire
, "Could not create packages: %m\n");
2159 // Perform post build checks
2160 r
= pakfire_build_post_check(build
);
2164 // Copy packages to their destination
2165 r
= pakfire_build_copy_packages(build
);
2170 r
= pakfire_format_time(duration
, pakfire_build_duration(build
));
2174 INFO(build
->pakfire
, "Build successfully completed in %s\n", duration
);
2178 pakfire_parser_unref(makefile
);
2180 pakfire_package_unref(package
);
2182 // Cleanup buildroot
2184 pakfire_rmtree(buildroot
, 0);
2190 Compatibility function to keep the legacy API.
2192 PAKFIRE_EXPORT
int pakfire_build(struct pakfire
* pakfire
, const char* path
,
2193 const char* target
, const char* id
, int flags
) {
2194 struct pakfire_build
* build
= NULL
;
2197 // Check if path is set
2203 // Create a new build environment
2204 r
= pakfire_build_create(&build
, pakfire
, id
, flags
);
2210 r
= pakfire_build_set_target(build
, target
);
2216 r
= pakfire_build_exec(build
, path
);
2220 pakfire_build_unref(build
);
2225 int pakfire_build_clean(struct pakfire
* pakfire
, int flags
) {
2226 struct pakfire_repo
* local
= NULL
;
2229 // Fetch local repository
2230 local
= pakfire_get_repo(pakfire
, PAKFIRE_REPO_LOCAL
);
2232 ERROR(pakfire
, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL
);
2236 // Destroy everything in it
2237 r
= pakfire_repo_clean(local
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
2243 pakfire_repo_unref(local
);
2249 This is a convenience function that sets up a build environment and
2250 then drops the user into an interactive shell.
2252 PAKFIRE_EXPORT
int pakfire_shell(struct pakfire
* pakfire
, const char** packages
, int flags
) {
2253 struct pakfire_build
* build
= NULL
;
2256 // Shells are always interactive
2257 flags
|= PAKFIRE_BUILD_INTERACTIVE
;
2259 // Create a new build environment
2260 r
= pakfire_build_create(&build
, pakfire
, NULL
, flags
);
2262 ERROR(pakfire
, "Could not create build: %m\n");
2266 // Initialize the build environment
2267 r
= pakfire_build_init(build
);
2271 // Install any additional packages
2273 r
= pakfire_install(build
->pakfire
, 0, 0, packages
, NULL
, 0, NULL
, NULL
, NULL
);
2279 r
= pakfire_build_shell(build
);
2283 pakfire_build_unref(build
);