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