]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/build.c
build: Remove any *.a and *.la files internally instead of using a script
[people/stevee/pakfire.git] / src / libpakfire / build.c
CommitLineData
1a276007
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2021 Pakfire development team #
5# #
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. #
10# #
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. #
15# #
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/>. #
18# #
19#############################################################################*/
20
21#include <errno.h>
22#include <stdlib.h>
22a0733e 23#include <sys/mount.h>
cee6363a 24#include <unistd.h>
57e2cf99 25#include <uuid/uuid.h>
1a276007 26
79049ef5
MT
27#define PCRE2_CODE_UNIT_WIDTH 8
28#include <pcre2.h>
29
1a276007 30#include <pakfire/build.h>
f877fdfa 31#include <pakfire/cgroup.h>
2a623cf8 32#include <pakfire/dependencies.h>
1a276007 33#include <pakfire/dist.h>
ae7968a7 34#include <pakfire/file.h>
e545f6ec 35#include <pakfire/i18n.h>
8e99f22d 36#include <pakfire/jail.h>
1a276007 37#include <pakfire/logging.h>
163851bc 38#include <pakfire/mount.h>
4c07774f 39#include <pakfire/package.h>
48c6f2e7 40#include <pakfire/packager.h>
1a276007
MT
41#include <pakfire/parser.h>
42#include <pakfire/private.h>
8ad8d09b 43#include <pakfire/problem.h>
4651122b 44#include <pakfire/repo.h>
99a56775 45#include <pakfire/request.h>
106d2edd 46#include <pakfire/scriptlet.h>
c0f2502a 47#include <pakfire/snapshot.h>
8ad8d09b 48#include <pakfire/solution.h>
d973a13d 49#include <pakfire/string.h>
1a276007
MT
50#include <pakfire/util.h>
51
5a06668c
MT
52#define CCACHE_DIR "/var/cache/ccache"
53
882ae03b 54// We guarantee 2 GiB of memory to every build container
0a1284ff 55#define PAKFIRE_BUILD_MEMORY_GUARANTEED (size_t)2 * 1024 * 1024 * 1024
882ae03b 56
de4c8fe6
MT
57// We allow only up to 2048 processes/threads for every build container
58#define PAKFIRE_BUILD_PID_LIMIT (size_t)2048
59
abbad00b
MT
60struct pakfire_build {
61 struct pakfire* pakfire;
62 int nrefs;
63
64 // Flags
65 int flags;
66
67 // Build ID
68 uuid_t id;
f877fdfa
MT
69 char _id[UUID_STR_LEN];
70
a84624be
MT
71 char target[PATH_MAX];
72
f877fdfa
MT
73 // cgroup
74 struct pakfire_cgroup* cgroup;
753ddf74
MT
75
76 // Jail
77 struct pakfire_jail* jail;
e545f6ec 78
a6144133
MT
79 // The build repository
80 struct pakfire_repo* repo;
d6451238 81
6ed07bc4
MT
82 // A list of all built packages
83 struct pakfire_packagelist* packages;
84
6fc3956f
MT
85 // Buildroot
86 char buildroot[PATH_MAX];
87
8dbb69f9
MT
88 // States
89 int init:1;
abbad00b
MT
90};
91
1a276007
MT
92#define TEMPLATE \
93 "#!/bin/bash --login\n" \
94 "\n" \
95 "set -e\n" \
96 "set -x\n" \
97 "\n" \
98 "%%{_%s}\n" \
99 "\n" \
100 "exit 0\n"
101
c0f2502a
MT
102static int pakfire_build_has_flag(struct pakfire_build* build, int flag) {
103 return build->flags & flag;
104}
105
b7c52276
MT
106static int __pakfire_build_setup_repo(struct pakfire* pakfire,
107 struct pakfire_repo* repo, void* p) {
108 char path[PATH_MAX];
109 FILE* f = NULL;
110 int r;
111
112 struct pakfire_build* build = (struct pakfire_build*)p;
113
114 // Skip processing the installed repository
115 if (pakfire_repo_is_installed_repo(repo))
116 return 0;
117
118 // Skip processing any other internal repositories
119 if (pakfire_repo_is_internal(repo))
120 return 0;
121
122 const char* name = pakfire_repo_get_name(repo);
123
124 DEBUG(pakfire, "Exporting repository configuration for '%s'\n", name);
125
126 // Make path for configuration file
127 r = pakfire_path(build->pakfire, path, PAKFIRE_CONFIG_DIR "/repos/%s.repo", name);
128 if (r) {
129 ERROR(pakfire, "Could not make repository configuration path for %s: %m\n", name);
130 goto ERROR;
131 }
132
b1bd7202
MT
133 // Create the parent directory
134 r = pakfire_mkparentdir(path, 0755);
135 if (r)
136 goto ERROR;
137
b7c52276
MT
138 // Open the repository configuration
139 f = fopen(path, "w");
140 if (!f) {
141 ERROR(pakfire, "Could not open %s for writing: %m\n", path);
142 goto ERROR;
143 }
144
145 // Write repository configuration
146 r = pakfire_repo_write_config(repo, f);
147 if (r) {
148 ERROR(pakfire, "Could not write repository configuration for %s: %m\n", name);
149 goto ERROR;
150 }
151
152 // Bind-mount any local repositories
153 if (pakfire_repo_is_local(repo)) {
154 const char* _path = pakfire_repo_get_path(repo);
155
156 // Bind-mount the repository data read-only
157 r = pakfire_jail_bind(build->jail, _path, _path, MS_RDONLY);
158 if (r) {
159 ERROR(pakfire, "Could not bind-mount the repository at %s: %m\n", _path);
160 goto ERROR;
161 }
162 }
163
164ERROR:
165 if (f)
166 fclose(f);
167
168 return r;
169}
170
5f6e42a2 171/*
7a347de7 172 This function enables the local repository so that it can be accessed by
5f6e42a2
MT
173 a pakfire instance running inside the chroot.
174*/
175static int pakfire_build_enable_repos(struct pakfire_build* build) {
b7c52276 176 return pakfire_repo_walk(build->pakfire, __pakfire_build_setup_repo, build);
5f6e42a2
MT
177}
178
179/*
180 Drops the user into a shell
181*/
182static int pakfire_build_shell(struct pakfire_build* build) {
183 int r;
184
185 // Export local repository if running in interactive mode
186 r = pakfire_build_enable_repos(build);
187 if (r)
188 return r;
189
190 // Run shell
191 return pakfire_jail_shell(build->jail);
192}
193
ccdd2e95
MT
194static int pakfire_build_read_script(struct pakfire_build* build,
195 const char* filename, char** buffer, size_t* length) {
8d0f3a35 196 char path[PATH_MAX];
ccdd2e95
MT
197 FILE* f = NULL;
198 int r;
8d0f3a35 199
ccdd2e95
MT
200 // Compose the source path
201 r = pakfire_path_join(path, PAKFIRE_SCRIPTS_DIR, filename);
202 if (r) {
203 ERROR(build->pakfire, "Could not compose path for script '%s': %m\n", filename);
204 goto ERROR;
205 }
8d0f3a35 206
ccdd2e95 207 DEBUG(build->pakfire, "Reading script from %s...\n", path);
8d0f3a35 208
ccdd2e95
MT
209 // Open the file
210 f = fopen(path, "r");
8d0f3a35 211 if (!f) {
ccdd2e95
MT
212 ERROR(build->pakfire, "Could not open script %s: %m\n", path);
213 goto ERROR;
8d0f3a35
MT
214 }
215
ccdd2e95
MT
216 // Read the file into a the buffer
217 r = pakfire_read_file_into_buffer(f, buffer, length);
8d0f3a35 218 if (r) {
ccdd2e95 219 ERROR(build->pakfire, "Could not read script: %m\n");
8d0f3a35
MT
220 goto ERROR;
221 }
222
ccdd2e95
MT
223ERROR:
224 if (f)
225 fclose(f);
226
227 return r;
228}
229
230static int pakfire_build_run_script(
231 struct pakfire_build* build,
232 const char* filename,
233 const char* args[],
234 pakfire_jail_communicate_in communicate_in,
235 pakfire_jail_communicate_out communicate_out,
236 void* data) {
237 int r;
238
239 char* script = NULL;
240 size_t length = 0;
241
242 DEBUG(build->pakfire, "Running build script '%s'...\n", filename);
243
244 // Read the script
245 r = pakfire_build_read_script(build, filename, &script, &length);
246 if (r) {
247 ERROR(build->pakfire, "Could not read script %s: %m\n", filename);
248 return r;
249 }
250
8e99f22d 251 // Execute the script
ccdd2e95
MT
252 r = pakfire_jail_exec_script(build->jail, script, length, args,
253 communicate_in, communicate_out, data);
8d0f3a35 254 if (r) {
779e16de 255 ERROR(build->pakfire, "Script '%s' failed with status %d\n", filename, r);
8d0f3a35
MT
256 }
257
8d0f3a35
MT
258 if (script)
259 free(script);
260
261 return r;
262}
263
2a3025cc
MT
264struct pakfire_find_deps_ctx {
265 struct pakfire_package* pkg;
266 int dep;
0e7a1dee 267 struct pakfire_scriptlet* scriptlet;
71f6f465 268 int class;
79049ef5 269 const pcre2_code* filter;
06b864ae
MT
270
271 struct pakfire_filelist* filelist;
272 unsigned int i;
ccdd2e95
MT
273};
274
79049ef5
MT
275static 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;
278 int r = 0;
279
280 // Fetch the pattern
281 pattern = pakfire_parser_get(makefile, namespace, filter);
282
283 // Nothing if to if there is no or an empty pattern
284 if (!pattern || !*pattern)
285 goto ERROR;
286
287 DEBUG(build->pakfire, "Found filter for %s: %s\n", filter, pattern);
288
289 // Compile the regular expression
290 r = pakfire_compile_regex(build->pakfire, regex, pattern);
291 if (r)
292 goto ERROR;
293
294ERROR:
295 if (pattern)
296 free(pattern);
297
298 return r;
299}
300
06b864ae
MT
301static 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;
304 int r = 0;
305
306 const size_t length = pakfire_filelist_size(ctx->filelist);
307
308 // Check if we have reached the end of the filelist
309 if (ctx->i >= length)
310 return EOF;
311
312 // Fetch the next file
313 file = pakfire_filelist_get(ctx->filelist, ctx->i);
314 if (!file) {
315 DEBUG(pakfire, "Could not fetch file %d: %m\n", ctx->i);
316 r = 1;
317 goto ERROR;
318 }
ccdd2e95 319
2a3025cc 320 // Fetch the path of the file
ccdd2e95
MT
321 const char* path = pakfire_file_get_path(file);
322 if (!path) {
323 ERROR(pakfire, "Received a file with an empty path\n");
06b864ae
MT
324 r = 1;
325 goto ERROR;
ccdd2e95
MT
326 }
327
71f6f465
MT
328 // Skip files that don't match what we are looking for
329 if (ctx->class && !pakfire_file_matches_class(file, ctx->class))
2f97b22a
MT
330 goto SKIP;
331
2a3025cc 332 // Write path to stdin
06b864ae 333 r = dprintf(fd, "%s\n", path);
ccdd2e95
MT
334 if (r < 0)
335 return r;
336
2f97b22a 337SKIP:
06b864ae
MT
338 // Move on to the next file
339 ctx->i++;
ccdd2e95 340
06b864ae
MT
341 // Success
342 r = 0;
343
344ERROR:
345 if (file)
346 pakfire_file_unref(file);
ccdd2e95 347
06b864ae 348 return r;
ccdd2e95
MT
349}
350
2a3025cc 351static int pakfire_build_process_deps(struct pakfire* pakfire,
ccdd2e95 352 void* data, int priority, const char* buffer, const size_t length) {
2a3025cc 353 const struct pakfire_find_deps_ctx* ctx = (struct pakfire_find_deps_ctx*)data;
c7aacb67 354 char dep[PATH_MAX];
79049ef5
MT
355 pcre2_match_data* match = NULL;
356 int r = 0;
2a3025cc 357
c7aacb67
MT
358 // Nothing to do for an empty buffer
359 if (!buffer || !*buffer)
360 return 0;
361
2a3025cc
MT
362 switch (priority) {
363 // Add every dependency that we have received
364 case LOG_INFO:
c7aacb67
MT
365 // Copy the dependency to the stack (and remove the trailing newline)
366 r = pakfire_string_format(dep, "%.*s", (int)length - 1, buffer);
367 if (r)
368 return r;
369
370 DEBUG(pakfire, "Processing dependency: %s\n", dep);
371
b1173add
MT
372 // Filter out any dependencies that are provided by this package
373 if (ctx->dep == PAKFIRE_PKG_REQUIRES) {
c7aacb67
MT
374 // If this is a file, we check if it is on the filelist
375 if (pakfire_filelist_contains(ctx->filelist, dep))
376 goto SKIP;
377
378 // Otherwise check if this dependency is provided by this package
379 else if (pakfire_package_matches_dep(ctx->pkg, PAKFIRE_PKG_PROVIDES, dep))
380 goto SKIP;
b1173add
MT
381 }
382
79049ef5
MT
383 // Check if this dependency should be filtered
384 if (ctx->filter) {
385 match = pcre2_match_data_create_from_pattern(ctx->filter, NULL);
386 if (!match) {
387 ERROR(pakfire, "Could not allocate PCRE match data: %m\n");
388 goto ERROR;
389 }
390
391 // Perform matching
392 r = pcre2_jit_match(ctx->filter, (PCRE2_SPTR)dep, length - 1,
393 0, 0, match, NULL);
394
395 // No match
396 if (r == PCRE2_ERROR_NOMATCH) {
397 // Fall through...
398
399 // Handle any errors
400 } else if (r < 0) {
401 char error[120];
402
403 // Fetch the error message
404 r = pcre2_get_error_message(r, (PCRE2_UCHAR*)error, sizeof(error));
405 if (r < 0) {
406 ERROR(pakfire, "Could not fetch PCRE error message: %m\n");
407 r = 1;
408 goto ERROR;
409 }
410
411 ERROR(pakfire, "Could not match the filter: %s\n", error);
412 r = 1;
413 goto ERROR;
414
415 // Match!
416 } else {
417 DEBUG(pakfire, "Skipping dependency that has been filtered: %s\n", dep);
418 r = 0;
419 goto ERROR;
420 }
421 }
422
b1173add 423 // Add dependency
2a3025cc
MT
424 r = pakfire_package_add_dep(ctx->pkg, ctx->dep, buffer);
425 if (r) {
426 ERROR(pakfire, "Could not process dependency '%s': %m\n", buffer);
427 return r;
428 }
429 break;
430
431 // Send everything else to the default logger
432 default:
433 ERROR(pakfire, "%s\n", buffer);
434 break;
435 }
ccdd2e95 436
79049ef5 437 goto ERROR;
c7aacb67
MT
438
439SKIP:
440 DEBUG(pakfire, "Skipping dependency that is provided by the package itself: %s\n", dep);
441
79049ef5
MT
442ERROR:
443 if (match)
444 pcre2_match_data_free(match);
445
446 return r;
ccdd2e95
MT
447}
448
2a3025cc
MT
449/*
450 This function is a special way to run a script.
451
452 It will pipe the filelist into the standard input of the called script
453 and will read any dependencies from the standard output.
454*/
455static int pakfire_build_find_deps(struct pakfire_build* build,
456 struct pakfire_package* pkg, int dep, const char* script,
34dd7fbf 457 struct pakfire_filelist* filelist, int class, const pcre2_code* filter) {
2a3025cc
MT
458 // Construct the context
459 struct pakfire_find_deps_ctx ctx = {
460 .pkg = pkg,
461 .dep = dep,
71f6f465 462 .class = class,
79049ef5 463 .filter = filter,
06b864ae
MT
464
465 // Filelist
466 .filelist = filelist,
467 .i = 0,
ccdd2e95 468 };
c9184392
MT
469 int r;
470
34dd7fbf
MT
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);
474 return 0;
475 }
476
2a3025cc
MT
477 // Pass the buildroot as first argument
478 const char* args[] = {
479 pakfire_relpath(build->pakfire, build->buildroot),
480 NULL,
481 };
ccdd2e95 482
c9184392 483 // Run the script
ccdd2e95 484 r = pakfire_build_run_script(build, script, args,
2a3025cc
MT
485 pakfire_build_send_filelist, pakfire_build_process_deps, &ctx);
486 if (r)
c9184392 487 ERROR(build->pakfire, "%s returned with error %d\n", script, r);
c9184392
MT
488
489 return r;
490}
491
bd95a433 492static int pakfire_build_find_dependencies(struct pakfire_build* build,
79049ef5 493 struct pakfire_parser* makefile, const char* namespace,
2a3025cc 494 struct pakfire_package* pkg, struct pakfire_filelist* filelist) {
79049ef5
MT
495 pcre2_code* filter_provides = NULL;
496 pcre2_code* filter_requires = NULL;
ccdd2e95 497 int r;
5b0b3dc2 498
79049ef5
MT
499 // Fetch the provides filter
500 r = pakfire_build_make_filter(build, &filter_provides,
501 makefile, namespace, "filter_provides");
502 if (r) {
503 ERROR(build->pakfire, "Provides filter is broken: %m\n");
504 goto ERROR;
505 }
506
507 // Fetch the requires filter
508 r = pakfire_build_make_filter(build, &filter_requires,
509 makefile, namespace, "filter_requires");
510 if (r) {
511 ERROR(build->pakfire, "Requires filter is broken: %m\n");
512 goto ERROR;
513 }
514
5b0b3dc2 515 // Find all provides
2a3025cc 516 r = pakfire_build_find_deps(build, pkg,
71f6f465 517 PAKFIRE_PKG_PROVIDES, "find-provides", filelist, 0, filter_provides);
ccdd2e95 518 if (r)
79049ef5 519 goto ERROR;
ccdd2e95
MT
520
521 // Find all Perl provides
2a3025cc 522 r = pakfire_build_find_deps(build, pkg,
71f6f465 523 PAKFIRE_PKG_PROVIDES, "perl.prov", filelist, PAKFIRE_FILE_PERL, filter_provides);
c9184392 524 if (r)
79049ef5 525 goto ERROR;
5b0b3dc2
MT
526
527 // Find all requires
2a3025cc 528 r = pakfire_build_find_deps(build, pkg,
71f6f465 529 PAKFIRE_PKG_REQUIRES, "find-requires", filelist, 0, filter_requires);
ccdd2e95 530 if (r)
79049ef5 531 goto ERROR;
ccdd2e95
MT
532
533 // Find all Perl requires
2a3025cc 534 r = pakfire_build_find_deps(build, pkg,
71f6f465 535 PAKFIRE_PKG_REQUIRES, "perl.req", filelist, PAKFIRE_FILE_PERL, filter_requires);
c9184392 536 if (r)
79049ef5 537 goto ERROR;
5b0b3dc2 538
79049ef5
MT
539ERROR:
540 if (filter_provides)
541 pcre2_code_free(filter_provides);
542 if (filter_requires)
543 pcre2_code_free(filter_requires);
544
545 return r;
5b0b3dc2
MT
546}
547
2a3025cc 548static int append_to_array(char*** array, const char* s) {
73543ae3
MT
549 unsigned int length = 0;
550
551 // Determine the length of the existing array
552 if (*array) {
7b3d940f 553 for (char** element = *array; *element; element++)
73543ae3
MT
554 length++;
555 }
556
557 // Allocate space
558 *array = reallocarray(*array, length + 2, sizeof(**array));
559 if (!*array)
560 return 1;
561
23f431f7
MT
562 // Copy the string to the heap
563 char* p = strdup(s);
564 if (!p)
565 return 1;
566
567 // Append p and terminate the array
568 (*array)[length] = p;
73543ae3
MT
569 (*array)[length + 1] = NULL;
570
571 return 0;
572}
573
adfa3573
MT
574static 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) {
1bbbfb9e 577 struct pakfire_filelist* filelist = NULL;
73543ae3
MT
578 int r = 1;
579
23f431f7
MT
580 char** includes = NULL;
581 char** excludes = NULL;
582 char* p = NULL;
73543ae3
MT
583
584 // Fetch filelist from makefile
23f431f7 585 char* files = pakfire_parser_get(makefile, namespace, "files");
73543ae3
MT
586
587 // No files to package?
588 if (!files)
589 return 0;
590
23f431f7
MT
591 const char* file = strtok_r(files, " \n", &p);
592
73543ae3 593 // Split into includes and excludes
23f431f7
MT
594 while (file) {
595 if (*file == '!')
596 r = append_to_array(&excludes, file + 1);
73543ae3 597 else
23f431f7 598 r = append_to_array(&includes, file);
73543ae3
MT
599 if (r)
600 goto ERROR;
23f431f7
MT
601
602 // Move on to the next token
603 file = strtok_r(NULL, " \n", &p);
73543ae3
MT
604 }
605
606 // Allocate a new filelist
adfa3573 607 r = pakfire_filelist_create(&filelist, build->pakfire);
73543ae3
MT
608 if (r)
609 goto ERROR;
610
611 // Scan for files
23f431f7
MT
612 r = pakfire_filelist_scan(filelist, build->buildroot,
613 (const char**)includes, (const char**)excludes);
73543ae3
MT
614 if (r)
615 goto ERROR;
616
ae7968a7 617 const size_t length = pakfire_filelist_size(filelist);
adfa3573 618 DEBUG(build->pakfire, "%zu file(s) found\n", length);
73543ae3 619
84556307
MT
620 // Nothing to do if the filelist is empty
621 if (!length)
622 goto ERROR;
623
2a3025cc
MT
624 // Dump the filelist
625 pakfire_filelist_dump(filelist, 1);
626
5b0b3dc2 627 // Find dependencies
79049ef5 628 r = pakfire_build_find_dependencies(build, makefile, namespace, pkg, filelist);
5b0b3dc2 629 if (r) {
adfa3573 630 ERROR(build->pakfire, "Finding dependencies failed: %m\n");
5b0b3dc2
MT
631 goto ERROR;
632 }
633
ae7968a7 634 // Add all files to the package
5d5da764 635 r = pakfire_packager_add_files(packager, filelist);
814b7fee
MT
636 if (r)
637 goto ERROR;
73543ae3
MT
638
639ERROR:
640 if (filelist)
641 pakfire_filelist_unref(filelist);
23f431f7
MT
642 if (files)
643 free(files);
644 if (includes) {
645 for (char** include = includes; *include; include++)
646 free(*include);
73543ae3 647 free(includes);
23f431f7
MT
648 }
649 if (excludes) {
650 for (char** exclude = excludes; *exclude; exclude++)
651 free(*exclude);
73543ae3 652 free(excludes);
23f431f7 653 }
73543ae3
MT
654
655 return r;
656}
657
0e7a1dee
MT
658static 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;
660 size_t length = 0;
106d2edd 661
0e7a1dee
MT
662 // Fetch the scriptlet
663 const char* p = pakfire_scriptlet_get_data(ctx->scriptlet, &length);
664 if (!p) {
665 ERROR(pakfire, "Could not fetch scriptlet: %m\n");
106d2edd 666 return 1;
0e7a1dee 667 }
106d2edd 668
0e7a1dee
MT
669 // Write it into the pipe
670 ssize_t bytes_written = write(fd, p, length);
106d2edd 671 if (bytes_written < 0) {
0e7a1dee
MT
672 ERROR(pakfire, "Could not send scriptlet: %m\n");
673 return 1;
106d2edd
MT
674 }
675
1ec2cee0 676 return EOF;
0e7a1dee 677}
106d2edd 678
0e7a1dee
MT
679static int pakfire_build_add_scriptlet_requires(struct pakfire_build* build,
680 struct pakfire_package* pkg, struct pakfire_scriptlet* scriptlet) {
681 int r;
682
683 struct pakfire_find_deps_ctx ctx = {
684 .pkg = pkg,
685 .dep = PAKFIRE_PKG_PREREQUIRES,
686 .scriptlet = scriptlet,
106d2edd
MT
687 };
688
689 // Find all pre-requires
0e7a1dee
MT
690 r = pakfire_build_run_script(build, "find-prerequires", NULL,
691 pakfire_build_send_scriptlet, pakfire_build_process_deps, &ctx);
106d2edd
MT
692 if (r)
693 goto ERROR;
694
106d2edd 695ERROR:
106d2edd
MT
696 return r;
697}
698
9df89a8f
MT
699static 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) {
106d2edd
MT
702 struct pakfire_scriptlet* scriptlet = NULL;
703 char* shell = NULL;
704 int r;
705
706 // Wrap scriptlet into a shell script
a7ad6d4f 707 r = asprintf(&shell, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data);
106d2edd
MT
708 if (r < 0)
709 goto ERROR;
710
711 // Create a scriptlet
9df89a8f 712 r = pakfire_scriptlet_create(&scriptlet, build->pakfire, type, shell, 0);
106d2edd
MT
713 if (r)
714 goto ERROR;
715
716 // Add it to the package
717 r = pakfire_packager_add_scriptlet(packager, scriptlet);
718 if (r) {
9df89a8f 719 ERROR(build->pakfire, "Could not add scriptlet %s\n", type);
106d2edd
MT
720 goto ERROR;
721 }
722
723 // Add scriptlet requirements
9df89a8f 724 r = pakfire_build_add_scriptlet_requires(build, pkg, scriptlet);
106d2edd 725 if (r) {
9df89a8f 726 ERROR(build->pakfire, "Could not add scriptlet requirements: %m\n");
106d2edd
MT
727 goto ERROR;
728 }
729
730 // Success
731 r = 0;
732
733ERROR:
734 if (scriptlet)
735 pakfire_scriptlet_unref(scriptlet);
736 if (shell)
737 free(shell);
738
739 return r;
740}
741
9df89a8f
MT
742static 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) {
106d2edd
MT
745 char name[NAME_MAX];
746 int r;
747
748 for (const char** type = pakfire_scriptlet_types; *type; type++) {
749 r = pakfire_string_format(name, "scriptlet:%s", *type);
a60955af 750 if (r)
106d2edd
MT
751 return r;
752
753 // Fetch the scriptlet
754 char* data = pakfire_parser_get(makefile, namespace, name);
755 if (!data)
756 continue;
757
758 // Add it to the package
9df89a8f 759 r = pakfire_build_package_add_scriptlet(build, pkg, packager, *type, data);
106d2edd
MT
760 if (r) {
761 free(data);
762 return r;
763 }
764
765 free(data);
766 }
767
768 return 0;
769}
770
0e177be7
MT
771static int pakfire_build_package(struct pakfire_build* build, struct pakfire_parser* makefile,
772 const char* buildroot, const char* namespace) {
31480bee 773 struct pakfire_package* pkg = NULL;
48c6f2e7 774 struct pakfire_packager* packager = NULL;
73543ae3 775
a50bde9c
MT
776 int r = 1;
777
778 // Expand the handle into the package name
4c07774f 779 char* name = pakfire_parser_expand(makefile, "packages", namespace);
a50bde9c 780 if (!name) {
0e177be7 781 ERROR(build->pakfire, "Could not get package name: %m\n");
a50bde9c
MT
782 goto ERROR;
783 }
784
0e177be7 785 INFO(build->pakfire, "Building package '%s'...\n", name);
0f9bb14d 786 DEBUG(build->pakfire, " buildroot = %s\n", buildroot);
a50bde9c 787
4c07774f 788 // Fetch build architecture
0e177be7 789 const char* arch = pakfire_get_arch(build->pakfire);
4c07774f
MT
790 if (!arch)
791 goto ERROR;
792
4c07774f 793 // Fetch package from makefile
6ebd55e2 794 r = pakfire_parser_create_package(makefile, &pkg, NULL, namespace, arch);
4c07774f 795 if (r) {
0e177be7 796 ERROR(build->pakfire, "Could not create package from makefile: %m\n");
4c07774f
MT
797 goto ERROR;
798 }
799
ca002cae
MT
800 // Set distribution
801 const char* distribution = pakfire_parser_get(makefile, NULL, "DISTRO_NAME");
74468e4f
MT
802 if (distribution) {
803 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_DISTRO, distribution);
804 if (r)
805 goto ERROR;
806 }
ca002cae 807
7996020a 808 // Set build ID
3bea955d 809 pakfire_package_set_uuid(pkg, PAKFIRE_PKG_BUILD_ID, build->id);
7996020a 810
571539a7
MT
811 // Set source package
812 const char* source_name = pakfire_parser_get(makefile, NULL, "name");
988ce1bc
MT
813 if (source_name) {
814 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_SOURCE_NAME, source_name);
815 if (r)
816 goto ERROR;
817 }
571539a7
MT
818
819 // Set source EVR
820 const char* source_evr = pakfire_parser_get(makefile, NULL, "evr");
988ce1bc
MT
821 if (source_evr) {
822 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_SOURCE_EVR, source_evr);
823 if (r)
824 goto ERROR;
825 }
571539a7
MT
826
827 // Set source arch
988ce1bc
MT
828 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_SOURCE_ARCH, "src");
829 if (r)
830 goto ERROR;
571539a7 831
48c6f2e7 832 // Create a packager
0e177be7 833 r = pakfire_packager_create(&packager, build->pakfire, pkg);
48c6f2e7
MT
834 if (r)
835 goto ERROR;
836
73543ae3 837 // Add files
adfa3573 838 r = pakfire_build_package_add_files(build, makefile, buildroot, namespace,
5b0b3dc2 839 pkg, packager);
73543ae3
MT
840 if (r)
841 goto ERROR;
842
106d2edd 843 // Add scriptlets
9df89a8f 844 r = pakfire_build_package_add_scriptlets(build, makefile, namespace,
0e177be7 845 pkg, packager);
106d2edd
MT
846 if (r)
847 goto ERROR;
848
a6144133 849 const char* path = pakfire_repo_get_path(build->repo);
733efe16 850
ae7968a7 851 // Write the finished package
733efe16 852 r = pakfire_packager_finish_to_directory(packager, path, NULL);
ae7968a7 853 if (r) {
0e177be7 854 ERROR(build->pakfire, "pakfire_packager_finish() failed: %m\n");
ae7968a7
MT
855 goto ERROR;
856 }
857
2a838122
MT
858 // Cleanup all packaged files
859 r = pakfire_packager_cleanup(packager);
860 if (r)
861 goto ERROR;
862
a50bde9c
MT
863 // Success
864 r = 0;
865
866ERROR:
48c6f2e7
MT
867 if (packager)
868 pakfire_packager_unref(packager);
4c07774f
MT
869 if (pkg)
870 pakfire_package_unref(pkg);
a50bde9c
MT
871 if (name)
872 free(name);
873
874 return r;
875}
876
6ed07bc4
MT
877static 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);
880 if (!dump)
881 return 1;
882
883 INFO(pakfire, "%s\n", dump);
884 free(dump);
885
886 return 0;
887}
888
0e177be7 889static int pakfire_build_packages(struct pakfire_build* build,
03dc1d52 890 struct pakfire_parser* makefile) {
0e177be7 891 DEBUG(build->pakfire, "Creating packages...");
a50bde9c
MT
892 int r = 1;
893
03dc1d52
MT
894 const char* buildroot = pakfire_relpath(build->pakfire, build->buildroot);
895
a50bde9c
MT
896 // Fetch a list all all packages
897 char** packages = pakfire_parser_list_namespaces(makefile, "packages.package:*");
898 if (!packages) {
0e177be7 899 ERROR(build->pakfire, "Could not find any packages: %m\n");
a50bde9c
MT
900 goto ERROR;
901 }
902
903 unsigned int num_packages = 0;
904
905 // Count how many packages we have
906 for (char** package = packages; *package; package++)
907 num_packages++;
908
0e177be7 909 DEBUG(build->pakfire, "Found %d package(s)\n", num_packages);
a50bde9c
MT
910
911 // Build packages in reverse order
912 for (int i = num_packages - 1; i >= 0; i--) {
0e177be7 913 r = pakfire_build_package(build, makefile, buildroot, packages[i]);
a50bde9c
MT
914 if (r)
915 goto ERROR;
916 }
917
d6451238 918 // Rescan the build repository to import all packages again
a6144133 919 r = pakfire_repo_scan(build->repo, 0);
d6451238
MT
920 if (r)
921 goto ERROR;
922
6ed07bc4
MT
923 // Fetch all packages
924 r = pakfire_repo_create_packagelist(build->repo, &build->packages);
925 if (r)
926 goto ERROR;
927
928 // Dump them all
929 r = pakfire_packagelist_walk(build->packages, pakfire_build_package_dump, NULL);
930 if (r)
931 goto ERROR;
932
a50bde9c
MT
933 // Success
934 r = 0;
935
936ERROR:
937 if (packages)
938 free(packages);
939
940 return r;
941}
942
46748697
MT
943static int pakfire_build_stage(struct pakfire_build* build,
944 struct pakfire_parser* makefile, const char* stage) {
1a276007
MT
945 char template[1024];
946
947 // Prepare template for this stage
948 int r = pakfire_string_format(template, TEMPLATE, stage);
a60955af 949 if (r)
1a276007
MT
950 return r;
951
2ffd21f9
MT
952 // Fetch the environment
953 char** envp = pakfire_parser_make_environ(makefile);
954
1a276007
MT
955 // Create the build script
956 char* script = pakfire_parser_expand(makefile, "build", template);
957 if (!script) {
46748697
MT
958 ERROR(build->pakfire, "Could not generate the build script for stage '%s': %m\n",
959 stage);
1a276007
MT
960 goto ERROR;
961 }
962
46748697 963 INFO(build->pakfire, "Running build stage '%s'\n", stage);
1a276007 964
830f5d18 965 // Import environment
44d5ebfd
MT
966 // XXX is this a good idea?
967 r = pakfire_jail_import_env(build->jail, (const char**)envp);
830f5d18 968 if (r) {
46748697 969 ERROR(build->pakfire, "Could not import environment: %m\n");
830f5d18
MT
970 goto ERROR;
971 }
972
973 // Run the script
ccdd2e95 974 r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL, NULL, NULL, NULL);
1a276007 975 if (r) {
46748697 976 ERROR(build->pakfire, "Build stage '%s' failed with status %d\n", stage, r);
1a276007
MT
977 }
978
979ERROR:
2ffd21f9
MT
980 if (envp) {
981 for (char** e = envp; *e; e++)
982 free(*e);
983 free(envp);
984 }
1a276007
MT
985 if (script)
986 free(script);
987
988 return r;
989}
990
45dd1960
MT
991/*
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.
994*/
995static 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;
999 int r;
1000
1001 // Create a filelist with objects that need to be removed
1002 r = pakfire_filelist_create(&removees, build->pakfire);
1003 if (r)
1004 goto ERROR;
1005
1006 // Find all files that need to be removed
1007 r = pakfire_filelist_walk(filelist, callback, removees);
1008 if (r)
1009 goto ERROR;
1010
1011 if (!pakfire_filelist_is_empty(removees)) {
1012 if (description)
1013 INFO(build->pakfire, "%s\n", description);
1014
1015 // Show all files which will be removed
1016 pakfire_filelist_dump(removees, 0);
1017
1018 // Remove all files on the removee list
1019 r = pakfire_filelist_cleanup(removees);
1020 if (r)
1021 goto ERROR;
1022
1023 // Remove all files from the filelist
1024 r = pakfire_filelist_remove_all(filelist, removees);
1025 if (r)
1026 goto ERROR;
1027 }
1028
1029ERROR:
1030 if (removees)
1031 pakfire_filelist_unref(removees);
1032
1033 return r;
1034}
1035
1036static 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;
1039
1040 // Find all static libraries
1041 if (pakfire_file_matches_class(file, PAKFIRE_FILE_STATIC_LIBRARY))
1042 return pakfire_filelist_append(removees, file);
1043
1044 return 0;
1045}
1046
1047static 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);
1051}
1052
1053static 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;
1056
1057 // Find all libtool archive files
1058 if (pakfire_file_matches_class(file, PAKFIRE_FILE_LIBTOOL_ARCHIVE))
1059 return pakfire_filelist_append(removees, file);
1060
1061 return 0;
1062}
1063
1064static 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);
1068}
1069
1070static int pakfire_build_run_post_build_checks(struct pakfire_build* build) {
1071 struct pakfire_filelist* filelist = NULL;
1072 int r;
1073
1074 // Create a filelist of all files in the build
1075 r = pakfire_filelist_create(&filelist, build->pakfire);
1076 if (r) {
1077 ERROR(build->pakfire, "Could not create filelist: %m\n");
1078 goto ERROR;
1079 }
1080
1081 // Scan for all files in BUILDROOT
1082 r = pakfire_filelist_scan(filelist, build->buildroot, NULL, NULL);
1083 if (r)
1084 goto ERROR;
1085
1086 const size_t length = pakfire_filelist_size(filelist);
1087
1088 // If the filelist is empty, we can are done
1089 if (length == 0) {
1090 DEBUG(build->pakfire, "Empty BUILDROOT. Skipping post build checks...\n");
1091 r = 0;
1092 goto ERROR;
1093 }
1094
1095 // Remove any static libraries
1096 r = pakfire_build_post_remove_static_libraries(build, filelist);
1097 if (r)
1098 goto ERROR;
1099
1100 // Remove any libtool archives
1101 r = pakfire_build_post_remove_libtool_archives(build, filelist);
1102 if (r)
1103 goto ERROR;
1104
1105ERROR:
1106 if (filelist)
1107 pakfire_filelist_unref(filelist);
1108
1109 return r;
1110}
1111
39f45b30 1112static const char* post_build_scripts[] = {
1f62ffae 1113 "check-symlinks",
022b794e 1114 "check-unsafe-files",
0b5f0bbc 1115 "check-libraries",
16043831 1116 "check-rpaths",
99aee237 1117 "check-buildroot",
7e1fec6f 1118 "check-include",
dd864160 1119 "check-hardening",
ae703321 1120 "check-interpreters",
2504194a 1121 "check-fhs",
39f45b30 1122 "compress-man-pages",
ffb65de6 1123 "strip",
39f45b30
MT
1124 NULL,
1125};
1126
03dc1d52
MT
1127static int pakfire_build_run_post_build_scripts(struct pakfire_build* build) {
1128 // Fetch buildroot
1129 const char* buildroot = pakfire_relpath(build->pakfire, build->buildroot);
1130
39f45b30
MT
1131 // Set default arguments for build scripts
1132 const char* args[] = {
1133 buildroot, NULL
1134 };
1135
1136 // Run them one by one
1137 for (const char** script = post_build_scripts; *script; script++) {
ccdd2e95 1138 int r = pakfire_build_run_script(build, *script, args, NULL, NULL, NULL);
39f45b30
MT
1139 if (r)
1140 return r;
1141 }
1142
1143 return 0;
1144}
1145
abbad00b 1146static void pakfire_build_free(struct pakfire_build* build) {
6ed07bc4
MT
1147 if (build->packages)
1148 pakfire_packagelist_unref(build->packages);
1149
a6144133
MT
1150 if (build->repo) {
1151 pakfire_repo_clean(build->repo, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY);
1152 pakfire_repo_unref(build->repo);
d6451238
MT
1153 }
1154
753ddf74
MT
1155 if (build->jail)
1156 pakfire_jail_unref(build->jail);
1157
49fd9926
MT
1158 if (build->cgroup) {
1159 // Destroy the cgroup
1160 pakfire_cgroup_destroy(build->cgroup);
1161
1162 // Free it
1163 pakfire_cgroup_unref(build->cgroup);
1164 }
1165
abbad00b
MT
1166 pakfire_unref(build->pakfire);
1167 free(build);
1168}
1169
1170static int pakfire_build_parse_id(struct pakfire_build* build, const char* id) {
1171 int r;
1172
1173 // Try parsing the Build ID
1174 if (id) {
1175 r = uuid_parse(id, build->id);
1176 if (r) {
1177 ERROR(build->pakfire, "Could not parse build ID '%s'\n", id);
1df321ff 1178 errno = EINVAL;
abbad00b
MT
1179 return r;
1180 }
1181
1182 // Otherwise initialize the Build ID with something random
1183 } else {
1184 uuid_generate_random(build->id);
1185 }
1186
f877fdfa
MT
1187 // Store the ID as string, too
1188 uuid_unparse_lower(build->id, build->_id);
1189
1190 return 0;
1191}
1192
1193/*
1194 Sets up a new cgroup for this build
1195*/
1196static int pakfire_build_setup_cgroup(struct pakfire_build* build) {
0a1284ff 1197 struct pakfire_config* config = NULL;
f877fdfa
MT
1198 char path[PATH_MAX];
1199 int r;
1200
1201 // Compose path
1202 r = pakfire_string_format(path, "pakfire/build-%s", build->_id);
a60955af 1203 if (r) {
f877fdfa 1204 ERROR(build->pakfire, "Could not compose path for cgroup: %m\n");
0a1284ff 1205 goto ERROR;
f877fdfa
MT
1206 }
1207
1208 // Create a new cgroup
1209 r = pakfire_cgroup_open(&build->cgroup, build->pakfire, path,
1210 PAKFIRE_CGROUP_ENABLE_ACCOUNTING);
1211 if (r) {
1212 ERROR(build->pakfire, "Could not create cgroup for build %s: %m\n", build->_id);
0a1284ff 1213 goto ERROR;
f877fdfa
MT
1214 }
1215
0a1284ff
MT
1216 // Fetch config
1217 config = pakfire_get_config(build->pakfire);
1218 if (!config)
1219 goto ERROR;
1220
882ae03b 1221 // Guarantee some minimum memory
0a1284ff
MT
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);
1226 if (r)
1227 goto ERROR;
1228 }
882ae03b 1229
5b877e84
MT
1230 // Limit memory
1231 size_t memory_limit = pakfire_config_get_bytes(config, "build", "memory_limit", 0);
1232 if (memory_limit) {
1233 r = pakfire_cgroup_set_memory_limit(build->cgroup, memory_limit);
1234 if (r)
1235 goto ERROR;
1236 }
1237
de4c8fe6 1238 // Set PID limit
0a1284ff
MT
1239 size_t pid_limit = pakfire_config_get_int(config, "build",
1240 "pid_limit", PAKFIRE_BUILD_PID_LIMIT);
1241 if (pid_limit) {
1242 r = pakfire_cgroup_set_pid_limit(build->cgroup, pid_limit);
1243 if (r)
1244 goto ERROR;
1245 }
de4c8fe6 1246
0a1284ff
MT
1247ERROR:
1248 if (config)
1249 pakfire_config_unref(config);
1250
1251 return r;
abbad00b
MT
1252}
1253
753ddf74
MT
1254/*
1255 Sets up a new jail for this build
1256*/
1257static int pakfire_build_setup_jail(struct pakfire_build* build) {
1258 int r;
1259
1260 // Create a new jail
1261 r = pakfire_jail_create(&build->jail, build->pakfire, 0);
1262 if (r) {
1263 ERROR(build->pakfire, "Could not create jail for build %s: %m\n", build->_id);
1264 return r;
1265 }
1266
15503538
MT
1267 // Connect the jail to our cgroup
1268 r = pakfire_jail_set_cgroup(build->jail, build->cgroup);
1269 if (r) {
1270 ERROR(build->pakfire, "Could not set cgroup for jail: %m\n");
1271 return r;
1272 }
1273
753ddf74
MT
1274 // Done
1275 return 0;
1276}
1277
5a06668c
MT
1278/*
1279 Sets up the ccache for this build
1280*/
1281static int pakfire_build_setup_ccache(struct pakfire_build* build) {
1282 char path[PATH_MAX];
1283 int r;
1284
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");
0570ccd2
MT
1288
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");
1291 if (r) {
1292 ERROR(build->pakfire, "Could not disable ccache: %m\n");
1293 return r;
1294 }
1295
5a06668c
MT
1296 return 0;
1297 }
1298
1299 // Compose path
df1409ef
MT
1300 r = pakfire_cache_path(build->pakfire, path, "%s", "ccache");
1301 if (r) {
5a06668c
MT
1302 ERROR(build->pakfire, "Could not compose ccache path: %m\n");
1303 return 1;
1304 }
1305
1306 DEBUG(build->pakfire, "Mounting ccache from %s\n", path);
1307
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);
1312 return r;
1313 }
1314
1315 // Bind-mount the directory
1316 r = pakfire_jail_bind(build->jail, path, CCACHE_DIR, MS_NOSUID|MS_NOEXEC|MS_NODEV);
1317 if (r) {
1318 ERROR(build->pakfire, "Could not mount ccache: %m\n");
1319 return r;
1320 }
1321
1322 return 0;
1323}
1324
d8c8cdc4 1325static int pakfire_build_setup_repo(struct pakfire_build* build) {
eb3e6c00 1326 char path[PATH_MAX] = PAKFIRE_TMP_DIR "/pakfire-build-repo.XXXXXX";
d6451238
MT
1327 char url[PATH_MAX];
1328 int r;
1329
1330 // Create a new repository
a6144133 1331 r = pakfire_repo_create(&build->repo, build->pakfire, PAKFIRE_REPO_RESULT);
d6451238
MT
1332 if (r) {
1333 ERROR(build->pakfire, "Could not create repository %s: %m", PAKFIRE_REPO_RESULT);
1334 return r;
1335 }
1336
1337 // Set description
a6144133 1338 pakfire_repo_set_description(build->repo, _("Build Repository"));
d6451238
MT
1339
1340 // Create a temporary directory
1341 const char* p = pakfire_mkdtemp(path);
1342 if (!p) {
1343 ERROR(build->pakfire, "Could not create a the build repository: %m\n");
1344 return 1;
1345 }
1346
1347 // Format the URL
1348 r = pakfire_string_format(url, "file://%s", path);
1349 if (r)
1350 return r;
1351
1352 // Set the URL
a6144133 1353 pakfire_repo_set_baseurl(build->repo, url);
d6451238
MT
1354
1355 return r;
1356}
1357
abbad00b
MT
1358PAKFIRE_EXPORT int pakfire_build_create(struct pakfire_build** build,
1359 struct pakfire* pakfire, const char* id, int flags) {
1360 int r;
1361
1362 // Allocate build object
1363 struct pakfire_build* b = calloc(1, sizeof(*b));
1364 if (!b)
1365 return 1;
1366
1367 // Reference pakfire
1368 b->pakfire = pakfire_ref(pakfire);
1369
1370 // Initialize reference counter
1371 b->nrefs = 1;
1372
1373 // Copy flags
1374 b->flags = flags;
1375
1376 // Parse ID
1377 r = pakfire_build_parse_id(b, id);
1378 if (r)
1379 goto ERROR;
1380
d8c8cdc4
MT
1381 // Setup repo
1382 r = pakfire_build_setup_repo(b);
e545f6ec
MT
1383 if (r)
1384 goto ERROR;
1385
f877fdfa
MT
1386 // Create cgroup
1387 r = pakfire_build_setup_cgroup(b);
1388 if (r)
1389 goto ERROR;
1390
753ddf74
MT
1391 // Create jail
1392 r = pakfire_build_setup_jail(b);
1393 if (r)
1394 goto ERROR;
1395
5a06668c
MT
1396 // Setup ccache
1397 r = pakfire_build_setup_ccache(b);
1398 if (r)
1399 goto ERROR;
1400
abbad00b
MT
1401 *build = b;
1402 return 0;
1403
1404ERROR:
1405 pakfire_build_free(b);
1406 return r;
1407}
1408
77a1964f 1409PAKFIRE_EXPORT struct pakfire_build* pakfire_build_ref(struct pakfire_build* build) {
abbad00b
MT
1410 ++build->nrefs;
1411
1412 return build;
1413}
1414
77a1964f 1415PAKFIRE_EXPORT struct pakfire_build* pakfire_build_unref(struct pakfire_build* build) {
abbad00b
MT
1416 if (--build->nrefs > 0)
1417 return build;
1418
1419 pakfire_build_free(build);
1420 return NULL;
1421}
1422
ea924657
MT
1423PAKFIRE_EXPORT int pakfire_build_set_target(
1424 struct pakfire_build* build, const char* target) {
a60955af 1425 return pakfire_string_set(build->target, target);
ea924657 1426}
57e2cf99 1427
c0f2502a
MT
1428static int pakfire_build_install_packages(struct pakfire_build* build,
1429 int* snapshot_needs_update) {
57185995 1430 int r;
c0f2502a 1431
57185995
MT
1432 const char* packages[] = {
1433 "build-essential",
1434 NULL,
1435 };
c0f2502a
MT
1436
1437 int changed = 0;
1438
1439 // Install everything
57185995 1440 r = pakfire_install(build->pakfire, 0, 0, packages, NULL, 0,
c0f2502a
MT
1441 &changed, NULL, NULL);
1442 if (r) {
1443 ERROR(build->pakfire, "Could not install build dependencies: %m\n");
57185995 1444 return r;
c0f2502a
MT
1445 }
1446
1447 // Mark snapshot as changed if new packages were installed
1448 if (changed)
1449 *snapshot_needs_update = 1;
1450
1451 // Update everything
1452 r = pakfire_sync(build->pakfire, 0, 0, &changed, NULL, NULL);
1453 if (r) {
1454 ERROR(build->pakfire, "Could not update packages: %m\n");
57185995 1455 return r;
c0f2502a
MT
1456 }
1457
1458 // Has anything changed?
1459 if (changed)
1460 *snapshot_needs_update = 1;
1461
57185995 1462 return 0;
c0f2502a
MT
1463}
1464
8dbb69f9
MT
1465/*
1466 Initializes the build environment
1467*/
1468static int pakfire_build_init(struct pakfire_build* build) {
c0f2502a
MT
1469 char path[PATH_MAX];
1470 int r;
1471
8dbb69f9
MT
1472 // Don't do it again
1473 if (build->init) {
1474 DEBUG(build->pakfire, "Build environment has already been initialized\n");
1475 return 0;
1476 }
1477
1ea7b360 1478 // Compose path for snapshot
df1409ef
MT
1479 r = pakfire_cache_path(build->pakfire, path, "%s", "snapshot.tar.zst");
1480 if (r) {
1ea7b360
MT
1481 ERROR(build->pakfire, "Could not compose snapshot path: %m\n");
1482 return 1;
1483 }
1484
ffc2630d
MT
1485 // Tells us whether we need to (re-)create the snapshot
1486 int snapshot_needs_update = 0;
c0f2502a 1487
1ea7b360 1488 // Extract snapshot
ffc2630d 1489 if (!pakfire_build_has_flag(build, PAKFIRE_BUILD_DISABLE_SNAPSHOT)) {
ffc2630d 1490 // Try restoring the snapshot
4667a2ca
MT
1491 r = pakfire_snapshot_restore(build->pakfire, path);
1492 if (r && errno != ENOENT)
1493 return r;
c0f2502a
MT
1494 }
1495
c0f2502a
MT
1496 // Install or update any build dependencies
1497 r = pakfire_build_install_packages(build, &snapshot_needs_update);
1498 if (r)
1499 return r;
1500
ffc2630d
MT
1501 // Update the snapshot if there were changes
1502 if (!pakfire_build_has_flag(build, PAKFIRE_BUILD_DISABLE_SNAPSHOT) && snapshot_needs_update) {
c0f2502a 1503 // Create a new snapshot
4667a2ca 1504 r = pakfire_snapshot_create(build->pakfire, path);
c0f2502a
MT
1505 if (r)
1506 return r;
1507 }
1508
8dbb69f9
MT
1509 // Mark as initialized
1510 build->init = 1;
1511
c0f2502a
MT
1512 return 0;
1513}
1514
e57188c0
MT
1515static int pakfire_build_read_makefile(struct pakfire_build* build,
1516 struct pakfire_parser** parser, struct pakfire_package* package) {
e57188c0
MT
1517 char path[PATH_MAX];
1518 int r;
1519
1520 struct pakfire_parser_error* error = NULL;
1521
74468e4f
MT
1522 const char* nevra = pakfire_package_get_string(package, PAKFIRE_PKG_NEVRA);
1523 const char* name = pakfire_package_get_string(package, PAKFIRE_PKG_NAME);
e57188c0
MT
1524
1525 // Compose path to makefile
77e26129 1526 r = pakfire_path(build->pakfire, path, "/usr/src/packages/%s/%s.nm", nevra, name);
e57188c0
MT
1527 if (r < 0)
1528 return 1;
1529
1530 // Read makefile
1531 r = pakfire_read_makefile(parser, build->pakfire, path, &error);
1532 if (r) {
1533 if (error) {
1534 ERROR(build->pakfire, "Could not parse makefile %s: %s\n", path,
1535 pakfire_parser_error_get_message(error));
1536 } else {
1537 ERROR(build->pakfire, "Could not parse makefile %s: %m\n", path);
1538 }
1539
1540 goto ERROR;
1541 }
1542
6fc3956f 1543 // Set BUILDROOT
5caf06e3 1544 const char* buildroot = pakfire_relpath(build->pakfire, build->buildroot);
6fc3956f
MT
1545 if (buildroot)
1546 pakfire_parser_set(*parser, NULL, "BUILDROOT", buildroot, 0);
1547
e57188c0
MT
1548ERROR:
1549 if (error)
1550 pakfire_parser_error_unref(error);
1551
1552 return r;
1553}
1554
03dc1d52
MT
1555static int pakfire_build_perform(struct pakfire_build* build,
1556 struct pakfire_parser* makefile) {
1557 int r;
1558
b8786cdb
MT
1559 // Prepare the build
1560 r = pakfire_build_stage(build, makefile, "prepare");
1561 if (r)
1562 goto ERROR;
03dc1d52 1563
b8786cdb
MT
1564 // Perform the build
1565 r = pakfire_build_stage(build, makefile, "build");
1566 if (r)
1567 goto ERROR;
1568
1569 // Test the build
9605d535
MT
1570 if (!pakfire_build_has_flag(build, PAKFIRE_BUILD_DISABLE_TESTS)) {
1571 r = pakfire_build_stage(build, makefile, "test");
1572 if (r)
1573 goto ERROR;
1574 }
b8786cdb
MT
1575
1576 // Install everything
1577 r = pakfire_build_stage(build, makefile, "install");
1578 if (r)
1579 goto ERROR;
03dc1d52 1580
45dd1960
MT
1581 // Run post build checks
1582 r = pakfire_build_run_post_build_checks(build);
1583 if (r)
1584 goto ERROR;
1585
03dc1d52 1586 // Run post build scripts
b8786cdb
MT
1587 r = pakfire_build_run_post_build_scripts(build);
1588 if (r)
1589 goto ERROR;
1590
1591 // Done!
1592 return 0;
1593
1594ERROR:
1595 // Drop to a shell for debugging
cebfd3f6 1596 if (pakfire_build_has_flag(build, PAKFIRE_BUILD_INTERACTIVE))
b8786cdb
MT
1597 pakfire_build_shell(build);
1598
1599 return r;
03dc1d52
MT
1600}
1601
0f9bb14d
MT
1602static int __pakfire_build_unpackaged_file(struct pakfire* pakfire,
1603 struct pakfire_file* file, void* p) {
1604 char* s = pakfire_file_dump(file);
6cb8b2b5 1605 if (s) {
0f9bb14d 1606 ERROR(pakfire, "%s\n", s);
6cb8b2b5
MT
1607 free(s);
1608 }
0f9bb14d
MT
1609
1610 return 0;
1611}
1612
1613static int pakfire_build_check_unpackaged_files(struct pakfire_build* build) {
1614 struct pakfire_filelist* filelist = NULL;
1615 int r;
1616
1617 // Create a new filelist
1618 r = pakfire_filelist_create(&filelist, build->pakfire);
1619 if (r)
1620 goto ERROR;
1621
1622 // Scan for all files in BUILDROOT
1623 r = pakfire_filelist_scan(filelist, build->buildroot, NULL, NULL);
1624 if (r)
1625 goto ERROR;
1626
1627 const size_t length = pakfire_filelist_size(filelist);
1628
1629 if (length) {
1630 ERROR(build->pakfire, "Unpackaged files found:\n");
1631
48ff07ff 1632 r = pakfire_filelist_walk(filelist, __pakfire_build_unpackaged_file, NULL);
0f9bb14d
MT
1633 if (r)
1634 goto ERROR;
1635
1636 // Report an error
1637 r = 1;
1638 }
1639
1640ERROR:
1641 if (filelist)
1642 pakfire_filelist_unref(filelist);
1643
1644 return r;
1645}
1646
8ad8d09b
MT
1647static int pakfire_build_install_package(struct pakfire* pakfire,
1648 struct pakfire_package* pkg, void* p) {
1649 struct pakfire_request* request = (struct pakfire_request*)p;
1650
37dade64
MT
1651 return pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, pkg,
1652 PAKFIRE_REQUEST_ESSENTIAL);
8ad8d09b
MT
1653}
1654
1655static 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;
1660 int r;
1661
1662 // Create a new request
1663 r = pakfire_request_create(&request, build->pakfire, 0);
1664 if (r)
1665 goto ERROR;
1666
1667 // Add all packages
1668 r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, request);
1669
1670 // Solve the request
b3e36a6d 1671 r = pakfire_request_solve(request);
8ad8d09b
MT
1672 switch (r) {
1673 // All okay
1674 case 0:
1675 break;
1676
1677 // Dependency Error
1678 case 2:
1679 ERROR(build->pakfire, "Install test failed:\n");
1680
1681 // Walk through all problems
1682 for (;;) {
1683 r = pakfire_request_next_problem(request, &problem);
1684 if (r)
1685 goto ERROR;
1686
1687 // There are no more problems
1688 if (!problem)
1689 break;
1690
1691 // Format the problem into something human-readable
1692 s = pakfire_problem_to_string(problem);
1693 if (!s)
1694 continue;
1695
1696 ERROR(build->pakfire, " * %s\n", s);
1697
1698 // Walk through all solutions
1699 for (;;) {
1700 r = pakfire_problem_next_solution(problem, &solution);
1701 if (r)
1702 goto ERROR;
1703
1704 // There are no more solutions
1705 if (!solution)
1706 break;
1707
1708 // Format the solution into something human-readable
1709 s = pakfire_solution_to_string(solution);
1710 if (!s)
1711 continue;
1712
1713 ERROR(build->pakfire, " * %s\n", s);
1714 }
1715 }
1716
1717 break;
1718
1719 // Any other errors
1720 default:
1721 goto ERROR;
1722 }
1723
1724ERROR:
1725 if (r)
1726 ERROR(build->pakfire, "Install test failed: %m\n");
1727 if (request)
1728 pakfire_request_unref(request);
1729 if (problem)
1730 pakfire_problem_unref(problem);
1731 if (solution)
1732 pakfire_solution_unref(solution);
1733
1734 return r;
1735}
1736
0f9bb14d
MT
1737static int pakfire_build_post_check(struct pakfire_build* build) {
1738 int r;
1739
1740 // Check for unpackaged files
1741 r = pakfire_build_check_unpackaged_files(build);
1742 if (r)
1743 return r;
1744
62bca61d
MT
1745 // Perform install test
1746 r = pakfire_build_install_test(build);
1747 if (r)
1748 return r;
62bca61d 1749
0f9bb14d
MT
1750 return 0;
1751}
1752
62bca61d
MT
1753static 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];
1757 int r;
1758
1759 const char* target = (const char*)p;
1760
1761 if (!target) {
1762 errno = EINVAL;
1763 return 1;
1764 }
1765
1766 // Fetch the package filename
1767 const char* filename = pakfire_package_get_string(pkg, PAKFIRE_PKG_FILENAME);
1768 if (!filename) {
1769 r = 1;
1770 goto ERROR;
1771 }
1772
1773 // Format the destination path
1774 r = pakfire_string_format(path, "%s/%s", target, filename);
1775 if (r)
1776 goto ERROR;
1777
1778 // Open the archive
1779 archive = pakfire_package_get_archive(pkg);
1780 if (!archive) {
1781 r = 1;
1782 goto ERROR;
1783 }
1784
1785 // Copy it to its destination
1786 r = pakfire_archive_copy(archive, path);
1787 if (r)
1788 goto ERROR;
1789
1790ERROR:
1791 if (archive)
1792 pakfire_archive_unref(archive);
1793
1794 return r;
1795}
1796
1797static int pakfire_build_copy_packages(struct pakfire_build* build) {
1798 struct pakfire_repo* local = NULL;
1799 int r = 0;
1800
1801 DEBUG(build->pakfire, "Copying built packages\n");
1802
1803 // Fetch local repository
1804 local = pakfire_get_repo(build->pakfire, PAKFIRE_REPO_LOCAL);
1805
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);
1810 if (r)
1811 goto ERROR;
1812 }
1813
1814 // If we have a local repository, we copy all packages to it
1815 if (local) {
1816 const char* path = pakfire_repo_get_path(local);
1817 if (path) {
1818 r = pakfire_packagelist_walk(build->packages,
1819 pakfire_build_copy_package, (void*)path);
1820 if (r)
1821 goto ERROR;
1822 }
1823 }
1824
1825ERROR:
1826 if (local)
1827 pakfire_repo_unref(local);
1828
1829 return r;
1830}
1831
fcc68dff
MT
1832static 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;
1836 int r;
1837
1838 // Create a new request
1839 r = pakfire_request_create(&request, build->pakfire, 0);
1840 if (r)
1841 goto ERROR;
1842
1843 // Add the package
1844 r = pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, package,
1845 PAKFIRE_REQUEST_ESSENTIAL);
1846 if (r)
1847 goto ERROR;
1848
1849 // Solve the request
1850 r = pakfire_request_solve(request);
1851 if (r)
1852 goto ERROR;
1853
1854 // Fetch the transaction
1855 r = pakfire_request_get_transaction(request, &transaction);
1856 if (r)
1857 goto ERROR;
1858
1859 // Set how many packages have been changed
1860 const size_t changes = pakfire_transaction_count(transaction);
1861
1862 // Sanity check to see if we actually try to install anything
1863 if (!changes) {
1864 ERROR(build->pakfire, "The source package did not get installed\n");
1865 r = 1;
1866 goto ERROR;
1867 }
1868
1869 // Run the transaction
1870 r = pakfire_transaction_run(transaction, 0);
1871 if (r)
1872 goto ERROR;
1873
1874ERROR:
1875 if (transaction)
1876 pakfire_transaction_unref(transaction);
1877 if (request)
1878 pakfire_request_unref(request);
1879
1880 return r;
1881}
1882
ea924657 1883PAKFIRE_EXPORT int pakfire_build_exec(struct pakfire_build* build, const char* path) {
33a8ba3c 1884 struct pakfire_package* package = NULL;
e57188c0 1885 struct pakfire_parser* makefile = NULL;
6fc3956f 1886 char* buildroot = NULL;
ea924657 1887 int r;
01b29895 1888
6fc3956f 1889 // Set buildroot
eb3e6c00
MT
1890 r = pakfire_path(build->pakfire, build->buildroot, "%s",
1891 PAKFIRE_TMP_DIR "/pakfire-buildroot.XXXXXX");
77e26129
MT
1892 if (r)
1893 goto ERROR;
6fc3956f 1894
bf9b62e6
MT
1895 // Open the source package
1896 r = pakfire_commandline_add(build->pakfire, path, &package);
1897 if (r)
33a8ba3c 1898 goto ERROR;
33a8ba3c 1899
74468e4f 1900 const char* nevra = pakfire_package_get_string(package, PAKFIRE_PKG_NEVRA);
33a8ba3c
MT
1901
1902 INFO(build->pakfire, "Building %s...\n", nevra);
01b29895 1903
8dbb69f9
MT
1904 // Initialize the build environment
1905 r = pakfire_build_init(build);
1906 if (r)
c0f2502a 1907 goto ERROR;
c0f2502a 1908
fcc68dff
MT
1909 // Install the source package
1910 r = pakfire_build_install_source_package(build, package);
01b29895 1911 if (r) {
fcc68dff 1912 ERROR(build->pakfire, "Could not install the source package: %m\n");
33a8ba3c 1913 goto ERROR;
01b29895
MT
1914 }
1915
6fc3956f
MT
1916 // Create BUILDROOT
1917 buildroot = pakfire_mkdtemp(build->buildroot);
1918 if (!buildroot) {
1919 ERROR(build->pakfire, "Could not create BUILDROOT: %m\n");
1920 goto ERROR;
1921 }
1922
e57188c0
MT
1923 // Open the makefile
1924 r = pakfire_build_read_makefile(build, &makefile, package);
1925 if (r)
01b29895
MT
1926 goto ERROR;
1927
03dc1d52
MT
1928 // Perform the actual build
1929 r = pakfire_build_perform(build, makefile);
1930 if (r)
1931 goto ERROR;
1932
1933 // Create the packages
1934 r = pakfire_build_packages(build, makefile);
01b29895 1935 if (r) {
03dc1d52 1936 ERROR(build->pakfire, "Could not create packages: %m\n");
01b29895
MT
1937 goto ERROR;
1938 }
1939
0f9bb14d
MT
1940 // Perform post build checks
1941 r = pakfire_build_post_check(build);
1942 if (r)
1943 goto ERROR;
1944
62bca61d
MT
1945 // Copy packages to their destination
1946 r = pakfire_build_copy_packages(build);
1947 if (r)
1948 goto ERROR;
1949
01b29895 1950ERROR:
e57188c0
MT
1951 if (makefile)
1952 pakfire_parser_unref(makefile);
33a8ba3c
MT
1953 if (package)
1954 pakfire_package_unref(package);
1955
6fc3956f
MT
1956 // Cleanup buildroot
1957 if (buildroot)
1958 pakfire_rmtree(buildroot, 0);
1959
01b29895
MT
1960 return r;
1961}
1962
ea924657
MT
1963/*
1964 Compatibility function to keep the legacy API.
1965*/
1966PAKFIRE_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;
1969 int r;
1970
1971 // Check if path is set
1972 if (!path) {
1973 errno = EINVAL;
1974 return 1;
1975 }
1976
1977 // Create a new build environment
1978 r = pakfire_build_create(&build, pakfire, id, flags);
1979 if (r)
1980 goto ERROR;
1981
1982 // Set target
1983 if (target) {
1984 r = pakfire_build_set_target(build, target);
1985 if (r)
1986 goto ERROR;
1987 }
1988
1989 // Run build
1990 r = pakfire_build_exec(build, path);
1991
1992ERROR:
1993 if (build)
1994 pakfire_build_unref(build);
1995
1996 return r;
1997}
1998
5f6e42a2
MT
1999int pakfire_build_clean(struct pakfire* pakfire, int flags) {
2000 struct pakfire_repo* local = NULL;
2001 int r = 0;
22a0733e 2002
5f6e42a2
MT
2003 // Fetch local repository
2004 local = pakfire_get_repo(pakfire, PAKFIRE_REPO_LOCAL);
2005 if (!local) {
2006 ERROR(pakfire, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL);
22a0733e
MT
2007 goto ERROR;
2008 }
2009
5f6e42a2
MT
2010 // Destroy everything in it
2011 r = pakfire_repo_clean(local, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY);
2012 if (r)
22a0733e 2013 goto ERROR;
22a0733e
MT
2014
2015ERROR:
5f6e42a2
MT
2016 if (local)
2017 pakfire_repo_unref(local);
22a0733e
MT
2018
2019 return r;
2020}
2021
5f6e42a2
MT
2022/*
2023 This is a convenience function that sets up a build environment and
2024 then drops the user into an interactive shell.
2025*/
51840d97 2026PAKFIRE_EXPORT int pakfire_shell(struct pakfire* pakfire, const char** packages, int flags) {
5f6e42a2 2027 struct pakfire_build* build = NULL;
48dc31f7 2028 int r;
1a276007 2029
51840d97
MT
2030 // Shells are always interactive
2031 flags |= PAKFIRE_BUILD_INTERACTIVE;
2032
5f6e42a2 2033 // Create a new build environment
51840d97 2034 r = pakfire_build_create(&build, pakfire, NULL, flags);
5f6e42a2
MT
2035 if (r) {
2036 ERROR(pakfire, "Could not create build: %m\n");
2037 goto ERROR;
7f068a08
MT
2038 }
2039
8dbb69f9
MT
2040 // Initialize the build environment
2041 r = pakfire_build_init(build);
2042 if (r)
2043 goto ERROR;
22a0733e 2044
5f6e42a2
MT
2045 // Install any additional packages
2046 if (packages) {
2047 r = pakfire_install(build->pakfire, 0, 0, packages, NULL, 0, NULL, NULL, NULL);
2048 if (r)
2049 return r;
397371db
MT
2050 }
2051
5f6e42a2
MT
2052 // Run shell
2053 r = pakfire_build_shell(build);
397371db
MT
2054
2055ERROR:
5f6e42a2
MT
2056 if (build)
2057 pakfire_build_unref(build);
397371db
MT
2058
2059 return r;
2060}