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 44 static 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 61 int ftsoptions = FTS_PHYSICAL; 62 int bflag, cflag, Cflag, dflag, Dflag, eflag, iflag, jflag, lflag, mflag, 63 nflag, qflag, rflag, sflag, tflag, uflag, Uflag, wflag; 64 char fullpath[MAXPATHLEN]; 65 66 static 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 77 int 78 main(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 310 static void 311 usage(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