1331722Seadler/* 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 * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 301558Srgrimes#ifndef lint 3137906Scharnier#if 0 3223685Speterstatic char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95"; 3337906Scharnier#endif 3437906Scharnierstatic const char rcsid[] = 3550476Speter "$FreeBSD$"; 361558Srgrimes#endif /* not lint */ 371558Srgrimes 381558Srgrimes#include <sys/param.h> 391558Srgrimes#include <sys/stat.h> 401558Srgrimes 411558Srgrimes#include <ufs/ufs/dinode.h> 421558Srgrimes#include <ufs/ufs/dir.h> 431558Srgrimes 441558Srgrimes#include <errno.h> 45103949Smike#include <limits.h> 461558Srgrimes#include <stdio.h> 4778732Sdd#include <stdlib.h> 481558Srgrimes#include <string.h> 491558Srgrimes#include <unistd.h> 501558Srgrimes 511558Srgrimes#include "restore.h" 521558Srgrimes#include "extern.h" 531558Srgrimes 541558Srgrimes/* 551558Srgrimes * Insure that all the components of a pathname exist. 561558Srgrimes */ 571558Srgrimesvoid 5892837Simppathcheck(char *name) 591558Srgrimes{ 6092806Sobrien char *cp; 611558Srgrimes struct entry *ep; 621558Srgrimes char *start; 631558Srgrimes 6423685Speter start = strchr(name, '/'); 65298205Saraujo if (start == NULL) 661558Srgrimes return; 671558Srgrimes for (cp = start; *cp != '\0'; cp++) { 681558Srgrimes if (*cp != '/') 691558Srgrimes continue; 701558Srgrimes *cp = '\0'; 711558Srgrimes ep = lookupname(name); 721558Srgrimes if (ep == NULL) { 731558Srgrimes /* Safe; we know the pathname exists in the dump. */ 741558Srgrimes ep = addentry(name, pathsearch(name)->d_ino, NODE); 751558Srgrimes newnode(ep); 761558Srgrimes } 771558Srgrimes ep->e_flags |= NEW|KEEP; 781558Srgrimes *cp = '/'; 791558Srgrimes } 801558Srgrimes} 811558Srgrimes 821558Srgrimes/* 831558Srgrimes * Change a name to a unique temporary name. 841558Srgrimes */ 851558Srgrimesvoid 8692837Simpmktempname(struct entry *ep) 871558Srgrimes{ 881558Srgrimes char oldname[MAXPATHLEN]; 891558Srgrimes 901558Srgrimes if (ep->e_flags & TMPNAME) 911558Srgrimes badentry(ep, "mktempname: called with TMPNAME"); 921558Srgrimes ep->e_flags |= TMPNAME; 931558Srgrimes (void) strcpy(oldname, myname(ep)); 941558Srgrimes freename(ep->e_name); 951558Srgrimes ep->e_name = savename(gentempname(ep)); 961558Srgrimes ep->e_namlen = strlen(ep->e_name); 971558Srgrimes renameit(oldname, myname(ep)); 981558Srgrimes} 991558Srgrimes 1001558Srgrimes/* 1011558Srgrimes * Generate a temporary name for an entry. 1021558Srgrimes */ 1031558Srgrimeschar * 10492837Simpgentempname(struct entry *ep) 1051558Srgrimes{ 1061558Srgrimes static char name[MAXPATHLEN]; 1071558Srgrimes struct entry *np; 1081558Srgrimes long i = 0; 1091558Srgrimes 1101558Srgrimes for (np = lookupino(ep->e_ino); 1111558Srgrimes np != NULL && np != ep; np = np->e_links) 1121558Srgrimes i++; 1131558Srgrimes if (np == NULL) 1141558Srgrimes badentry(ep, "not on ino list"); 11537240Sbde (void) sprintf(name, "%s%ld%lu", TMPHDR, i, (u_long)ep->e_ino); 1161558Srgrimes return (name); 1171558Srgrimes} 1181558Srgrimes 1191558Srgrimes/* 1201558Srgrimes * Rename a file or directory. 1211558Srgrimes */ 1221558Srgrimesvoid 12392837Simprenameit(char *from, char *to) 1241558Srgrimes{ 1251558Srgrimes if (!Nflag && rename(from, to) < 0) { 1261558Srgrimes fprintf(stderr, "warning: cannot rename %s to %s: %s\n", 1271558Srgrimes from, to, strerror(errno)); 1281558Srgrimes return; 1291558Srgrimes } 1301558Srgrimes vprintf(stdout, "rename %s to %s\n", from, to); 1311558Srgrimes} 1321558Srgrimes 1331558Srgrimes/* 1341558Srgrimes * Create a new node (directory). 1351558Srgrimes */ 1361558Srgrimesvoid 13792837Simpnewnode(struct entry *np) 1381558Srgrimes{ 1391558Srgrimes char *cp; 1401558Srgrimes 1411558Srgrimes if (np->e_type != NODE) 1421558Srgrimes badentry(np, "newnode: not a node"); 1431558Srgrimes cp = myname(np); 14435852Sjkh if (!Nflag && mkdir(cp, 0777) < 0 && !uflag) { 1451558Srgrimes np->e_flags |= EXISTED; 1461558Srgrimes fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 1471558Srgrimes return; 1481558Srgrimes } 1491558Srgrimes vprintf(stdout, "Make node %s\n", cp); 1501558Srgrimes} 1511558Srgrimes 1521558Srgrimes/* 1531558Srgrimes * Remove an old node (directory). 1541558Srgrimes */ 1551558Srgrimesvoid 15692837Simpremovenode(struct entry *ep) 1571558Srgrimes{ 1581558Srgrimes char *cp; 1591558Srgrimes 1601558Srgrimes if (ep->e_type != NODE) 1611558Srgrimes badentry(ep, "removenode: not a node"); 1621558Srgrimes if (ep->e_entries != NULL) 1631558Srgrimes badentry(ep, "removenode: non-empty directory"); 1641558Srgrimes ep->e_flags |= REMOVED; 1651558Srgrimes ep->e_flags &= ~TMPNAME; 1661558Srgrimes cp = myname(ep); 1671558Srgrimes if (!Nflag && rmdir(cp) < 0) { 1681558Srgrimes fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 1691558Srgrimes return; 1701558Srgrimes } 1711558Srgrimes vprintf(stdout, "Remove node %s\n", cp); 1721558Srgrimes} 1731558Srgrimes 1741558Srgrimes/* 1751558Srgrimes * Remove a leaf. 1761558Srgrimes */ 1771558Srgrimesvoid 17892837Simpremoveleaf(struct entry *ep) 1791558Srgrimes{ 1801558Srgrimes char *cp; 1811558Srgrimes 1821558Srgrimes if (ep->e_type != LEAF) 1831558Srgrimes badentry(ep, "removeleaf: not a leaf"); 1841558Srgrimes ep->e_flags |= REMOVED; 1851558Srgrimes ep->e_flags &= ~TMPNAME; 1861558Srgrimes cp = myname(ep); 1871558Srgrimes if (!Nflag && unlink(cp) < 0) { 1881558Srgrimes fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 1891558Srgrimes return; 1901558Srgrimes } 1911558Srgrimes vprintf(stdout, "Remove leaf %s\n", cp); 1921558Srgrimes} 1931558Srgrimes 1941558Srgrimes/* 1951558Srgrimes * Create a link. 1961558Srgrimes */ 1971558Srgrimesint 19892837Simplinkit(char *existing, char *new, int type) 1991558Srgrimes{ 2001558Srgrimes 20135852Sjkh /* if we want to unlink first, do it now so *link() won't fail */ 20235852Sjkh if (uflag && !Nflag) 20335852Sjkh (void)unlink(new); 20435852Sjkh 2051558Srgrimes if (type == SYMLINK) { 2061558Srgrimes if (!Nflag && symlink(existing, new) < 0) { 2071558Srgrimes fprintf(stderr, 2081558Srgrimes "warning: cannot create symbolic link %s->%s: %s\n", 2091558Srgrimes new, existing, strerror(errno)); 2101558Srgrimes return (FAIL); 2111558Srgrimes } 2121558Srgrimes } else if (type == HARDLINK) { 21337523Sjdp int ret; 21437523Sjdp 21537523Sjdp if (!Nflag && (ret = link(existing, new)) < 0) { 21637523Sjdp struct stat s; 21737523Sjdp 21837523Sjdp /* 21937523Sjdp * Most likely, the schg flag is set. Clear the 22037523Sjdp * flags and try again. 22137523Sjdp */ 22237523Sjdp if (stat(existing, &s) == 0 && s.st_flags != 0 && 22337523Sjdp chflags(existing, 0) == 0) { 22437523Sjdp ret = link(existing, new); 22537523Sjdp chflags(existing, s.st_flags); 22637523Sjdp } 22737523Sjdp if (ret < 0) { 22837523Sjdp fprintf(stderr, "warning: cannot create " 22937523Sjdp "hard link %s->%s: %s\n", 23037523Sjdp new, existing, strerror(errno)); 23137523Sjdp return (FAIL); 23237523Sjdp } 2331558Srgrimes } 2341558Srgrimes } else { 2351558Srgrimes panic("linkit: unknown type %d\n", type); 2361558Srgrimes return (FAIL); 2371558Srgrimes } 2381558Srgrimes vprintf(stdout, "Create %s link %s->%s\n", 2391558Srgrimes type == SYMLINK ? "symbolic" : "hard", new, existing); 2401558Srgrimes return (GOOD); 2411558Srgrimes} 2421558Srgrimes 2431558Srgrimes/* 24423685Speter * Create a whiteout. 24523685Speter */ 24623685Speterint 24792837Simpaddwhiteout(char *name) 24823685Speter{ 24923685Speter 25023685Speter if (!Nflag && mknod(name, S_IFWHT, 0) < 0) { 25123685Speter fprintf(stderr, "warning: cannot create whiteout %s: %s\n", 25223685Speter name, strerror(errno)); 25323685Speter return (FAIL); 25423685Speter } 25523685Speter vprintf(stdout, "Create whiteout %s\n", name); 25623685Speter return (GOOD); 25723685Speter} 25823685Speter 25923685Speter/* 26023685Speter * Delete a whiteout. 26123685Speter */ 26223685Spetervoid 26392837Simpdelwhiteout(struct entry *ep) 26423685Speter{ 26523685Speter char *name; 26623685Speter 26723685Speter if (ep->e_type != LEAF) 26823685Speter badentry(ep, "delwhiteout: not a leaf"); 26923685Speter ep->e_flags |= REMOVED; 27023685Speter ep->e_flags &= ~TMPNAME; 27123685Speter name = myname(ep); 27223685Speter if (!Nflag && undelete(name) < 0) { 27323685Speter fprintf(stderr, "warning: cannot delete whiteout %s: %s\n", 27423685Speter name, strerror(errno)); 27523685Speter return; 27623685Speter } 27723685Speter vprintf(stdout, "Delete whiteout %s\n", name); 27823685Speter} 27923685Speter 28023685Speter/* 2811558Srgrimes * find lowest number file (above "start") that needs to be extracted 2821558Srgrimes */ 2831558Srgrimesino_t 28492837Simplowerbnd(ino_t start) 2851558Srgrimes{ 28692806Sobrien struct entry *ep; 2871558Srgrimes 2881558Srgrimes for ( ; start < maxino; start++) { 2891558Srgrimes ep = lookupino(start); 2901558Srgrimes if (ep == NULL || ep->e_type == NODE) 2911558Srgrimes continue; 2921558Srgrimes if (ep->e_flags & (NEW|EXTRACT)) 2931558Srgrimes return (start); 2941558Srgrimes } 2951558Srgrimes return (start); 2961558Srgrimes} 2971558Srgrimes 2981558Srgrimes/* 2991558Srgrimes * find highest number file (below "start") that needs to be extracted 3001558Srgrimes */ 3011558Srgrimesino_t 30292837Simpupperbnd(ino_t start) 3031558Srgrimes{ 30492806Sobrien struct entry *ep; 3051558Srgrimes 3061558Srgrimes for ( ; start > ROOTINO; start--) { 3071558Srgrimes ep = lookupino(start); 3081558Srgrimes if (ep == NULL || ep->e_type == NODE) 3091558Srgrimes continue; 3101558Srgrimes if (ep->e_flags & (NEW|EXTRACT)) 3111558Srgrimes return (start); 3121558Srgrimes } 3131558Srgrimes return (start); 3141558Srgrimes} 3151558Srgrimes 3161558Srgrimes/* 3171558Srgrimes * report on a badly formed entry 3181558Srgrimes */ 3191558Srgrimesvoid 32092837Simpbadentry(struct entry *ep, char *msg) 3211558Srgrimes{ 3221558Srgrimes 3231558Srgrimes fprintf(stderr, "bad entry: %s\n", msg); 3241558Srgrimes fprintf(stderr, "name: %s\n", myname(ep)); 3251558Srgrimes fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 3261558Srgrimes if (ep->e_sibling != NULL) 3271558Srgrimes fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 3281558Srgrimes if (ep->e_entries != NULL) 3291558Srgrimes fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 3301558Srgrimes if (ep->e_links != NULL) 3311558Srgrimes fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 3321558Srgrimes if (ep->e_next != NULL) 3331558Srgrimes fprintf(stderr, 3341558Srgrimes "next hashchain name: %s\n", myname(ep->e_next)); 3351558Srgrimes fprintf(stderr, "entry type: %s\n", 3361558Srgrimes ep->e_type == NODE ? "NODE" : "LEAF"); 33737240Sbde fprintf(stderr, "inode number: %lu\n", (u_long)ep->e_ino); 3381558Srgrimes panic("flags: %s\n", flagvalues(ep)); 3391558Srgrimes} 3401558Srgrimes 3411558Srgrimes/* 3421558Srgrimes * Construct a string indicating the active flag bits of an entry. 3431558Srgrimes */ 3441558Srgrimeschar * 34592837Simpflagvalues(struct entry *ep) 3461558Srgrimes{ 3471558Srgrimes static char flagbuf[BUFSIZ]; 3481558Srgrimes 3491558Srgrimes (void) strcpy(flagbuf, "|NIL"); 3501558Srgrimes flagbuf[0] = '\0'; 3511558Srgrimes if (ep->e_flags & REMOVED) 3521558Srgrimes (void) strcat(flagbuf, "|REMOVED"); 3531558Srgrimes if (ep->e_flags & TMPNAME) 3541558Srgrimes (void) strcat(flagbuf, "|TMPNAME"); 3551558Srgrimes if (ep->e_flags & EXTRACT) 3561558Srgrimes (void) strcat(flagbuf, "|EXTRACT"); 3571558Srgrimes if (ep->e_flags & NEW) 3581558Srgrimes (void) strcat(flagbuf, "|NEW"); 3591558Srgrimes if (ep->e_flags & KEEP) 3601558Srgrimes (void) strcat(flagbuf, "|KEEP"); 3611558Srgrimes if (ep->e_flags & EXISTED) 3621558Srgrimes (void) strcat(flagbuf, "|EXISTED"); 3631558Srgrimes return (&flagbuf[1]); 3641558Srgrimes} 3651558Srgrimes 3661558Srgrimes/* 3671558Srgrimes * Check to see if a name is on a dump tape. 3681558Srgrimes */ 3691558Srgrimesino_t 37092837Simpdirlookup(const char *name) 3711558Srgrimes{ 3721558Srgrimes struct direct *dp; 3731558Srgrimes ino_t ino; 3748871Srgrimes 3751558Srgrimes ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino; 3761558Srgrimes 3771558Srgrimes if (ino == 0 || TSTINO(ino, dumpmap) == 0) 3781558Srgrimes fprintf(stderr, "%s is not on the tape\n", name); 3791558Srgrimes return (ino); 3801558Srgrimes} 3811558Srgrimes 3821558Srgrimes/* 3831558Srgrimes * Elicit a reply. 3841558Srgrimes */ 3851558Srgrimesint 38692837Simpreply(char *question) 3871558Srgrimes{ 38869906Siedowse int c; 3891558Srgrimes 3901558Srgrimes do { 3911558Srgrimes fprintf(stderr, "%s? [yn] ", question); 3921558Srgrimes (void) fflush(stderr); 3931558Srgrimes c = getc(terminal); 3941558Srgrimes while (c != '\n' && getc(terminal) != '\n') 39569906Siedowse if (c == EOF) 3961558Srgrimes return (FAIL); 3971558Srgrimes } while (c != 'y' && c != 'n'); 3981558Srgrimes if (c == 'y') 3991558Srgrimes return (GOOD); 4001558Srgrimes return (FAIL); 4011558Srgrimes} 4021558Srgrimes 4031558Srgrimes/* 4041558Srgrimes * handle unexpected inconsistencies 4051558Srgrimes */ 4061558Srgrimes#include <stdarg.h> 4071558Srgrimes 4081558Srgrimesvoid 4091558Srgrimespanic(const char *fmt, ...) 4101558Srgrimes{ 4111558Srgrimes va_list ap; 4121558Srgrimes va_start(ap, fmt); 4131558Srgrimes vfprintf(stderr, fmt, ap); 414236213Skevlo va_end(ap); 4151558Srgrimes if (yflag) 4161558Srgrimes return; 4171558Srgrimes if (reply("abort") == GOOD) { 4181558Srgrimes if (reply("dump core") == GOOD) 4191558Srgrimes abort(); 4201558Srgrimes done(1); 4211558Srgrimes } 4221558Srgrimes} 423