1 /* $OpenBSD: main.c,v 1.25 2016/07/28 21:37:10 tedu Exp $ */ 2 /* $NetBSD: main.c,v 1.13 1997/07/01 05:37:51 lukem Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/stat.h> 34 #include <sys/time.h> 35 36 #include <ufs/ffs/fs.h> 37 #include <ufs/ufs/dinode.h> 38 #include <protocols/dumprestore.h> 39 40 #include <err.h> 41 #include <paths.h> 42 #include <signal.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include <limits.h> 48 49 #include "restore.h" 50 #include "extern.h" 51 52 int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0; 53 int hflag = 1, mflag = 1, Nflag = 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 char *tmpdir; 65 66 static void obsolete(int *, char **[]); 67 static void usage(void); 68 69 int 70 main(int argc, char *argv[]) 71 { 72 int ch; 73 ino_t ino; 74 char *inputdev; 75 char *symtbl = "./restoresymtable"; 76 char *p, name[PATH_MAX]; 77 78 /* Temp files should *not* be readable. We set permissions later. */ 79 (void)umask(077); 80 81 if (argc < 2) 82 usage(); 83 84 if ((inputdev = getenv("TAPE")) == NULL || *inputdev == '\0') 85 inputdev = _PATH_DEFTAPE; 86 if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') 87 tmpdir = _PATH_TMP; 88 if ((tmpdir = strdup(tmpdir)) == NULL) 89 err(1, NULL); 90 for (p = tmpdir + strlen(tmpdir) - 1; p >= tmpdir && *p == '/'; p--) 91 continue; 92 obsolete(&argc, &argv); 93 while ((ch = getopt(argc, argv, "b:cdf:himNRrs:tvxy")) != -1) 94 switch(ch) { 95 case 'b': 96 /* Change default tape blocksize. */ 97 bflag = 1; 98 ntrec = strtol(optarg, &p, 10); 99 if (*p) 100 errx(1, "illegal blocksize -- %s", optarg); 101 if (ntrec <= 0) 102 errx(1, "block size must be greater than 0"); 103 break; 104 case 'c': 105 cvtflag = 1; 106 break; 107 case 'd': 108 dflag = 1; 109 break; 110 case 'f': 111 inputdev = optarg; 112 break; 113 case 'h': 114 hflag = 0; 115 break; 116 case 'i': 117 case 'R': 118 case 'r': 119 case 't': 120 case 'x': 121 if (command != '\0') 122 errx(1, 123 "%c and %c options are mutually exclusive", 124 ch, command); 125 command = ch; 126 break; 127 case 'm': 128 mflag = 0; 129 break; 130 case 'N': 131 Nflag = 1; 132 break; 133 case 's': 134 /* Dumpnum (skip to) for multifile dump tapes. */ 135 dumpnum = strtol(optarg, &p, 10); 136 if (*p) 137 errx(1, "illegal dump number -- %s", optarg); 138 if (dumpnum <= 0) 139 errx(1, "dump number must be greater than 0"); 140 break; 141 case 'v': 142 vflag = 1; 143 break; 144 case 'y': 145 yflag = 1; 146 break; 147 default: 148 usage(); 149 } 150 argc -= optind; 151 argv += optind; 152 153 if (command == '\0') 154 errx(1, "none of i, R, r, t or x options specified"); 155 156 if (signal(SIGINT, onintr) == SIG_IGN) 157 (void)signal(SIGINT, SIG_IGN); 158 if (signal(SIGTERM, onintr) == SIG_IGN) 159 (void)signal(SIGTERM, SIG_IGN); 160 setvbuf(stderr, NULL, _IOLBF, 0); 161 162 atexit(cleanup); 163 164 setinput(inputdev); 165 166 if (argc == 0) { 167 argc = 1; 168 *--argv = "."; 169 } 170 171 switch (command) { 172 /* 173 * Interactive mode. 174 */ 175 case 'i': 176 setup(); 177 extractdirs(1); 178 initsymtable(NULL); 179 runcmdshell(); 180 break; 181 /* 182 * Incremental restoration of a file system. 183 */ 184 case 'r': 185 setup(); 186 if (dumptime > 0) { 187 /* 188 * This is an incremental dump tape. 189 */ 190 Vprintf(stdout, "Begin incremental restore\n"); 191 initsymtable(symtbl); 192 extractdirs(1); 193 removeoldleaves(); 194 Vprintf(stdout, "Calculate node updates.\n"); 195 treescan(".", ROOTINO, nodeupdates); 196 findunreflinks(); 197 removeoldnodes(); 198 } else { 199 /* 200 * This is a level zero dump tape. 201 */ 202 Vprintf(stdout, "Begin level 0 restore\n"); 203 initsymtable(NULL); 204 extractdirs(1); 205 Vprintf(stdout, "Calculate extraction list.\n"); 206 treescan(".", ROOTINO, nodeupdates); 207 } 208 createleaves(symtbl); 209 createlinks(); 210 setdirmodes(FORCE); 211 checkrestore(); 212 if (dflag) { 213 Vprintf(stdout, "Verify the directory structure\n"); 214 treescan(".", ROOTINO, verifyfile); 215 } 216 dumpsymtable(symtbl, (long)1); 217 break; 218 /* 219 * Resume an incremental file system restoration. 220 */ 221 case 'R': 222 initsymtable(symtbl); 223 skipmaps(); 224 skipdirs(); 225 createleaves(symtbl); 226 createlinks(); 227 setdirmodes(FORCE); 228 checkrestore(); 229 dumpsymtable(symtbl, (long)1); 230 break; 231 /* 232 * List contents of tape. 233 */ 234 case 't': 235 setup(); 236 extractdirs(0); 237 initsymtable(NULL); 238 while (argc--) { 239 canon(*argv++, name, sizeof name); 240 ino = dirlookup(name); 241 if (ino == 0) 242 continue; 243 treescan(name, ino, listfile); 244 } 245 break; 246 /* 247 * Batch extraction of tape contents. 248 */ 249 case 'x': 250 setup(); 251 extractdirs(1); 252 initsymtable(NULL); 253 while (argc--) { 254 canon(*argv++, name, sizeof name); 255 ino = dirlookup(name); 256 if (ino == 0) 257 continue; 258 if (mflag) 259 pathcheck(name); 260 treescan(name, ino, addfile); 261 } 262 createfiles(); 263 createlinks(); 264 setdirmodes(0); 265 if (dflag) 266 checkrestore(); 267 break; 268 } 269 return (0); 270 } 271 272 static void 273 usage(void) 274 { 275 276 (void)fprintf(stderr, "usage: %s [-chimRrtvxy] [-b blocksize] [-f file] [-s fileno] [file ...]\n", __progname); 277 exit(1); 278 } 279 280 /* 281 * obsolete -- 282 * Change set of key letters and ordered arguments into something 283 * getopt(3) will like. 284 */ 285 static void 286 obsolete(int *argcp, char **argvp[]) 287 { 288 int argc, flags; 289 char *ap, **argv, *flagsp, **nargv, *p; 290 size_t len; 291 292 /* Setup. */ 293 argv = *argvp; 294 argc = *argcp; 295 296 /* Return if no arguments or first argument has leading dash. */ 297 ap = argv[1]; 298 if (argc == 1 || *ap == '-') 299 return; 300 301 /* Allocate space for new arguments. */ 302 if ((*argvp = nargv = calloc(argc + 1, sizeof(char *))) == NULL || 303 (p = flagsp = malloc(strlen(ap) + 2)) == NULL) 304 err(1, NULL); 305 306 *nargv++ = *argv; 307 argv += 2; 308 309 for (flags = 0; *ap; ++ap) { 310 switch (*ap) { 311 case 'b': 312 case 'f': 313 case 's': 314 if (*argv == NULL) { 315 warnx("option requires an argument -- %c", *ap); 316 usage(); 317 } 318 len = strlen(*argv) + 2 + 1; 319 if ((nargv[0] = malloc(len)) == NULL) 320 err(1, NULL); 321 nargv[0][0] = '-'; 322 nargv[0][1] = *ap; 323 (void)strlcpy(&nargv[0][2], *argv, len-2); 324 ++argv; 325 ++nargv; 326 break; 327 default: 328 if (!flags) { 329 *p++ = '-'; 330 flags = 1; 331 } 332 *p++ = *ap; 333 break; 334 } 335 } 336 337 /* Terminate flags. */ 338 if (flags) { 339 *p = '\0'; 340 *nargv++ = flagsp; 341 } else { 342 free(flagsp); 343 } 344 345 /* Copy remaining arguments. */ 346 while ((*nargv++ = *argv++)) 347 continue; 348 349 /* Update argument count. */ 350 *argcp = nargv - *argvp - 1; 351 } 352