1 /* $NetBSD: main.c,v 1.28 2004/10/24 17:01:07 wiz Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 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 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/4/95"; 41 #else 42 __RCSID("$NetBSD: main.c,v 1.28 2004/10/24 17:01:07 wiz Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/time.h> 48 49 #include <ufs/ufs/dinode.h> 50 #include <ufs/ffs/fs.h> 51 #include <protocols/dumprestore.h> 52 53 #include <err.h> 54 #include <errno.h> 55 #include <paths.h> 56 #include <signal.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #include "restore.h" 63 #include "extern.h" 64 65 int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0; 66 int hflag = 1, mflag = 1, Dflag = 0, Nflag = 0; 67 char command = '\0'; 68 int32_t dumpnum = 1; 69 int32_t volno = 0; 70 int32_t ntrec; 71 char *dumpmap; 72 char *usedinomap; 73 ino_t maxino; 74 time_t dumptime; 75 time_t dumpdate; 76 size_t pagesize; 77 FILE *terminal; 78 char *tmpdir; 79 80 FILE *Mtreefile = NULL; 81 82 int main __P((int, char *[])); 83 static void obsolete __P((int *, char **[])); 84 static void usage __P((void)); 85 86 int 87 main(argc, argv) 88 int argc; 89 char *argv[]; 90 { 91 int ch; 92 ino_t ino; 93 char *inputdev; 94 char *symtbl = "./restoresymtable"; 95 char *p, name[MAXPATHLEN]; 96 97 if (argc < 2) 98 usage(); 99 100 if ((inputdev = getenv("TAPE")) == NULL) 101 inputdev = _PATH_DEFTAPE; 102 if ((tmpdir = getenv("TMPDIR")) == NULL) 103 tmpdir = _PATH_TMP; 104 obsolete(&argc, &argv); 105 while ((ch = getopt(argc, argv, "b:cD:df:himM:NRrs:tuvxy")) != -1) 106 switch (ch) { 107 case 'b': 108 /* Change default tape blocksize. */ 109 bflag = 1; 110 ntrec = strtol(optarg, &p, 10); 111 if (*p) 112 errx(1, "illegal blocksize -- %s", optarg); 113 if (ntrec <= 0) 114 errx(1, "block size must be greater than 0"); 115 break; 116 case 'c': 117 cvtflag = 1; 118 break; 119 case 'D': 120 ddesc = digest_lookup(optarg); 121 if (ddesc == NULL) 122 err(1, "unknown digest algorithm: %s", optarg); 123 Dflag = 1; 124 break; 125 case 'd': 126 dflag = 1; 127 break; 128 case 'f': 129 inputdev = optarg; 130 break; 131 case 'h': 132 hflag = 0; 133 break; 134 case 'i': 135 case 'R': 136 case 'r': 137 case 't': 138 case 'x': 139 if (command != '\0') 140 errx(1, 141 "%c and %c options are mutually exclusive", 142 ch, command); 143 command = ch; 144 break; 145 case 'm': 146 mflag = 0; 147 break; 148 case 'N': 149 Nflag = 1; 150 break; 151 case 'M': 152 Mtreefile = fopen(optarg, "a"); 153 if (Mtreefile == NULL) 154 err(1, "can't open %s", optarg); 155 break; 156 case 's': 157 /* Dumpnum (skip to) for multifile dump tapes. */ 158 dumpnum = strtol(optarg, &p, 10); 159 if (*p) 160 errx(1, "illegal dump number -- %s", optarg); 161 if (dumpnum <= 0) 162 errx(1, "dump number must be greater than 0"); 163 break; 164 case 'u': 165 uflag = 1; 166 break; 167 case 'v': 168 vflag = 1; 169 break; 170 case 'y': 171 yflag = 1; 172 break; 173 default: 174 usage(); 175 } 176 argc -= optind; 177 argv += optind; 178 179 if (command == '\0') 180 errx(1, "none of i, R, r, t or x options specified"); 181 182 if (Nflag || command == 't') 183 uflag = 0; 184 185 if (signal(SIGINT, onintr) == SIG_IGN) 186 (void) signal(SIGINT, SIG_IGN); 187 if (signal(SIGTERM, onintr) == SIG_IGN) 188 (void) signal(SIGTERM, SIG_IGN); 189 setlinebuf(stderr); 190 pagesize = sysconf(_SC_PAGESIZE); 191 192 atexit(cleanup); 193 194 setinput(inputdev); 195 196 if (argc == 0) { 197 argc = 1; 198 *--argv = "."; 199 } 200 201 switch (command) { 202 /* 203 * Interactive mode. 204 */ 205 case 'i': 206 setup(); 207 extractdirs(1); 208 initsymtable(NULL); 209 runcmdshell(); 210 break; 211 /* 212 * Incremental restoration of a file system. 213 */ 214 case 'r': 215 setup(); 216 if (dumptime > 0) { 217 /* 218 * This is an incremental dump tape. 219 */ 220 vprintf(stdout, "Begin incremental restore\n"); 221 initsymtable(symtbl); 222 extractdirs(1); 223 removeoldleaves(); 224 vprintf(stdout, "Calculate node updates.\n"); 225 treescan(".", ROOTINO, nodeupdates); 226 findunreflinks(); 227 removeoldnodes(); 228 } else { 229 /* 230 * This is a level zero dump tape. 231 */ 232 vprintf(stdout, "Begin level 0 restore\n"); 233 initsymtable((char *)0); 234 extractdirs(1); 235 vprintf(stdout, "Calculate extraction list.\n"); 236 treescan(".", ROOTINO, nodeupdates); 237 } 238 createleaves(symtbl); 239 createlinks(); 240 setdirmodes(FORCE); 241 checkrestore(); 242 if (dflag) { 243 vprintf(stdout, "Verify the directory structure\n"); 244 treescan(".", ROOTINO, verifyfile); 245 } 246 dumpsymtable(symtbl, (long)1); 247 break; 248 /* 249 * Resume an incremental file system restoration. 250 */ 251 case 'R': 252 initsymtable(symtbl); 253 skipmaps(); 254 skipdirs(); 255 createleaves(symtbl); 256 createlinks(); 257 setdirmodes(FORCE); 258 checkrestore(); 259 dumpsymtable(symtbl, (long)1); 260 break; 261 /* 262 * List contents of tape. 263 */ 264 case 't': 265 setup(); 266 extractdirs(0); 267 initsymtable((char *)0); 268 while (argc--) { 269 canon(*argv++, name); 270 ino = dirlookup(name); 271 if (ino == 0) 272 continue; 273 treescan(name, ino, listfile); 274 } 275 break; 276 /* 277 * Batch extraction of tape contents. 278 */ 279 case 'x': 280 setup(); 281 extractdirs(1); 282 initsymtable((char *)0); 283 while (argc--) { 284 canon(*argv++, name); 285 ino = dirlookup(name); 286 if (ino == 0) 287 continue; 288 if (mflag) 289 pathcheck(name); 290 treescan(name, ino, addfile); 291 } 292 createfiles(); 293 createlinks(); 294 setdirmodes(0); 295 if (dflag) 296 checkrestore(); 297 break; 298 } 299 exit(0); 300 /* NOTREACHED */ 301 } 302 303 static void 304 usage() 305 { 306 const char *progname = getprogname(); 307 308 (void)fprintf(stderr, 309 "usage: %s -i [-cdhmvyN] [-b bsize] [-D algorithm] " 310 "[-f file] [-M mtreefile] [-s fileno]\n", progname); 311 (void)fprintf(stderr, 312 " %s -R [-cdvyN] [-b bsize] [-D algorithm] [-f file] " 313 "[-M mtreefile] [-s fileno]\n", progname); 314 (void)fprintf(stderr, 315 " %s -r [-cdvyN] [-b bsize] [-D algorithm] [-f file] " 316 "[-M mtreefile] [-s fileno]\n", progname); 317 (void)fprintf(stderr, 318 " %s -t [-cdhvy] [-b bsize] [-D algorithm] [-f file]\n" 319 " [-s fileno] [file ...]\n", progname); 320 (void)fprintf(stderr, 321 " %s -x [-cdhmvyN] [-b bsize] [-D algorithm] [-f file]\n" 322 " [-M mtreefile] [-s fileno] [file ...]\n", progname); 323 exit(1); 324 } 325 326 /* 327 * obsolete -- 328 * Change set of key letters and ordered arguments into something 329 * getopt(3) will like. 330 */ 331 static void 332 obsolete(argcp, argvp) 333 int *argcp; 334 char **argvp[]; 335 { 336 int argc, flags; 337 char *ap, **argv, *flagsp, **nargv, *p; 338 339 /* Setup. */ 340 argv = *argvp; 341 argc = *argcp; 342 343 /* Return if no arguments or first argument has leading dash. */ 344 ap = argv[1]; 345 if (argc == 1 || *ap == '-') 346 return; 347 348 /* Allocate space for new arguments. */ 349 if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL || 350 (p = flagsp = malloc(strlen(ap) + 2)) == NULL) 351 err(1, NULL); 352 353 *nargv++ = *argv; 354 argv += 2; 355 356 for (flags = 0; *ap; ++ap) { 357 switch (*ap) { 358 case 'b': 359 case 'f': 360 case 's': 361 if (*argv == NULL) { 362 warnx("option requires an argument -- %c", *ap); 363 usage(); 364 } 365 if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL) 366 err(1, NULL); 367 nargv[0][0] = '-'; 368 nargv[0][1] = *ap; 369 (void)strcpy(&nargv[0][2], *argv); 370 ++argv; 371 ++nargv; 372 break; 373 default: 374 if (!flags) { 375 *p++ = '-'; 376 flags = 1; 377 } 378 *p++ = *ap; 379 break; 380 } 381 } 382 383 /* Terminate flags. */ 384 if (flags) { 385 *p = '\0'; 386 *nargv++ = flagsp; 387 } 388 389 /* Copy remaining arguments. */ 390 while ((*nargv++ = *argv++) != NULL) 391 ; 392 393 /* Update argument count. */ 394 *argcp = nargv - *argvp - 1; 395 } 396