11558Srgrimes/* 21558Srgrimes * Copyright (c) 1983, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 301558Srgrimes#ifndef lint 3137906Scharnierstatic const char copyright[] = 321558Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 331558Srgrimes The Regents of the University of California. All rights reserved.\n"; 341558Srgrimes#endif /* not lint */ 351558Srgrimes 361558Srgrimes#ifndef lint 3737906Scharnier#if 0 3823685Speterstatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/4/95"; 3937906Scharnier#endif 401558Srgrimes#endif /* not lint */ 411558Srgrimes 42146754Scharnier#include <sys/cdefs.h> 43146754Scharnier__FBSDID("$FreeBSD$"); 44146754Scharnier 451558Srgrimes#include <sys/param.h> 4637906Scharnier#include <sys/stat.h> 471558Srgrimes 4823685Speter#include <ufs/ufs/dinode.h> 491558Srgrimes#include <protocols/dumprestore.h> 501558Srgrimes 511558Srgrimes#include <err.h> 52103949Smike#include <limits.h> 53118526Sache#include <locale.h> 5473986Sobrien#include <paths.h> 551558Srgrimes#include <stdio.h> 561558Srgrimes#include <stdlib.h> 5778732Sdd#include <string.h> 5823685Speter#include <unistd.h> 591558Srgrimes 601558Srgrimes#include "restore.h" 611558Srgrimes#include "extern.h" 621558Srgrimes 63164911Sdwmaloneint bflag = 0, cvtflag = 0, dflag = 0, Dflag = 0, vflag = 0, yflag = 0; 641558Srgrimesint hflag = 1, mflag = 1, Nflag = 0; 6535852Sjkhint uflag = 0; 66128175Sgreenint pipecmd = 0; 671558Srgrimeschar command = '\0'; 681558Srgrimeslong dumpnum = 1; 691558Srgrimeslong volno = 0; 701558Srgrimeslong ntrec; 711558Srgrimeschar *dumpmap; 7223685Speterchar *usedinomap; 731558Srgrimesino_t maxino; 741558Srgrimestime_t dumptime; 751558Srgrimestime_t dumpdate; 761558SrgrimesFILE *terminal; 771558Srgrimes 7892837Simpstatic void obsolete(int *, char **[]); 7992837Simpstatic void usage(void) __dead2; 801558Srgrimes 811558Srgrimesint 8292837Simpmain(int argc, char *argv[]) 831558Srgrimes{ 841558Srgrimes int ch; 851558Srgrimes ino_t ino; 8621149Simp char *inputdev; 871558Srgrimes char *symtbl = "./restoresymtable"; 881558Srgrimes char *p, name[MAXPATHLEN]; 891558Srgrimes 9021149Simp /* Temp files should *not* be readable. We set permissions later. */ 9121149Simp (void) umask(077); 9221149Simp 931558Srgrimes if (argc < 2) 941558Srgrimes usage(); 951558Srgrimes 96118526Sache (void)setlocale(LC_ALL, ""); 97118526Sache 98128175Sgreen inputdev = NULL; 991558Srgrimes obsolete(&argc, &argv); 100164911Sdwmalone while ((ch = getopt(argc, argv, "b:dDf:himNP:Rrs:tuvxy")) != -1) 1011558Srgrimes switch(ch) { 1021558Srgrimes case 'b': 1031558Srgrimes /* Change default tape blocksize. */ 1041558Srgrimes bflag = 1; 1051558Srgrimes ntrec = strtol(optarg, &p, 10); 1061558Srgrimes if (*p) 1071558Srgrimes errx(1, "illegal blocksize -- %s", optarg); 1081558Srgrimes if (ntrec <= 0) 1091558Srgrimes errx(1, "block size must be greater than 0"); 1101558Srgrimes break; 1111558Srgrimes case 'd': 1121558Srgrimes dflag = 1; 1131558Srgrimes break; 114164911Sdwmalone case 'D': 115164911Sdwmalone Dflag = 1; 116164911Sdwmalone break; 1171558Srgrimes case 'f': 118128175Sgreen if (pipecmd) 119128175Sgreen errx(1, 120128175Sgreen "-P and -f options are mutually exclusive"); 1211558Srgrimes inputdev = optarg; 1221558Srgrimes break; 123128175Sgreen case 'P': 124128175Sgreen if (!pipecmd && inputdev) 125128175Sgreen errx(1, 126128175Sgreen "-P and -f options are mutually exclusive"); 127128175Sgreen inputdev = optarg; 128128175Sgreen pipecmd = 1; 129128175Sgreen break; 1301558Srgrimes case 'h': 1311558Srgrimes hflag = 0; 1321558Srgrimes break; 1331558Srgrimes case 'i': 1341558Srgrimes case 'R': 1351558Srgrimes case 'r': 1361558Srgrimes case 't': 1371558Srgrimes case 'x': 1381558Srgrimes if (command != '\0') 1391558Srgrimes errx(1, 1401558Srgrimes "%c and %c options are mutually exclusive", 1411558Srgrimes ch, command); 1421558Srgrimes command = ch; 1431558Srgrimes break; 1441558Srgrimes case 'm': 1451558Srgrimes mflag = 0; 1461558Srgrimes break; 1471558Srgrimes case 'N': 1481558Srgrimes Nflag = 1; 1491558Srgrimes break; 1501558Srgrimes case 's': 1511558Srgrimes /* Dumpnum (skip to) for multifile dump tapes. */ 1521558Srgrimes dumpnum = strtol(optarg, &p, 10); 1531558Srgrimes if (*p) 1541558Srgrimes errx(1, "illegal dump number -- %s", optarg); 1551558Srgrimes if (dumpnum <= 0) 1561558Srgrimes errx(1, "dump number must be greater than 0"); 1571558Srgrimes break; 15835852Sjkh case 'u': 15935852Sjkh uflag = 1; 16035852Sjkh break; 1611558Srgrimes case 'v': 1621558Srgrimes vflag = 1; 1631558Srgrimes break; 1641558Srgrimes case 'y': 1651558Srgrimes yflag = 1; 1661558Srgrimes break; 1671558Srgrimes default: 1681558Srgrimes usage(); 1691558Srgrimes } 1701558Srgrimes argc -= optind; 1711558Srgrimes argv += optind; 1721558Srgrimes 1731558Srgrimes if (command == '\0') 1741558Srgrimes errx(1, "none of i, R, r, t or x options specified"); 1751558Srgrimes 1761558Srgrimes if (signal(SIGINT, onintr) == SIG_IGN) 1771558Srgrimes (void) signal(SIGINT, SIG_IGN); 1781558Srgrimes if (signal(SIGTERM, onintr) == SIG_IGN) 1791558Srgrimes (void) signal(SIGTERM, SIG_IGN); 1801558Srgrimes setlinebuf(stderr); 1811558Srgrimes 182128175Sgreen if (inputdev == NULL && (inputdev = getenv("TAPE")) == NULL) 183128175Sgreen inputdev = _PATH_DEFTAPE; 184128175Sgreen setinput(inputdev, pipecmd); 1851558Srgrimes 1861558Srgrimes if (argc == 0) { 1871558Srgrimes argc = 1; 1881558Srgrimes *--argv = "."; 1891558Srgrimes } 1901558Srgrimes 1911558Srgrimes switch (command) { 1921558Srgrimes /* 1931558Srgrimes * Interactive mode. 1941558Srgrimes */ 1951558Srgrimes case 'i': 1961558Srgrimes setup(); 1971558Srgrimes extractdirs(1); 1981558Srgrimes initsymtable(NULL); 1991558Srgrimes runcmdshell(); 2001558Srgrimes break; 2011558Srgrimes /* 202102231Strhodes * Incremental restoration of a file system. 2031558Srgrimes */ 2041558Srgrimes case 'r': 2051558Srgrimes setup(); 2061558Srgrimes if (dumptime > 0) { 2071558Srgrimes /* 2081558Srgrimes * This is an incremental dump tape. 2091558Srgrimes */ 2101558Srgrimes vprintf(stdout, "Begin incremental restore\n"); 2111558Srgrimes initsymtable(symtbl); 2121558Srgrimes extractdirs(1); 2131558Srgrimes removeoldleaves(); 2141558Srgrimes vprintf(stdout, "Calculate node updates.\n"); 2151558Srgrimes treescan(".", ROOTINO, nodeupdates); 2161558Srgrimes findunreflinks(); 2171558Srgrimes removeoldnodes(); 2181558Srgrimes } else { 2191558Srgrimes /* 2201558Srgrimes * This is a level zero dump tape. 2211558Srgrimes */ 2221558Srgrimes vprintf(stdout, "Begin level 0 restore\n"); 2231558Srgrimes initsymtable((char *)0); 2241558Srgrimes extractdirs(1); 2251558Srgrimes vprintf(stdout, "Calculate extraction list.\n"); 2261558Srgrimes treescan(".", ROOTINO, nodeupdates); 2271558Srgrimes } 2281558Srgrimes createleaves(symtbl); 2291558Srgrimes createlinks(); 2301558Srgrimes setdirmodes(FORCE); 2311558Srgrimes checkrestore(); 2321558Srgrimes if (dflag) { 2331558Srgrimes vprintf(stdout, "Verify the directory structure\n"); 2341558Srgrimes treescan(".", ROOTINO, verifyfile); 2351558Srgrimes } 2361558Srgrimes dumpsymtable(symtbl, (long)1); 2371558Srgrimes break; 2381558Srgrimes /* 239102231Strhodes * Resume an incremental file system restoration. 2401558Srgrimes */ 2411558Srgrimes case 'R': 2421558Srgrimes initsymtable(symtbl); 2431558Srgrimes skipmaps(); 2441558Srgrimes skipdirs(); 2451558Srgrimes createleaves(symtbl); 2461558Srgrimes createlinks(); 2471558Srgrimes setdirmodes(FORCE); 2481558Srgrimes checkrestore(); 2491558Srgrimes dumpsymtable(symtbl, (long)1); 2501558Srgrimes break; 2511558Srgrimes /* 2521558Srgrimes * List contents of tape. 2531558Srgrimes */ 2541558Srgrimes case 't': 2551558Srgrimes setup(); 2561558Srgrimes extractdirs(0); 2571558Srgrimes initsymtable((char *)0); 2581558Srgrimes while (argc--) { 25921174Sguido canon(*argv++, name, sizeof(name)); 2601558Srgrimes ino = dirlookup(name); 2611558Srgrimes if (ino == 0) 2621558Srgrimes continue; 2631558Srgrimes treescan(name, ino, listfile); 2641558Srgrimes } 2651558Srgrimes break; 2661558Srgrimes /* 2671558Srgrimes * Batch extraction of tape contents. 2681558Srgrimes */ 2691558Srgrimes case 'x': 2701558Srgrimes setup(); 2711558Srgrimes extractdirs(1); 2721558Srgrimes initsymtable((char *)0); 2731558Srgrimes while (argc--) { 27421174Sguido canon(*argv++, name, sizeof(name)); 2751558Srgrimes ino = dirlookup(name); 2761558Srgrimes if (ino == 0) 2771558Srgrimes continue; 2781558Srgrimes if (mflag) 2791558Srgrimes pathcheck(name); 2801558Srgrimes treescan(name, ino, addfile); 2811558Srgrimes } 2821558Srgrimes createfiles(); 2831558Srgrimes createlinks(); 2841558Srgrimes setdirmodes(0); 2851558Srgrimes if (dflag) 2861558Srgrimes checkrestore(); 2871558Srgrimes break; 2881558Srgrimes } 2891558Srgrimes done(0); 2901558Srgrimes /* NOTREACHED */ 2911558Srgrimes} 2921558Srgrimes 2931558Srgrimesstatic void 2941558Srgrimesusage() 2951558Srgrimes{ 296128175Sgreen const char *const common = 297141611Sru "[-b blocksize] [-f file | -P pipecommand] [-s fileno]"; 298128175Sgreen const char *const fileell = "[file ...]"; 299128175Sgreen 300128175Sgreen (void)fprintf(stderr, "usage:\t%s %s\n\t%s %s\n\t%s %s\n" 301128175Sgreen "\t%s %s %s\n\t%s %s %s\n", 302143817Simp "restore -i [-dhmNuvy]", common, 303143817Simp "restore -R [-dNuvy]", common, 304143817Simp "restore -r [-dNuvy]", common, 305143817Simp "restore -t [-dhNuvy]", common, fileell, 306143817Simp "restore -x [-dhmNuvy]", common, fileell); 3071558Srgrimes done(1); 3081558Srgrimes} 3091558Srgrimes 3101558Srgrimes/* 3111558Srgrimes * obsolete -- 3121558Srgrimes * Change set of key letters and ordered arguments into something 3131558Srgrimes * getopt(3) will like. 3141558Srgrimes */ 3151558Srgrimesstatic void 31692837Simpobsolete(int *argcp, char **argvp[]) 3171558Srgrimes{ 3181558Srgrimes int argc, flags; 3191558Srgrimes char *ap, **argv, *flagsp, **nargv, *p; 3201558Srgrimes 3211558Srgrimes /* Setup. */ 3221558Srgrimes argv = *argvp; 3231558Srgrimes argc = *argcp; 3241558Srgrimes 3251558Srgrimes /* Return if no arguments or first argument has leading dash. */ 3261558Srgrimes ap = argv[1]; 3271558Srgrimes if (argc == 1 || *ap == '-') 3281558Srgrimes return; 3291558Srgrimes 3301558Srgrimes /* Allocate space for new arguments. */ 3311558Srgrimes if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL || 3321558Srgrimes (p = flagsp = malloc(strlen(ap) + 2)) == NULL) 3331558Srgrimes err(1, NULL); 3341558Srgrimes 3351558Srgrimes *nargv++ = *argv; 33617261Sjkh argv += 2, argc -= 2; 3371558Srgrimes 3381558Srgrimes for (flags = 0; *ap; ++ap) { 33923685Speter switch (*ap) { 3401558Srgrimes case 'b': 3411558Srgrimes case 'f': 3421558Srgrimes case 's': 34323685Speter if (*argv == NULL) { 34423685Speter warnx("option requires an argument -- %c", *ap); 34523685Speter usage(); 34623685Speter } 3471558Srgrimes if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL) 3481558Srgrimes err(1, NULL); 3491558Srgrimes nargv[0][0] = '-'; 3501558Srgrimes nargv[0][1] = *ap; 3511558Srgrimes (void)strcpy(&nargv[0][2], *argv); 35223685Speter ++argv; 3531558Srgrimes ++nargv; 3541558Srgrimes break; 3551558Srgrimes default: 3561558Srgrimes if (!flags) { 3571558Srgrimes *p++ = '-'; 3581558Srgrimes flags = 1; 3591558Srgrimes } 3601558Srgrimes *p++ = *ap; 3611558Srgrimes break; 3621558Srgrimes } 3631558Srgrimes } 3641558Srgrimes 3651558Srgrimes /* Terminate flags. */ 3661558Srgrimes if (flags) { 3671558Srgrimes *p = '\0'; 3681558Srgrimes *nargv++ = flagsp; 369299148Spfg } else 370299148Spfg free(flagsp); 3711558Srgrimes 3721558Srgrimes /* Copy remaining arguments. */ 37337906Scharnier while ((*nargv++ = *argv++)); 37423685Speter 37523685Speter /* Update argument count. */ 37623685Speter *argcp = nargv - *argvp - 1; 3771558Srgrimes} 378