GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/restore/utilities.c Lines: 0 137 0.0 %
Date: 2016-12-06 Branches: 0 136 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: utilities.c,v 1.19 2015/11/07 21:52:55 guenther Exp $	*/
2
/*	$NetBSD: utilities.c,v 1.11 1997/03/19 08:42:56 lukem Exp $	*/
3
4
/*
5
 * Copyright (c) 1983, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/stat.h>
34
35
#include <ufs/ufs/dinode.h>
36
#include <ufs/ufs/dir.h>
37
38
#include <err.h>
39
#include <fcntl.h>
40
#include <stdarg.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <unistd.h>
45
#include <limits.h>
46
47
#include "restore.h"
48
#include "extern.h"
49
50
/*
51
 * Insure that all the components of a pathname exist.
52
 */
53
void
54
pathcheck(char *name)
55
{
56
	char *cp;
57
	struct entry *ep;
58
	char *start;
59
60
	start = strchr(name, '/');
61
	if (start == 0)
62
		return;
63
	for (cp = start; *cp != '\0'; cp++) {
64
		if (*cp != '/')
65
			continue;
66
		*cp = '\0';
67
		ep = lookupname(name);
68
		if (ep == NULL) {
69
			/* Safe; we know the pathname exists in the dump. */
70
			ep = addentry(name, pathsearch(name)->d_ino, NODE);
71
			newnode(ep);
72
		}
73
		ep->e_flags |= NEW|KEEP;
74
		*cp = '/';
75
	}
76
}
77
78
/*
79
 * Change a name to a unique temporary name.
80
 */
81
void
82
mktempname(struct entry *ep)
83
{
84
	char oldname[PATH_MAX];
85
86
	if (ep->e_flags & TMPNAME)
87
		badentry(ep, "mktempname: called with TMPNAME");
88
	ep->e_flags |= TMPNAME;
89
	(void)strlcpy(oldname, myname(ep), sizeof oldname);
90
	freename(ep->e_name);
91
	ep->e_name = savename(gentempname(ep));
92
	ep->e_namlen = strlen(ep->e_name);
93
	renameit(oldname, myname(ep));
94
}
95
96
/*
97
 * Generate a temporary name for an entry.
98
 */
99
char *
100
gentempname(struct entry *ep)
101
{
102
	static char name[PATH_MAX];
103
	struct entry *np;
104
	long i = 0;
105
106
	for (np = lookupino(ep->e_ino);
107
	    np != NULL && np != ep; np = np->e_links)
108
		i++;
109
	if (np == NULL)
110
		badentry(ep, "not on ino list");
111
	(void)snprintf(name, sizeof(name), "%s%ld%llu", TMPHDR, i,
112
	    (unsigned long long)ep->e_ino);
113
	return (name);
114
}
115
116
/*
117
 * Rename a file or directory.
118
 */
119
void
120
renameit(char *from, char *to)
121
{
122
	if (!Nflag && rename(from, to) < 0) {
123
		warn("cannot rename %s to %s", from, to);
124
		return;
125
	}
126
	Vprintf(stdout, "rename %s to %s\n", from, to);
127
}
128
129
/*
130
 * Create a new node (directory).
131
 */
132
void
133
newnode(struct entry *np)
134
{
135
	char *cp;
136
137
	if (np->e_type != NODE)
138
		badentry(np, "newnode: not a node");
139
	cp = myname(np);
140
	if (!Nflag && mkdir(cp, 0777) < 0) {
141
		np->e_flags |= EXISTED;
142
		warn("%s", cp);
143
		return;
144
	}
145
	Vprintf(stdout, "Make node %s\n", cp);
146
}
147
148
/*
149
 * Remove an old node (directory).
150
 */
151
void
152
removenode(struct entry *ep)
153
{
154
	char *cp;
155
156
	if (ep->e_type != NODE)
157
		badentry(ep, "removenode: not a node");
158
	if (ep->e_entries != NULL)
159
		badentry(ep, "removenode: non-empty directory");
160
	ep->e_flags |= REMOVED;
161
	ep->e_flags &= ~TMPNAME;
162
	cp = myname(ep);
163
	if (!Nflag && rmdir(cp) < 0) {
164
		warn("%s", cp);
165
		return;
166
	}
167
	Vprintf(stdout, "Remove node %s\n", cp);
168
}
169
170
/*
171
 * Remove a leaf.
172
 */
173
void
174
removeleaf(struct entry *ep)
175
{
176
	char *cp;
177
178
	if (ep->e_type != LEAF)
179
		badentry(ep, "removeleaf: not a leaf");
180
	ep->e_flags |= REMOVED;
181
	ep->e_flags &= ~TMPNAME;
182
	cp = myname(ep);
183
	if (!Nflag && unlink(cp) < 0) {
184
		warn("%s", cp);
185
		return;
186
	}
187
	Vprintf(stdout, "Remove leaf %s\n", cp);
188
}
189
190
/*
191
 * Create a link.
192
 */
193
int
194
linkit(char *existing, char *new, int type)
195
{
196
197
	if (type == SYMLINK) {
198
		if (!Nflag && symlink(existing, new) < 0) {
199
			warn("cannot create symbolic link %s->%s",
200
			    new, existing);
201
			return (FAIL);
202
		}
203
	} else if (type == HARDLINK) {
204
		if (!Nflag && linkat(AT_FDCWD, existing, AT_FDCWD, new, 0)
205
		    < 0) {
206
			warn("cannot create hard link %s->%s",
207
			    new, existing);
208
			return (FAIL);
209
		}
210
	} else {
211
		panic("linkit: unknown type %d\n", type);
212
		return (FAIL);
213
	}
214
	Vprintf(stdout, "Create %s link %s->%s\n",
215
		type == SYMLINK ? "symbolic" : "hard", new, existing);
216
	return (GOOD);
217
}
218
219
/*
220
 * find lowest number file (above "start") that needs to be extracted
221
 */
222
ino_t
223
lowerbnd(ino_t start)
224
{
225
	struct entry *ep;
226
227
	for ( ; start < maxino; start++) {
228
		ep = lookupino(start);
229
		if (ep == NULL || ep->e_type == NODE)
230
			continue;
231
		if (ep->e_flags & (NEW|EXTRACT))
232
			return (start);
233
	}
234
	return (start);
235
}
236
237
/*
238
 * find highest number file (below "start") that needs to be extracted
239
 */
240
ino_t
241
upperbnd(ino_t start)
242
{
243
	struct entry *ep;
244
245
	for ( ; start > ROOTINO; start--) {
246
		ep = lookupino(start);
247
		if (ep == NULL || ep->e_type == NODE)
248
			continue;
249
		if (ep->e_flags & (NEW|EXTRACT))
250
			return (start);
251
	}
252
	return (start);
253
}
254
255
/*
256
 * report on a badly formed entry
257
 */
258
void
259
badentry(struct entry *ep, char *msg)
260
{
261
262
	fprintf(stderr, "bad entry: %s\n", msg);
263
	fprintf(stderr, "name: %s\n", myname(ep));
264
	fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
265
	if (ep->e_sibling != NULL)
266
		fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
267
	if (ep->e_entries != NULL)
268
		fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
269
	if (ep->e_links != NULL)
270
		fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
271
	if (ep->e_next != NULL)
272
		fprintf(stderr,
273
		    "next hashchain name: %s\n", myname(ep->e_next));
274
	fprintf(stderr, "entry type: %s\n",
275
		ep->e_type == NODE ? "NODE" : "LEAF");
276
	fprintf(stderr, "inode number: %llu\n",
277
	    (unsigned long long)ep->e_ino);
278
	panic("flags: %s\n", flagvalues(ep));
279
}
280
281
/*
282
 * Construct a string indicating the active flag bits of an entry.
283
 */
284
char *
285
flagvalues(struct entry *ep)
286
{
287
	static char flagbuf[BUFSIZ];
288
289
	(void)strlcpy(flagbuf, "|NIL", sizeof flagbuf);
290
	flagbuf[0] = '\0';
291
	if (ep->e_flags & REMOVED)
292
		(void)strlcat(flagbuf, "|REMOVED", sizeof flagbuf);
293
	if (ep->e_flags & TMPNAME)
294
		(void)strlcat(flagbuf, "|TMPNAME", sizeof flagbuf);
295
	if (ep->e_flags & EXTRACT)
296
		(void)strlcat(flagbuf, "|EXTRACT", sizeof flagbuf);
297
	if (ep->e_flags & NEW)
298
		(void)strlcat(flagbuf, "|NEW", sizeof flagbuf);
299
	if (ep->e_flags & KEEP)
300
		(void)strlcat(flagbuf, "|KEEP", sizeof flagbuf);
301
	if (ep->e_flags & EXISTED)
302
		(void)strlcat(flagbuf, "|EXISTED", sizeof flagbuf);
303
	return (&flagbuf[1]);
304
}
305
306
/*
307
 * Check to see if a name is on a dump tape.
308
 */
309
ino_t
310
dirlookup(const char *name)
311
{
312
	struct direct *dp;
313
	ino_t ino;
314
315
	ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
316
317
	if (ino == 0 || TSTINO(ino, dumpmap) == 0)
318
		fprintf(stderr, "%s is not on the tape\n", name);
319
	return (ino);
320
}
321
322
/*
323
 * Elicit a reply.
324
 */
325
int
326
reply(char *question)
327
{
328
	int c;
329
330
	do	{
331
		fprintf(stderr, "%s? [yn] ", question);
332
		(void)fflush(stderr);
333
		c = getc(terminal);
334
		while (c != '\n' && getc(terminal) != '\n')
335
			if (feof(terminal))
336
				return (FAIL);
337
	} while (c != 'y' && c != 'n');
338
	if (c == 'y')
339
		return (GOOD);
340
	return (FAIL);
341
}
342
343
/*
344
 * handle unexpected inconsistencies
345
 */
346
void
347
panic(const char *fmt, ...)
348
{
349
	va_list ap;
350
	va_start(ap, fmt);
351
352
	vfprintf(stderr, fmt, ap);
353
	va_end(ap);
354
	if (yflag)
355
		return;
356
	if (reply("abort") == GOOD) {
357
		if (reply("dump core") == GOOD)
358
			abort();
359
		exit(1);
360
	}
361
}