1 /* 2 * Copyright 1998, 2001-2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1983 Regents of the University of California. 11 * All rights reserved. The Berkeley software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 /* 18 * Modified to recursively extract all files within a subtree 19 * (supressed by the h option) and recreate the heirarchical 20 * structure of that subtree and move extracted files to their 21 * proper homes (supressed by the m option). 22 * Includes the s (skip files) option for use with multiple 23 * dumps on a single tape. 24 * 8/29/80 by Mike Litzkow 25 * 26 * Modified to work on the new file system and to recover from 27 * tape read errors. 28 * 1/19/82 by Kirk McKusick 29 * 30 * Full incremental restore running entirely in user code and 31 * interactive tape browser. 32 * 1/19/83 by Kirk McKusick 33 */ 34 35 #include "restore.h" 36 #include <signal.h> 37 #include <byteorder.h> 38 #include <priv_utils.h> 39 40 #include <euc.h> 41 #include <getwidth.h> 42 #include <sys/mtio.h> 43 eucwidth_t wp; 44 45 int bflag = 0, dflag = 0, vflag = 0, yflag = 0; 46 int hflag = 1, mflag = 1, paginating = 0, offline = 0, autoload = 0; 47 int autoload_tries; 48 int autoload_period; 49 int cvtflag = 0; /* Converting from old dump format */ 50 char command = '\0'; 51 long dumpnum = 1; 52 int volno = 0; 53 uint_t ntrec; /* blocking factor, in KB */ 54 uint_t saved_ntrec; /* saved blocking factor, in KB */ 55 ssize_t tape_rec_size = 0; /* tape record size (ntrec * tp_bsize) */ 56 size_t newtapebuf_size = 0; /* save size of last call to newtapebuf */ 57 char *progname; 58 char *dumpmap; 59 char *clrimap; 60 char *c_label; /* if non-NULL, we must see this tape label */ 61 ino_t maxino; 62 time_t dumptime; 63 time_t dumpdate; 64 FILE *terminal; 65 char *tmpdir; 66 char *pager_catenated; 67 char **pager_vector; 68 int pager_len; 69 int inattrspace = 0; 70 int savepwd; 71 int32_t tp_bsize = TP_BSIZE_MIN; 72 struct byteorder_ctx *byteorder; 73 74 static void set_tmpdir(void); 75 76 main(argc, argv) 77 int argc; 78 char *argv[]; 79 { 80 static struct arglist alist = { 0, 0, 0, 0, 0 }; 81 int count; 82 char *cp; 83 char *fname; 84 ino_t ino; 85 char *inputdev; 86 char *archivefile = 0; 87 char *symtbl = RESTORESYMTABLE; 88 char name[MAXPATHLEN]; 89 int fflag = 0; 90 struct sigaction sa, osa; 91 int multiplier; 92 char units; 93 94 if ((progname = strrchr(argv[0], '/')) != NULL) 95 progname++; 96 else 97 progname = argv[0]; 98 99 if (strcmp("hsmrestore", progname) == 0) { 100 (void) fprintf(stderr, 101 gettext("hsmrestore emulation is no longer supported.\n")); 102 done(1); 103 } 104 105 /* 106 * Convert the effective uid of 0 to the single privilege 107 * we really want. When running with all privileges, this 108 * is a no-op. When the set-uid bit is stripped restore 109 * still works for local tapes. Fail when trying to access 110 * a remote tape in that case and not immediately. 111 */ 112 (void) __init_suid_priv(0, PRIV_NET_PRIVADDR, (char *)NULL); 113 114 inputdev = DEFTAPE; 115 116 /* 117 * This doesn't work because ufsrestore is statically linked: 118 * (void) setlocale(LC_ALL, ""); 119 * The problem seems to be with LC_COLLATE, so set all the 120 * others explicitly. Bug 1157128 was created against the I18N 121 * library. When that bug is fixed this should go back to the way 122 * it was. 123 * XXX 1157128 was closed as a dup of 1099747. That bug was fixed by 124 * disallowing setlocale() to anything other than "C". "" is 125 * allowed, but only if none of the envars LC_ALL, LC_COLLATE, or LANG 126 * select anything other than "C". 127 */ 128 (void) setlocale(LC_CTYPE, ""); 129 (void) setlocale(LC_NUMERIC, ""); 130 (void) setlocale(LC_TIME, ""); 131 (void) setlocale(LC_MONETARY, ""); 132 (void) setlocale(LC_MESSAGES, ""); 133 #if !defined(TEXT_DOMAIN) 134 #define TEXT_DOMAIN "SYS_TEST" 135 #endif 136 (void) textdomain(TEXT_DOMAIN); 137 getwidth(&wp); 138 if ((byteorder = byteorder_create()) == NULL) { 139 (void) fprintf(stderr, 140 gettext("Cannot create byteorder context\n")); 141 done(1); 142 } 143 144 if ((savepwd = open(".", O_RDONLY)) < 0) { 145 (void) fprintf(stderr, 146 gettext("Cannot save current directory context\n")); 147 done(1); 148 } 149 150 set_tmpdir(); 151 152 autoload_period = 12; 153 autoload_tries = 12; /* traditional default of ~2.5 minutes */ 154 155 sa.sa_handler = onintr; 156 sa.sa_flags = SA_RESTART; 157 (void) sigemptyset(&sa.sa_mask); 158 159 (void) sigaction(SIGINT, &sa, &osa); 160 if (osa.sa_handler == SIG_IGN) 161 (void) sigaction(SIGINT, &osa, (struct sigaction *)0); 162 163 (void) sigaction(SIGTERM, &sa, &osa); 164 if (osa.sa_handler == SIG_IGN) 165 (void) sigaction(SIGTERM, &osa, (struct sigaction *)0); 166 if (argc < 2) { 167 usage: 168 (void) fprintf(stderr, gettext("Usage:\n\ 169 \t%s tabcdfhsvyLloT [file file ...]\n\ 170 \t%s xabcdfhmsvyLloT [file file ...]\n\ 171 \t%s iabcdfhmsvyLloT\n\ 172 \t%s rabcdfsvyLloT\n\ 173 \t%s RabcdfsvyLloT\n\n\ 174 a requires an archive file name\n\ 175 b requires a blocking factor\n\ 176 f requires a dump file\n\ 177 s requires a file number\n\ 178 L requires a tape label\n\ 179 If set, the envar TMPDIR selects where temporary files are kept\n"), 180 progname, progname, progname, progname, progname); 181 done(1); 182 } 183 184 argv++; /* the bag-of-options */ 185 argc -= 2; /* count of parameters to the options */ 186 command = '\0'; 187 c_label = (char *)NULL; /* any tape's acceptable */ 188 for (cp = *argv++; *cp; cp++) { 189 switch (*cp) { /* BE CAUTIOUS OF FALLTHROUGHS */ 190 case 'T': 191 if (argc < 1) { 192 (void) fprintf(stderr, gettext( 193 "Missing autoload timeout period\n")); 194 done(1); 195 } 196 197 count = atoi(*argv); 198 if (count < 1) { 199 (void) fprintf(stderr, gettext( 200 "Unreasonable autoload timeout period `%s'\n"), 201 *argv); 202 done(1); 203 } 204 units = *(*argv + strlen(*argv) - 1); 205 switch (units) { 206 case 's': 207 multiplier = 1; 208 break; 209 case 'h': 210 multiplier = 3600; 211 break; 212 case '0': case '1': case '2': case '3': case '4': 213 case '5': case '6': case '7': case '8': case '9': 214 case 'm': 215 multiplier = 60; 216 break; 217 default: 218 (void) fprintf(stderr, gettext( 219 "Unknown timeout units indicator `%c'\n"), 220 units); 221 done(1); 222 } 223 autoload_tries = 1 + 224 ((count * multiplier) / autoload_period); 225 argv++; 226 argc--; 227 break; 228 case 'l': 229 autoload++; 230 /*FALLTHROUGH*/ 231 case 'o': 232 offline++; 233 break; 234 case '-': 235 break; 236 case 'a': 237 if (argc < 1) { 238 (void) fprintf(stderr, 239 gettext("missing archive file name\n")); 240 done(1); 241 } 242 archivefile = *argv++; 243 if (*archivefile == '\0') { 244 (void) fprintf(stderr, 245 gettext("empty archive file name\n")); 246 done(1); 247 } 248 argc--; 249 break; 250 case 'c': 251 cvtflag++; 252 break; 253 case 'd': 254 dflag++; 255 break; 256 case 'D': 257 /* 258 * This used to be the Dflag, but it doesn't 259 * hurt to always check, so was removed. This 260 * case is here for backward compatability. 261 */ 262 break; 263 case 'h': 264 hflag = 0; 265 break; 266 case 'm': 267 mflag = 0; 268 break; 269 case 'v': 270 vflag++; 271 break; 272 case 'y': 273 yflag++; 274 break; 275 case 'f': 276 if (argc < 1) { 277 (void) fprintf(stderr, 278 gettext("missing device specifier\n")); 279 done(1); 280 } 281 inputdev = *argv++; 282 if (*inputdev == '\0') { 283 (void) fprintf(stderr, 284 gettext("empty device specifier\n")); 285 done(1); 286 } 287 fflag++; 288 argc--; 289 break; 290 case 'b': 291 /* 292 * change default tape blocksize 293 */ 294 bflag++; 295 if (argc < 1) { 296 (void) fprintf(stderr, 297 gettext("missing block size\n")); 298 done(1); 299 } 300 saved_ntrec = ntrec = atoi(*argv++); 301 if (ntrec == 0 || (ntrec&1)) { 302 (void) fprintf(stderr, gettext( 303 "Block size must be a positive, even integer\n")); 304 done(1); 305 } 306 ntrec /= (tp_bsize/DEV_BSIZE); 307 argc--; 308 break; 309 case 's': 310 /* 311 * dumpnum (skip to) for multifile dump tapes 312 */ 313 if (argc < 1) { 314 (void) fprintf(stderr, 315 gettext("missing dump number\n")); 316 done(1); 317 } 318 dumpnum = atoi(*argv++); 319 if (dumpnum <= 0) { 320 (void) fprintf(stderr, gettext( 321 "Dump number must be a positive integer\n")); 322 done(1); 323 } 324 argc--; 325 break; 326 case 't': 327 case 'R': 328 case 'r': 329 case 'x': 330 case 'i': 331 if (command != '\0') { 332 (void) fprintf(stderr, gettext( 333 "%c and %c are mutually exclusive\n"), 334 (uchar_t)*cp, (uchar_t)command); 335 goto usage; 336 } 337 command = *cp; 338 break; 339 case 'L': 340 if (argc < 1 || **argv == '\0') { 341 (void) fprintf(stderr, 342 gettext("Missing tape label name\n")); 343 done(1); 344 } 345 c_label = *argv++; /* must get tape with this label */ 346 if (strlen(c_label) > (sizeof (spcl.c_label) - 1)) { 347 c_label[sizeof (spcl.c_label) - 1] = '\0'; 348 (void) fprintf(stderr, gettext( 349 "Truncating label to maximum supported length: `%s'\n"), 350 c_label); 351 } 352 argc--; 353 break; 354 355 default: 356 (void) fprintf(stderr, 357 gettext("Bad key character %c\n"), (uchar_t)*cp); 358 goto usage; 359 } 360 } 361 if (command == '\0') { 362 (void) fprintf(stderr, 363 gettext("must specify i, t, r, R, or x\n")); 364 goto usage; 365 } 366 setinput(inputdev, archivefile); 367 if (argc == 0) { /* re-use last argv slot for default */ 368 argc = 1; 369 *--argv = mflag ? "." : "2"; 370 } 371 switch (command) { 372 373 /* 374 * Interactive mode. 375 */ 376 case 'i': 377 setup(); 378 extractdirs(1); 379 initsymtable((char *)0); 380 initpagercmd(); 381 runcmdshell(); 382 done(0); 383 /* NOTREACHED */ 384 /* 385 * Incremental restoration of a file system. 386 */ 387 case 'r': 388 setup(); 389 if (dumptime > 0) { 390 /* 391 * This is an incremental dump tape. 392 */ 393 vprintf(stdout, gettext("Begin incremental restore\n")); 394 initsymtable(symtbl); 395 extractdirs(1); 396 removeoldleaves(); 397 vprintf(stdout, gettext("Calculate node updates.\n")); 398 strcpy(name, "."); 399 name[2] = '\0'; 400 treescan(name, ROOTINO, nodeupdates); 401 attrscan(1, nodeupdates); 402 findunreflinks(); 403 removeoldnodes(); 404 } else { 405 /* 406 * This is a level zero dump tape. 407 */ 408 vprintf(stdout, gettext("Begin level 0 restore\n")); 409 initsymtable((char *)0); 410 extractdirs(1); 411 vprintf(stdout, 412 gettext("Calculate extraction list.\n")); 413 strcpy(name, "."); 414 name[2] = '\0'; 415 treescan(name, ROOTINO, nodeupdates); 416 attrscan(1, nodeupdates); 417 } 418 createleaves(symtbl); 419 createlinks(); 420 setdirmodes(); 421 checkrestore(); 422 if (dflag) { 423 vprintf(stdout, 424 gettext("Verify the directory structure\n")); 425 strcpy(name, "."); 426 name[2] = '\0'; 427 treescan(name, ROOTINO, verifyfile); 428 } 429 dumpsymtable(symtbl, (long)1); 430 done(0); 431 /* NOTREACHED */ 432 /* 433 * Resume an incremental file system restoration. 434 */ 435 case 'R': 436 setupR(); 437 initsymtable(symtbl); 438 skipmaps(); 439 skipdirs(); 440 createleaves(symtbl); 441 createlinks(); 442 setdirmodes(); 443 checkrestore(); 444 dumpsymtable(symtbl, (long)1); 445 done(0); 446 /* NOTREACHED */ 447 /* 448 * List contents of tape. 449 */ 450 case 't': 451 setup(); 452 extractdirs(0); 453 initsymtable((char *)0); 454 if (vflag) 455 printdumpinfo(); 456 while (argc--) { 457 canon(*argv++, name, sizeof (name)); 458 name[strlen(name)+1] = '\0'; 459 ino = dirlookup(name); 460 if (ino == 0) 461 continue; 462 treescan(name, ino, listfile); 463 } 464 done(0); 465 /* NOTREACHED */ 466 /* 467 * Batch extraction of tape contents. 468 */ 469 case 'x': 470 setup(); 471 extractdirs(1); 472 initsymtable((char *)0); 473 while (argc--) { 474 if (mflag) { 475 canon(*argv++, name, sizeof (name)); 476 if (expand(name, 0, &alist) == 0) { 477 /* no meta-characters to expand */ 478 ino = dirlookup(name); 479 if (ino == 0) 480 continue; 481 pathcheck(name); 482 } else { 483 /* add each of the expansions */ 484 while ((alist.last - alist.head) > 0) { 485 fname = alist.head->fname; 486 ino = dirlookup(fname); 487 if (ino != 0) { 488 pathcheck(fname); 489 treescan(fname, ino, 490 addfile); 491 } 492 freename(fname); 493 alist.head++; 494 } 495 alist.head = (struct afile *)NULL; 496 continue; /* argc loop */ 497 } 498 } else { 499 ino = (ino_t)atol(*argv); 500 if ((*(*argv++) == '-') || ino < ROOTINO) { 501 (void) fprintf(stderr, gettext( 502 "bad inode number: %ld\n"), 503 ino); 504 done(1); 505 } 506 name[0] = '\0'; 507 } 508 treescan(name, ino, addfile); 509 attrscan(0, addfile); 510 } 511 createfiles(); 512 createlinks(); 513 setdirmodes(); 514 if (dflag) 515 checkrestore(); 516 done(0); 517 /* NOTREACHED */ 518 } 519 #ifdef lint 520 return (0); 521 #endif 522 } 523 524 /* 525 * Determine where the user wants us to put our temporary files, 526 * and make sure we can actually do so. Bail out if there's a problem. 527 */ 528 void 529 set_tmpdir(void) 530 { 531 int fd; 532 char name[MAXPATHLEN]; 533 534 tmpdir = getenv("TMPDIR"); 535 if ((tmpdir == (char *)NULL) || (*tmpdir == '\0')) 536 tmpdir = "/tmp"; 537 538 if (*tmpdir != '/') { 539 (void) fprintf(stderr, 540 gettext("TMPDIR is not an absolute path (`%s').\n"), 541 tmpdir); 542 done(1); 543 } 544 545 /* 546 * The actual use of tmpdir is in dirs.c, and is of the form 547 * tmpdir + "/rst" + type (three characters) + "%ld.XXXXXX" + 548 * a trailing NUL, where %ld is an arbitrary time_t. 549 * 550 * Thus, the magic 31 is strlen(itoa(MAX_TIME_T)) + "/rst" + 551 * ".XXXXXX" + '\0'. A time_t is 64 bits, so MAX_TIME_T is 552 * LONG_MAX - nineteen digits. In theory, so many things in 553 * ufsrestore will break once time_t's value goes beyond 32 554 * bits that it's not worth worrying about this particular 555 * instance at this time, but we've got to start somewhere. 556 * 557 * Note that the use of a pid below is just for testing the 558 * validity of the named directory. 559 */ 560 if (strlen(tmpdir) > (MAXPATHLEN - 31)) { 561 (void) fprintf(stderr, gettext("TMPDIR too long\n")); 562 done(1); 563 } 564 565 /* Guaranteed to fit by above test (sizeof(time_t) >= sizeof(pid_t)) */ 566 (void) snprintf(name, sizeof (name), "%s/rstdir.%ld", tmpdir, getpid()); 567 568 /* 569 * This is effectively a stripped-down version of safe_open(), 570 * because if the file exists, we want to fail. 571 */ 572 fd = open(name, O_CREAT|O_EXCL|O_RDWR, 0600); 573 if (fd < 0) { 574 perror(gettext("Can not create temporary file")); 575 done(1); 576 } 577 578 (void) close(fd); 579 if (unlink(name) < 0) { 580 perror(gettext("Can not delete temporary file")); 581 done(1); 582 } 583 } 584