utilities.c revision 92806
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1983, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3537906Scharnier#if 0 3623685Speterstatic char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95"; 3737906Scharnier#endif 3837906Scharnierstatic const char rcsid[] = 3950476Speter "$FreeBSD: head/sbin/restore/utilities.c 92806 2002-03-20 17:55:10Z obrien $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 431558Srgrimes#include <sys/stat.h> 441558Srgrimes 451558Srgrimes#include <ufs/ufs/dinode.h> 461558Srgrimes#include <ufs/ufs/dir.h> 471558Srgrimes 481558Srgrimes#include <errno.h> 491558Srgrimes#include <stdio.h> 5078732Sdd#include <stdlib.h> 511558Srgrimes#include <string.h> 521558Srgrimes#include <unistd.h> 531558Srgrimes 541558Srgrimes#include "restore.h" 551558Srgrimes#include "extern.h" 561558Srgrimes 571558Srgrimes/* 581558Srgrimes * Insure that all the components of a pathname exist. 591558Srgrimes */ 601558Srgrimesvoid 611558Srgrimespathcheck(name) 621558Srgrimes char *name; 631558Srgrimes{ 6492806Sobrien char *cp; 651558Srgrimes struct entry *ep; 661558Srgrimes char *start; 671558Srgrimes 6823685Speter start = strchr(name, '/'); 691558Srgrimes if (start == 0) 701558Srgrimes return; 711558Srgrimes for (cp = start; *cp != '\0'; cp++) { 721558Srgrimes if (*cp != '/') 731558Srgrimes continue; 741558Srgrimes *cp = '\0'; 751558Srgrimes ep = lookupname(name); 761558Srgrimes if (ep == NULL) { 771558Srgrimes /* Safe; we know the pathname exists in the dump. */ 781558Srgrimes ep = addentry(name, pathsearch(name)->d_ino, NODE); 791558Srgrimes newnode(ep); 801558Srgrimes } 811558Srgrimes ep->e_flags |= NEW|KEEP; 821558Srgrimes *cp = '/'; 831558Srgrimes } 841558Srgrimes} 851558Srgrimes 861558Srgrimes/* 871558Srgrimes * Change a name to a unique temporary name. 881558Srgrimes */ 891558Srgrimesvoid 901558Srgrimesmktempname(ep) 9192806Sobrien struct entry *ep; 921558Srgrimes{ 931558Srgrimes char oldname[MAXPATHLEN]; 941558Srgrimes 951558Srgrimes if (ep->e_flags & TMPNAME) 961558Srgrimes badentry(ep, "mktempname: called with TMPNAME"); 971558Srgrimes ep->e_flags |= TMPNAME; 981558Srgrimes (void) strcpy(oldname, myname(ep)); 991558Srgrimes freename(ep->e_name); 1001558Srgrimes ep->e_name = savename(gentempname(ep)); 1011558Srgrimes ep->e_namlen = strlen(ep->e_name); 1021558Srgrimes renameit(oldname, myname(ep)); 1031558Srgrimes} 1041558Srgrimes 1051558Srgrimes/* 1061558Srgrimes * Generate a temporary name for an entry. 1071558Srgrimes */ 1081558Srgrimeschar * 1091558Srgrimesgentempname(ep) 1101558Srgrimes struct entry *ep; 1111558Srgrimes{ 1121558Srgrimes static char name[MAXPATHLEN]; 1131558Srgrimes struct entry *np; 1141558Srgrimes long i = 0; 1151558Srgrimes 1161558Srgrimes for (np = lookupino(ep->e_ino); 1171558Srgrimes np != NULL && np != ep; np = np->e_links) 1181558Srgrimes i++; 1191558Srgrimes if (np == NULL) 1201558Srgrimes badentry(ep, "not on ino list"); 12137240Sbde (void) sprintf(name, "%s%ld%lu", TMPHDR, i, (u_long)ep->e_ino); 1221558Srgrimes return (name); 1231558Srgrimes} 1241558Srgrimes 1251558Srgrimes/* 1261558Srgrimes * Rename a file or directory. 1271558Srgrimes */ 1281558Srgrimesvoid 1291558Srgrimesrenameit(from, to) 1301558Srgrimes char *from, *to; 1311558Srgrimes{ 1321558Srgrimes if (!Nflag && rename(from, to) < 0) { 1331558Srgrimes fprintf(stderr, "warning: cannot rename %s to %s: %s\n", 1341558Srgrimes from, to, strerror(errno)); 1351558Srgrimes return; 1361558Srgrimes } 1371558Srgrimes vprintf(stdout, "rename %s to %s\n", from, to); 1381558Srgrimes} 1391558Srgrimes 1401558Srgrimes/* 1411558Srgrimes * Create a new node (directory). 1421558Srgrimes */ 1431558Srgrimesvoid 1441558Srgrimesnewnode(np) 1451558Srgrimes struct entry *np; 1461558Srgrimes{ 1471558Srgrimes char *cp; 1481558Srgrimes 1491558Srgrimes if (np->e_type != NODE) 1501558Srgrimes badentry(np, "newnode: not a node"); 1511558Srgrimes cp = myname(np); 15235852Sjkh if (!Nflag && mkdir(cp, 0777) < 0 && !uflag) { 1531558Srgrimes np->e_flags |= EXISTED; 1541558Srgrimes fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 1551558Srgrimes return; 1561558Srgrimes } 1571558Srgrimes vprintf(stdout, "Make node %s\n", cp); 1581558Srgrimes} 1591558Srgrimes 1601558Srgrimes/* 1611558Srgrimes * Remove an old node (directory). 1621558Srgrimes */ 1631558Srgrimesvoid 1641558Srgrimesremovenode(ep) 16592806Sobrien struct entry *ep; 1661558Srgrimes{ 1671558Srgrimes char *cp; 1681558Srgrimes 1691558Srgrimes if (ep->e_type != NODE) 1701558Srgrimes badentry(ep, "removenode: not a node"); 1711558Srgrimes if (ep->e_entries != NULL) 1721558Srgrimes badentry(ep, "removenode: non-empty directory"); 1731558Srgrimes ep->e_flags |= REMOVED; 1741558Srgrimes ep->e_flags &= ~TMPNAME; 1751558Srgrimes cp = myname(ep); 1761558Srgrimes if (!Nflag && rmdir(cp) < 0) { 1771558Srgrimes fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 1781558Srgrimes return; 1791558Srgrimes } 1801558Srgrimes vprintf(stdout, "Remove node %s\n", cp); 1811558Srgrimes} 1821558Srgrimes 1831558Srgrimes/* 1841558Srgrimes * Remove a leaf. 1851558Srgrimes */ 1861558Srgrimesvoid 1871558Srgrimesremoveleaf(ep) 18892806Sobrien struct entry *ep; 1891558Srgrimes{ 1901558Srgrimes char *cp; 1911558Srgrimes 1921558Srgrimes if (ep->e_type != LEAF) 1931558Srgrimes badentry(ep, "removeleaf: not a leaf"); 1941558Srgrimes ep->e_flags |= REMOVED; 1951558Srgrimes ep->e_flags &= ~TMPNAME; 1961558Srgrimes cp = myname(ep); 1971558Srgrimes if (!Nflag && unlink(cp) < 0) { 1981558Srgrimes fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 1991558Srgrimes return; 2001558Srgrimes } 2011558Srgrimes vprintf(stdout, "Remove leaf %s\n", cp); 2021558Srgrimes} 2031558Srgrimes 2041558Srgrimes/* 2051558Srgrimes * Create a link. 2061558Srgrimes */ 2071558Srgrimesint 2081558Srgrimeslinkit(existing, new, type) 2091558Srgrimes char *existing, *new; 2101558Srgrimes int type; 2111558Srgrimes{ 2121558Srgrimes 21335852Sjkh /* if we want to unlink first, do it now so *link() won't fail */ 21435852Sjkh if (uflag && !Nflag) 21535852Sjkh (void)unlink(new); 21635852Sjkh 2171558Srgrimes if (type == SYMLINK) { 2181558Srgrimes if (!Nflag && symlink(existing, new) < 0) { 2191558Srgrimes fprintf(stderr, 2201558Srgrimes "warning: cannot create symbolic link %s->%s: %s\n", 2211558Srgrimes new, existing, strerror(errno)); 2221558Srgrimes return (FAIL); 2231558Srgrimes } 2241558Srgrimes } else if (type == HARDLINK) { 22537523Sjdp int ret; 22637523Sjdp 22737523Sjdp if (!Nflag && (ret = link(existing, new)) < 0) { 22837523Sjdp struct stat s; 22937523Sjdp 23037523Sjdp /* 23137523Sjdp * Most likely, the schg flag is set. Clear the 23237523Sjdp * flags and try again. 23337523Sjdp */ 23437523Sjdp if (stat(existing, &s) == 0 && s.st_flags != 0 && 23537523Sjdp chflags(existing, 0) == 0) { 23637523Sjdp ret = link(existing, new); 23737523Sjdp chflags(existing, s.st_flags); 23837523Sjdp } 23937523Sjdp if (ret < 0) { 24037523Sjdp fprintf(stderr, "warning: cannot create " 24137523Sjdp "hard link %s->%s: %s\n", 24237523Sjdp new, existing, strerror(errno)); 24337523Sjdp return (FAIL); 24437523Sjdp } 2451558Srgrimes } 2461558Srgrimes } else { 2471558Srgrimes panic("linkit: unknown type %d\n", type); 2481558Srgrimes return (FAIL); 2491558Srgrimes } 2501558Srgrimes vprintf(stdout, "Create %s link %s->%s\n", 2511558Srgrimes type == SYMLINK ? "symbolic" : "hard", new, existing); 2521558Srgrimes return (GOOD); 2531558Srgrimes} 2541558Srgrimes 2551558Srgrimes/* 25623685Speter * Create a whiteout. 25723685Speter */ 25823685Speterint 25923685Speteraddwhiteout(name) 26023685Speter char *name; 26123685Speter{ 26223685Speter 26323685Speter if (!Nflag && mknod(name, S_IFWHT, 0) < 0) { 26423685Speter fprintf(stderr, "warning: cannot create whiteout %s: %s\n", 26523685Speter name, strerror(errno)); 26623685Speter return (FAIL); 26723685Speter } 26823685Speter vprintf(stdout, "Create whiteout %s\n", name); 26923685Speter return (GOOD); 27023685Speter} 27123685Speter 27223685Speter/* 27323685Speter * Delete a whiteout. 27423685Speter */ 27523685Spetervoid 27623685Speterdelwhiteout(ep) 27792806Sobrien struct entry *ep; 27823685Speter{ 27923685Speter char *name; 28023685Speter 28123685Speter if (ep->e_type != LEAF) 28223685Speter badentry(ep, "delwhiteout: not a leaf"); 28323685Speter ep->e_flags |= REMOVED; 28423685Speter ep->e_flags &= ~TMPNAME; 28523685Speter name = myname(ep); 28623685Speter if (!Nflag && undelete(name) < 0) { 28723685Speter fprintf(stderr, "warning: cannot delete whiteout %s: %s\n", 28823685Speter name, strerror(errno)); 28923685Speter return; 29023685Speter } 29123685Speter vprintf(stdout, "Delete whiteout %s\n", name); 29223685Speter} 29323685Speter 29423685Speter/* 2951558Srgrimes * find lowest number file (above "start") that needs to be extracted 2961558Srgrimes */ 2971558Srgrimesino_t 2981558Srgrimeslowerbnd(start) 2991558Srgrimes ino_t start; 3001558Srgrimes{ 30192806Sobrien struct entry *ep; 3021558Srgrimes 3031558Srgrimes for ( ; start < maxino; start++) { 3041558Srgrimes ep = lookupino(start); 3051558Srgrimes if (ep == NULL || ep->e_type == NODE) 3061558Srgrimes continue; 3071558Srgrimes if (ep->e_flags & (NEW|EXTRACT)) 3081558Srgrimes return (start); 3091558Srgrimes } 3101558Srgrimes return (start); 3111558Srgrimes} 3121558Srgrimes 3131558Srgrimes/* 3141558Srgrimes * find highest number file (below "start") that needs to be extracted 3151558Srgrimes */ 3161558Srgrimesino_t 3171558Srgrimesupperbnd(start) 3181558Srgrimes ino_t start; 3191558Srgrimes{ 32092806Sobrien struct entry *ep; 3211558Srgrimes 3221558Srgrimes for ( ; start > ROOTINO; start--) { 3231558Srgrimes ep = lookupino(start); 3241558Srgrimes if (ep == NULL || ep->e_type == NODE) 3251558Srgrimes continue; 3261558Srgrimes if (ep->e_flags & (NEW|EXTRACT)) 3271558Srgrimes return (start); 3281558Srgrimes } 3291558Srgrimes return (start); 3301558Srgrimes} 3311558Srgrimes 3321558Srgrimes/* 3331558Srgrimes * report on a badly formed entry 3341558Srgrimes */ 3351558Srgrimesvoid 3361558Srgrimesbadentry(ep, msg) 33792806Sobrien struct entry *ep; 3381558Srgrimes char *msg; 3391558Srgrimes{ 3401558Srgrimes 3411558Srgrimes fprintf(stderr, "bad entry: %s\n", msg); 3421558Srgrimes fprintf(stderr, "name: %s\n", myname(ep)); 3431558Srgrimes fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 3441558Srgrimes if (ep->e_sibling != NULL) 3451558Srgrimes fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 3461558Srgrimes if (ep->e_entries != NULL) 3471558Srgrimes fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 3481558Srgrimes if (ep->e_links != NULL) 3491558Srgrimes fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 3501558Srgrimes if (ep->e_next != NULL) 3511558Srgrimes fprintf(stderr, 3521558Srgrimes "next hashchain name: %s\n", myname(ep->e_next)); 3531558Srgrimes fprintf(stderr, "entry type: %s\n", 3541558Srgrimes ep->e_type == NODE ? "NODE" : "LEAF"); 35537240Sbde fprintf(stderr, "inode number: %lu\n", (u_long)ep->e_ino); 3561558Srgrimes panic("flags: %s\n", flagvalues(ep)); 3571558Srgrimes} 3581558Srgrimes 3591558Srgrimes/* 3601558Srgrimes * Construct a string indicating the active flag bits of an entry. 3611558Srgrimes */ 3621558Srgrimeschar * 3631558Srgrimesflagvalues(ep) 36492806Sobrien struct entry *ep; 3651558Srgrimes{ 3661558Srgrimes static char flagbuf[BUFSIZ]; 3671558Srgrimes 3681558Srgrimes (void) strcpy(flagbuf, "|NIL"); 3691558Srgrimes flagbuf[0] = '\0'; 3701558Srgrimes if (ep->e_flags & REMOVED) 3711558Srgrimes (void) strcat(flagbuf, "|REMOVED"); 3721558Srgrimes if (ep->e_flags & TMPNAME) 3731558Srgrimes (void) strcat(flagbuf, "|TMPNAME"); 3741558Srgrimes if (ep->e_flags & EXTRACT) 3751558Srgrimes (void) strcat(flagbuf, "|EXTRACT"); 3761558Srgrimes if (ep->e_flags & NEW) 3771558Srgrimes (void) strcat(flagbuf, "|NEW"); 3781558Srgrimes if (ep->e_flags & KEEP) 3791558Srgrimes (void) strcat(flagbuf, "|KEEP"); 3801558Srgrimes if (ep->e_flags & EXISTED) 3811558Srgrimes (void) strcat(flagbuf, "|EXISTED"); 3821558Srgrimes return (&flagbuf[1]); 3831558Srgrimes} 3841558Srgrimes 3851558Srgrimes/* 3861558Srgrimes * Check to see if a name is on a dump tape. 3871558Srgrimes */ 3881558Srgrimesino_t 3891558Srgrimesdirlookup(name) 3901558Srgrimes const char *name; 3911558Srgrimes{ 3921558Srgrimes struct direct *dp; 3931558Srgrimes ino_t ino; 3948871Srgrimes 3951558Srgrimes ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino; 3961558Srgrimes 3971558Srgrimes if (ino == 0 || TSTINO(ino, dumpmap) == 0) 3981558Srgrimes fprintf(stderr, "%s is not on the tape\n", name); 3991558Srgrimes return (ino); 4001558Srgrimes} 4011558Srgrimes 4021558Srgrimes/* 4031558Srgrimes * Elicit a reply. 4041558Srgrimes */ 4051558Srgrimesint 4061558Srgrimesreply(question) 4071558Srgrimes char *question; 4081558Srgrimes{ 40969906Siedowse int c; 4101558Srgrimes 4111558Srgrimes do { 4121558Srgrimes fprintf(stderr, "%s? [yn] ", question); 4131558Srgrimes (void) fflush(stderr); 4141558Srgrimes c = getc(terminal); 4151558Srgrimes while (c != '\n' && getc(terminal) != '\n') 41669906Siedowse if (c == EOF) 4171558Srgrimes return (FAIL); 4181558Srgrimes } while (c != 'y' && c != 'n'); 4191558Srgrimes if (c == 'y') 4201558Srgrimes return (GOOD); 4211558Srgrimes return (FAIL); 4221558Srgrimes} 4231558Srgrimes 4241558Srgrimes/* 4251558Srgrimes * handle unexpected inconsistencies 4261558Srgrimes */ 4271558Srgrimes#if __STDC__ 4281558Srgrimes#include <stdarg.h> 4291558Srgrimes#else 4301558Srgrimes#include <varargs.h> 4311558Srgrimes#endif 4321558Srgrimes 4331558Srgrimesvoid 4341558Srgrimes#if __STDC__ 4351558Srgrimespanic(const char *fmt, ...) 4361558Srgrimes#else 4371558Srgrimespanic(fmt, va_alist) 4381558Srgrimes char *fmt; 4391558Srgrimes va_dcl 4401558Srgrimes#endif 4411558Srgrimes{ 4421558Srgrimes va_list ap; 4431558Srgrimes#if __STDC__ 4441558Srgrimes va_start(ap, fmt); 4451558Srgrimes#else 4461558Srgrimes va_start(ap); 4471558Srgrimes#endif 4481558Srgrimes 4491558Srgrimes vfprintf(stderr, fmt, ap); 4501558Srgrimes if (yflag) 4511558Srgrimes return; 4521558Srgrimes if (reply("abort") == GOOD) { 4531558Srgrimes if (reply("dump core") == GOOD) 4541558Srgrimes abort(); 4551558Srgrimes done(1); 4561558Srgrimes } 4571558Srgrimes} 458