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