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