utilities.c revision 1558
11558Srgrimes/*
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 * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *	This product includes software developed by the University of
161558Srgrimes *	California, Berkeley and its contributors.
171558Srgrimes * 4. Neither the name of the University nor the names of its contributors
181558Srgrimes *    may be used to endorse or promote products derived from this software
191558Srgrimes *    without specific prior written permission.
201558Srgrimes *
211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311558Srgrimes * SUCH DAMAGE.
321558Srgrimes */
331558Srgrimes
341558Srgrimes#ifndef lint
351558Srgrimesstatic char sccsid[] = "@(#)utilities.c	8.2 (Berkeley) 3/25/94";
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>
451558Srgrimes#include <stdio.h>
461558Srgrimes#include <stdlib.h>
471558Srgrimes#include <string.h>
481558Srgrimes#include <unistd.h>
491558Srgrimes
501558Srgrimes#include "restore.h"
511558Srgrimes#include "extern.h"
521558Srgrimes
531558Srgrimes/*
541558Srgrimes * Insure that all the components of a pathname exist.
551558Srgrimes */
561558Srgrimesvoid
571558Srgrimespathcheck(name)
581558Srgrimes	char *name;
591558Srgrimes{
601558Srgrimes	register char *cp;
611558Srgrimes	struct entry *ep;
621558Srgrimes	char *start;
631558Srgrimes
641558Srgrimes	start = index(name, '/');
651558Srgrimes	if (start == 0)
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
861558Srgrimesmktempname(ep)
871558Srgrimes	register struct entry *ep;
881558Srgrimes{
891558Srgrimes	char oldname[MAXPATHLEN];
901558Srgrimes
911558Srgrimes	if (ep->e_flags & TMPNAME)
921558Srgrimes		badentry(ep, "mktempname: called with TMPNAME");
931558Srgrimes	ep->e_flags |= TMPNAME;
941558Srgrimes	(void) strcpy(oldname, myname(ep));
951558Srgrimes	freename(ep->e_name);
961558Srgrimes	ep->e_name = savename(gentempname(ep));
971558Srgrimes	ep->e_namlen = strlen(ep->e_name);
981558Srgrimes	renameit(oldname, myname(ep));
991558Srgrimes}
1001558Srgrimes
1011558Srgrimes/*
1021558Srgrimes * Generate a temporary name for an entry.
1031558Srgrimes */
1041558Srgrimeschar *
1051558Srgrimesgentempname(ep)
1061558Srgrimes	struct entry *ep;
1071558Srgrimes{
1081558Srgrimes	static char name[MAXPATHLEN];
1091558Srgrimes	struct entry *np;
1101558Srgrimes	long i = 0;
1111558Srgrimes
1121558Srgrimes	for (np = lookupino(ep->e_ino);
1131558Srgrimes	    np != NULL && np != ep; np = np->e_links)
1141558Srgrimes		i++;
1151558Srgrimes	if (np == NULL)
1161558Srgrimes		badentry(ep, "not on ino list");
1171558Srgrimes	(void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino);
1181558Srgrimes	return (name);
1191558Srgrimes}
1201558Srgrimes
1211558Srgrimes/*
1221558Srgrimes * Rename a file or directory.
1231558Srgrimes */
1241558Srgrimesvoid
1251558Srgrimesrenameit(from, to)
1261558Srgrimes	char *from, *to;
1271558Srgrimes{
1281558Srgrimes	if (!Nflag && rename(from, to) < 0) {
1291558Srgrimes		fprintf(stderr, "warning: cannot rename %s to %s: %s\n",
1301558Srgrimes		    from, to, strerror(errno));
1311558Srgrimes		return;
1321558Srgrimes	}
1331558Srgrimes	vprintf(stdout, "rename %s to %s\n", from, to);
1341558Srgrimes}
1351558Srgrimes
1361558Srgrimes/*
1371558Srgrimes * Create a new node (directory).
1381558Srgrimes */
1391558Srgrimesvoid
1401558Srgrimesnewnode(np)
1411558Srgrimes	struct entry *np;
1421558Srgrimes{
1431558Srgrimes	char *cp;
1441558Srgrimes
1451558Srgrimes	if (np->e_type != NODE)
1461558Srgrimes		badentry(np, "newnode: not a node");
1471558Srgrimes	cp = myname(np);
1481558Srgrimes	if (!Nflag && mkdir(cp, 0777) < 0) {
1491558Srgrimes		np->e_flags |= EXISTED;
1501558Srgrimes		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
1511558Srgrimes		return;
1521558Srgrimes	}
1531558Srgrimes	vprintf(stdout, "Make node %s\n", cp);
1541558Srgrimes}
1551558Srgrimes
1561558Srgrimes/*
1571558Srgrimes * Remove an old node (directory).
1581558Srgrimes */
1591558Srgrimesvoid
1601558Srgrimesremovenode(ep)
1611558Srgrimes	register struct entry *ep;
1621558Srgrimes{
1631558Srgrimes	char *cp;
1641558Srgrimes
1651558Srgrimes	if (ep->e_type != NODE)
1661558Srgrimes		badentry(ep, "removenode: not a node");
1671558Srgrimes	if (ep->e_entries != NULL)
1681558Srgrimes		badentry(ep, "removenode: non-empty directory");
1691558Srgrimes	ep->e_flags |= REMOVED;
1701558Srgrimes	ep->e_flags &= ~TMPNAME;
1711558Srgrimes	cp = myname(ep);
1721558Srgrimes	if (!Nflag && rmdir(cp) < 0) {
1731558Srgrimes		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
1741558Srgrimes		return;
1751558Srgrimes	}
1761558Srgrimes	vprintf(stdout, "Remove node %s\n", cp);
1771558Srgrimes}
1781558Srgrimes
1791558Srgrimes/*
1801558Srgrimes * Remove a leaf.
1811558Srgrimes */
1821558Srgrimesvoid
1831558Srgrimesremoveleaf(ep)
1841558Srgrimes	register struct entry *ep;
1851558Srgrimes{
1861558Srgrimes	char *cp;
1871558Srgrimes
1881558Srgrimes	if (ep->e_type != LEAF)
1891558Srgrimes		badentry(ep, "removeleaf: not a leaf");
1901558Srgrimes	ep->e_flags |= REMOVED;
1911558Srgrimes	ep->e_flags &= ~TMPNAME;
1921558Srgrimes	cp = myname(ep);
1931558Srgrimes	if (!Nflag && unlink(cp) < 0) {
1941558Srgrimes		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
1951558Srgrimes		return;
1961558Srgrimes	}
1971558Srgrimes	vprintf(stdout, "Remove leaf %s\n", cp);
1981558Srgrimes}
1991558Srgrimes
2001558Srgrimes/*
2011558Srgrimes * Create a link.
2021558Srgrimes */
2031558Srgrimesint
2041558Srgrimeslinkit(existing, new, type)
2051558Srgrimes	char *existing, *new;
2061558Srgrimes	int type;
2071558Srgrimes{
2081558Srgrimes
2091558Srgrimes	if (type == SYMLINK) {
2101558Srgrimes		if (!Nflag && symlink(existing, new) < 0) {
2111558Srgrimes			fprintf(stderr,
2121558Srgrimes			    "warning: cannot create symbolic link %s->%s: %s\n",
2131558Srgrimes			    new, existing, strerror(errno));
2141558Srgrimes			return (FAIL);
2151558Srgrimes		}
2161558Srgrimes	} else if (type == HARDLINK) {
2171558Srgrimes		if (!Nflag && link(existing, new) < 0) {
2181558Srgrimes			fprintf(stderr,
2191558Srgrimes			    "warning: cannot create hard link %s->%s: %s\n",
2201558Srgrimes			    new, existing, strerror(errno));
2211558Srgrimes			return (FAIL);
2221558Srgrimes		}
2231558Srgrimes	} else {
2241558Srgrimes		panic("linkit: unknown type %d\n", type);
2251558Srgrimes		return (FAIL);
2261558Srgrimes	}
2271558Srgrimes	vprintf(stdout, "Create %s link %s->%s\n",
2281558Srgrimes		type == SYMLINK ? "symbolic" : "hard", new, existing);
2291558Srgrimes	return (GOOD);
2301558Srgrimes}
2311558Srgrimes
2321558Srgrimes/*
2331558Srgrimes * find lowest number file (above "start") that needs to be extracted
2341558Srgrimes */
2351558Srgrimesino_t
2361558Srgrimeslowerbnd(start)
2371558Srgrimes	ino_t start;
2381558Srgrimes{
2391558Srgrimes	register struct entry *ep;
2401558Srgrimes
2411558Srgrimes	for ( ; start < maxino; start++) {
2421558Srgrimes		ep = lookupino(start);
2431558Srgrimes		if (ep == NULL || ep->e_type == NODE)
2441558Srgrimes			continue;
2451558Srgrimes		if (ep->e_flags & (NEW|EXTRACT))
2461558Srgrimes			return (start);
2471558Srgrimes	}
2481558Srgrimes	return (start);
2491558Srgrimes}
2501558Srgrimes
2511558Srgrimes/*
2521558Srgrimes * find highest number file (below "start") that needs to be extracted
2531558Srgrimes */
2541558Srgrimesino_t
2551558Srgrimesupperbnd(start)
2561558Srgrimes	ino_t start;
2571558Srgrimes{
2581558Srgrimes	register struct entry *ep;
2591558Srgrimes
2601558Srgrimes	for ( ; start > ROOTINO; start--) {
2611558Srgrimes		ep = lookupino(start);
2621558Srgrimes		if (ep == NULL || ep->e_type == NODE)
2631558Srgrimes			continue;
2641558Srgrimes		if (ep->e_flags & (NEW|EXTRACT))
2651558Srgrimes			return (start);
2661558Srgrimes	}
2671558Srgrimes	return (start);
2681558Srgrimes}
2691558Srgrimes
2701558Srgrimes/*
2711558Srgrimes * report on a badly formed entry
2721558Srgrimes */
2731558Srgrimesvoid
2741558Srgrimesbadentry(ep, msg)
2751558Srgrimes	register struct entry *ep;
2761558Srgrimes	char *msg;
2771558Srgrimes{
2781558Srgrimes
2791558Srgrimes	fprintf(stderr, "bad entry: %s\n", msg);
2801558Srgrimes	fprintf(stderr, "name: %s\n", myname(ep));
2811558Srgrimes	fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
2821558Srgrimes	if (ep->e_sibling != NULL)
2831558Srgrimes		fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
2841558Srgrimes	if (ep->e_entries != NULL)
2851558Srgrimes		fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
2861558Srgrimes	if (ep->e_links != NULL)
2871558Srgrimes		fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
2881558Srgrimes	if (ep->e_next != NULL)
2891558Srgrimes		fprintf(stderr,
2901558Srgrimes		    "next hashchain name: %s\n", myname(ep->e_next));
2911558Srgrimes	fprintf(stderr, "entry type: %s\n",
2921558Srgrimes		ep->e_type == NODE ? "NODE" : "LEAF");
2931558Srgrimes	fprintf(stderr, "inode number: %ld\n", ep->e_ino);
2941558Srgrimes	panic("flags: %s\n", flagvalues(ep));
2951558Srgrimes}
2961558Srgrimes
2971558Srgrimes/*
2981558Srgrimes * Construct a string indicating the active flag bits of an entry.
2991558Srgrimes */
3001558Srgrimeschar *
3011558Srgrimesflagvalues(ep)
3021558Srgrimes	register struct entry *ep;
3031558Srgrimes{
3041558Srgrimes	static char flagbuf[BUFSIZ];
3051558Srgrimes
3061558Srgrimes	(void) strcpy(flagbuf, "|NIL");
3071558Srgrimes	flagbuf[0] = '\0';
3081558Srgrimes	if (ep->e_flags & REMOVED)
3091558Srgrimes		(void) strcat(flagbuf, "|REMOVED");
3101558Srgrimes	if (ep->e_flags & TMPNAME)
3111558Srgrimes		(void) strcat(flagbuf, "|TMPNAME");
3121558Srgrimes	if (ep->e_flags & EXTRACT)
3131558Srgrimes		(void) strcat(flagbuf, "|EXTRACT");
3141558Srgrimes	if (ep->e_flags & NEW)
3151558Srgrimes		(void) strcat(flagbuf, "|NEW");
3161558Srgrimes	if (ep->e_flags & KEEP)
3171558Srgrimes		(void) strcat(flagbuf, "|KEEP");
3181558Srgrimes	if (ep->e_flags & EXISTED)
3191558Srgrimes		(void) strcat(flagbuf, "|EXISTED");
3201558Srgrimes	return (&flagbuf[1]);
3211558Srgrimes}
3221558Srgrimes
3231558Srgrimes/*
3241558Srgrimes * Check to see if a name is on a dump tape.
3251558Srgrimes */
3261558Srgrimesino_t
3271558Srgrimesdirlookup(name)
3281558Srgrimes	const char *name;
3291558Srgrimes{
3301558Srgrimes	struct direct *dp;
3311558Srgrimes	ino_t ino;
3321558Srgrimes
3331558Srgrimes	ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
3341558Srgrimes
3351558Srgrimes	if (ino == 0 || TSTINO(ino, dumpmap) == 0)
3361558Srgrimes		fprintf(stderr, "%s is not on the tape\n", name);
3371558Srgrimes	return (ino);
3381558Srgrimes}
3391558Srgrimes
3401558Srgrimes/*
3411558Srgrimes * Elicit a reply.
3421558Srgrimes */
3431558Srgrimesint
3441558Srgrimesreply(question)
3451558Srgrimes	char *question;
3461558Srgrimes{
3471558Srgrimes	char c;
3481558Srgrimes
3491558Srgrimes	do	{
3501558Srgrimes		fprintf(stderr, "%s? [yn] ", question);
3511558Srgrimes		(void) fflush(stderr);
3521558Srgrimes		c = getc(terminal);
3531558Srgrimes		while (c != '\n' && getc(terminal) != '\n')
3541558Srgrimes			if (feof(terminal))
3551558Srgrimes				return (FAIL);
3561558Srgrimes	} while (c != 'y' && c != 'n');
3571558Srgrimes	if (c == 'y')
3581558Srgrimes		return (GOOD);
3591558Srgrimes	return (FAIL);
3601558Srgrimes}
3611558Srgrimes
3621558Srgrimes/*
3631558Srgrimes * handle unexpected inconsistencies
3641558Srgrimes */
3651558Srgrimes#if __STDC__
3661558Srgrimes#include <stdarg.h>
3671558Srgrimes#else
3681558Srgrimes#include <varargs.h>
3691558Srgrimes#endif
3701558Srgrimes
3711558Srgrimesvoid
3721558Srgrimes#if __STDC__
3731558Srgrimespanic(const char *fmt, ...)
3741558Srgrimes#else
3751558Srgrimespanic(fmt, va_alist)
3761558Srgrimes	char *fmt;
3771558Srgrimes	va_dcl
3781558Srgrimes#endif
3791558Srgrimes{
3801558Srgrimes	va_list ap;
3811558Srgrimes#if __STDC__
3821558Srgrimes	va_start(ap, fmt);
3831558Srgrimes#else
3841558Srgrimes	va_start(ap);
3851558Srgrimes#endif
3861558Srgrimes
3871558Srgrimes	vfprintf(stderr, fmt, ap);
3881558Srgrimes	if (yflag)
3891558Srgrimes		return;
3901558Srgrimes	if (reply("abort") == GOOD) {
3911558Srgrimes		if (reply("dump core") == GOOD)
3921558Srgrimes			abort();
3931558Srgrimes		done(1);
3941558Srgrimes	}
3951558Srgrimes}
396