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