110315Smckusick #ifndef lint 2*18006Smckusick static char sccsid[] = "@(#)utilities.c 3.19 (Berkeley) 85/02/18"; 310315Smckusick #endif 410315Smckusick 514568Ssam /* Copyright (c) 1983 Regents of the University of California */ 614568Ssam 710315Smckusick #include "restore.h" 810315Smckusick 910315Smckusick /* 1010315Smckusick * Insure that all the components of a pathname exist. 1110315Smckusick */ 1211645Smckusick pathcheck(name) 1310315Smckusick char *name; 1410315Smckusick { 1510315Smckusick register char *cp; 1610315Smckusick struct entry *ep; 1711312Smckusick char *start; 1810315Smckusick 1910315Smckusick start = index(name, '/'); 2011312Smckusick if (start == 0) 2111645Smckusick return; 2210315Smckusick for (cp = start; *cp != '\0'; cp++) { 2310315Smckusick if (*cp != '/') 2410315Smckusick continue; 2510315Smckusick *cp = '\0'; 2610315Smckusick ep = lookupname(name); 2710315Smckusick if (ep == NIL) { 2811995Smckusick ep = addentry(name, psearch(name), NODE); 2910315Smckusick newnode(ep); 3011995Smckusick ep->e_flags |= NEW|KEEP; 3110315Smckusick } 3210315Smckusick *cp = '/'; 3310315Smckusick } 3410315Smckusick } 3510315Smckusick 3610315Smckusick /* 3710315Smckusick * Change a name to a unique temporary name. 3810315Smckusick */ 3910315Smckusick mktempname(ep) 4010315Smckusick register struct entry *ep; 4110315Smckusick { 4211645Smckusick char oldname[MAXPATHLEN]; 4310315Smckusick 4410315Smckusick if (ep->e_flags & TMPNAME) 4510315Smckusick badentry(ep, "mktempname: called with TMPNAME"); 4610315Smckusick ep->e_flags |= TMPNAME; 4711995Smckusick (void) strcpy(oldname, myname(ep)); 4811645Smckusick freename(ep->e_name); 4911645Smckusick ep->e_name = savename(gentempname(ep)); 5011645Smckusick ep->e_namlen = strlen(ep->e_name); 5110315Smckusick renameit(oldname, myname(ep)); 5210315Smckusick } 5310315Smckusick 5410315Smckusick /* 5511645Smckusick * Generate a temporary name for an entry. 5611645Smckusick */ 5711645Smckusick char * 5811645Smckusick gentempname(ep) 5911645Smckusick struct entry *ep; 6011645Smckusick { 6111645Smckusick static char name[MAXPATHLEN]; 6211645Smckusick struct entry *np; 6311645Smckusick long i = 0; 6411645Smckusick 6511645Smckusick for (np = lookupino(ep->e_ino); np != NIL && np != ep; np = np->e_links) 6611645Smckusick i++; 6711645Smckusick if (np == NIL) 6811645Smckusick badentry(ep, "not on ino list"); 6911733Smckusick (void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino); 7011645Smckusick return (name); 7111645Smckusick } 7211645Smckusick 7311645Smckusick /* 7410315Smckusick * Rename a file or directory. 7510315Smckusick */ 7610315Smckusick renameit(from, to) 7710315Smckusick char *from, *to; 7810315Smckusick { 7910315Smckusick if (rename(from, to) < 0) { 8012557Smckusick fprintf(stderr, "Warning: cannot rename %s to %s", from, to); 8112557Smckusick (void) fflush(stderr); 8212557Smckusick perror(""); 8311923Smckusick return; 8410315Smckusick } 8510315Smckusick vprintf(stdout, "rename %s to %s\n", from, to); 8610315Smckusick } 8710315Smckusick 8810315Smckusick /* 8910315Smckusick * Create a new node (directory). 9010315Smckusick */ 9110315Smckusick newnode(np) 9210315Smckusick struct entry *np; 9310315Smckusick { 9410315Smckusick char *cp; 9510315Smckusick 9610315Smckusick if (np->e_type != NODE) 9710315Smckusick badentry(np, "newnode: not a node"); 9810315Smckusick cp = myname(np); 9911312Smckusick if (mkdir(cp, 0777) < 0) { 100*18006Smckusick np->e_flags |= EXISTED; 10111740Smckusick fprintf(stderr, "Warning: "); 10211995Smckusick (void) fflush(stderr); 10311740Smckusick perror(cp); 10411740Smckusick return; 10510315Smckusick } 10610315Smckusick vprintf(stdout, "Make node %s\n", cp); 10710315Smckusick } 10810315Smckusick 10910315Smckusick /* 11010315Smckusick * Remove an old node (directory). 11110315Smckusick */ 11210315Smckusick removenode(ep) 11310315Smckusick register struct entry *ep; 11410315Smckusick { 11510315Smckusick char *cp; 11610315Smckusick 11710315Smckusick if (ep->e_type != NODE) 11810315Smckusick badentry(ep, "removenode: not a node"); 11910315Smckusick if (ep->e_entries != NIL) 12010315Smckusick badentry(ep, "removenode: non-empty directory"); 12111923Smckusick ep->e_flags |= REMOVED; 12211923Smckusick ep->e_flags &= ~TMPNAME; 12310315Smckusick cp = myname(ep); 12410315Smckusick if (rmdir(cp) < 0) { 12511923Smckusick fprintf(stderr, "Warning: "); 12611995Smckusick (void) fflush(stderr); 12711923Smckusick perror(cp); 12811923Smckusick return; 12910315Smckusick } 13010315Smckusick vprintf(stdout, "Remove node %s\n", cp); 13110315Smckusick } 13210315Smckusick 13310315Smckusick /* 13410315Smckusick * Remove a leaf. 13510315Smckusick */ 13610315Smckusick removeleaf(ep) 13710315Smckusick register struct entry *ep; 13810315Smckusick { 13910315Smckusick char *cp; 14010315Smckusick 14110315Smckusick if (ep->e_type != LEAF) 14210315Smckusick badentry(ep, "removeleaf: not a leaf"); 14311923Smckusick ep->e_flags |= REMOVED; 14411923Smckusick ep->e_flags &= ~TMPNAME; 14510315Smckusick cp = myname(ep); 14610315Smckusick if (unlink(cp) < 0) { 14711923Smckusick fprintf(stderr, "Warning: "); 14811995Smckusick (void) fflush(stderr); 14911923Smckusick perror(cp); 15011923Smckusick return; 15110315Smckusick } 15210315Smckusick vprintf(stdout, "Remove leaf %s\n", cp); 15310315Smckusick } 15410315Smckusick 15510315Smckusick /* 15610315Smckusick * Create a link. 15710315Smckusick */ 15810315Smckusick linkit(existing, new, type) 15910315Smckusick char *existing, *new; 16010315Smckusick int type; 16110315Smckusick { 16210315Smckusick 16310315Smckusick if (type == SYMLINK) { 16410315Smckusick if (symlink(existing, new) < 0) { 16511923Smckusick fprintf(stderr, 16615782Smckusick "Warning: cannot create symbolic link %s->%s: ", 16710315Smckusick new, existing); 16812557Smckusick (void) fflush(stderr); 16912557Smckusick perror(""); 17015782Smckusick return (FAIL); 17110315Smckusick } 17210315Smckusick } else if (type == HARDLINK) { 17310315Smckusick if (link(existing, new) < 0) { 17411923Smckusick fprintf(stderr, 17515782Smckusick "Warning: cannot create hard link %s->%s: ", 17610315Smckusick new, existing); 17712557Smckusick (void) fflush(stderr); 17812557Smckusick perror(""); 17915782Smckusick return (FAIL); 18010315Smckusick } 18110315Smckusick } else { 18210315Smckusick panic("linkit: unknown type %d\n", type); 18315782Smckusick return (FAIL); 18410315Smckusick } 18510315Smckusick vprintf(stdout, "Create %s link %s->%s\n", 18610315Smckusick type == SYMLINK ? "symbolic" : "hard", new, existing); 18715782Smckusick return (GOOD); 18810315Smckusick } 18910315Smckusick 19010315Smckusick /* 19110315Smckusick * find lowest number file (above "start") that needs to be extracted 19210315Smckusick */ 19310315Smckusick ino_t 19410315Smckusick lowerbnd(start) 19510315Smckusick ino_t start; 19610315Smckusick { 19710315Smckusick register struct entry *ep; 19810315Smckusick 19910315Smckusick for ( ; start < maxino; start++) { 20010315Smckusick ep = lookupino(start); 20111995Smckusick if (ep == NIL || ep->e_type == NODE) 20210315Smckusick continue; 20311645Smckusick if (ep->e_flags & (NEW|EXTRACT)) 20410315Smckusick return (start); 20510315Smckusick } 20610315Smckusick return (start); 20710315Smckusick } 20810315Smckusick 20910315Smckusick /* 21010315Smckusick * find highest number file (below "start") that needs to be extracted 21110315Smckusick */ 21210315Smckusick ino_t 21310315Smckusick upperbnd(start) 21410315Smckusick ino_t start; 21510315Smckusick { 21610315Smckusick register struct entry *ep; 21710315Smckusick 21810315Smckusick for ( ; start > ROOTINO; start--) { 21910315Smckusick ep = lookupino(start); 22011995Smckusick if (ep == NIL || ep->e_type == NODE) 22110315Smckusick continue; 22211645Smckusick if (ep->e_flags & (NEW|EXTRACT)) 22310315Smckusick return (start); 22410315Smckusick } 22510315Smckusick return (start); 22610315Smckusick } 22710315Smckusick 22810315Smckusick /* 22910315Smckusick * report on a badly formed entry 23010315Smckusick */ 23110315Smckusick badentry(ep, msg) 23210315Smckusick register struct entry *ep; 23310315Smckusick char *msg; 23410315Smckusick { 23510315Smckusick 23610315Smckusick fprintf(stderr, "bad entry: %s\n", msg); 23710315Smckusick fprintf(stderr, "name: %s\n", myname(ep)); 23810315Smckusick fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 23910315Smckusick if (ep->e_sibling != NIL) 24010315Smckusick fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 24110315Smckusick if (ep->e_entries != NIL) 24210315Smckusick fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 24310315Smckusick if (ep->e_links != NIL) 24410315Smckusick fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 24511645Smckusick if (ep->e_next != NIL) 24611645Smckusick fprintf(stderr, "next hashchain name: %s\n", myname(ep->e_next)); 24710315Smckusick fprintf(stderr, "entry type: %s\n", 24810315Smckusick ep->e_type == NODE ? "NODE" : "LEAF"); 24910315Smckusick fprintf(stderr, "inode number: %ld\n", ep->e_ino); 25011898Smckusick panic("flags: %s\n", flagvalues(ep)); 25111898Smckusick } 25211898Smckusick 25311898Smckusick /* 25411898Smckusick * Construct a string indicating the active flag bits of an entry. 25511898Smckusick */ 25611898Smckusick char * 25711898Smckusick flagvalues(ep) 25811898Smckusick register struct entry *ep; 25911898Smckusick { 26011898Smckusick static char flagbuf[BUFSIZ]; 26111898Smckusick 26211898Smckusick (void) strcpy(flagbuf, "|NIL"); 26310315Smckusick flagbuf[0] = '\0'; 26410315Smckusick if (ep->e_flags & REMOVED) 26511898Smckusick (void) strcat(flagbuf, "|REMOVED"); 26610315Smckusick if (ep->e_flags & TMPNAME) 26711898Smckusick (void) strcat(flagbuf, "|TMPNAME"); 26810315Smckusick if (ep->e_flags & EXTRACT) 26911898Smckusick (void) strcat(flagbuf, "|EXTRACT"); 27010315Smckusick if (ep->e_flags & NEW) 27111898Smckusick (void) strcat(flagbuf, "|NEW"); 27210315Smckusick if (ep->e_flags & KEEP) 27311898Smckusick (void) strcat(flagbuf, "|KEEP"); 274*18006Smckusick if (ep->e_flags & EXISTED) 275*18006Smckusick (void) strcat(flagbuf, "|EXISTED"); 27611898Smckusick return (&flagbuf[1]); 27710315Smckusick } 27810315Smckusick 27910315Smckusick /* 28011995Smckusick * Check to see if a name is on a dump tape. 28111321Smckusick */ 28211995Smckusick ino_t 28311995Smckusick dirlookup(name) 28411995Smckusick char *name; 28511995Smckusick { 28611995Smckusick ino_t ino; 28711995Smckusick 28811995Smckusick ino = psearch(name); 28911995Smckusick if (ino == 0 || BIT(ino, dumpmap) == 0) 29011995Smckusick fprintf(stderr, "%s is not on tape\n", name); 29111995Smckusick return (ino); 29211995Smckusick } 29311995Smckusick 29411995Smckusick /* 29511995Smckusick * Elicit a reply. 29610315Smckusick */ 29710315Smckusick reply(question) 29810315Smckusick char *question; 29910315Smckusick { 30010315Smckusick char c; 30110315Smckusick 30210315Smckusick fprintf(stderr, "%s? ", question); 30310315Smckusick do { 30410315Smckusick fprintf(stderr, "[yn] "); 30512557Smckusick (void) fflush(stderr); 30611995Smckusick c = getc(terminal); 30711995Smckusick while (c != '\n' && getc(terminal) != '\n') 30817711Smckusick if (feof(terminal)) 30917711Smckusick done(1); 31010315Smckusick } while (c != 'y' && c != 'n'); 31110315Smckusick if (c == 'y') 31210315Smckusick return (GOOD); 31310315Smckusick return (FAIL); 31410315Smckusick } 31511995Smckusick 31611995Smckusick /* 31711995Smckusick * handle unexpected inconsistencies 31811995Smckusick */ 31911995Smckusick /* VARARGS1 */ 32011995Smckusick panic(msg, d1, d2) 32111995Smckusick char *msg; 32211995Smckusick long d1, d2; 32311995Smckusick { 32411995Smckusick 32511995Smckusick fprintf(stderr, msg, d1, d2); 32611995Smckusick if (reply("abort") == GOOD) { 32711995Smckusick if (reply("dump core") == GOOD) 32811995Smckusick abort(); 32911995Smckusick done(1); 33011995Smckusick } 33111995Smckusick } 332