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