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