1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 04/28/95"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/stat.h> 14 15 #include <ufs/ufs/dinode.h> 16 #include <ufs/ufs/dir.h> 17 18 #include <errno.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <unistd.h> 23 24 #include "restore.h" 25 #include "extern.h" 26 27 /* 28 * Insure that all the components of a pathname exist. 29 */ 30 void 31 pathcheck(name) 32 char *name; 33 { 34 register char *cp; 35 struct entry *ep; 36 char *start; 37 38 start = strchr(name, '/'); 39 if (start == 0) 40 return; 41 for (cp = start; *cp != '\0'; cp++) { 42 if (*cp != '/') 43 continue; 44 *cp = '\0'; 45 ep = lookupname(name); 46 if (ep == NULL) { 47 /* Safe; we know the pathname exists in the dump. */ 48 ep = addentry(name, pathsearch(name)->d_ino, NODE); 49 newnode(ep); 50 } 51 ep->e_flags |= NEW|KEEP; 52 *cp = '/'; 53 } 54 } 55 56 /* 57 * Change a name to a unique temporary name. 58 */ 59 void 60 mktempname(ep) 61 register struct entry *ep; 62 { 63 char oldname[MAXPATHLEN]; 64 65 if (ep->e_flags & TMPNAME) 66 badentry(ep, "mktempname: called with TMPNAME"); 67 ep->e_flags |= TMPNAME; 68 (void) strcpy(oldname, myname(ep)); 69 freename(ep->e_name); 70 ep->e_name = savename(gentempname(ep)); 71 ep->e_namlen = strlen(ep->e_name); 72 renameit(oldname, myname(ep)); 73 } 74 75 /* 76 * Generate a temporary name for an entry. 77 */ 78 char * 79 gentempname(ep) 80 struct entry *ep; 81 { 82 static char name[MAXPATHLEN]; 83 struct entry *np; 84 long i = 0; 85 86 for (np = lookupino(ep->e_ino); 87 np != NULL && np != ep; np = np->e_links) 88 i++; 89 if (np == NULL) 90 badentry(ep, "not on ino list"); 91 (void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino); 92 return (name); 93 } 94 95 /* 96 * Rename a file or directory. 97 */ 98 void 99 renameit(from, to) 100 char *from, *to; 101 { 102 if (!Nflag && rename(from, to) < 0) { 103 fprintf(stderr, "warning: cannot rename %s to %s: %s\n", 104 from, to, strerror(errno)); 105 return; 106 } 107 vprintf(stdout, "rename %s to %s\n", from, to); 108 } 109 110 /* 111 * Create a new node (directory). 112 */ 113 void 114 newnode(np) 115 struct entry *np; 116 { 117 char *cp; 118 119 if (np->e_type != NODE) 120 badentry(np, "newnode: not a node"); 121 cp = myname(np); 122 if (!Nflag && mkdir(cp, 0777) < 0) { 123 np->e_flags |= EXISTED; 124 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 125 return; 126 } 127 vprintf(stdout, "Make node %s\n", cp); 128 } 129 130 /* 131 * Remove an old node (directory). 132 */ 133 void 134 removenode(ep) 135 register struct entry *ep; 136 { 137 char *cp; 138 139 if (ep->e_type != NODE) 140 badentry(ep, "removenode: not a node"); 141 if (ep->e_entries != NULL) 142 badentry(ep, "removenode: non-empty directory"); 143 ep->e_flags |= REMOVED; 144 ep->e_flags &= ~TMPNAME; 145 cp = myname(ep); 146 if (!Nflag && rmdir(cp) < 0) { 147 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 148 return; 149 } 150 vprintf(stdout, "Remove node %s\n", cp); 151 } 152 153 /* 154 * Remove a leaf. 155 */ 156 void 157 removeleaf(ep) 158 register struct entry *ep; 159 { 160 char *cp; 161 162 if (ep->e_type != LEAF) 163 badentry(ep, "removeleaf: not a leaf"); 164 ep->e_flags |= REMOVED; 165 ep->e_flags &= ~TMPNAME; 166 cp = myname(ep); 167 if (!Nflag && unlink(cp) < 0) { 168 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 169 return; 170 } 171 vprintf(stdout, "Remove leaf %s\n", cp); 172 } 173 174 /* 175 * Create a link. 176 */ 177 int 178 linkit(existing, new, type) 179 char *existing, *new; 180 int type; 181 { 182 183 if (type == SYMLINK) { 184 if (!Nflag && symlink(existing, new) < 0) { 185 fprintf(stderr, 186 "warning: cannot create symbolic link %s->%s: %s\n", 187 new, existing, strerror(errno)); 188 return (FAIL); 189 } 190 } else if (type == HARDLINK) { 191 if (!Nflag && link(existing, new) < 0) { 192 fprintf(stderr, 193 "warning: cannot create hard link %s->%s: %s\n", 194 new, existing, strerror(errno)); 195 return (FAIL); 196 } 197 } else { 198 panic("linkit: unknown type %d\n", type); 199 return (FAIL); 200 } 201 vprintf(stdout, "Create %s link %s->%s\n", 202 type == SYMLINK ? "symbolic" : "hard", new, existing); 203 return (GOOD); 204 } 205 206 /* 207 * Create a whiteout. 208 */ 209 int 210 addwhiteout(name) 211 char *name; 212 { 213 214 if (!Nflag && mknod(name, S_IFWHT, 0) < 0) { 215 fprintf(stderr, "warning: cannot create whiteout %s: %s\n", 216 name, strerror(errno)); 217 return (FAIL); 218 } 219 vprintf(stdout, "Create whiteout %s\n", name); 220 return (GOOD); 221 } 222 223 /* 224 * Delete a whiteout. 225 */ 226 void 227 delwhiteout(ep) 228 register struct entry *ep; 229 { 230 char *name; 231 232 if (ep->e_type != LEAF) 233 badentry(ep, "delwhiteout: not a leaf"); 234 ep->e_flags |= REMOVED; 235 ep->e_flags &= ~TMPNAME; 236 name = myname(ep); 237 if (!Nflag && undelete(name) < 0) { 238 fprintf(stderr, "warning: cannot delete whiteout %s: %s\n", 239 name, strerror(errno)); 240 return; 241 } 242 vprintf(stdout, "Delete whiteout %s\n", name); 243 } 244 245 /* 246 * find lowest number file (above "start") that needs to be extracted 247 */ 248 ino_t 249 lowerbnd(start) 250 ino_t start; 251 { 252 register struct entry *ep; 253 254 for ( ; start < maxino; start++) { 255 ep = lookupino(start); 256 if (ep == NULL || ep->e_type == NODE) 257 continue; 258 if (ep->e_flags & (NEW|EXTRACT)) 259 return (start); 260 } 261 return (start); 262 } 263 264 /* 265 * find highest number file (below "start") that needs to be extracted 266 */ 267 ino_t 268 upperbnd(start) 269 ino_t start; 270 { 271 register struct entry *ep; 272 273 for ( ; start > ROOTINO; start--) { 274 ep = lookupino(start); 275 if (ep == NULL || ep->e_type == NODE) 276 continue; 277 if (ep->e_flags & (NEW|EXTRACT)) 278 return (start); 279 } 280 return (start); 281 } 282 283 /* 284 * report on a badly formed entry 285 */ 286 void 287 badentry(ep, msg) 288 register struct entry *ep; 289 char *msg; 290 { 291 292 fprintf(stderr, "bad entry: %s\n", msg); 293 fprintf(stderr, "name: %s\n", myname(ep)); 294 fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 295 if (ep->e_sibling != NULL) 296 fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 297 if (ep->e_entries != NULL) 298 fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 299 if (ep->e_links != NULL) 300 fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 301 if (ep->e_next != NULL) 302 fprintf(stderr, 303 "next hashchain name: %s\n", myname(ep->e_next)); 304 fprintf(stderr, "entry type: %s\n", 305 ep->e_type == NODE ? "NODE" : "LEAF"); 306 fprintf(stderr, "inode number: %ld\n", ep->e_ino); 307 panic("flags: %s\n", flagvalues(ep)); 308 } 309 310 /* 311 * Construct a string indicating the active flag bits of an entry. 312 */ 313 char * 314 flagvalues(ep) 315 register struct entry *ep; 316 { 317 static char flagbuf[BUFSIZ]; 318 319 (void) strcpy(flagbuf, "|NIL"); 320 flagbuf[0] = '\0'; 321 if (ep->e_flags & REMOVED) 322 (void) strcat(flagbuf, "|REMOVED"); 323 if (ep->e_flags & TMPNAME) 324 (void) strcat(flagbuf, "|TMPNAME"); 325 if (ep->e_flags & EXTRACT) 326 (void) strcat(flagbuf, "|EXTRACT"); 327 if (ep->e_flags & NEW) 328 (void) strcat(flagbuf, "|NEW"); 329 if (ep->e_flags & KEEP) 330 (void) strcat(flagbuf, "|KEEP"); 331 if (ep->e_flags & EXISTED) 332 (void) strcat(flagbuf, "|EXISTED"); 333 return (&flagbuf[1]); 334 } 335 336 /* 337 * Check to see if a name is on a dump tape. 338 */ 339 ino_t 340 dirlookup(name) 341 const char *name; 342 { 343 struct direct *dp; 344 ino_t ino; 345 346 ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino; 347 348 if (ino == 0 || TSTINO(ino, dumpmap) == 0) 349 fprintf(stderr, "%s is not on the tape\n", name); 350 return (ino); 351 } 352 353 /* 354 * Elicit a reply. 355 */ 356 int 357 reply(question) 358 char *question; 359 { 360 char c; 361 362 do { 363 fprintf(stderr, "%s? [yn] ", question); 364 (void) fflush(stderr); 365 c = getc(terminal); 366 while (c != '\n' && getc(terminal) != '\n') 367 if (feof(terminal)) 368 return (FAIL); 369 } while (c != 'y' && c != 'n'); 370 if (c == 'y') 371 return (GOOD); 372 return (FAIL); 373 } 374 375 /* 376 * handle unexpected inconsistencies 377 */ 378 #if __STDC__ 379 #include <stdarg.h> 380 #else 381 #include <varargs.h> 382 #endif 383 384 void 385 #if __STDC__ 386 panic(const char *fmt, ...) 387 #else 388 panic(fmt, va_alist) 389 char *fmt; 390 va_dcl 391 #endif 392 { 393 va_list ap; 394 #if __STDC__ 395 va_start(ap, fmt); 396 #else 397 va_start(ap); 398 #endif 399 400 vfprintf(stderr, fmt, ap); 401 if (yflag) 402 return; 403 if (reply("abort") == GOOD) { 404 if (reply("dump core") == GOOD) 405 abort(); 406 done(1); 407 } 408 } 409