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 <linux/limits.h>
26 #include <sys/types.h>
31 #include <archive_entry.h>
35 // Enable legacy logging
36 #define PAKFIRE_LEGACY_LOGGING
38 #include <pakfire/archive.h>
39 #include <pakfire/compress.h>
40 #include <pakfire/constants.h>
41 #include <pakfire/logging.h>
42 #include <pakfire/package.h>
43 #include <pakfire/packager.h>
44 #include <pakfire/pakfire.h>
45 #include <pakfire/pwd.h>
46 #include <pakfire/string.h>
47 #include <pakfire/util.h>
49 struct pakfire_packager
{
50 struct pakfire
* pakfire
;
54 struct pakfire_package
* pkg
;
55 char filename
[PATH_MAX
];
58 struct archive
* reader
;
61 struct pakfire_filelist
* filelist
;
64 struct pakfire_scriptlet
** scriptlets
;
65 unsigned int num_scriptlets
;
71 static void pakfire_packager_free(struct pakfire_packager
* packager
) {
73 if (packager
->scriptlets
) {
74 for (unsigned int i
= 0; i
< packager
->num_scriptlets
; i
++)
75 pakfire_scriptlet_unref(packager
->scriptlets
[i
]);
76 free(packager
->scriptlets
);
80 archive_read_free(packager
->reader
);
82 if (packager
->filelist
)
83 pakfire_filelist_unref(packager
->filelist
);
84 pakfire_package_unref(packager
->pkg
);
85 pakfire_unref(packager
->pakfire
);
89 int pakfire_packager_create(struct pakfire_packager
** packager
,
90 struct pakfire
* pakfire
, struct pakfire_package
* pkg
) {
91 struct pakfire_packager
* p
= NULL
;
92 char hostname
[HOST_NAME_MAX
];
95 // Allocate the packager object
96 p
= calloc(1, sizeof(*p
));
100 // Save creation time
101 p
->time_created
= time(NULL
);
103 // Initialize reference counting
106 // Store a reference to Pakfire
107 p
->pakfire
= pakfire_ref(pakfire
);
109 // Store a reference to the package
110 p
->pkg
= pakfire_package_ref(pkg
);
112 // Use the default digests
113 p
->digests
= PAKFIRE_PACKAGER_DIGESTS
;
116 const char* tag
= pakfire_get_distro_tag(p
->pakfire
);
118 ERROR(p
->pakfire
, "Distribution tag is not configured: %m\n");
122 pakfire_package_set_string(pkg
, PAKFIRE_PKG_DISTRO
, tag
);
124 // Fetch the hostname
125 r
= gethostname(hostname
, sizeof(hostname
));
127 ERROR(p
->pakfire
, "Could not determine the hostname: %m\n");
132 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_BUILD_HOST
, hostname
);
134 ERROR_ERRNO(p
->pakfire
, r
, "Could not set the hostname: %m\n");
139 pakfire_package_set_num(pkg
, PAKFIRE_PKG_BUILD_TIME
, p
->time_created
);
142 p
->reader
= pakfire_make_archive_disk_reader(p
->pakfire
, 1);
147 r
= pakfire_filelist_create(&p
->filelist
, p
->pakfire
);
151 // Add a requirement for the cryptographic algorithms we are using
152 if (p
->digests
& PAKFIRE_DIGEST_SHA3_512
) {
153 r
= pakfire_package_add_dep(p
->pkg
,
154 PAKFIRE_PKG_REQUIRES
, "pakfire(Digest-SHA3-512)");
158 if (p
->digests
& PAKFIRE_DIGEST_SHA3_256
) {
159 r
= pakfire_package_add_dep(p
->pkg
,
160 PAKFIRE_PKG_REQUIRES
, "pakfire(Digest-SHA3-256)");
164 if (p
->digests
& PAKFIRE_DIGEST_BLAKE2B512
) {
165 r
= pakfire_package_add_dep(p
->pkg
,
166 PAKFIRE_PKG_REQUIRES
, "pakfire(Digest-BLAKE2b512)");
170 if (p
->digests
& PAKFIRE_DIGEST_BLAKE2S256
) {
171 r
= pakfire_package_add_dep(p
->pkg
,
172 PAKFIRE_PKG_REQUIRES
, "pakfire(Digest-BLAKE2s256)");
176 if (p
->digests
& PAKFIRE_DIGEST_SHA2_512
) {
177 r
= pakfire_package_add_dep(p
->pkg
,
178 PAKFIRE_PKG_REQUIRES
, "pakfire(Digest-SHA2-512)");
182 if (p
->digests
& PAKFIRE_DIGEST_SHA2_256
) {
183 r
= pakfire_package_add_dep(p
->pkg
,
184 PAKFIRE_PKG_REQUIRES
, "pakfire(Digest-SHA2-256)");
189 // Return a reference
190 *packager
= pakfire_packager_ref(p
);
194 pakfire_packager_unref(p
);
199 struct pakfire_packager
* pakfire_packager_ref(
200 struct pakfire_packager
* packager
) {
206 struct pakfire_packager
* pakfire_packager_unref(
207 struct pakfire_packager
* packager
) {
208 if (--packager
->nrefs
> 0)
211 pakfire_packager_free(packager
);
215 const char* pakfire_packager_filename(struct pakfire_packager
* packager
) {
216 if (!*packager
->filename
) {
217 const char* filename
= pakfire_package_get_string(packager
->pkg
, PAKFIRE_PKG_FILENAME
);
220 if (pakfire_package_is_source(packager
->pkg
))
221 pakfire_string_set(packager
->filename
, filename
);
223 const char* arch
= pakfire_package_get_string(packager
->pkg
, PAKFIRE_PKG_ARCH
);
225 pakfire_string_format(packager
->filename
, "%s/%s", arch
, filename
);
229 return packager
->filename
;
232 static struct archive_entry
* pakfire_packager_create_file(
233 struct pakfire_packager
* packager
, const char* filename
, size_t size
, mode_t mode
) {
234 // Create a new file entry
235 struct archive_entry
* entry
= archive_entry_new();
240 archive_entry_set_pathname(entry
, filename
);
242 // This is a regular file
243 archive_entry_set_filetype(entry
, AE_IFREG
);
244 archive_entry_set_perm(entry
, mode
);
247 archive_entry_set_size(entry
, size
);
250 archive_entry_set_uname(entry
, "root");
251 archive_entry_set_uid(entry
, 0);
252 archive_entry_set_gname(entry
, "root");
253 archive_entry_set_gid(entry
, 0);
256 archive_entry_set_birthtime(entry
, packager
->time_created
, 0);
257 archive_entry_set_ctime(entry
, packager
->time_created
, 0);
258 archive_entry_set_mtime(entry
, packager
->time_created
, 0);
259 archive_entry_set_atime(entry
, packager
->time_created
, 0);
264 static int pakfire_packager_write_file_from_buffer(struct pakfire_packager
* packager
,
265 struct archive
* a
, const char* filename
, mode_t mode
, const char* buffer
) {
266 size_t size
= strlen(buffer
);
269 struct archive_entry
* entry
= pakfire_packager_create_file(packager
, filename
, size
, mode
);
271 ERROR(packager
->pakfire
, "Could not create file '%s'\n", filename
);
275 // This is the end of the header
276 int r
= archive_write_header(a
, entry
);
278 ERROR(packager
->pakfire
, "Error writing header: %s\n", archive_error_string(a
));
283 r
= archive_write_data(a
, buffer
, strlen(buffer
));
285 ERROR(packager
->pakfire
, "Error writing data: %s\n", archive_error_string(a
));
293 archive_entry_free(entry
);
298 static int pakfire_packager_write_format(struct pakfire_packager
* packager
,
300 const char buffer
[] = TO_STRING(PACKAGE_FORMAT
) "\n";
302 DEBUG(packager
->pakfire
, "Writing package format\n");
304 int r
= pakfire_packager_write_file_from_buffer(packager
, a
,
305 "pakfire-format", 0444, buffer
);
309 // Add package format marker
310 r
= pakfire_package_add_dep(packager
->pkg
, PAKFIRE_PKG_REQUIRES
,
311 "pakfire(PackageFormat-" TO_STRING(PACKAGE_FORMAT
) ")");
318 static char* pakfire_packager_make_metadata(struct pakfire_packager
* packager
) {
321 // Convert all package metadata to JSON
322 struct json_object
* md
= pakfire_package_to_json(packager
->pkg
);
326 // Serialize JSON to file
327 const char* s
= json_object_to_json_string_ext(md
, 0);
331 // Copy result onto heap
344 static int pakfire_packager_write_metadata(struct pakfire_packager
* packager
,
347 char* buffer
= pakfire_packager_make_metadata(packager
);
351 DEBUG(packager
->pakfire
, "Generated package metadata:\n%s\n", buffer
);
354 int r
= pakfire_packager_write_file_from_buffer(packager
, a
,
355 ".PKGINFO", 0444, buffer
);
362 static int pakfire_packager_write_scriptlet(struct pakfire_packager
* packager
,
363 struct archive
* a
, struct pakfire_scriptlet
* scriptlet
) {
364 char filename
[PATH_MAX
];
369 const char* type
= pakfire_scriptlet_get_type(scriptlet
);
371 DEBUG(packager
->pakfire
, "Writing scriptlet '%s' to package\n", type
);
374 r
= pakfire_string_format(filename
, ".scriptlets/%s", type
);
379 const char* data
= pakfire_scriptlet_get_data(scriptlet
, &size
);
382 return pakfire_packager_write_file_from_buffer(packager
, a
, filename
, 0544, data
);
386 This function is being called at the end when all data has been added to the package.
388 It will create a new archive and write the package to the given file descriptor.
390 int pakfire_packager_finish(struct pakfire_packager
* packager
, FILE* f
) {
391 struct archive
* a
= NULL
;
395 const char* nevra
= pakfire_package_get_string(packager
->pkg
, PAKFIRE_PKG_NEVRA
);
397 // Add requires feature markers
398 if (pakfire_package_has_rich_deps(packager
->pkg
)) {
399 r
= pakfire_package_add_dep(packager
->pkg
,
400 PAKFIRE_PKG_REQUIRES
, "pakfire(RichDependencies)");
406 r
= pakfire_package_set_filelist(packager
->pkg
, packager
->filelist
);
410 const size_t installsize
= pakfire_filelist_total_size(packager
->filelist
);
412 // Store total install size
413 r
= pakfire_package_set_num(packager
->pkg
, PAKFIRE_PKG_INSTALLSIZE
, installsize
);
417 // Select compression level
418 if (pakfire_package_is_source(packager
->pkg
))
423 // Create a new archive that is being compressed as fast as possible
424 r
= pakfire_compress_create_archive(packager
->pakfire
, &a
, f
,
425 PAKFIRE_COMPRESS_ZSTD
, level
);
429 // Add feature marker
430 pakfire_package_add_dep(packager
->pkg
,
431 PAKFIRE_PKG_REQUIRES
, "pakfire(Compress-Zstandard)");
433 // Start with the format file
434 r
= pakfire_packager_write_format(packager
, a
);
436 ERROR(packager
->pakfire
, "Could not add format file to archive: %s\n",
437 archive_error_string(a
));
441 // Write the metadata
442 r
= pakfire_packager_write_metadata(packager
, a
);
444 ERROR(packager
->pakfire
, "Could not add metadata file to archive: %s\n",
445 archive_error_string(a
));
450 for (unsigned int i
= 0; i
< packager
->num_scriptlets
; i
++) {
451 r
= pakfire_packager_write_scriptlet(packager
, a
, packager
->scriptlets
[i
]);
453 ERROR(packager
->pakfire
, "Could not add scriptlet to the archive: %m\n");
459 r
= pakfire_compress(packager
->pakfire
, a
, packager
->filelist
, nevra
,
460 PAKFIRE_COMPRESS_SHOW_THROUGHPUT
, PAKFIRE_PACKAGER_DIGESTS
);
464 // Flush all buffers to disk
472 archive_write_free(a
);
477 int pakfire_packager_finish_to_directory(struct pakfire_packager
* packager
,
478 const char* target
, char** result
) {
480 char tmppath
[PATH_MAX
];
484 // target cannot be empty
490 // Get the filename of the package
491 const char* filename
= pakfire_packager_filename(packager
);
493 ERROR(packager
->pakfire
, "Could not generate filename for package: %m\n");
498 // Make the package path
499 r
= pakfire_string_format(path
, "%s/%s", target
, filename
);
503 // Create the parent directory
504 r
= pakfire_mkparentdir(path
, 0755);
508 // Create a temporary file in the target directory
509 r
= pakfire_string_format(tmppath
, "%s.XXXXXX", path
);
513 // Create a temporary result file
514 f
= pakfire_mktemp(tmppath
, 0);
518 // Write the finished package
519 r
= pakfire_packager_finish(packager
, f
);
521 ERROR(packager
->pakfire
, "pakfire_packager_finish() failed: %m\n");
525 // Move the temporary file to destination
526 r
= rename(tmppath
, path
);
528 ERROR(packager
->pakfire
, "Could not move %s to %s: %m\n", tmppath
, path
);
532 DEBUG(packager
->pakfire
, "Package written to %s\n", path
);
534 // Store result path if requested
536 *result
= strdup(path
);
550 // Remove temporary file
557 int pakfire_packager_add_file(struct pakfire_packager
* packager
, struct pakfire_file
* file
) {
567 const char* path
= pakfire_file_get_path(file
);
569 // Files cannot have an empty path
570 if (!path
|| !*path
) {
571 ERROR(packager
->pakfire
, "Cannot add a file with an empty path\n");
575 // Hidden files cannot be added
576 } else if (*path
== '.') {
577 ERROR(packager
->pakfire
, "Hidden files cannot be added to a package: %s\n", path
);
582 DEBUG(packager
->pakfire
, "Adding file to payload: %s\n", path
);
584 // Detect the MIME type
585 r
= pakfire_file_detect_mimetype(file
);
589 // Overwrite a couple of things for source archives
590 if (pakfire_package_is_source(packager
->pkg
)) {
592 pakfire_file_set_perms(file
, 0644);
594 // Reset file ownership
595 pakfire_file_set_uname(file
, "root");
596 pakfire_file_set_gname(file
, "root");
599 // Handle systemd sysusers
600 if (pakfire_file_matches(file
, "/usr/lib/sysusers.d/*.conf")) {
601 pakfire_package_add_dep(packager
->pkg
,
602 PAKFIRE_PKG_REQUIRES
, "pakfire(systemd-sysusers)");
604 // Ask to pre-install /usr/bin/systemd-sysusers
605 pakfire_package_add_dep(packager
->pkg
,
606 PAKFIRE_PKG_PREREQUIRES
, "/usr/bin/systemd-sysusers");
609 // Handle systemd tmpfiles
610 if (pakfire_file_matches(file
, "/usr/lib/tmpfiles.d/*.conf")) {
611 pakfire_package_add_dep(packager
->pkg
,
612 PAKFIRE_PKG_REQUIRES
, "pakfire(systemd-tmpfiles)");
614 // Ask to pre-install systemd
615 pakfire_package_add_dep(packager
->pkg
,
616 PAKFIRE_PKG_PREREQUIRES
, "systemd");
619 // Append the file to the filelist
620 return pakfire_filelist_add(packager
->filelist
, file
);
623 int pakfire_packager_add(struct pakfire_packager
* packager
,
624 const char* sourcepath
, const char* path
) {
625 struct pakfire_file
* file
= NULL
;
628 // Create a new file object
629 r
= pakfire_file_create(&file
, packager
->pakfire
);
633 // Read the meta information
634 r
= pakfire_file_read(file
, packager
->reader
, sourcepath
);
641 // Assign a new path for inside the archive
642 r
= pakfire_file_set_path(file
, path
);
646 // Call the main function
647 r
= pakfire_packager_add_file(packager
, file
);
651 pakfire_file_unref(file
);
656 static int __pakfire_packager_add_files(struct pakfire
* pakfire
,
657 struct pakfire_file
* file
, void* p
) {
658 struct pakfire_packager
* packager
= (struct pakfire_packager
*)p
;
660 return pakfire_packager_add_file(packager
, file
);
663 int pakfire_packager_add_files(
664 struct pakfire_packager
* packager
, struct pakfire_filelist
* filelist
) {
665 // Add all files on the filelist
666 return pakfire_filelist_walk(filelist
, __pakfire_packager_add_files
, packager
, 0);
669 int pakfire_packager_add_scriptlet(struct pakfire_packager
* packager
,
670 struct pakfire_scriptlet
* scriptlet
) {
677 packager
->scriptlets
= reallocarray(packager
->scriptlets
,
678 packager
->num_scriptlets
+ 1, sizeof(*packager
->scriptlets
));
679 if (!packager
->scriptlets
)
683 packager
->scriptlets
[packager
->num_scriptlets
++] = pakfire_scriptlet_ref(scriptlet
);
689 Removes all files on the filelist
691 int pakfire_packager_cleanup(struct pakfire_packager
* packager
) {
692 // Delete all files on the filelist
693 return pakfire_filelist_cleanup(packager
->filelist
, PAKFIRE_FILE_CLEANUP_TIDY
);