16846Smckusick #ifndef lint 2*14564Ssam static char sccsid[] = "@(#)main.c 3.12 (Berkeley) 83/08/11"; 36846Smckusick #endif 44610Smckusick 5*14564Ssam /* Copyright (c) 1983 Regents of the University of California */ 6*14564Ssam 710312Smckusick /* 810312Smckusick * Modified to recursively extract all files within a subtree 910312Smckusick * (supressed by the h option) and recreate the heirarchical 1010312Smckusick * structure of that subtree and move extracted files to their 1110312Smckusick * proper homes (supressed by the m option). 1210312Smckusick * Includes the s (skip files) option for use with multiple 1310312Smckusick * dumps on a single tape. 144610Smckusick * 8/29/80 by Mike Litzkow 154610Smckusick * 1610312Smckusick * Modified to work on the new file system and to recover from 1710312Smckusick * tape read errors. 186846Smckusick * 1/19/82 by Kirk McKusick 196846Smckusick * 2011993Smckusick * Full incremental restore running entirely in user code and 2111993Smckusick * interactive tape browser. 2210312Smckusick * 1/19/83 by Kirk McKusick 234610Smckusick */ 244610Smckusick 2510312Smckusick #include "restore.h" 264610Smckusick #include <signal.h> 274610Smckusick 2810312Smckusick int cvtflag = 0, dflag = 0, vflag = 0, yflag = 0; 2910312Smckusick int hflag = 1, mflag = 1; 3010312Smckusick char command = '\0'; 3110312Smckusick long dumpnum = 1; 3211438Smckusick long volno = 0; 335327Smckusic char *dumpmap; 345327Smckusic char *clrimap; 3510312Smckusick ino_t maxino; 3610312Smckusick time_t dumptime; 3711302Smckusick time_t dumpdate; 3811993Smckusick FILE *terminal; 394610Smckusick 406846Smckusick main(argc, argv) 414700Smckusic int argc; 424700Smckusic char *argv[]; 434610Smckusick { 444610Smckusick register char *cp; 4511308Smckusick ino_t ino; 4610312Smckusick char *inputdev = "/dev/rmt8"; 4711308Smckusick char *symtbl = "./restoresymtable"; 4811993Smckusick char name[MAXPATHLEN]; 494700Smckusic int (*signal())(); 5010312Smckusick extern int onintr(); 514610Smckusick 5210312Smckusick if (signal(SIGINT, onintr) == SIG_IGN) 5311438Smckusick (void) signal(SIGINT, SIG_IGN); 5410312Smckusick if (signal(SIGTERM, onintr) == SIG_IGN) 5511438Smckusick (void) signal(SIGTERM, SIG_IGN); 5611308Smckusick setlinebuf(stderr); 574610Smckusick if (argc < 2) { 584610Smckusick usage: 5911993Smckusick fprintf(stderr, "Usage:\n%s%s%s%s%s", 6011993Smckusick "\trestore tfhsvy [file file ...]\n", 6111993Smckusick "\trestore xfhmsvy [file file ...]\n", 6211993Smckusick "\trestore ifhmsvy\n", 6311993Smckusick "\trestore rfsvy\n", 6411993Smckusick "\trestore Rfsvy\n"); 654700Smckusic done(1); 664610Smckusick } 674610Smckusick argv++; 684610Smckusick argc -= 2; 6910202Smckusick command = '\0'; 704610Smckusick for (cp = *argv++; *cp; cp++) { 714610Smckusick switch (*cp) { 724610Smckusick case '-': 734610Smckusick break; 748302Smckusick case 'c': 758302Smckusick cvtflag++; 768302Smckusick break; 7710312Smckusick case 'd': 7810312Smckusick dflag++; 794610Smckusick break; 804610Smckusick case 'h': 8110202Smckusick hflag = 0; 824610Smckusick break; 834610Smckusick case 'm': 8410202Smckusick mflag = 0; 854610Smckusick break; 868374Smckusick case 'v': 878374Smckusick vflag++; 888374Smckusick break; 898374Smckusick case 'y': 908374Smckusick yflag++; 918374Smckusick break; 9210312Smckusick case 'f': 9311400Smckusick if (argc < 1) { 9411400Smckusick fprintf(stderr, "missing device specifier\n"); 9511400Smckusick done(1); 9611400Smckusick } 9710312Smckusick inputdev = *argv++; 9810312Smckusick argc--; 9910312Smckusick break; 10010312Smckusick case 's': 10110312Smckusick /* 10210312Smckusick * dumpnum (skip to) for multifile dump tapes 10310312Smckusick */ 10411400Smckusick if (argc < 1) { 10511400Smckusick fprintf(stderr, "missing dump number\n"); 10611400Smckusick done(1); 10711400Smckusick } 10810312Smckusick dumpnum = atoi(*argv++); 10910312Smckusick if (dumpnum <= 0) { 11010312Smckusick fprintf(stderr, "Dump number must be a positive integer\n"); 11110312Smckusick done(1); 11210312Smckusick } 11310312Smckusick argc--; 11410312Smckusick break; 1154610Smckusick case 't': 11610312Smckusick case 'R': 11710312Smckusick case 'r': 11810312Smckusick case 'x': 11911993Smckusick case 'i': 12010202Smckusick if (command != '\0') { 12110312Smckusick fprintf(stderr, 12211400Smckusick "%c and %c are mutually exclusive\n", 12311400Smckusick *cp, command); 12410202Smckusick goto usage; 12510202Smckusick } 12611400Smckusick command = *cp; 1274610Smckusick break; 1284610Smckusick default: 1294700Smckusic fprintf(stderr, "Bad key character %c\n", *cp); 1304610Smckusick goto usage; 1314610Smckusick } 1324610Smckusick } 13310202Smckusick if (command == '\0') { 13411993Smckusick fprintf(stderr, "must specify i, t, r, R, or x\n"); 13510202Smckusick goto usage; 13610202Smckusick } 13710312Smckusick setinput(inputdev); 13810202Smckusick if (argc == 0) { 13910312Smckusick argc = 1; 14010202Smckusick *--argv = "."; 14110202Smckusick } 14210312Smckusick switch (command) { 14311993Smckusick /* 14411993Smckusick * Interactive mode. 14511993Smckusick */ 14611993Smckusick case 'i': 14710312Smckusick setup(); 14811993Smckusick extractdirs(1); 14911438Smckusick initsymtable((char *)0); 15011993Smckusick runcmdshell(); 15110312Smckusick done(0); 15211993Smckusick /* 15311993Smckusick * Incremental restoration of a file system. 15411993Smckusick */ 15510312Smckusick case 'r': 15610312Smckusick setup(); 15710312Smckusick if (dumptime > 0) { 15811438Smckusick /* 15911438Smckusick * This is an incremental dump tape. 16011438Smckusick */ 16111438Smckusick vprintf(stdout, "Begin incremental restore\n"); 16210312Smckusick initsymtable(symtbl); 16311993Smckusick extractdirs(1); 16411438Smckusick removeoldleaves(); 16511438Smckusick vprintf(stdout, "Calculate node updates.\n"); 16611438Smckusick treescan(".", ROOTINO, nodeupdates); 16711438Smckusick findunreflinks(); 16811438Smckusick removeoldnodes(); 16910312Smckusick } else { 17011438Smckusick /* 17111438Smckusick * This is a level zero dump tape. 17211438Smckusick */ 17311438Smckusick vprintf(stdout, "Begin level 0 restore\n"); 17411438Smckusick initsymtable((char *)0); 17511993Smckusick extractdirs(1); 17611438Smckusick vprintf(stdout, "Calculate extraction list.\n"); 17711438Smckusick treescan(".", ROOTINO, nodeupdates); 1784843Smckusic } 17910312Smckusick createleaves(symtbl); 18010312Smckusick createlinks(); 18111993Smckusick setdirmodes(); 18210312Smckusick checkrestore(); 18310312Smckusick if (dflag) { 18410312Smckusick vprintf(stdout, "Verify the directory structure\n"); 18510312Smckusick treescan(".", ROOTINO, verifyfile); 1864610Smckusick } 18710312Smckusick dumpsymtable(symtbl, (long)1); 18810312Smckusick done(0); 18911993Smckusick /* 19011993Smckusick * Resume an incremental file system restoration. 19111993Smckusick */ 19210312Smckusick case 'R': 19310312Smckusick initsymtable(symtbl); 19411320Smckusick skipmaps(); 19511320Smckusick skipdirs(); 19610312Smckusick createleaves(symtbl); 19710312Smckusick createlinks(); 19811993Smckusick setdirmodes(); 19910312Smckusick checkrestore(); 20010312Smckusick dumpsymtable(symtbl, (long)1); 20110312Smckusick done(0); 20211993Smckusick /* 20311993Smckusick * List contents of tape. 20411993Smckusick */ 20511993Smckusick case 't': 20611993Smckusick setup(); 20711993Smckusick extractdirs(0); 20811993Smckusick while (argc--) { 20911993Smckusick canon(*argv++, name); 21011993Smckusick ino = dirlookup(name); 21111993Smckusick if (ino == 0) 21211993Smckusick continue; 21311993Smckusick treescan(name, ino, listfile); 21411993Smckusick } 21511993Smckusick done(0); 21611993Smckusick /* 21711993Smckusick * Batch extraction of tape contents. 21811993Smckusick */ 21911993Smckusick case 'x': 22011993Smckusick setup(); 22111993Smckusick extractdirs(1); 22211993Smckusick initsymtable((char *)0); 22311993Smckusick while (argc--) { 22411993Smckusick canon(*argv++, name); 22511993Smckusick ino = dirlookup(name); 22611993Smckusick if (ino == 0) 22711993Smckusick continue; 22811993Smckusick if (mflag) 22911993Smckusick pathcheck(name); 23011993Smckusick treescan(name, ino, addfile); 23111993Smckusick } 23211993Smckusick createfiles(); 23311993Smckusick createlinks(); 23411993Smckusick setdirmodes(); 23511993Smckusick if (dflag) 23611993Smckusick checkrestore(); 23711993Smckusick done(0); 2384843Smckusic } 2394843Smckusic } 24011993Smckusick 24111993Smckusick /* 24211993Smckusick * Read and execute commands from the terminal. 24311993Smckusick */ 24411993Smckusick runcmdshell() 24511993Smckusick { 24611993Smckusick register struct entry *np; 24711993Smckusick ino_t ino; 24811993Smckusick char curdir[MAXPATHLEN]; 24911993Smckusick char name[MAXPATHLEN]; 25011993Smckusick char cmd[BUFSIZ]; 25111993Smckusick 25211993Smckusick canon("/", curdir); 25311993Smckusick loop: 25411993Smckusick getcmd(curdir, cmd, name); 25511993Smckusick switch (cmd[0]) { 25611993Smckusick /* 25711993Smckusick * Add elements to the extraction list. 25811993Smckusick */ 25911993Smckusick case 'a': 26011993Smckusick ino = dirlookup(name); 26111993Smckusick if (ino == 0) 26211993Smckusick break; 26311993Smckusick if (mflag) 26411993Smckusick pathcheck(name); 26511993Smckusick treescan(name, ino, addfile); 26611993Smckusick break; 26711993Smckusick /* 26811993Smckusick * Change working directory. 26911993Smckusick */ 27011993Smckusick case 'c': 27111993Smckusick ino = dirlookup(name); 27211993Smckusick if (ino == 0) 27311993Smckusick break; 27411993Smckusick if (inodetype(ino) == LEAF) { 27511993Smckusick fprintf(stderr, "%s: not a directory\n", name); 27611993Smckusick break; 27711993Smckusick } 27811993Smckusick (void) strcpy(curdir, name); 27911993Smckusick break; 28011993Smckusick /* 28111993Smckusick * Delete elements from the extraction list. 28211993Smckusick */ 28311993Smckusick case 'd': 28411993Smckusick np = lookupname(name); 28511993Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 28611993Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 28711993Smckusick break; 28811993Smckusick } 28911993Smckusick treescan(name, np->e_ino, deletefile); 29011993Smckusick break; 29111993Smckusick /* 29211993Smckusick * Extract the requested list. 29311993Smckusick */ 29411993Smckusick case 'e': 29511993Smckusick createfiles(); 29611993Smckusick createlinks(); 29711993Smckusick setdirmodes(); 29811993Smckusick if (dflag) 29911993Smckusick checkrestore(); 30011993Smckusick volno = 0; 30111993Smckusick break; 30211993Smckusick /* 30311993Smckusick * List available commands. 30411993Smckusick */ 30511993Smckusick case 'h': 30611993Smckusick case '?': 30711993Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 30811993Smckusick "Available commands are:\n", 30911993Smckusick "\tls [arg] - list directory\n", 31011993Smckusick "\tcd arg - change directory\n", 31111993Smckusick "\tpwd - print current directory\n", 31211993Smckusick "\tadd [arg] - add `arg' to list of", 31311993Smckusick " files to be extracted\n", 31411993Smckusick "\tdelete [arg] - delete `arg' from", 31511993Smckusick " list of files to be extracted\n", 31611993Smckusick "\textract - extract requested files\n", 31711993Smckusick "\tquit - immediately exit program\n", 31811993Smckusick "\tverbose - toggle verbose flag", 31911993Smckusick " (useful with ``ls'')\n", 32011993Smckusick "\thelp or `?' - print this list\n", 32111993Smckusick "If no `arg' is supplied, the current", 32211993Smckusick " directory is used\n"); 32311993Smckusick break; 32411993Smckusick /* 32511993Smckusick * List a directory. 32611993Smckusick */ 32711993Smckusick case 'l': 32811993Smckusick ino = dirlookup(name); 32911993Smckusick if (ino == 0) 33011993Smckusick break; 33111993Smckusick printlist(name, ino); 33211993Smckusick break; 33311993Smckusick /* 33411993Smckusick * Print current directory. 33511993Smckusick */ 33611993Smckusick case 'p': 33711993Smckusick if (curdir[1] == '\0') 33811993Smckusick fprintf(stderr, "/\n"); 33911993Smckusick else 34011993Smckusick fprintf(stderr, "%s\n", &curdir[1]); 34111993Smckusick break; 34211993Smckusick /* 34311993Smckusick * Quit. 34411993Smckusick */ 34511993Smckusick case 'q': 34613208Smckusick case 'x': 34711993Smckusick return; 34811993Smckusick /* 34911993Smckusick * Toggle verbose mode. 35011993Smckusick */ 35111993Smckusick case 'v': 35211993Smckusick if (vflag) { 35311993Smckusick fprintf(stderr, "verbose mode off\n"); 35411993Smckusick vflag = 0; 35511993Smckusick break; 35611993Smckusick } 35711993Smckusick fprintf(stderr, "verbose mode on\n"); 35811993Smckusick vflag++; 35911993Smckusick break; 36011993Smckusick /* 36112455Smckusick * Turn on debugging. 36212455Smckusick */ 36312455Smckusick case 'D': 36412455Smckusick if (dflag) { 36512455Smckusick fprintf(stderr, "debugging mode off\n"); 36612455Smckusick dflag = 0; 36712455Smckusick break; 36812455Smckusick } 36912455Smckusick fprintf(stderr, "debugging mode on\n"); 37012455Smckusick dflag++; 37112455Smckusick break; 37212455Smckusick /* 37311993Smckusick * Unknown command. 37411993Smckusick */ 37511993Smckusick default: 37611993Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 37711993Smckusick break; 37811993Smckusick } 37911993Smckusick goto loop; 38011993Smckusick } 381