1/* $NetBSD: build.c,v 1.3 2021/04/10 19:49:59 nia Exp $ */ 2 3#if HAVE_CONFIG_H 4#include "config.h" 5#endif 6#include <nbcompat.h> 7#if HAVE_SYS_CDEFS_H 8#include <sys/cdefs.h> 9#endif 10__RCSID("$NetBSD: build.c,v 1.3 2021/04/10 19:49:59 nia Exp $"); 11 12/*- 13 * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. 14 * All rights reserved. 15 * 16 * This code was developed as part of Google's Summer of Code 2007 program. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 22 * 1. Redistributions of source code must retain the above copyright 23 * notice, this list of conditions and the following disclaimer. 24 * 2. Redistributions in binary form must reproduce the above copyright 25 * notice, this list of conditions and the following disclaimer in 26 * the documentation and/or other materials provided with the 27 * distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 32 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 33 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 34 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 35 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 37 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 38 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 39 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 */ 42 43/* 44 * FreeBSD install - a package for the installation and maintainance 45 * of non-core utilities. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 56 * Jordan K. Hubbard 57 * 18 July 1993 58 * 59 * This is the main body of the create module. 60 * 61 */ 62 63#include "lib.h" 64#include "create.h" 65 66#if HAVE_ERR_H 67#include <err.h> 68#endif 69#if HAVE_GRP_H 70#include <grp.h> 71#endif 72#if HAVE_PWD_H 73#include <pwd.h> 74#endif 75#if HAVE_UNISTD_H 76#include <unistd.h> 77#endif 78#if HAVE_FCNTL_H 79#include <fcntl.h> 80#endif 81 82#include <archive.h> 83#include <archive_entry.h> 84 85static struct memory_file *contents_file; 86static struct memory_file *comment_file; 87static struct memory_file *desc_file; 88static struct memory_file *install_file; 89static struct memory_file *deinstall_file; 90static struct memory_file *display_file; 91static struct memory_file *build_version_file; 92static struct memory_file *build_info_file; 93static struct memory_file *size_pkg_file; 94static struct memory_file *size_all_file; 95static struct memory_file *preserve_file; 96 97static void 98write_meta_file(struct memory_file *file, struct archive *archive) 99{ 100 struct archive_entry *entry; 101 102 entry = archive_entry_new(); 103 archive_entry_set_pathname(entry, file->name); 104 archive_entry_copy_stat(entry, &file->st); 105 106 archive_entry_set_uname(entry, file->owner); 107 archive_entry_set_gname(entry, file->group); 108 109 if (archive_write_header(archive, entry)) 110 errx(2, "cannot write to archive: %s", archive_error_string(archive)); 111 112 archive_write_data(archive, file->data, file->len); 113 114 archive_entry_free(entry); 115} 116 117static void 118write_entry(struct archive *archive, struct archive_entry *entry) 119{ 120 char buf[16384]; 121 const char *name; 122 int fd; 123 off_t len; 124 ssize_t buf_len; 125 126 if (archive_entry_pathname(entry) == NULL) { 127 warnx("entry with NULL path"); 128 return; 129 } 130 131 if (archive_write_header(archive, entry)) { 132 errx(2, "cannot write %s to archive: %s", 133 archive_entry_pathname(entry), 134 archive_error_string(archive)); 135 } 136 137 /* Only regular files can have data. */ 138 if (archive_entry_filetype(entry) != AE_IFREG || 139 archive_entry_size(entry) == 0) { 140 archive_entry_free(entry); 141 return; 142 } 143 144 name = archive_entry_pathname(entry); 145 146 if ((fd = open(name, O_RDONLY)) == -1) 147 err(2, "cannot open data file %s", name); 148 149 len = archive_entry_size(entry); 150 151 while (len > 0) { 152 buf_len = (len > (off_t)sizeof(buf)) ? (ssize_t)sizeof(buf) : (ssize_t)len; 153 154 if ((buf_len = read(fd, buf, buf_len)) == 0) 155 break; 156 else if (buf_len < 0) 157 err(2, "cannot read from %s", name); 158 159 archive_write_data(archive, buf, (size_t)buf_len); 160 len -= buf_len; 161 } 162 163 close(fd); 164 165 archive_entry_free(entry); 166} 167 168static void 169write_normal_file(const char *name, struct archive *archive, 170 struct archive_entry_linkresolver *resolver, 171 const char *owner, const char *group) 172{ 173 char buf[16384]; 174 ssize_t buf_len; 175 struct archive_entry *entry, *sparse_entry; 176 struct stat st; 177 178 if (lstat(name, &st) == -1) 179 err(2, "lstat failed for file %s", name); 180 181 entry = archive_entry_new(); 182 archive_entry_set_pathname(entry, name); 183 archive_entry_copy_stat(entry, &st); 184 185 if (owner != NULL) { 186 uid_t uid; 187 188 archive_entry_set_uname(entry, owner); 189 if (uid_from_user(owner, &uid) == -1) 190 errx(2, "user %s unknown", owner); 191 archive_entry_set_uid(entry, uid); 192 } else { 193 archive_entry_set_uname(entry, user_from_uid(st.st_uid, 1)); 194 } 195 196 if (group != NULL) { 197 gid_t gid; 198 199 archive_entry_set_gname(entry, group); 200 if (gid_from_group(group, &gid) == -1) 201 errx(2, "group %s unknown", group); 202 archive_entry_set_gid(entry, gid); 203 } else { 204 archive_entry_set_gname(entry, group_from_gid(st.st_gid, 1)); 205 } 206 207 if ((st.st_mode & S_IFMT) == S_IFLNK) { 208 buf_len = readlink(name, buf, sizeof buf); 209 if (buf_len < 0) 210 err(2, "cannot read symlink %s", name); 211 buf[buf_len] = '\0'; 212 archive_entry_set_symlink(entry, buf); 213 } 214 215 archive_entry_linkify(resolver, &entry, &sparse_entry); 216 217 if (entry != NULL) 218 write_entry(archive, entry); 219 if (sparse_entry != NULL) 220 write_entry(archive, sparse_entry); 221} 222 223static void 224make_dist(const char *pkg, const char *suffix, const package_t *plist) 225{ 226 char *archive_name; 227 const char *owner, *group; 228 const plist_t *p; 229 struct archive *archive; 230 struct archive_entry *entry, *sparse_entry; 231 struct archive_entry_linkresolver *resolver; 232 char *initial_cwd; 233 234 archive = archive_write_new(); 235 archive_write_set_format_pax_restricted(archive); 236 archive_write_set_options(archive, "hdrcharset=BINARY"); 237 if ((resolver = archive_entry_linkresolver_new()) == NULL) 238 errx(2, "cannot create link resolver"); 239 archive_entry_linkresolver_set_strategy(resolver, 240 archive_format(archive)); 241 242 if (CompressionType == NULL) { 243 if (strcmp(suffix, "tbz") == 0 || 244 strcmp(suffix, "tar.bz2") == 0) 245 CompressionType = "bzip2"; 246 else if (strcmp(suffix, "tgz") == 0 || 247 strcmp(suffix, "tar.gz") == 0) 248 CompressionType = "gzip"; 249 else 250 CompressionType = "none"; 251 } 252 253 if (strcmp(CompressionType, "bzip2") == 0) 254 archive_write_add_filter_bzip2(archive); 255 else if (strcmp(CompressionType, "gzip") == 0) 256 archive_write_add_filter_gzip(archive); 257 else if (strcmp(CompressionType, "xz") == 0) 258 archive_write_add_filter_xz(archive); 259 else if (strcmp(CompressionType, "none") != 0) 260 errx(1, "Unspported compression type for -F: %s", 261 CompressionType); 262 263 archive_name = xasprintf("%s.%s", pkg, suffix); 264 265 if (archive_write_open_filename(archive, archive_name)) 266 errx(2, "cannot create archive: %s", archive_error_string(archive)); 267 268 free(archive_name); 269 270 owner = DefaultOwner; 271 group = DefaultGroup; 272 273 write_meta_file(contents_file, archive); 274 write_meta_file(comment_file, archive); 275 write_meta_file(desc_file, archive); 276 277 if (Install) 278 write_meta_file(install_file, archive); 279 if (DeInstall) 280 write_meta_file(deinstall_file, archive); 281 if (Display) 282 write_meta_file(display_file, archive); 283 if (BuildVersion) 284 write_meta_file(build_version_file, archive); 285 if (BuildInfo) 286 write_meta_file(build_info_file, archive); 287 if (SizePkg) 288 write_meta_file(size_pkg_file, archive); 289 if (SizeAll) 290 write_meta_file(size_all_file, archive); 291 if (Preserve) 292 write_meta_file(preserve_file, archive); 293 294 initial_cwd = getcwd(NULL, 0); 295 296 for (p = plist->head; p; p = p->next) { 297 if (p->type == PLIST_FILE) { 298 write_normal_file(p->name, archive, resolver, owner, group); 299 } else if (p->type == PLIST_CWD) { 300 chdir(p->name); 301 } else if (p->type == PLIST_IGNORE) { 302 p = p->next; 303 } else if (p->type == PLIST_CHOWN) { 304 if (p->name != NULL) 305 owner = p->name; 306 else 307 owner = DefaultOwner; 308 } else if (p->type == PLIST_CHGRP) { 309 if (p->name != NULL) 310 group = p->name; 311 else 312 group = DefaultGroup; 313 } 314 } 315 316 entry = NULL; 317 archive_entry_linkify(resolver, &entry, &sparse_entry); 318 while (entry != NULL) { 319 write_entry(archive, entry); 320 entry = NULL; 321 archive_entry_linkify(resolver, &entry, &sparse_entry); 322 } 323 324 archive_entry_linkresolver_free(resolver); 325 326 if (archive_write_free(archive)) 327 errx(2, "cannot finish archive: %s", archive_error_string(archive)); 328 329 free(initial_cwd); 330} 331 332static struct memory_file * 333load_and_add(package_t *plist, const char *input_name, 334 const char *target_name, mode_t perm) 335{ 336 struct memory_file *file; 337 338 file = load_memory_file(input_name, target_name, DefaultOwner, 339 DefaultGroup, perm); 340 add_plist(plist, PLIST_IGNORE, NULL); 341 add_plist(plist, PLIST_FILE, target_name); 342 343 return file; 344} 345 346static struct memory_file * 347make_and_add(package_t *plist, const char *target_name, 348 char *content, mode_t perm) 349{ 350 struct memory_file *file; 351 352 file = make_memory_file(target_name, content, strlen(content), 353 DefaultOwner, DefaultGroup, perm); 354 add_plist(plist, PLIST_IGNORE, NULL); 355 add_plist(plist, PLIST_FILE, target_name); 356 357 return file; 358} 359 360int 361pkg_build(const char *pkg, const char *full_pkg, const char *suffix, 362 package_t *plist) 363{ 364 char *plist_buf; 365 size_t plist_len; 366 367 /* Now put the release specific items in */ 368 add_plist(plist, PLIST_CWD, "."); 369 comment_file = make_and_add(plist, COMMENT_FNAME, Comment, 0444); 370 desc_file = make_and_add(plist, DESC_FNAME, Desc, 0444); 371 372 if (Install) { 373 install_file = load_and_add(plist, Install, INSTALL_FNAME, 374 0555); 375 } 376 if (DeInstall) { 377 deinstall_file = load_and_add(plist, DeInstall, 378 DEINSTALL_FNAME, 0555); 379 } 380 if (Display) { 381 display_file = load_and_add(plist, Display, 382 DISPLAY_FNAME, 0444); 383 add_plist(plist, PLIST_DISPLAY, DISPLAY_FNAME); 384 } 385 if (BuildVersion) { 386 build_version_file = load_and_add(plist, BuildVersion, 387 BUILD_VERSION_FNAME, 0444); 388 } 389 if (BuildInfo) { 390 build_info_file = load_and_add(plist, BuildInfo, 391 BUILD_INFO_FNAME, 0444); 392 } 393 if (SizePkg) { 394 size_pkg_file = load_and_add(plist, SizePkg, 395 SIZE_PKG_FNAME, 0444); 396 } 397 if (SizeAll) { 398 size_all_file = load_and_add(plist, SizeAll, 399 SIZE_ALL_FNAME, 0444); 400 } 401 if (Preserve) { 402 preserve_file = load_and_add(plist, Preserve, 403 PRESERVE_FNAME, 0444); 404 } 405 406 /* Finally, write out the packing list */ 407 stringify_plist(plist, &plist_buf, &plist_len, realprefix); 408 contents_file = make_memory_file(CONTENTS_FNAME, plist_buf, plist_len, 409 DefaultOwner, DefaultGroup, 0644); 410 411 /* And stick it into a tar ball */ 412 make_dist(pkg, suffix, plist); 413 414 return TRUE; /* Success */ 415} 416