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