1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)utilities.c 8.5 (Berkeley) 4/28/95 34 * $FreeBSD: src/sbin/restore/utilities.c,v 1.8.2.2 2001/07/30 10:30:08 dd Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/stat.h> 39 40 #include <vfs/ufs/dinode.h> 41 #include <vfs/ufs/dir.h> 42 43 #include <errno.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "restore.h" 50 #include "extern.h" 51 52 /* 53 * Insure that all the components of a pathname exist. 54 */ 55 void 56 pathcheck(char *name) 57 { 58 char *cp; 59 struct entry *ep; 60 char *start; 61 62 start = strchr(name, '/'); 63 if (start == NULL) 64 return; 65 for (cp = start; *cp != '\0'; cp++) { 66 if (*cp != '/') 67 continue; 68 *cp = '\0'; 69 ep = lookupname(name); 70 if (ep == NULL) { 71 /* Safe; we know the pathname exists in the dump. */ 72 ep = addentry(name, pathsearch(name)->d_ino, NODE); 73 newnode(ep); 74 } 75 ep->e_flags |= NEW|KEEP; 76 *cp = '/'; 77 } 78 } 79 80 /* 81 * Change a name to a unique temporary name. 82 */ 83 void 84 mktempname(struct entry *ep) 85 { 86 char oldname[MAXPATHLEN]; 87 88 if (ep->e_flags & TMPNAME) 89 badentry(ep, "mktempname: called with TMPNAME"); 90 ep->e_flags |= TMPNAME; 91 strcpy(oldname, myname(ep)); 92 freename(ep->e_name); 93 ep->e_name = savename(gentempname(ep)); 94 ep->e_namlen = strlen(ep->e_name); 95 renameit(oldname, myname(ep)); 96 } 97 98 /* 99 * Generate a temporary name for an entry. 100 */ 101 char * 102 gentempname(struct entry *ep) 103 { 104 static char name[MAXPATHLEN]; 105 struct entry *np; 106 long i = 0; 107 108 for (np = lookupino(ep->e_ino); 109 np != NULL && np != ep; np = np->e_links) 110 i++; 111 if (np == NULL) 112 badentry(ep, "not on ino list"); 113 sprintf(name, "%s%ld%lu", TMPHDR, i, (u_long)ep->e_ino); 114 return (name); 115 } 116 117 /* 118 * Rename a file or directory. 119 */ 120 void 121 renameit(char *from, char *to) 122 { 123 if (!Nflag && rename(from, to) < 0) { 124 fprintf(stderr, "warning: cannot rename %s to %s: %s\n", 125 from, to, strerror(errno)); 126 return; 127 } 128 vprintf(stdout, "rename %s to %s\n", from, to); 129 } 130 131 /* 132 * Create a new node (directory). 133 */ 134 void 135 newnode(struct entry *np) 136 { 137 char *cp; 138 139 if (np->e_type != NODE) 140 badentry(np, "newnode: not a node"); 141 cp = myname(np); 142 if (!Nflag && mkdir(cp, 0777) < 0 && !uflag) { 143 np->e_flags |= EXISTED; 144 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 145 return; 146 } 147 vprintf(stdout, "Make node %s\n", cp); 148 } 149 150 /* 151 * Remove an old node (directory). 152 */ 153 void 154 removenode(struct entry *ep) 155 { 156 char *cp; 157 158 if (ep->e_type != NODE) 159 badentry(ep, "removenode: not a node"); 160 if (ep->e_entries != NULL) 161 badentry(ep, "removenode: non-empty directory"); 162 ep->e_flags |= REMOVED; 163 ep->e_flags &= ~TMPNAME; 164 cp = myname(ep); 165 if (!Nflag && rmdir(cp) < 0) { 166 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 167 return; 168 } 169 vprintf(stdout, "Remove node %s\n", cp); 170 } 171 172 /* 173 * Remove a leaf. 174 */ 175 void 176 removeleaf(struct entry *ep) 177 { 178 char *cp; 179 180 if (ep->e_type != LEAF) 181 badentry(ep, "removeleaf: not a leaf"); 182 ep->e_flags |= REMOVED; 183 ep->e_flags &= ~TMPNAME; 184 cp = myname(ep); 185 if (!Nflag && unlink(cp) < 0) { 186 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 187 return; 188 } 189 vprintf(stdout, "Remove leaf %s\n", cp); 190 } 191 192 /* 193 * Create a link. 194 */ 195 int 196 linkit(char *existing, char *new, int type) 197 { 198 199 /* if we want to unlink first, do it now so *link() won't fail */ 200 if (uflag && !Nflag) 201 unlink(new); 202 203 if (type == SYMLINK) { 204 if (!Nflag && symlink(existing, new) < 0) { 205 fprintf(stderr, 206 "warning: cannot create symbolic link %s->%s: %s\n", 207 new, existing, strerror(errno)); 208 return (FAIL); 209 } 210 } else if (type == HARDLINK) { 211 int ret; 212 213 if (!Nflag && (ret = link(existing, new)) < 0) { 214 struct stat s; 215 216 /* 217 * Most likely, the schg flag is set. Clear the 218 * flags and try again. 219 */ 220 if (stat(existing, &s) == 0 && s.st_flags != 0 && 221 chflags(existing, 0) == 0) { 222 ret = link(existing, new); 223 chflags(existing, s.st_flags); 224 } 225 if (ret < 0) { 226 fprintf(stderr, "warning: cannot create " 227 "hard link %s->%s: %s\n", 228 new, existing, strerror(errno)); 229 return (FAIL); 230 } 231 } 232 } else { 233 panic("linkit: unknown type %d\n", type); 234 return (FAIL); 235 } 236 vprintf(stdout, "Create %s link %s->%s\n", 237 type == SYMLINK ? "symbolic" : "hard", new, existing); 238 return (GOOD); 239 } 240 241 /* 242 * Create a whiteout. 243 */ 244 int 245 addwhiteout(char *name) 246 { 247 248 if (!Nflag && mknod(name, S_IFWHT, 0) < 0) { 249 fprintf(stderr, "warning: cannot create whiteout %s: %s\n", 250 name, strerror(errno)); 251 return (FAIL); 252 } 253 vprintf(stdout, "Create whiteout %s\n", name); 254 return (GOOD); 255 } 256 257 /* 258 * Delete a whiteout. 259 */ 260 void 261 delwhiteout(struct entry *ep) 262 { 263 char *name; 264 265 if (ep->e_type != LEAF) 266 badentry(ep, "delwhiteout: not a leaf"); 267 ep->e_flags |= REMOVED; 268 ep->e_flags &= ~TMPNAME; 269 name = myname(ep); 270 if (!Nflag && undelete(name) < 0) { 271 fprintf(stderr, "warning: cannot delete whiteout %s: %s\n", 272 name, strerror(errno)); 273 return; 274 } 275 vprintf(stdout, "Delete whiteout %s\n", name); 276 } 277 278 /* 279 * find lowest number file (above "start") that needs to be extracted 280 */ 281 ufs1_ino_t 282 lowerbnd(ufs1_ino_t start) 283 { 284 struct entry *ep; 285 286 for ( ; start < maxino; start++) { 287 ep = lookupino(start); 288 if (ep == NULL || ep->e_type == NODE) 289 continue; 290 if (ep->e_flags & (NEW|EXTRACT)) 291 return (start); 292 } 293 return (start); 294 } 295 296 /* 297 * find highest number file (below "start") that needs to be extracted 298 */ 299 ufs1_ino_t 300 upperbnd(ufs1_ino_t start) 301 { 302 struct entry *ep; 303 304 for ( ; start > ROOTINO; start--) { 305 ep = lookupino(start); 306 if (ep == NULL || ep->e_type == NODE) 307 continue; 308 if (ep->e_flags & (NEW|EXTRACT)) 309 return (start); 310 } 311 return (start); 312 } 313 314 /* 315 * report on a badly formed entry 316 */ 317 void 318 badentry(struct entry *ep, char *msg) 319 { 320 321 fprintf(stderr, "bad entry: %s\n", msg); 322 fprintf(stderr, "name: %s\n", myname(ep)); 323 fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 324 if (ep->e_sibling != NULL) 325 fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 326 if (ep->e_entries != NULL) 327 fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 328 if (ep->e_links != NULL) 329 fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 330 if (ep->e_next != NULL) 331 fprintf(stderr, 332 "next hashchain name: %s\n", myname(ep->e_next)); 333 fprintf(stderr, "entry type: %s\n", 334 ep->e_type == NODE ? "NODE" : "LEAF"); 335 fprintf(stderr, "inode number: %lu\n", (u_long)ep->e_ino); 336 panic("flags: %s\n", flagvalues(ep)); 337 } 338 339 /* 340 * Construct a string indicating the active flag bits of an entry. 341 */ 342 char * 343 flagvalues(struct entry *ep) 344 { 345 static char flagbuf[BUFSIZ]; 346 347 strcpy(flagbuf, "|NIL"); 348 flagbuf[0] = '\0'; 349 if (ep->e_flags & REMOVED) 350 strcat(flagbuf, "|REMOVED"); 351 if (ep->e_flags & TMPNAME) 352 strcat(flagbuf, "|TMPNAME"); 353 if (ep->e_flags & EXTRACT) 354 strcat(flagbuf, "|EXTRACT"); 355 if (ep->e_flags & NEW) 356 strcat(flagbuf, "|NEW"); 357 if (ep->e_flags & KEEP) 358 strcat(flagbuf, "|KEEP"); 359 if (ep->e_flags & EXISTED) 360 strcat(flagbuf, "|EXISTED"); 361 return (&flagbuf[1]); 362 } 363 364 /* 365 * Check to see if a name is on a dump tape. 366 */ 367 ufs1_ino_t 368 dirlookup(const char *name) 369 { 370 struct direct *dp; 371 ufs1_ino_t ino; 372 373 ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino; 374 375 if (ino == 0 || TSTINO(ino, dumpmap) == 0) 376 fprintf(stderr, "%s is not on the tape\n", name); 377 return (ino); 378 } 379 380 /* 381 * Elicit a reply. 382 */ 383 int 384 reply(char *question) 385 { 386 int c; 387 388 do { 389 fprintf(stderr, "%s? [yn] ", question); 390 fflush(stderr); 391 c = getc(terminal); 392 while (c != '\n' && getc(terminal) != '\n') 393 if (c == EOF) 394 return (FAIL); 395 } while (c != 'y' && c != 'n'); 396 if (c == 'y') 397 return (GOOD); 398 return (FAIL); 399 } 400 401 /* 402 * handle unexpected inconsistencies 403 */ 404 #include <stdarg.h> 405 406 void 407 panic(const char *fmt, ...) 408 { 409 va_list ap; 410 411 va_start(ap, fmt); 412 vfprintf(stderr, fmt, ap); 413 if (yflag) 414 return; 415 if (reply("abort") == GOOD) { 416 if (reply("dump core") == GOOD) 417 abort(); 418 done(1); 419 } 420 } 421