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.2 (Berkeley) 03/25/94"; 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 = index(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 * find lowest number file (above "start") that needs to be extracted 208 */ 209 ino_t 210 lowerbnd(start) 211 ino_t start; 212 { 213 register struct entry *ep; 214 215 for ( ; start < maxino; start++) { 216 ep = lookupino(start); 217 if (ep == NULL || ep->e_type == NODE) 218 continue; 219 if (ep->e_flags & (NEW|EXTRACT)) 220 return (start); 221 } 222 return (start); 223 } 224 225 /* 226 * find highest number file (below "start") that needs to be extracted 227 */ 228 ino_t 229 upperbnd(start) 230 ino_t start; 231 { 232 register struct entry *ep; 233 234 for ( ; start > ROOTINO; start--) { 235 ep = lookupino(start); 236 if (ep == NULL || ep->e_type == NODE) 237 continue; 238 if (ep->e_flags & (NEW|EXTRACT)) 239 return (start); 240 } 241 return (start); 242 } 243 244 /* 245 * report on a badly formed entry 246 */ 247 void 248 badentry(ep, msg) 249 register struct entry *ep; 250 char *msg; 251 { 252 253 fprintf(stderr, "bad entry: %s\n", msg); 254 fprintf(stderr, "name: %s\n", myname(ep)); 255 fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 256 if (ep->e_sibling != NULL) 257 fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 258 if (ep->e_entries != NULL) 259 fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 260 if (ep->e_links != NULL) 261 fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 262 if (ep->e_next != NULL) 263 fprintf(stderr, 264 "next hashchain name: %s\n", myname(ep->e_next)); 265 fprintf(stderr, "entry type: %s\n", 266 ep->e_type == NODE ? "NODE" : "LEAF"); 267 fprintf(stderr, "inode number: %ld\n", ep->e_ino); 268 panic("flags: %s\n", flagvalues(ep)); 269 } 270 271 /* 272 * Construct a string indicating the active flag bits of an entry. 273 */ 274 char * 275 flagvalues(ep) 276 register struct entry *ep; 277 { 278 static char flagbuf[BUFSIZ]; 279 280 (void) strcpy(flagbuf, "|NIL"); 281 flagbuf[0] = '\0'; 282 if (ep->e_flags & REMOVED) 283 (void) strcat(flagbuf, "|REMOVED"); 284 if (ep->e_flags & TMPNAME) 285 (void) strcat(flagbuf, "|TMPNAME"); 286 if (ep->e_flags & EXTRACT) 287 (void) strcat(flagbuf, "|EXTRACT"); 288 if (ep->e_flags & NEW) 289 (void) strcat(flagbuf, "|NEW"); 290 if (ep->e_flags & KEEP) 291 (void) strcat(flagbuf, "|KEEP"); 292 if (ep->e_flags & EXISTED) 293 (void) strcat(flagbuf, "|EXISTED"); 294 return (&flagbuf[1]); 295 } 296 297 /* 298 * Check to see if a name is on a dump tape. 299 */ 300 ino_t 301 dirlookup(name) 302 const char *name; 303 { 304 struct direct *dp; 305 ino_t ino; 306 307 ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino; 308 309 if (ino == 0 || TSTINO(ino, dumpmap) == 0) 310 fprintf(stderr, "%s is not on the tape\n", name); 311 return (ino); 312 } 313 314 /* 315 * Elicit a reply. 316 */ 317 int 318 reply(question) 319 char *question; 320 { 321 char c; 322 323 do { 324 fprintf(stderr, "%s? [yn] ", question); 325 (void) fflush(stderr); 326 c = getc(terminal); 327 while (c != '\n' && getc(terminal) != '\n') 328 if (feof(terminal)) 329 return (FAIL); 330 } while (c != 'y' && c != 'n'); 331 if (c == 'y') 332 return (GOOD); 333 return (FAIL); 334 } 335 336 /* 337 * handle unexpected inconsistencies 338 */ 339 #if __STDC__ 340 #include <stdarg.h> 341 #else 342 #include <varargs.h> 343 #endif 344 345 void 346 #if __STDC__ 347 panic(const char *fmt, ...) 348 #else 349 panic(fmt, va_alist) 350 char *fmt; 351 va_dcl 352 #endif 353 { 354 va_list ap; 355 #if __STDC__ 356 va_start(ap, fmt); 357 #else 358 va_start(ap); 359 #endif 360 361 vfprintf(stderr, fmt, ap); 362 if (yflag) 363 return; 364 if (reply("abort") == GOOD) { 365 if (reply("dump core") == GOOD) 366 abort(); 367 done(1); 368 } 369 } 370