1/*	$NetBSD: perform.c,v 1.1.1.13 2010/02/20 04:41:55 joerg 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#if HAVE_SYS_QUEUE_H
11#include <sys/queue.h>
12#endif
13#if HAVE_SYS_WAIT_H
14#include <sys/wait.h>
15#endif
16__RCSID("$NetBSD: perform.c,v 1.1.1.13 2010/02/20 04:41:55 joerg Exp $");
17
18/*-
19 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 *
26 * 1. Redistributions of source code must retain the above copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in
30 *    the documentation and/or other materials provided with the
31 *    distribution.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
36 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
37 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
39 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
40 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
41 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47/*
48 * FreeBSD install - a package for the installation and maintainance
49 * of non-core utilities.
50 *
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
53 * are met:
54 * 1. Redistributions of source code must retain the above copyright
55 *    notice, this list of conditions and the following disclaimer.
56 * 2. Redistributions in binary form must reproduce the above copyright
57 *    notice, this list of conditions and the following disclaimer in the
58 *    documentation and/or other materials provided with the distribution.
59 *
60 * Jordan K. Hubbard
61 * 23 Aug 1993
62 *
63 * This is the main body of the info module.
64 *
65 */
66
67#include "lib.h"
68#include "info.h"
69
70#if HAVE_SYS_TYPES_H
71#include <sys/types.h>
72#endif
73#if HAVE_SYS_STAT_H
74#include <sys/stat.h>
75#endif
76
77#ifndef BOOTSTRAP
78#include <archive.h>
79#include <archive_entry.h>
80#endif
81#if HAVE_ERR_H
82#include <err.h>
83#endif
84#if HAVE_ERRNO_H
85#include <errno.h>
86#endif
87#if HAVE_FCNTL_H
88#include <fcntl.h>
89#endif
90#if HAVE_SIGNAL_H
91#include <signal.h>
92#endif
93#if HAVE_DIRENT_H
94#include <dirent.h>
95#endif
96#if HAVE_CTYPE_H
97#include <ctype.h>
98#endif
99#include <stddef.h>
100
101#define	LOAD_CONTENTS		(1 << 0)
102#define	LOAD_COMMENT		(1 << 1)
103#define	LOAD_DESC		(1 << 2)
104#define	LOAD_INSTALL		(1 << 3)
105#define	LOAD_DEINSTALL		(1 << 4)
106#define	LOAD_DISPLAY		(1 << 5)
107#define	LOAD_MTREE		(1 << 6)
108#define	LOAD_BUILD_VERSION	(1 << 7)
109#define	LOAD_BUILD_INFO		(1 << 8)
110#define	LOAD_SIZE_PKG		(1 << 9)
111#define	LOAD_SIZE_ALL		(1 << 10)
112#define	LOAD_PRESERVE		(1 << 11)
113#define	LOAD_VIEWS		(1 << 12)
114#define	LOAD_REQUIRED_BY	(1 << 13)
115#define	LOAD_INSTALLED_INFO	(1 << 14)
116
117static const struct pkg_meta_desc {
118	size_t entry_offset;
119	const char *entry_filename;
120	int entry_mask;
121	int required_file;
122} pkg_meta_descriptors[] = {
123	{ offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME,
124	    LOAD_CONTENTS, 1},
125	{ offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME,
126	    LOAD_COMMENT, 1 },
127	{ offsetof(struct pkg_meta, meta_desc), DESC_FNAME,
128	    LOAD_DESC, 1 },
129	{ offsetof(struct pkg_meta, meta_install), INSTALL_FNAME,
130	    LOAD_INSTALL, 0 },
131	{ offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME,
132	    LOAD_DEINSTALL, 0 },
133	{ offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME,
134	    LOAD_DISPLAY, 0 },
135	{ offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME,
136	    LOAD_MTREE, 0 },
137	{ offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME,
138	    LOAD_BUILD_VERSION, 0 },
139	{ offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME,
140	    LOAD_BUILD_INFO, 0 },
141	{ offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME,
142	    LOAD_SIZE_PKG, 0 },
143	{ offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME,
144	    LOAD_SIZE_ALL, 0 },
145	{ offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME,
146	    LOAD_PRESERVE, 0 },
147	{ offsetof(struct pkg_meta, meta_views), VIEWS_FNAME,
148	    LOAD_VIEWS, 0 },
149	{ offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME,
150	    LOAD_REQUIRED_BY, 0 },
151	{ offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME,
152	    LOAD_INSTALLED_INFO, 0 },
153	{ 0, NULL, 0, 0 },
154};
155
156static int desired_meta_data;
157
158static void
159free_pkg_meta(struct pkg_meta *meta)
160{
161	const struct pkg_meta_desc *descr;
162
163	for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr)
164		free(*(char **)((char *)meta + descr->entry_offset));
165
166	free(meta);
167}
168
169#ifndef BOOTSTRAP
170static struct pkg_meta *
171read_meta_data_from_archive(struct archive *archive,
172    struct archive_entry *entry)
173{
174	struct pkg_meta *meta;
175	const char *fname;
176	const struct pkg_meta_desc *descr, *last_descr;
177	char **target;
178	int64_t size;
179	int r, found_required;
180
181	found_required = 0;
182
183	meta = xcalloc(1, sizeof(*meta));
184
185	last_descr = 0;
186	if (entry != NULL) {
187		r = ARCHIVE_OK;
188		goto has_entry;
189	}
190
191	while ((r = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
192has_entry:
193		fname = archive_entry_pathname(entry);
194
195		for (descr = pkg_meta_descriptors; descr->entry_filename;
196		     ++descr) {
197			if (strcmp(descr->entry_filename, fname) == 0)
198				break;
199		}
200		if (descr->entry_filename == NULL)
201			break;
202
203		if (descr->required_file)
204			++found_required;
205
206		target = (char **)((char *)meta + descr->entry_offset);
207		if (*target)
208			errx(2, "duplicate entry, package corrupt");
209		if (descr < last_descr)
210			warnx("misordered package, continuing");
211		else
212			last_descr = descr;
213
214		if ((descr->entry_mask & desired_meta_data) == 0) {
215			if (archive_read_data_skip(archive))
216				errx(2, "cannot read package meta data");
217			continue;
218		}
219
220		size = archive_entry_size(entry);
221		if (size > SSIZE_MAX - 1)
222			errx(2, "package meta data too large to process");
223		*target = xmalloc(size + 1);
224		if (archive_read_data(archive, *target, size) != size)
225			errx(2, "cannot read package meta data");
226		(*target)[size] = '\0';
227	}
228
229	for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
230		if (descr->required_file)
231			--found_required;
232	}
233
234	meta->is_installed = 0;
235	if (found_required != 0 || (r != ARCHIVE_OK && r != ARCHIVE_EOF)) {
236		free_pkg_meta(meta);
237		meta = NULL;
238	}
239
240	return meta;
241}
242#endif
243
244static struct pkg_meta *
245read_meta_data_from_pkgdb(const char *pkg)
246{
247	struct pkg_meta *meta;
248	const struct pkg_meta_desc *descr;
249	char **target;
250	char *fname;
251	int fd;
252	struct stat st;
253
254	meta = xcalloc(1, sizeof(*meta));
255
256	for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
257		if ((descr->entry_mask & desired_meta_data) == 0)
258			continue;
259
260		fname = pkgdb_pkg_file(pkg, descr->entry_filename);
261		fd = open(fname, O_RDONLY, 0);
262		free(fname);
263		if (fd == -1) {
264			if (errno == ENOENT && descr->required_file == 0)
265				continue;
266			err(2, "cannot read meta data file %s of package %s",
267			    descr->entry_filename, pkg);
268		}
269		target = (char **)((char *)meta + descr->entry_offset);
270
271		if (fstat(fd, &st) == -1)
272			err(2, "cannot stat meta data");
273		if ((st.st_mode & S_IFMT) != S_IFREG)
274			errx(1, "meta data is not regular file");
275		if (st.st_size > SSIZE_MAX - 1)
276			err(2, "meta data file too large to process");
277		*target = xmalloc(st.st_size + 1);
278		if (read(fd, *target, st.st_size) != st.st_size)
279			err(2, "cannot read meta data");
280		(*target)[st.st_size] = '\0';
281		close(fd);
282	}
283
284	meta->is_installed = 1;
285
286	return meta;
287}
288
289static void
290build_full_reqby(lpkg_head_t *reqby, struct pkg_meta *meta, int limit)
291{
292	char *iter, *eol, *next;
293	lpkg_t *lpp;
294	struct pkg_meta *meta_dep;
295
296	if (limit == 65536)
297		errx(1, "Cycle in the dependency tree, bailing out");
298
299	if (meta->is_installed == 0 || meta->meta_required_by == NULL)
300		return;
301
302	for (iter = meta->meta_required_by; *iter != '\0'; iter = next) {
303		eol = iter + strcspn(iter, "\n");
304		if (*eol == '\n')
305			next = eol + 1;
306		else
307			next = eol;
308		if (iter == eol)
309			continue;
310		TAILQ_FOREACH(lpp, reqby, lp_link) {
311			if (strlen(lpp->lp_name) + iter != eol)
312				continue;
313			if (memcmp(lpp->lp_name, iter, eol - iter) == 0)
314				break;
315		}
316		if (lpp != NULL)
317			continue;
318		*eol = '\0';
319		lpp = alloc_lpkg(iter);
320		if (next != eol)
321			*eol = '\n';
322
323		meta_dep = read_meta_data_from_pkgdb(lpp->lp_name);
324		if (meta_dep == NULL)
325			continue;
326		build_full_reqby(reqby, meta_dep, limit + 1);
327		free_pkg_meta(meta_dep);
328
329		TAILQ_INSERT_HEAD(reqby, lpp, lp_link);
330	}
331}
332
333static lfile_head_t files;
334
335static int
336pkg_do(const char *pkg)
337{
338	struct pkg_meta *meta;
339	int     code = 0;
340	const char   *binpkgfile = NULL;
341	char *pkgdir;
342
343	if (IS_URL(pkg) || (fexists(pkg) && isfile(pkg))) {
344#ifdef BOOTSTRAP
345		errx(2, "Binary packages not supported during bootstrap");
346#else
347		struct archive *archive;
348		struct archive_entry *entry;
349		char *archive_name, *pkgname;
350
351		archive = open_archive(pkg, &archive_name);
352		if (archive == NULL) {
353			warnx("can't find package `%s', skipped", pkg);
354			return -1;
355		}
356		pkgname = NULL;
357		entry = NULL;
358		pkg_verify_signature(archive_name, &archive, &entry, &pkgname);
359		if (archive == NULL)
360			return -1;
361		free(pkgname);
362
363		meta = read_meta_data_from_archive(archive, entry);
364		archive_read_finish(archive);
365		if (!IS_URL(pkg))
366			binpkgfile = pkg;
367#endif
368	} else {
369		/*
370	         * It's not an uninstalled package, try and find it among the
371	         * installed
372	         */
373		pkgdir = pkgdb_pkg_dir(pkg);
374		if (!fexists(pkgdir) || !(isdir(pkgdir) || islinktodir(pkgdir))) {
375			switch (add_installed_pkgs_by_basename(pkg, &pkgs)) {
376			case 1:
377				return 0;
378			case 0:
379				/* No match */
380				warnx("can't find package `%s'", pkg);
381				return 1;
382			case -1:
383				errx(EXIT_FAILURE, "Error during search in pkgdb for %s", pkg);
384			}
385		}
386		free(pkgdir);
387		meta = read_meta_data_from_pkgdb(pkg);
388	}
389
390	if (meta == NULL) {
391		warnx("invalid package `%s' skipped", pkg);
392		return 1;
393	}
394
395	/*
396         * Index is special info type that has to override all others to make
397         * any sense.
398         */
399	if (Flags & SHOW_INDEX) {
400		char    tmp[MaxPathSize];
401
402		(void) snprintf(tmp, sizeof(tmp), "%-19s ", pkg);
403		show_index(meta->meta_comment, tmp);
404	} else if (Flags & SHOW_BI_VAR) {
405		if (strcspn(BuildInfoVariable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
406		    == strlen(BuildInfoVariable)) {
407			if (meta->meta_installed_info)
408				show_var(meta->meta_installed_info, BuildInfoVariable);
409		} else {
410			if (meta->meta_build_info)
411				show_var(meta->meta_build_info, BuildInfoVariable);
412			else
413				warnx("Build information missing");
414		}
415	} else {
416		package_t plist;
417
418		/* Read the contents list */
419		parse_plist(&plist, meta->meta_contents);
420
421		/* Start showing the package contents */
422		if (!Quiet && !(Flags & SHOW_SUMMARY)) {
423			printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
424			if (meta->meta_preserve) {
425				printf("*** PACKAGE MAY NOT BE DELETED ***\n");
426			}
427		}
428		if (Flags & SHOW_SUMMARY) {
429			show_summary(meta, &plist, binpkgfile);
430		}
431		if (Flags & SHOW_COMMENT) {
432			show_file(meta->meta_comment, "Comment:\n", TRUE);
433		}
434		if (Flags & SHOW_DEPENDS) {
435			show_depends("Requires:\n", &plist);
436		}
437		if (Flags & SHOW_BLD_DEPENDS) {
438			show_bld_depends("Built using:\n", &plist);
439		}
440		if ((Flags & SHOW_REQBY) && meta->meta_required_by) {
441			show_file(meta->meta_required_by, "Required by:\n", TRUE);
442		}
443		if ((Flags & SHOW_FULL_REQBY) && meta->is_installed) {
444			lpkg_head_t reqby;
445			TAILQ_INIT(&reqby);
446			build_full_reqby(&reqby, meta, 0);
447			show_list(&reqby, "Full required by list:\n");
448		}
449		if (Flags & SHOW_DESC) {
450			show_file(meta->meta_desc, "Description:\n", TRUE);
451		}
452		if ((Flags & SHOW_DISPLAY) && meta->meta_display) {
453			show_file(meta->meta_display, "Install notice:\n",
454				  TRUE);
455		}
456		if (Flags & SHOW_PLIST) {
457			show_plist("Packing list:\n", &plist, PLIST_SHOW_ALL);
458		}
459		if ((Flags & SHOW_INSTALL) && meta->meta_install) {
460			show_file(meta->meta_install, "Install script:\n",
461				  TRUE);
462		}
463		if ((Flags & SHOW_DEINSTALL) && meta->meta_deinstall) {
464			show_file(meta->meta_deinstall, "De-Install script:\n",
465				  TRUE);
466		}
467		if ((Flags & SHOW_MTREE) && meta->meta_mtree) {
468			show_file(meta->meta_mtree, "mtree file:\n", TRUE);
469		}
470		if (Flags & SHOW_PREFIX) {
471			show_plist("Prefix(s):\n", &plist, PLIST_CWD);
472		}
473		if (Flags & SHOW_FILES) {
474			show_files("Files:\n", &plist);
475		}
476		if ((Flags & SHOW_BUILD_VERSION) && meta->meta_build_version) {
477			show_file(meta->meta_build_version, "Build version:\n",
478				  TRUE);
479		}
480		if (Flags & SHOW_BUILD_INFO) {
481			if (meta->meta_build_info) {
482				show_file(meta->meta_build_info, "Build information:\n",
483					  TRUE);
484			}
485			if (meta->meta_installed_info) {
486				show_file(meta->meta_installed_info, "Installed information:\n",
487					  TRUE);
488			}
489		}
490		if ((Flags & SHOW_PKG_SIZE) && meta->meta_size_pkg) {
491			show_file(meta->meta_size_pkg, "Size of this package in bytes: ",
492				  TRUE);
493		}
494		if ((Flags & SHOW_ALL_SIZE) && meta->meta_size_all) {
495			show_file(meta->meta_size_all, "Size in bytes including required pkgs: ",
496				  TRUE);
497		}
498		if (!Quiet && !(Flags & SHOW_SUMMARY)) {
499			if (meta->meta_preserve) {
500				printf("*** PACKAGE MAY NOT BE DELETED ***\n\n");
501			}
502			puts(InfoPrefix);
503		}
504		free_plist(&plist);
505	}
506	free_pkg_meta(meta);
507	return code;
508}
509
510struct print_matching_arg {
511	const char *pattern;
512	int got_match;
513};
514
515static int
516print_matching_pkg(const char *pkgname, void *cookie)
517{
518	struct print_matching_arg *arg= cookie;
519
520	if (pkg_match(arg->pattern, pkgname)) {
521		if (!Quiet)
522			puts(pkgname);
523		arg->got_match = 1;
524	}
525
526	return 0;
527}
528
529/*
530 * Returns 0 if at least one package matching pkgname.
531 * Returns 1 otherwise.
532 *
533 * If -q was not specified, print all matching packages to stdout.
534 */
535int
536CheckForPkg(const char *pkgname)
537{
538	struct print_matching_arg arg;
539
540	arg.pattern = pkgname;
541	arg.got_match = 0;
542
543	if (iterate_pkg_db(print_matching_pkg, &arg) == -1) {
544		warnx("cannot iterate pkgdb");
545		return 1;
546	}
547
548	if (arg.got_match == 0 && !ispkgpattern(pkgname)) {
549		char *pattern;
550
551		pattern = xasprintf("%s-[0-9]*", pkgname);
552
553		arg.pattern = pattern;
554		arg.got_match = 0;
555
556		if (iterate_pkg_db(print_matching_pkg, &arg) == -1) {
557			free(pattern);
558			warnx("cannot iterate pkgdb");
559			return 1;
560		}
561		free(pattern);
562	}
563
564	if (arg.got_match)
565		return 0;
566	else
567		return 1;
568}
569
570/*
571 * Returns 0 if at least one package matching pkgname.
572 * Returns 1 otherwise.
573 *
574 * If -q was not specified, print best match to stdout.
575 */
576int
577CheckForBestPkg(const char *pkgname)
578{
579	char *pattern, *best_match;
580
581	best_match = find_best_matching_installed_pkg(pkgname);
582	if (best_match == NULL) {
583		if (ispkgpattern(pkgname))
584			return 1;
585
586		pattern = xasprintf("%s-[0-9]*", pkgname);
587		best_match = find_best_matching_installed_pkg(pattern);
588		free(pattern);
589	}
590
591	if (best_match == NULL)
592		return 1;
593	if (!Quiet)
594		puts(best_match);
595	free(best_match);
596	return 0;
597}
598
599static int
600perform_single_pkg(const char *pkg, void *cookie)
601{
602	int *err_cnt = cookie;
603
604	if (Which == WHICH_ALL || !is_automatic_installed(pkg))
605		*err_cnt += pkg_do(pkg);
606
607	return 0;
608}
609
610int
611pkg_perform(lpkg_head_t *pkghead)
612{
613	int     err_cnt = 0;
614
615	TAILQ_INIT(&files);
616
617	desired_meta_data = 0;
618	if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0)
619		desired_meta_data |= LOAD_PRESERVE;
620	if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0)
621		desired_meta_data |= LOAD_CONTENTS;
622	if (Flags & (SHOW_COMMENT | SHOW_INDEX | SHOW_SUMMARY))
623		desired_meta_data |= LOAD_COMMENT;
624	if (Flags & (SHOW_BI_VAR | SHOW_BUILD_INFO | SHOW_SUMMARY))
625		desired_meta_data |= LOAD_BUILD_INFO | LOAD_INSTALLED_INFO;
626	if (Flags & (SHOW_SUMMARY | SHOW_PKG_SIZE))
627		desired_meta_data |= LOAD_SIZE_PKG;
628	if (Flags & SHOW_ALL_SIZE)
629		desired_meta_data |= LOAD_SIZE_ALL;
630	if (Flags & (SHOW_SUMMARY | SHOW_DESC))
631		desired_meta_data |= LOAD_DESC;
632	if (Flags & (SHOW_REQBY | SHOW_FULL_REQBY))
633		desired_meta_data |= LOAD_REQUIRED_BY;
634	if (Flags & SHOW_DISPLAY)
635		desired_meta_data |= LOAD_DISPLAY;
636	if (Flags & SHOW_INSTALL)
637		desired_meta_data |= LOAD_INSTALL;
638	if (Flags & SHOW_DEINSTALL)
639		desired_meta_data |= LOAD_DEINSTALL;
640	if (Flags & SHOW_MTREE)
641		desired_meta_data |= LOAD_MTREE;
642	if (Flags & SHOW_BUILD_VERSION)
643		desired_meta_data |= LOAD_BUILD_VERSION;
644
645	if (Which != WHICH_LIST) {
646		if (File2Pkg) {
647			/* Show all files with the package they belong to */
648			if (pkgdb_dump() == -1)
649				err_cnt = 1;
650		} else {
651			if (iterate_pkg_db(perform_single_pkg, &err_cnt) == -1)
652				err_cnt = 1;
653		}
654	} else {
655		/* Show info on individual pkg(s) */
656		lpkg_t *lpp;
657
658		while ((lpp = TAILQ_FIRST(pkghead)) != NULL) {
659			TAILQ_REMOVE(pkghead, lpp, lp_link);
660			err_cnt += pkg_do(lpp->lp_name);
661			free_lpkg(lpp);
662		}
663	}
664	return err_cnt;
665}
666