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