110312Smckusick /* Copyright (c) 1983 Regents of the University of California */ 24610Smckusick 36846Smckusick #ifndef lint 4*11993Smckusick static char sccsid[] = "@(#)main.c 3.9 (Berkeley) 83/04/19"; 56846Smckusick #endif 64610Smckusick 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 * 20*11993Smckusick * Full incremental restore running entirely in user code and 21*11993Smckusick * 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; 38*11993Smckusick 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"; 48*11993Smckusick 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: 59*11993Smckusick fprintf(stderr, "Usage:\n%s%s%s%s%s", 60*11993Smckusick "\trestore tfhsvy [file file ...]\n", 61*11993Smckusick "\trestore xfhmsvy [file file ...]\n", 62*11993Smckusick "\trestore ifhmsvy\n", 63*11993Smckusick "\trestore rfsvy\n", 64*11993Smckusick "\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': 119*11993Smckusick 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') { 134*11993Smckusick 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) { 143*11993Smckusick /* 144*11993Smckusick * Interactive mode. 145*11993Smckusick */ 146*11993Smckusick case 'i': 14710312Smckusick setup(); 148*11993Smckusick extractdirs(1); 14911438Smckusick initsymtable((char *)0); 150*11993Smckusick runcmdshell(); 15110312Smckusick done(0); 152*11993Smckusick /* 153*11993Smckusick * Incremental restoration of a file system. 154*11993Smckusick */ 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); 163*11993Smckusick 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); 175*11993Smckusick extractdirs(1); 17611438Smckusick vprintf(stdout, "Calculate extraction list.\n"); 17711438Smckusick treescan(".", ROOTINO, nodeupdates); 1784843Smckusic } 17910312Smckusick createleaves(symtbl); 18010312Smckusick createlinks(); 181*11993Smckusick 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); 189*11993Smckusick /* 190*11993Smckusick * Resume an incremental file system restoration. 191*11993Smckusick */ 19210312Smckusick case 'R': 19310312Smckusick initsymtable(symtbl); 19411320Smckusick skipmaps(); 19511320Smckusick skipdirs(); 19610312Smckusick createleaves(symtbl); 19710312Smckusick createlinks(); 198*11993Smckusick setdirmodes(); 19910312Smckusick checkrestore(); 20010312Smckusick dumpsymtable(symtbl, (long)1); 20110312Smckusick done(0); 202*11993Smckusick /* 203*11993Smckusick * List contents of tape. 204*11993Smckusick */ 205*11993Smckusick case 't': 206*11993Smckusick setup(); 207*11993Smckusick extractdirs(0); 208*11993Smckusick while (argc--) { 209*11993Smckusick canon(*argv++, name); 210*11993Smckusick ino = dirlookup(name); 211*11993Smckusick if (ino == 0) 212*11993Smckusick continue; 213*11993Smckusick treescan(name, ino, listfile); 214*11993Smckusick } 215*11993Smckusick done(0); 216*11993Smckusick /* 217*11993Smckusick * Batch extraction of tape contents. 218*11993Smckusick */ 219*11993Smckusick case 'x': 220*11993Smckusick setup(); 221*11993Smckusick extractdirs(1); 222*11993Smckusick initsymtable((char *)0); 223*11993Smckusick while (argc--) { 224*11993Smckusick canon(*argv++, name); 225*11993Smckusick ino = dirlookup(name); 226*11993Smckusick if (ino == 0) 227*11993Smckusick continue; 228*11993Smckusick if (mflag) 229*11993Smckusick pathcheck(name); 230*11993Smckusick treescan(name, ino, addfile); 231*11993Smckusick } 232*11993Smckusick createfiles(); 233*11993Smckusick createlinks(); 234*11993Smckusick setdirmodes(); 235*11993Smckusick if (dflag) 236*11993Smckusick checkrestore(); 237*11993Smckusick done(0); 2384843Smckusic } 2394843Smckusic } 240*11993Smckusick 241*11993Smckusick /* 242*11993Smckusick * Read and execute commands from the terminal. 243*11993Smckusick */ 244*11993Smckusick runcmdshell() 245*11993Smckusick { 246*11993Smckusick register struct entry *np; 247*11993Smckusick ino_t ino; 248*11993Smckusick char curdir[MAXPATHLEN]; 249*11993Smckusick char name[MAXPATHLEN]; 250*11993Smckusick char cmd[BUFSIZ]; 251*11993Smckusick 252*11993Smckusick canon("/", curdir); 253*11993Smckusick loop: 254*11993Smckusick getcmd(curdir, cmd, name); 255*11993Smckusick switch (cmd[0]) { 256*11993Smckusick /* 257*11993Smckusick * Add elements to the extraction list. 258*11993Smckusick */ 259*11993Smckusick case 'a': 260*11993Smckusick ino = dirlookup(name); 261*11993Smckusick if (ino == 0) 262*11993Smckusick break; 263*11993Smckusick if (mflag) 264*11993Smckusick pathcheck(name); 265*11993Smckusick treescan(name, ino, addfile); 266*11993Smckusick break; 267*11993Smckusick /* 268*11993Smckusick * Change working directory. 269*11993Smckusick */ 270*11993Smckusick case 'c': 271*11993Smckusick ino = dirlookup(name); 272*11993Smckusick if (ino == 0) 273*11993Smckusick break; 274*11993Smckusick if (inodetype(ino) == LEAF) { 275*11993Smckusick fprintf(stderr, "%s: not a directory\n", name); 276*11993Smckusick break; 277*11993Smckusick } 278*11993Smckusick (void) strcpy(curdir, name); 279*11993Smckusick break; 280*11993Smckusick /* 281*11993Smckusick * Delete elements from the extraction list. 282*11993Smckusick */ 283*11993Smckusick case 'd': 284*11993Smckusick np = lookupname(name); 285*11993Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 286*11993Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 287*11993Smckusick break; 288*11993Smckusick } 289*11993Smckusick treescan(name, np->e_ino, deletefile); 290*11993Smckusick break; 291*11993Smckusick /* 292*11993Smckusick * Extract the requested list. 293*11993Smckusick */ 294*11993Smckusick case 'e': 295*11993Smckusick createfiles(); 296*11993Smckusick createlinks(); 297*11993Smckusick setdirmodes(); 298*11993Smckusick if (dflag) 299*11993Smckusick checkrestore(); 300*11993Smckusick volno = 0; 301*11993Smckusick break; 302*11993Smckusick /* 303*11993Smckusick * List available commands. 304*11993Smckusick */ 305*11993Smckusick case 'h': 306*11993Smckusick case '?': 307*11993Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 308*11993Smckusick "Available commands are:\n", 309*11993Smckusick "\tls [arg] - list directory\n", 310*11993Smckusick "\tcd arg - change directory\n", 311*11993Smckusick "\tpwd - print current directory\n", 312*11993Smckusick "\tadd [arg] - add `arg' to list of", 313*11993Smckusick " files to be extracted\n", 314*11993Smckusick "\tdelete [arg] - delete `arg' from", 315*11993Smckusick " list of files to be extracted\n", 316*11993Smckusick "\textract - extract requested files\n", 317*11993Smckusick "\tquit - immediately exit program\n", 318*11993Smckusick "\tverbose - toggle verbose flag", 319*11993Smckusick " (useful with ``ls'')\n", 320*11993Smckusick "\thelp or `?' - print this list\n", 321*11993Smckusick "If no `arg' is supplied, the current", 322*11993Smckusick " directory is used\n"); 323*11993Smckusick break; 324*11993Smckusick /* 325*11993Smckusick * List a directory. 326*11993Smckusick */ 327*11993Smckusick case 'l': 328*11993Smckusick ino = dirlookup(name); 329*11993Smckusick if (ino == 0) 330*11993Smckusick break; 331*11993Smckusick printlist(name, ino); 332*11993Smckusick break; 333*11993Smckusick /* 334*11993Smckusick * Print current directory. 335*11993Smckusick */ 336*11993Smckusick case 'p': 337*11993Smckusick if (curdir[1] == '\0') 338*11993Smckusick fprintf(stderr, "/\n"); 339*11993Smckusick else 340*11993Smckusick fprintf(stderr, "%s\n", &curdir[1]); 341*11993Smckusick break; 342*11993Smckusick /* 343*11993Smckusick * Quit. 344*11993Smckusick */ 345*11993Smckusick case 'q': 346*11993Smckusick return; 347*11993Smckusick /* 348*11993Smckusick * Toggle verbose mode. 349*11993Smckusick */ 350*11993Smckusick case 'v': 351*11993Smckusick if (vflag) { 352*11993Smckusick fprintf(stderr, "verbose mode off\n"); 353*11993Smckusick vflag = 0; 354*11993Smckusick break; 355*11993Smckusick } 356*11993Smckusick fprintf(stderr, "verbose mode on\n"); 357*11993Smckusick vflag++; 358*11993Smckusick break; 359*11993Smckusick /* 360*11993Smckusick * Unknown command. 361*11993Smckusick */ 362*11993Smckusick default: 363*11993Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 364*11993Smckusick break; 365*11993Smckusick } 366*11993Smckusick goto loop; 367*11993Smckusick } 368