121171Sdist /* 261536Sbostic * Copyright (c) 1983, 1993 361536Sbostic * The Regents of the University of California. All rights reserved. 436105Sbostic * 542709Sbostic * %sccs.include.redist.c% 621171Sdist */ 721171Sdist 810315Smckusick #ifndef lint 9*67777Smckusick static char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 09/13/94"; 1036105Sbostic #endif /* not lint */ 1110315Smckusick 1256567Sbostic #include <sys/param.h> 1356567Sbostic #include <sys/stat.h> 1456567Sbostic 1556567Sbostic #include <ufs/ufs/dinode.h> 1656947Smckusick #include <ufs/ufs/dir.h> 1756567Sbostic 1856567Sbostic #include <errno.h> 1956567Sbostic #include <stdio.h> 2056567Sbostic #include <stdlib.h> 2156567Sbostic #include <string.h> 2256567Sbostic #include <unistd.h> 2356567Sbostic 2410315Smckusick #include "restore.h" 2556567Sbostic #include "extern.h" 2610315Smckusick 2710315Smckusick /* 2810315Smckusick * Insure that all the components of a pathname exist. 2910315Smckusick */ 3056567Sbostic void 3111645Smckusick pathcheck(name) 3210315Smckusick char *name; 3310315Smckusick { 3410315Smckusick register char *cp; 3510315Smckusick struct entry *ep; 3611312Smckusick char *start; 3710315Smckusick 3810315Smckusick start = index(name, '/'); 3911312Smckusick if (start == 0) 4011645Smckusick return; 4110315Smckusick for (cp = start; *cp != '\0'; cp++) { 4210315Smckusick if (*cp != '/') 4310315Smckusick continue; 4410315Smckusick *cp = '\0'; 4510315Smckusick ep = lookupname(name); 4656567Sbostic if (ep == NULL) { 4766443Sbostic /* Safe; we know the pathname exists in the dump. */ 4856947Smckusick ep = addentry(name, pathsearch(name)->d_ino, NODE); 4910315Smckusick newnode(ep); 5010315Smckusick } 5118009Smckusick ep->e_flags |= NEW|KEEP; 5210315Smckusick *cp = '/'; 5310315Smckusick } 5410315Smckusick } 5510315Smckusick 5610315Smckusick /* 5710315Smckusick * Change a name to a unique temporary name. 5810315Smckusick */ 5956567Sbostic void 6010315Smckusick mktempname(ep) 6110315Smckusick register struct entry *ep; 6210315Smckusick { 6311645Smckusick char oldname[MAXPATHLEN]; 6410315Smckusick 6510315Smckusick if (ep->e_flags & TMPNAME) 6610315Smckusick badentry(ep, "mktempname: called with TMPNAME"); 6710315Smckusick ep->e_flags |= TMPNAME; 6811995Smckusick (void) strcpy(oldname, myname(ep)); 6911645Smckusick freename(ep->e_name); 7011645Smckusick ep->e_name = savename(gentempname(ep)); 7111645Smckusick ep->e_namlen = strlen(ep->e_name); 7210315Smckusick renameit(oldname, myname(ep)); 7310315Smckusick } 7410315Smckusick 7510315Smckusick /* 7611645Smckusick * Generate a temporary name for an entry. 7711645Smckusick */ 7811645Smckusick char * 7911645Smckusick gentempname(ep) 8011645Smckusick struct entry *ep; 8111645Smckusick { 8211645Smckusick static char name[MAXPATHLEN]; 8311645Smckusick struct entry *np; 8411645Smckusick long i = 0; 8511645Smckusick 8656567Sbostic for (np = lookupino(ep->e_ino); 8756567Sbostic np != NULL && np != ep; np = np->e_links) 8811645Smckusick i++; 8956567Sbostic if (np == NULL) 9011645Smckusick badentry(ep, "not on ino list"); 9111733Smckusick (void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino); 9211645Smckusick return (name); 9311645Smckusick } 9411645Smckusick 9511645Smckusick /* 9610315Smckusick * Rename a file or directory. 9710315Smckusick */ 9856567Sbostic void 9910315Smckusick renameit(from, to) 10010315Smckusick char *from, *to; 10110315Smckusick { 10234268Smckusick if (!Nflag && rename(from, to) < 0) { 10356567Sbostic fprintf(stderr, "warning: cannot rename %s to %s: %s\n", 10456567Sbostic from, to, strerror(errno)); 10511923Smckusick return; 10610315Smckusick } 10710315Smckusick vprintf(stdout, "rename %s to %s\n", from, to); 10810315Smckusick } 10910315Smckusick 11010315Smckusick /* 11110315Smckusick * Create a new node (directory). 11210315Smckusick */ 11356567Sbostic void 11410315Smckusick newnode(np) 11510315Smckusick struct entry *np; 11610315Smckusick { 11710315Smckusick char *cp; 11810315Smckusick 11910315Smckusick if (np->e_type != NODE) 12010315Smckusick badentry(np, "newnode: not a node"); 12110315Smckusick cp = myname(np); 12234268Smckusick if (!Nflag && mkdir(cp, 0777) < 0) { 12318006Smckusick np->e_flags |= EXISTED; 12456567Sbostic fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 12511740Smckusick return; 12610315Smckusick } 12710315Smckusick vprintf(stdout, "Make node %s\n", cp); 12810315Smckusick } 12910315Smckusick 13010315Smckusick /* 13110315Smckusick * Remove an old node (directory). 13210315Smckusick */ 13356567Sbostic void 13410315Smckusick removenode(ep) 13510315Smckusick register struct entry *ep; 13610315Smckusick { 13710315Smckusick char *cp; 13810315Smckusick 13910315Smckusick if (ep->e_type != NODE) 14010315Smckusick badentry(ep, "removenode: not a node"); 14156567Sbostic if (ep->e_entries != NULL) 14210315Smckusick badentry(ep, "removenode: non-empty directory"); 14311923Smckusick ep->e_flags |= REMOVED; 14411923Smckusick ep->e_flags &= ~TMPNAME; 14510315Smckusick cp = myname(ep); 14634268Smckusick if (!Nflag && rmdir(cp) < 0) { 14756567Sbostic fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 14811923Smckusick return; 14910315Smckusick } 15010315Smckusick vprintf(stdout, "Remove node %s\n", cp); 15110315Smckusick } 15210315Smckusick 15310315Smckusick /* 15410315Smckusick * Remove a leaf. 15510315Smckusick */ 15656567Sbostic void 15710315Smckusick removeleaf(ep) 15810315Smckusick register struct entry *ep; 15910315Smckusick { 16010315Smckusick char *cp; 16110315Smckusick 16210315Smckusick if (ep->e_type != LEAF) 16310315Smckusick badentry(ep, "removeleaf: not a leaf"); 16411923Smckusick ep->e_flags |= REMOVED; 16511923Smckusick ep->e_flags &= ~TMPNAME; 16610315Smckusick cp = myname(ep); 16734268Smckusick if (!Nflag && unlink(cp) < 0) { 16856567Sbostic fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 16911923Smckusick return; 17010315Smckusick } 17110315Smckusick vprintf(stdout, "Remove leaf %s\n", cp); 17210315Smckusick } 17310315Smckusick 17410315Smckusick /* 17510315Smckusick * Create a link. 17610315Smckusick */ 17756567Sbostic int 17810315Smckusick linkit(existing, new, type) 17910315Smckusick char *existing, *new; 18010315Smckusick int type; 18110315Smckusick { 18210315Smckusick 18310315Smckusick if (type == SYMLINK) { 18434268Smckusick if (!Nflag && symlink(existing, new) < 0) { 18511923Smckusick fprintf(stderr, 18656567Sbostic "warning: cannot create symbolic link %s->%s: %s\n", 18756567Sbostic new, existing, strerror(errno)); 18815782Smckusick return (FAIL); 18910315Smckusick } 19010315Smckusick } else if (type == HARDLINK) { 19134268Smckusick if (!Nflag && link(existing, new) < 0) { 19211923Smckusick fprintf(stderr, 19356567Sbostic "warning: cannot create hard link %s->%s: %s\n", 19456567Sbostic new, existing, strerror(errno)); 19515782Smckusick return (FAIL); 19610315Smckusick } 19710315Smckusick } else { 19810315Smckusick panic("linkit: unknown type %d\n", type); 19915782Smckusick return (FAIL); 20010315Smckusick } 20110315Smckusick vprintf(stdout, "Create %s link %s->%s\n", 20210315Smckusick type == SYMLINK ? "symbolic" : "hard", new, existing); 20315782Smckusick return (GOOD); 20410315Smckusick } 20510315Smckusick 20610315Smckusick /* 207*67777Smckusick * Create a whiteout. 208*67777Smckusick */ 209*67777Smckusick int 210*67777Smckusick addwhiteout(name) 211*67777Smckusick char *name; 212*67777Smckusick { 213*67777Smckusick 214*67777Smckusick if (!Nflag && mknod(name, S_IFWHT, 0) < 0) { 215*67777Smckusick fprintf(stderr, "warning: cannot create whiteout %s: %s\n", 216*67777Smckusick name, strerror(errno)); 217*67777Smckusick return (FAIL); 218*67777Smckusick } 219*67777Smckusick vprintf(stdout, "Create whiteout %s\n", name); 220*67777Smckusick return (GOOD); 221*67777Smckusick } 222*67777Smckusick 223*67777Smckusick /* 224*67777Smckusick * Delete a whiteout. 225*67777Smckusick */ 226*67777Smckusick void 227*67777Smckusick delwhiteout(ep) 228*67777Smckusick register struct entry *ep; 229*67777Smckusick { 230*67777Smckusick char *name; 231*67777Smckusick 232*67777Smckusick if (ep->e_type != LEAF) 233*67777Smckusick badentry(ep, "delwhiteout: not a leaf"); 234*67777Smckusick ep->e_flags |= REMOVED; 235*67777Smckusick ep->e_flags &= ~TMPNAME; 236*67777Smckusick name = myname(ep); 237*67777Smckusick if (!Nflag && unwhiteout(name) < 0) { 238*67777Smckusick fprintf(stderr, "warning: cannot delete whiteout %s: %s\n", 239*67777Smckusick name, strerror(errno)); 240*67777Smckusick return; 241*67777Smckusick } 242*67777Smckusick vprintf(stdout, "Delete whiteout %s\n", name); 243*67777Smckusick } 244*67777Smckusick 245*67777Smckusick /* 24610315Smckusick * find lowest number file (above "start") that needs to be extracted 24710315Smckusick */ 24810315Smckusick ino_t 24910315Smckusick lowerbnd(start) 25010315Smckusick ino_t start; 25110315Smckusick { 25210315Smckusick register struct entry *ep; 25310315Smckusick 25410315Smckusick for ( ; start < maxino; start++) { 25510315Smckusick ep = lookupino(start); 25656567Sbostic if (ep == NULL || ep->e_type == NODE) 25710315Smckusick continue; 25811645Smckusick if (ep->e_flags & (NEW|EXTRACT)) 25910315Smckusick return (start); 26010315Smckusick } 26110315Smckusick return (start); 26210315Smckusick } 26310315Smckusick 26410315Smckusick /* 26510315Smckusick * find highest number file (below "start") that needs to be extracted 26610315Smckusick */ 26710315Smckusick ino_t 26810315Smckusick upperbnd(start) 26910315Smckusick ino_t start; 27010315Smckusick { 27110315Smckusick register struct entry *ep; 27210315Smckusick 27310315Smckusick for ( ; start > ROOTINO; start--) { 27410315Smckusick ep = lookupino(start); 27556567Sbostic if (ep == NULL || ep->e_type == NODE) 27610315Smckusick continue; 27711645Smckusick if (ep->e_flags & (NEW|EXTRACT)) 27810315Smckusick return (start); 27910315Smckusick } 28010315Smckusick return (start); 28110315Smckusick } 28210315Smckusick 28310315Smckusick /* 28410315Smckusick * report on a badly formed entry 28510315Smckusick */ 28656567Sbostic void 28710315Smckusick badentry(ep, msg) 28810315Smckusick register struct entry *ep; 28910315Smckusick char *msg; 29010315Smckusick { 29110315Smckusick 29210315Smckusick fprintf(stderr, "bad entry: %s\n", msg); 29310315Smckusick fprintf(stderr, "name: %s\n", myname(ep)); 29410315Smckusick fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 29556567Sbostic if (ep->e_sibling != NULL) 29610315Smckusick fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 29756567Sbostic if (ep->e_entries != NULL) 29810315Smckusick fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 29956567Sbostic if (ep->e_links != NULL) 30010315Smckusick fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 30156567Sbostic if (ep->e_next != NULL) 30256567Sbostic fprintf(stderr, 30356567Sbostic "next hashchain name: %s\n", myname(ep->e_next)); 30410315Smckusick fprintf(stderr, "entry type: %s\n", 30510315Smckusick ep->e_type == NODE ? "NODE" : "LEAF"); 30610315Smckusick fprintf(stderr, "inode number: %ld\n", ep->e_ino); 30711898Smckusick panic("flags: %s\n", flagvalues(ep)); 30811898Smckusick } 30911898Smckusick 31011898Smckusick /* 31111898Smckusick * Construct a string indicating the active flag bits of an entry. 31211898Smckusick */ 31311898Smckusick char * 31411898Smckusick flagvalues(ep) 31511898Smckusick register struct entry *ep; 31611898Smckusick { 31711898Smckusick static char flagbuf[BUFSIZ]; 31811898Smckusick 31911898Smckusick (void) strcpy(flagbuf, "|NIL"); 32010315Smckusick flagbuf[0] = '\0'; 32110315Smckusick if (ep->e_flags & REMOVED) 32211898Smckusick (void) strcat(flagbuf, "|REMOVED"); 32310315Smckusick if (ep->e_flags & TMPNAME) 32411898Smckusick (void) strcat(flagbuf, "|TMPNAME"); 32510315Smckusick if (ep->e_flags & EXTRACT) 32611898Smckusick (void) strcat(flagbuf, "|EXTRACT"); 32710315Smckusick if (ep->e_flags & NEW) 32811898Smckusick (void) strcat(flagbuf, "|NEW"); 32910315Smckusick if (ep->e_flags & KEEP) 33011898Smckusick (void) strcat(flagbuf, "|KEEP"); 33118006Smckusick if (ep->e_flags & EXISTED) 33218006Smckusick (void) strcat(flagbuf, "|EXISTED"); 33311898Smckusick return (&flagbuf[1]); 33410315Smckusick } 33510315Smckusick 33610315Smckusick /* 33711995Smckusick * Check to see if a name is on a dump tape. 33811321Smckusick */ 33911995Smckusick ino_t 34011995Smckusick dirlookup(name) 34157896Sbostic const char *name; 34211995Smckusick { 34366443Sbostic struct direct *dp; 34411995Smckusick ino_t ino; 34566443Sbostic 34666443Sbostic ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino; 34711995Smckusick 34856427Smckusick if (ino == 0 || TSTINO(ino, dumpmap) == 0) 34966443Sbostic fprintf(stderr, "%s is not on the tape\n", name); 35011995Smckusick return (ino); 35111995Smckusick } 35211995Smckusick 35311995Smckusick /* 35411995Smckusick * Elicit a reply. 35510315Smckusick */ 35656567Sbostic int 35710315Smckusick reply(question) 35810315Smckusick char *question; 35910315Smckusick { 36010315Smckusick char c; 36110315Smckusick 36210315Smckusick do { 36324185Smckusick fprintf(stderr, "%s? [yn] ", question); 36412557Smckusick (void) fflush(stderr); 36511995Smckusick c = getc(terminal); 36611995Smckusick while (c != '\n' && getc(terminal) != '\n') 36717711Smckusick if (feof(terminal)) 36824185Smckusick return (FAIL); 36910315Smckusick } while (c != 'y' && c != 'n'); 37010315Smckusick if (c == 'y') 37110315Smckusick return (GOOD); 37210315Smckusick return (FAIL); 37310315Smckusick } 37411995Smckusick 37511995Smckusick /* 37611995Smckusick * handle unexpected inconsistencies 37711995Smckusick */ 37856567Sbostic #if __STDC__ 37956567Sbostic #include <stdarg.h> 38056567Sbostic #else 38156567Sbostic #include <varargs.h> 38256567Sbostic #endif 38356567Sbostic 38456567Sbostic void 38556567Sbostic #if __STDC__ 38656567Sbostic panic(const char *fmt, ...) 38756567Sbostic #else 38856567Sbostic panic(fmt, va_alist) 38956567Sbostic char *fmt; 39056567Sbostic va_dcl 39156567Sbostic #endif 39211995Smckusick { 39356567Sbostic va_list ap; 39456567Sbostic #if __STDC__ 39556567Sbostic va_start(ap, fmt); 39656567Sbostic #else 39756567Sbostic va_start(ap); 39856567Sbostic #endif 39911995Smckusick 40056567Sbostic vfprintf(stderr, fmt, ap); 40142489Smckusick if (yflag) 40242489Smckusick return; 40311995Smckusick if (reply("abort") == GOOD) { 40411995Smckusick if (reply("dump core") == GOOD) 40511995Smckusick abort(); 40611995Smckusick done(1); 40711995Smckusick } 40811995Smckusick } 409