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