mtree.c revision 244541
1/*	$NetBSD: mtree.c,v 1.46 2012/12/20 19:09:25 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1989, 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#if HAVE_NBTOOL_CONFIG_H
33#include "nbtool_config.h"
34#endif
35
36#include <sys/cdefs.h>
37#if defined(__COPYRIGHT) && !defined(lint)
38__COPYRIGHT("@(#) Copyright (c) 1989, 1990, 1993\
39 The Regents of the University of California.  All rights reserved.");
40#endif /* not lint */
41
42#if defined(__RCSID) && !defined(lint)
43#if 0
44static char sccsid[] = "@(#)mtree.c	8.1 (Berkeley) 6/6/93";
45#else
46__RCSID("$NetBSD: mtree.c,v 1.46 2012/12/20 19:09:25 christos Exp $");
47#endif
48#endif /* not lint */
49
50#include <sys/param.h>
51#include <sys/stat.h>
52
53#include <errno.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <string.h>
57#include <unistd.h>
58
59#include "extern.h"
60
61int	ftsoptions = FTS_PHYSICAL;
62int	bflag, cflag, Cflag, dflag, Dflag, eflag, iflag, jflag, lflag, mflag,
63    	nflag, qflag, rflag, sflag, tflag, uflag, Uflag, wflag;
64char	fullpath[MAXPATHLEN];
65
66static struct {
67	enum flavor flavor;
68	const char name[9];
69} flavors[] = {
70	{F_MTREE, "mtree"},
71	{F_FREEBSD9, "freebsd9"},
72	{F_NETBSD6, "netbsd6"},
73};
74
75__dead static	void	usage(void);
76
77int
78main(int argc, char **argv)
79{
80	int	ch, status;
81	unsigned int	i;
82	char	*dir, *p;
83	FILE	*spec1, *spec2;
84
85	setprogname(argv[0]);
86
87	dir = NULL;
88	init_excludes();
89	spec1 = stdin;
90	spec2 = NULL;
91
92	while ((ch = getopt(argc, argv,
93	    "bcCdDeE:f:F:I:ijk:K:lLmMnN:p:PqrR:s:StuUwWxX:"))
94	    != -1) {
95		switch((char)ch) {
96		case 'b':
97			bflag = 1;
98			break;
99		case 'c':
100			cflag = 1;
101			break;
102		case 'C':
103			Cflag = 1;
104			break;
105		case 'd':
106			dflag = 1;
107			break;
108		case 'D':
109			Dflag = 1;
110			break;
111		case 'E':
112			parsetags(&excludetags, optarg);
113			break;
114		case 'e':
115			eflag = 1;
116			break;
117		case 'f':
118			if (spec1 == stdin) {
119				spec1 = fopen(optarg, "r");
120				if (spec1 == NULL)
121					mtree_err("%s: %s", optarg,
122					    strerror(errno));
123			} else if (spec2 == NULL) {
124				spec2 = fopen(optarg, "r");
125				if (spec2 == NULL)
126					mtree_err("%s: %s", optarg,
127					    strerror(errno));
128			} else
129				usage();
130			break;
131		case 'F':
132			for (i = 0; i < __arraycount(flavors); i++)
133				if (strcmp(optarg, flavors[i].name) == 0) {
134					flavor = flavors[i].flavor;
135					break;
136				}
137			if (i == __arraycount(flavors))
138				usage();
139			break;
140		case 'i':
141			iflag = 1;
142			break;
143		case 'I':
144			parsetags(&includetags, optarg);
145			break;
146		case 'j':
147			jflag = 1;
148			break;
149		case 'k':
150			keys = F_TYPE;
151			while ((p = strsep(&optarg, " \t,")) != NULL)
152				if (*p != '\0')
153					keys |= parsekey(p, NULL);
154			break;
155		case 'K':
156			while ((p = strsep(&optarg, " \t,")) != NULL)
157				if (*p != '\0')
158					keys |= parsekey(p, NULL);
159			break;
160		case 'l':
161			lflag = 1;
162			break;
163		case 'L':
164			ftsoptions &= ~FTS_PHYSICAL;
165			ftsoptions |= FTS_LOGICAL;
166			break;
167		case 'm':
168			mflag = 1;
169			break;
170		case 'M':
171			mtree_Mflag = 1;
172			break;
173		case 'n':
174			nflag = 1;
175			break;
176		case 'N':
177			if (! setup_getid(optarg))
178				mtree_err(
179			    "Unable to use user and group databases in `%s'",
180				    optarg);
181			break;
182		case 'p':
183			dir = optarg;
184			break;
185		case 'P':
186			ftsoptions &= ~FTS_LOGICAL;
187			ftsoptions |= FTS_PHYSICAL;
188			break;
189		case 'q':
190			qflag = 1;
191			break;
192		case 'r':
193			rflag = 1;
194			break;
195		case 'R':
196			while ((p = strsep(&optarg, " \t,")) != NULL)
197				if (*p != '\0')
198					keys &= ~parsekey(p, NULL);
199			break;
200		case 's':
201			sflag = 1;
202			crc_total = ~strtol(optarg, &p, 0);
203			if (*p)
204				mtree_err("illegal seed value -- %s", optarg);
205			break;
206		case 'S':
207			mtree_Sflag = 1;
208			break;
209		case 't':
210			tflag = 1;
211			break;
212		case 'u':
213			uflag = 1;
214			break;
215		case 'U':
216			Uflag = uflag = 1;
217			break;
218		case 'w':
219			wflag = 1;
220			break;
221		case 'W':
222			mtree_Wflag = 1;
223			break;
224		case 'x':
225			ftsoptions |= FTS_XDEV;
226			break;
227		case 'X':
228			read_excludes_file(optarg);
229			break;
230		case '?':
231		default:
232			usage();
233		}
234	}
235	argc -= optind;
236	argv += optind;
237
238	if (argc)
239		usage();
240
241	switch (flavor) {
242	case F_FREEBSD9:
243		if (cflag && iflag) {
244			warnx("-c and -i passed, replacing -i with -j for "
245			    "FreeBSD compatibility");
246			iflag = 0;
247			jflag = 1;
248		}
249		if (dflag && !bflag) {
250			warnx("Adding -b to -d for FreeBSD compatibility");
251			bflag = 1;
252		}
253		if (uflag && !iflag) {
254			warnx("Adding -i to -%c for FreeBSD compatibility",
255			    Uflag ? 'U' : 'u');
256			iflag = 1;
257		}
258		if (uflag && !tflag) {
259			warnx("Adding -t to -%c for FreeBSD compatibility",
260			    Uflag ? 'U' : 'u');
261			tflag = 1;
262		}
263		if (wflag)
264			warnx("The -w flag is a no-op");
265		break;
266	default:
267		if (wflag)
268			usage();
269	}
270
271	if (spec2 && (cflag || Cflag || Dflag))
272		mtree_err("Double -f, -c, -C and -D flags are mutually "
273		    "exclusive");
274
275	if (dir && spec2)
276		mtree_err("Double -f and -p flags are mutually exclusive");
277
278	if (dir && chdir(dir))
279		mtree_err("%s: %s", dir, strerror(errno));
280
281	if ((cflag || sflag) && !getcwd(fullpath, sizeof(fullpath)))
282		mtree_err("%s", strerror(errno));
283
284	if ((cflag && Cflag) || (cflag && Dflag) || (Cflag && Dflag))
285		mtree_err("-c, -C and -D flags are mutually exclusive");
286
287	if (iflag && mflag)
288		mtree_err("-i and -m flags are mutually exclusive");
289
290	if (lflag && uflag)
291		mtree_err("-l and -u flags are mutually exclusive");
292
293	if (cflag) {
294		cwalk();
295		exit(0);
296	}
297	if (Cflag || Dflag) {
298		dump_nodes("", spec(spec1), Dflag);
299		exit(0);
300	}
301	if (spec2 != NULL)
302		status = mtree_specspec(spec1, spec2);
303	else
304		status = verify(spec1);
305	if (Uflag && (status == MISMATCHEXIT))
306		status = 0;
307	exit(status);
308}
309
310static void
311usage(void)
312{
313	unsigned int i;
314
315	fprintf(stderr,
316	    "usage: %s [-bCcDdejLlMnPqrStUuWx] [-i|-m] [-E tags]\n"
317	    "\t\t[-f spec] [-f spec]\n"
318	    "\t\t[-I tags] [-K keywords] [-k keywords] [-N dbdir] [-p path]\n"
319	    "\t\t[-R keywords] [-s seed] [-X exclude-file]\n"
320	    "\t\t[-F flavor]\n",
321	    getprogname());
322	fprintf(stderr, "\nflavors:");
323	for (i = 0; i < __arraycount(flavors); i++)
324		fprintf(stderr, " %s", flavors[i].name);
325	fprintf(stderr, "\n");
326	exit(1);
327}
328