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