155714Skris/* 255714Skris * Copyright (c) 1983, 1993 355714Skris * The Regents of the University of California. All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms, with or without 655714Skris * modification, are permitted provided that the following conditions 755714Skris * are met: 855714Skris * 1. Redistributions of source code must retain the above copyright 955714Skris * notice, this list of conditions and the following disclaimer. 1055714Skris * 2. Redistributions in binary form must reproduce the above copyright 1155714Skris * notice, this list of conditions and the following disclaimer in the 1255714Skris * documentation and/or other materials provided with the distribution. 1355714Skris * 4. Neither the name of the University nor the names of its contributors 1455714Skris * may be used to endorse or promote products derived from this software 1555714Skris * without specific prior written permission. 1655714Skris * 1755714Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1855714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1955714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2055714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2155714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2255714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2355714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2455714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2555714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2655714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2755714Skris * SUCH DAMAGE. 2855714Skris */ 2955714Skris 3055714Skris#ifndef lint 3155714Skris#if 0 3255714Skrisstatic char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95"; 3355714Skris#endif 3455714Skrisstatic const char rcsid[] = 3555714Skris "$FreeBSD: releng/10.2/sbin/restore/utilities.c 236213 2012-05-29 01:48:06Z kevlo $"; 3655714Skris#endif /* not lint */ 3755714Skris 3855714Skris#include <sys/param.h> 3955714Skris#include <sys/stat.h> 4055714Skris 4155714Skris#include <ufs/ufs/dinode.h> 4255714Skris#include <ufs/ufs/dir.h> 4355714Skris 4455714Skris#include <errno.h> 4555714Skris#include <limits.h> 4655714Skris#include <stdio.h> 4755714Skris#include <stdlib.h> 4855714Skris#include <string.h> 4955714Skris#include <unistd.h> 5055714Skris 5155714Skris#include "restore.h" 5255714Skris#include "extern.h" 5355714Skris 5455714Skris/* 5555714Skris * Insure that all the components of a pathname exist. 5655714Skris */ 5755714Skrisvoid 5855714Skrispathcheck(char *name) 5955714Skris{ 6055714Skris char *cp; 6155714Skris struct entry *ep; 6255714Skris char *start; 6355714Skris 6455714Skris start = strchr(name, '/'); 6555714Skris if (start == 0) 6655714Skris return; 6755714Skris for (cp = start; *cp != '\0'; cp++) { 6855714Skris if (*cp != '/') 6955714Skris continue; 7055714Skris *cp = '\0'; 7155714Skris ep = lookupname(name); 7255714Skris if (ep == NULL) { 7355714Skris /* Safe; we know the pathname exists in the dump. */ 7455714Skris ep = addentry(name, pathsearch(name)->d_ino, NODE); 7555714Skris newnode(ep); 7655714Skris } 7755714Skris ep->e_flags |= NEW|KEEP; 7855714Skris *cp = '/'; 7955714Skris } 8055714Skris} 8155714Skris 8255714Skris/* 8355714Skris * Change a name to a unique temporary name. 8455714Skris */ 8555714Skrisvoid 8655714Skrismktempname(struct entry *ep) 8755714Skris{ 8855714Skris char oldname[MAXPATHLEN]; 8955714Skris 9055714Skris if (ep->e_flags & TMPNAME) 9155714Skris badentry(ep, "mktempname: called with TMPNAME"); 9255714Skris ep->e_flags |= TMPNAME; 9355714Skris (void) strcpy(oldname, myname(ep)); 9455714Skris freename(ep->e_name); 9555714Skris ep->e_name = savename(gentempname(ep)); 9655714Skris ep->e_namlen = strlen(ep->e_name); 9755714Skris renameit(oldname, myname(ep)); 9855714Skris} 9955714Skris 10055714Skris/* 10155714Skris * Generate a temporary name for an entry. 10255714Skris */ 10355714Skrischar * 10455714Skrisgentempname(struct entry *ep) 10555714Skris{ 10655714Skris static char name[MAXPATHLEN]; 10755714Skris struct entry *np; 10855714Skris long i = 0; 10955714Skris 11055714Skris for (np = lookupino(ep->e_ino); 11155714Skris np != NULL && np != ep; np = np->e_links) 11255714Skris i++; 11355714Skris if (np == NULL) 11455714Skris badentry(ep, "not on ino list"); 11555714Skris (void) sprintf(name, "%s%ld%lu", TMPHDR, i, (u_long)ep->e_ino); 11655714Skris return (name); 11755714Skris} 11855714Skris 11955714Skris/* 12055714Skris * Rename a file or directory. 12155714Skris */ 12255714Skrisvoid 12355714Skrisrenameit(char *from, char *to) 12455714Skris{ 12555714Skris if (!Nflag && rename(from, to) < 0) { 12655714Skris fprintf(stderr, "warning: cannot rename %s to %s: %s\n", 12755714Skris from, to, strerror(errno)); 12855714Skris return; 12955714Skris } 13055714Skris vprintf(stdout, "rename %s to %s\n", from, to); 13155714Skris} 13255714Skris 13355714Skris/* 13455714Skris * Create a new node (directory). 13555714Skris */ 13655714Skrisvoid 13755714Skrisnewnode(struct entry *np) 13855714Skris{ 13955714Skris char *cp; 14055714Skris 14155714Skris if (np->e_type != NODE) 14255714Skris badentry(np, "newnode: not a node"); 14355714Skris cp = myname(np); 14455714Skris if (!Nflag && mkdir(cp, 0777) < 0 && !uflag) { 14555714Skris np->e_flags |= EXISTED; 14655714Skris fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 14755714Skris return; 14855714Skris } 14955714Skris vprintf(stdout, "Make node %s\n", cp); 15055714Skris} 15155714Skris 15255714Skris/* 15355714Skris * Remove an old node (directory). 15455714Skris */ 15555714Skrisvoid 15655714Skrisremovenode(struct entry *ep) 15755714Skris{ 15855714Skris char *cp; 15955714Skris 16055714Skris if (ep->e_type != NODE) 16155714Skris badentry(ep, "removenode: not a node"); 16255714Skris if (ep->e_entries != NULL) 16355714Skris badentry(ep, "removenode: non-empty directory"); 16455714Skris ep->e_flags |= REMOVED; 16555714Skris ep->e_flags &= ~TMPNAME; 16655714Skris cp = myname(ep); 16755714Skris if (!Nflag && rmdir(cp) < 0) { 16855714Skris fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 16955714Skris return; 17055714Skris } 17155714Skris vprintf(stdout, "Remove node %s\n", cp); 17255714Skris} 17355714Skris 17455714Skris/* 17555714Skris * Remove a leaf. 17655714Skris */ 17755714Skrisvoid 17855714Skrisremoveleaf(struct entry *ep) 17955714Skris{ 18055714Skris char *cp; 18155714Skris 18255714Skris if (ep->e_type != LEAF) 18355714Skris badentry(ep, "removeleaf: not a leaf"); 18455714Skris ep->e_flags |= REMOVED; 18555714Skris ep->e_flags &= ~TMPNAME; 18655714Skris cp = myname(ep); 18755714Skris if (!Nflag && unlink(cp) < 0) { 18855714Skris fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno)); 18955714Skris return; 19055714Skris } 19155714Skris vprintf(stdout, "Remove leaf %s\n", cp); 19255714Skris} 19355714Skris 19455714Skris/* 19555714Skris * Create a link. 19655714Skris */ 19755714Skrisint 19855714Skrislinkit(char *existing, char *new, int type) 19955714Skris{ 20055714Skris 20155714Skris /* if we want to unlink first, do it now so *link() won't fail */ 20255714Skris if (uflag && !Nflag) 20355714Skris (void)unlink(new); 20455714Skris 20555714Skris if (type == SYMLINK) { 20655714Skris if (!Nflag && symlink(existing, new) < 0) { 20755714Skris fprintf(stderr, 20855714Skris "warning: cannot create symbolic link %s->%s: %s\n", 20955714Skris new, existing, strerror(errno)); 21055714Skris return (FAIL); 21155714Skris } 21255714Skris } else if (type == HARDLINK) { 21355714Skris int ret; 21455714Skris 21555714Skris if (!Nflag && (ret = link(existing, new)) < 0) { 21655714Skris struct stat s; 21755714Skris 21855714Skris /* 21955714Skris * Most likely, the schg flag is set. Clear the 22055714Skris * flags and try again. 22155714Skris */ 22255714Skris if (stat(existing, &s) == 0 && s.st_flags != 0 && 22355714Skris chflags(existing, 0) == 0) { 22455714Skris ret = link(existing, new); 22555714Skris chflags(existing, s.st_flags); 22655714Skris } 22755714Skris if (ret < 0) { 22855714Skris fprintf(stderr, "warning: cannot create " 22955714Skris "hard link %s->%s: %s\n", 23055714Skris new, existing, strerror(errno)); 23155714Skris return (FAIL); 23255714Skris } 23355714Skris } 23455714Skris } else { 23555714Skris panic("linkit: unknown type %d\n", type); 23655714Skris return (FAIL); 23755714Skris } 23855714Skris vprintf(stdout, "Create %s link %s->%s\n", 23955714Skris type == SYMLINK ? "symbolic" : "hard", new, existing); 24055714Skris return (GOOD); 24155714Skris} 24255714Skris 24355714Skris/* 24455714Skris * Create a whiteout. 24555714Skris */ 24655714Skrisint 24755714Skrisaddwhiteout(char *name) 24855714Skris{ 24955714Skris 25055714Skris if (!Nflag && mknod(name, S_IFWHT, 0) < 0) { 25155714Skris fprintf(stderr, "warning: cannot create whiteout %s: %s\n", 25255714Skris name, strerror(errno)); 25355714Skris return (FAIL); 25455714Skris } 25555714Skris vprintf(stdout, "Create whiteout %s\n", name); 25655714Skris return (GOOD); 25755714Skris} 25855714Skris 25955714Skris/* 26055714Skris * Delete a whiteout. 26155714Skris */ 26255714Skrisvoid 26355714Skrisdelwhiteout(struct entry *ep) 26455714Skris{ 26555714Skris char *name; 26655714Skris 26755714Skris if (ep->e_type != LEAF) 26855714Skris badentry(ep, "delwhiteout: not a leaf"); 26955714Skris ep->e_flags |= REMOVED; 27055714Skris ep->e_flags &= ~TMPNAME; 27155714Skris name = myname(ep); 27255714Skris if (!Nflag && undelete(name) < 0) { 27355714Skris fprintf(stderr, "warning: cannot delete whiteout %s: %s\n", 27455714Skris name, strerror(errno)); 27555714Skris return; 27655714Skris } 27755714Skris vprintf(stdout, "Delete whiteout %s\n", name); 27855714Skris} 27955714Skris 28055714Skris/* 28155714Skris * find lowest number file (above "start") that needs to be extracted 28255714Skris */ 28355714Skrisino_t 28455714Skrislowerbnd(ino_t start) 28555714Skris{ 28655714Skris struct entry *ep; 28755714Skris 28855714Skris for ( ; start < maxino; start++) { 28955714Skris ep = lookupino(start); 29055714Skris if (ep == NULL || ep->e_type == NODE) 29155714Skris continue; 29255714Skris if (ep->e_flags & (NEW|EXTRACT)) 29355714Skris return (start); 29455714Skris } 29555714Skris return (start); 29655714Skris} 29755714Skris 29855714Skris/* 29955714Skris * find highest number file (below "start") that needs to be extracted 30055714Skris */ 30155714Skrisino_t 30255714Skrisupperbnd(ino_t start) 30355714Skris{ 30455714Skris struct entry *ep; 30555714Skris 30655714Skris for ( ; start > ROOTINO; start--) { 30755714Skris ep = lookupino(start); 30855714Skris if (ep == NULL || ep->e_type == NODE) 30955714Skris continue; 31055714Skris if (ep->e_flags & (NEW|EXTRACT)) 31155714Skris return (start); 31255714Skris } 31355714Skris return (start); 31455714Skris} 31555714Skris 31655714Skris/* 31755714Skris * report on a badly formed entry 31855714Skris */ 31955714Skrisvoid 32055714Skrisbadentry(struct entry *ep, char *msg) 32155714Skris{ 32255714Skris 32355714Skris fprintf(stderr, "bad entry: %s\n", msg); 32455714Skris fprintf(stderr, "name: %s\n", myname(ep)); 32555714Skris fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); 32655714Skris if (ep->e_sibling != NULL) 32755714Skris fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); 32855714Skris if (ep->e_entries != NULL) 32955714Skris fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); 33055714Skris if (ep->e_links != NULL) 33155714Skris fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); 33255714Skris if (ep->e_next != NULL) 33355714Skris fprintf(stderr, 33455714Skris "next hashchain name: %s\n", myname(ep->e_next)); 33555714Skris fprintf(stderr, "entry type: %s\n", 33655714Skris ep->e_type == NODE ? "NODE" : "LEAF"); 33755714Skris fprintf(stderr, "inode number: %lu\n", (u_long)ep->e_ino); 33855714Skris panic("flags: %s\n", flagvalues(ep)); 33955714Skris} 34055714Skris 34155714Skris/* 34255714Skris * Construct a string indicating the active flag bits of an entry. 34355714Skris */ 34455714Skrischar * 34555714Skrisflagvalues(struct entry *ep) 34655714Skris{ 34755714Skris static char flagbuf[BUFSIZ]; 34855714Skris 34955714Skris (void) strcpy(flagbuf, "|NIL"); 35055714Skris flagbuf[0] = '\0'; 35155714Skris if (ep->e_flags & REMOVED) 35255714Skris (void) strcat(flagbuf, "|REMOVED"); 35355714Skris if (ep->e_flags & TMPNAME) 35455714Skris (void) strcat(flagbuf, "|TMPNAME"); 35555714Skris if (ep->e_flags & EXTRACT) 35655714Skris (void) strcat(flagbuf, "|EXTRACT"); 35755714Skris if (ep->e_flags & NEW) 35855714Skris (void) strcat(flagbuf, "|NEW"); 35955714Skris if (ep->e_flags & KEEP) 36055714Skris (void) strcat(flagbuf, "|KEEP"); 36155714Skris if (ep->e_flags & EXISTED) 36255714Skris (void) strcat(flagbuf, "|EXISTED"); 36355714Skris return (&flagbuf[1]); 36455714Skris} 36555714Skris 36655714Skris/* 36755714Skris * Check to see if a name is on a dump tape. 36855714Skris */ 36955714Skrisino_t 37055714Skrisdirlookup(const char *name) 37155714Skris{ 37255714Skris struct direct *dp; 37355714Skris ino_t ino; 37455714Skris 37555714Skris ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino; 37655714Skris 37755714Skris if (ino == 0 || TSTINO(ino, dumpmap) == 0) 37855714Skris fprintf(stderr, "%s is not on the tape\n", name); 37955714Skris return (ino); 38055714Skris} 38155714Skris 38255714Skris/* 38355714Skris * Elicit a reply. 38455714Skris */ 38555714Skrisint 38655714Skrisreply(char *question) 38755714Skris{ 38855714Skris int c; 38955714Skris 39055714Skris do { 39155714Skris fprintf(stderr, "%s? [yn] ", question); 39255714Skris (void) fflush(stderr); 39355714Skris c = getc(terminal); 39455714Skris while (c != '\n' && getc(terminal) != '\n') 39555714Skris if (c == EOF) 39655714Skris return (FAIL); 39755714Skris } while (c != 'y' && c != 'n'); 39855714Skris if (c == 'y') 39955714Skris return (GOOD); 40055714Skris return (FAIL); 40155714Skris} 40255714Skris 40355714Skris/* 40455714Skris * handle unexpected inconsistencies 40555714Skris */ 40655714Skris#include <stdarg.h> 40755714Skris 40855714Skrisvoid 40955714Skrispanic(const char *fmt, ...) 41055714Skris{ 41155714Skris va_list ap; 41255714Skris va_start(ap, fmt); 41355714Skris vfprintf(stderr, fmt, ap); 41455714Skris va_end(ap); 41555714Skris if (yflag) 41655714Skris return; 41755714Skris if (reply("abort") == GOOD) { 41855714Skris if (reply("dump core") == GOOD) 41955714Skris abort(); 42055714Skris done(1); 42155714Skris } 42255714Skris} 42355714Skris