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