Home | History | Annotate | Line # | Download | only in create
build.c revision 1.1.1.2
      1  1.1.1.2  joerg /*	$NetBSD: build.c,v 1.1.1.2 2009/02/02 20:44:03 joerg 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.1.1.2  joerg __RCSID("$NetBSD: build.c,v 1.1.1.2 2009/02/02 20:44:03 joerg 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 static struct memory_file *views_file;
     97      1.1  joerg 
     98      1.1  joerg static void
     99      1.1  joerg write_meta_file(struct memory_file *file, struct archive *archive)
    100      1.1  joerg {
    101      1.1  joerg 	struct archive_entry *entry;
    102      1.1  joerg 
    103      1.1  joerg 	entry = archive_entry_new();
    104      1.1  joerg 	archive_entry_set_pathname(entry, file->name);
    105      1.1  joerg 	archive_entry_copy_stat(entry, &file->st);
    106      1.1  joerg 
    107      1.1  joerg 	archive_entry_set_uname(entry, file->owner);
    108      1.1  joerg 	archive_entry_set_gname(entry, file->group);
    109      1.1  joerg 
    110      1.1  joerg 	if (archive_write_header(archive, entry))
    111      1.1  joerg 		errx(2, "cannot write to archive: %s", archive_error_string(archive));
    112      1.1  joerg 
    113      1.1  joerg 	archive_write_data(archive, file->data, file->len);
    114      1.1  joerg 
    115      1.1  joerg 	archive_entry_free(entry);
    116      1.1  joerg }
    117      1.1  joerg 
    118      1.1  joerg static void
    119      1.1  joerg write_entry(struct archive *archive, struct archive_entry *entry)
    120      1.1  joerg {
    121      1.1  joerg 	char buf[16384];
    122      1.1  joerg 	const char *name;
    123      1.1  joerg 	int fd;
    124      1.1  joerg 	off_t len;
    125      1.1  joerg 	ssize_t buf_len;
    126      1.1  joerg 
    127      1.1  joerg 	if (archive_entry_pathname(entry) == NULL) {
    128      1.1  joerg 		warnx("entry with NULL path");
    129      1.1  joerg 		return;
    130      1.1  joerg 	}
    131      1.1  joerg 
    132      1.1  joerg 	if (archive_write_header(archive, entry)) {
    133      1.1  joerg 		errx(2, "cannot write to archive: %s",
    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.1  joerg 		buf_len = (len > sizeof(buf)) ? 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 	char *initial_cwd;
    233      1.1  joerg 
    234      1.1  joerg 	archive = archive_write_new();
    235      1.1  joerg 	archive_write_set_format_pax_restricted(archive);
    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.1  joerg 	if (strcmp(suffix, "tbz") == 0 || strcmp(suffix, "tar.bz2") == 0)
    242      1.1  joerg 		archive_write_set_compression_bzip2(archive);
    243      1.1  joerg 	else if (strcmp(suffix, "tgz") == 0 || strcmp(suffix, "tar.gz") == 0)
    244      1.1  joerg 		archive_write_set_compression_gzip(archive);
    245      1.1  joerg 	else
    246      1.1  joerg 		archive_write_set_compression_none(archive);
    247      1.1  joerg 
    248  1.1.1.2  joerg 	archive_name = xasprintf("%s.%s", pkg, suffix);
    249      1.1  joerg 
    250      1.1  joerg 	if (archive_write_open_file(archive, archive_name))
    251      1.1  joerg 		errx(2, "cannot create archive: %s", archive_error_string(archive));
    252      1.1  joerg 
    253      1.1  joerg 	free(archive_name);
    254      1.1  joerg 
    255      1.1  joerg 	owner = DefaultOwner;
    256      1.1  joerg 	group = DefaultGroup;
    257      1.1  joerg 
    258      1.1  joerg 	write_meta_file(contents_file, archive);
    259      1.1  joerg 	write_meta_file(comment_file, archive);
    260      1.1  joerg 	write_meta_file(desc_file, archive);
    261      1.1  joerg 
    262      1.1  joerg 	if (Install)
    263      1.1  joerg 		write_meta_file(install_file, archive);
    264      1.1  joerg 	if (DeInstall)
    265      1.1  joerg 		write_meta_file(deinstall_file, archive);
    266      1.1  joerg 	if (Display)
    267      1.1  joerg 		write_meta_file(display_file, archive);
    268      1.1  joerg 	if (BuildVersion)
    269      1.1  joerg 		write_meta_file(build_version_file, archive);
    270      1.1  joerg 	if (BuildInfo)
    271      1.1  joerg 		write_meta_file(build_info_file, archive);
    272      1.1  joerg 	if (SizePkg)
    273      1.1  joerg 		write_meta_file(size_pkg_file, archive);
    274      1.1  joerg 	if (SizeAll)
    275      1.1  joerg 		write_meta_file(size_all_file, archive);
    276      1.1  joerg 	if (Preserve)
    277      1.1  joerg 		write_meta_file(preserve_file, archive);
    278      1.1  joerg 	if (create_views)
    279      1.1  joerg 		write_meta_file(views_file, archive);
    280      1.1  joerg 
    281      1.1  joerg 	initial_cwd = getcwd(NULL, 0);
    282      1.1  joerg 
    283      1.1  joerg 	for (p = plist->head; p; p = p->next) {
    284      1.1  joerg 		if (p->type == PLIST_FILE) {
    285      1.1  joerg 			write_normal_file(p->name, archive, resolver, owner, group);
    286      1.1  joerg 		} else if (p->type == PLIST_CWD || p->type == PLIST_SRC) {
    287      1.1  joerg 
    288      1.1  joerg 			/* XXX let PLIST_SRC override PLIST_CWD */
    289      1.1  joerg 			if (p->type == PLIST_CWD && p->next != NULL &&
    290      1.1  joerg 			    p->next->type == PLIST_SRC) {
    291      1.1  joerg 				continue;
    292      1.1  joerg 			}
    293      1.1  joerg 			chdir(p->name);
    294      1.1  joerg 		} else if (p->type == PLIST_IGNORE) {
    295      1.1  joerg 			p = p->next;
    296      1.1  joerg 		} else if (p->type == PLIST_CHOWN) {
    297      1.1  joerg 			if (p->name != NULL)
    298      1.1  joerg 				owner = p->name;
    299      1.1  joerg 			else
    300      1.1  joerg 				owner = DefaultOwner;
    301      1.1  joerg 		} else if (p->type == PLIST_CHGRP) {
    302      1.1  joerg 			if (p->name != NULL)
    303      1.1  joerg 				group = p->name;
    304      1.1  joerg 			else
    305      1.1  joerg 				group = DefaultGroup;
    306      1.1  joerg 		}
    307      1.1  joerg 	}
    308      1.1  joerg 
    309      1.1  joerg 	entry = NULL;
    310      1.1  joerg 	archive_entry_linkify(resolver, &entry, &sparse_entry);
    311      1.1  joerg 	while (entry != NULL) {
    312      1.1  joerg 		write_entry(archive, entry);
    313      1.1  joerg 		entry = NULL;
    314      1.1  joerg 		archive_entry_linkify(resolver, &entry, &sparse_entry);
    315      1.1  joerg 	}
    316      1.1  joerg 
    317      1.1  joerg 	archive_entry_linkresolver_free(resolver);
    318      1.1  joerg 
    319      1.1  joerg 	if (archive_write_close(archive))
    320      1.1  joerg 		errx(2, "cannot finish archive: %s", archive_error_string(archive));
    321      1.1  joerg 	archive_write_finish(archive);
    322      1.1  joerg 
    323      1.1  joerg 	chdir(initial_cwd);
    324      1.1  joerg 	free(initial_cwd);
    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 	if (create_views)
    401      1.1  joerg 		views_file = make_and_add(plist, VIEWS_FNAME, "", 0444);
    402      1.1  joerg 
    403      1.1  joerg 	/* Finally, write out the packing list */
    404      1.1  joerg 	stringify_plist(plist, &plist_buf, &plist_len, realprefix);
    405      1.1  joerg 	contents_file = make_memory_file(CONTENTS_FNAME, plist_buf, plist_len,
    406      1.1  joerg 	    DefaultOwner, DefaultGroup, 0644);
    407      1.1  joerg 
    408      1.1  joerg 	/* And stick it into a tar ball */
    409      1.1  joerg 	make_dist(pkg, suffix, plist);
    410      1.1  joerg 
    411      1.1  joerg 	return TRUE;		/* Success */
    412      1.1  joerg }
    413