xref: /original-bsd/sbin/restore/utilities.c (revision deff14a8)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)utilities.c	8.4 (Berkeley) 10/18/94";
10 #endif /* not lint */
11 
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 
15 #include <ufs/ufs/dinode.h>
16 #include <ufs/ufs/dir.h>
17 
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #include "restore.h"
25 #include "extern.h"
26 
27 /*
28  * Insure that all the components of a pathname exist.
29  */
30 void
31 pathcheck(name)
32 	char *name;
33 {
34 	register char *cp;
35 	struct entry *ep;
36 	char *start;
37 
38 	start = index(name, '/');
39 	if (start == 0)
40 		return;
41 	for (cp = start; *cp != '\0'; cp++) {
42 		if (*cp != '/')
43 			continue;
44 		*cp = '\0';
45 		ep = lookupname(name);
46 		if (ep == NULL) {
47 			/* Safe; we know the pathname exists in the dump. */
48 			ep = addentry(name, pathsearch(name)->d_ino, NODE);
49 			newnode(ep);
50 		}
51 		ep->e_flags |= NEW|KEEP;
52 		*cp = '/';
53 	}
54 }
55 
56 /*
57  * Change a name to a unique temporary name.
58  */
59 void
60 mktempname(ep)
61 	register struct entry *ep;
62 {
63 	char oldname[MAXPATHLEN];
64 
65 	if (ep->e_flags & TMPNAME)
66 		badentry(ep, "mktempname: called with TMPNAME");
67 	ep->e_flags |= TMPNAME;
68 	(void) strcpy(oldname, myname(ep));
69 	freename(ep->e_name);
70 	ep->e_name = savename(gentempname(ep));
71 	ep->e_namlen = strlen(ep->e_name);
72 	renameit(oldname, myname(ep));
73 }
74 
75 /*
76  * Generate a temporary name for an entry.
77  */
78 char *
79 gentempname(ep)
80 	struct entry *ep;
81 {
82 	static char name[MAXPATHLEN];
83 	struct entry *np;
84 	long i = 0;
85 
86 	for (np = lookupino(ep->e_ino);
87 	    np != NULL && np != ep; np = np->e_links)
88 		i++;
89 	if (np == NULL)
90 		badentry(ep, "not on ino list");
91 	(void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino);
92 	return (name);
93 }
94 
95 /*
96  * Rename a file or directory.
97  */
98 void
99 renameit(from, to)
100 	char *from, *to;
101 {
102 	if (!Nflag && rename(from, to) < 0) {
103 		fprintf(stderr, "warning: cannot rename %s to %s: %s\n",
104 		    from, to, strerror(errno));
105 		return;
106 	}
107 	vprintf(stdout, "rename %s to %s\n", from, to);
108 }
109 
110 /*
111  * Create a new node (directory).
112  */
113 void
114 newnode(np)
115 	struct entry *np;
116 {
117 	char *cp;
118 
119 	if (np->e_type != NODE)
120 		badentry(np, "newnode: not a node");
121 	cp = myname(np);
122 	if (!Nflag && mkdir(cp, 0777) < 0) {
123 		np->e_flags |= EXISTED;
124 		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
125 		return;
126 	}
127 	vprintf(stdout, "Make node %s\n", cp);
128 }
129 
130 /*
131  * Remove an old node (directory).
132  */
133 void
134 removenode(ep)
135 	register struct entry *ep;
136 {
137 	char *cp;
138 
139 	if (ep->e_type != NODE)
140 		badentry(ep, "removenode: not a node");
141 	if (ep->e_entries != NULL)
142 		badentry(ep, "removenode: non-empty directory");
143 	ep->e_flags |= REMOVED;
144 	ep->e_flags &= ~TMPNAME;
145 	cp = myname(ep);
146 	if (!Nflag && rmdir(cp) < 0) {
147 		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
148 		return;
149 	}
150 	vprintf(stdout, "Remove node %s\n", cp);
151 }
152 
153 /*
154  * Remove a leaf.
155  */
156 void
157 removeleaf(ep)
158 	register struct entry *ep;
159 {
160 	char *cp;
161 
162 	if (ep->e_type != LEAF)
163 		badentry(ep, "removeleaf: not a leaf");
164 	ep->e_flags |= REMOVED;
165 	ep->e_flags &= ~TMPNAME;
166 	cp = myname(ep);
167 	if (!Nflag && unlink(cp) < 0) {
168 		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
169 		return;
170 	}
171 	vprintf(stdout, "Remove leaf %s\n", cp);
172 }
173 
174 /*
175  * Create a link.
176  */
177 int
178 linkit(existing, new, type)
179 	char *existing, *new;
180 	int type;
181 {
182 
183 	if (type == SYMLINK) {
184 		if (!Nflag && symlink(existing, new) < 0) {
185 			fprintf(stderr,
186 			    "warning: cannot create symbolic link %s->%s: %s\n",
187 			    new, existing, strerror(errno));
188 			return (FAIL);
189 		}
190 	} else if (type == HARDLINK) {
191 		if (!Nflag && link(existing, new) < 0) {
192 			fprintf(stderr,
193 			    "warning: cannot create hard link %s->%s: %s\n",
194 			    new, existing, strerror(errno));
195 			return (FAIL);
196 		}
197 	} else {
198 		panic("linkit: unknown type %d\n", type);
199 		return (FAIL);
200 	}
201 	vprintf(stdout, "Create %s link %s->%s\n",
202 		type == SYMLINK ? "symbolic" : "hard", new, existing);
203 	return (GOOD);
204 }
205 
206 /*
207  * Create a whiteout.
208  */
209 int
210 addwhiteout(name)
211 	char *name;
212 {
213 
214 	if (!Nflag && mknod(name, S_IFWHT, 0) < 0) {
215 		fprintf(stderr, "warning: cannot create whiteout %s: %s\n",
216 		    name, strerror(errno));
217 		return (FAIL);
218 	}
219 	vprintf(stdout, "Create whiteout %s\n", name);
220 	return (GOOD);
221 }
222 
223 /*
224  * Delete a whiteout.
225  */
226 void
227 delwhiteout(ep)
228 	register struct entry *ep;
229 {
230 	char *name;
231 
232 	if (ep->e_type != LEAF)
233 		badentry(ep, "delwhiteout: not a leaf");
234 	ep->e_flags |= REMOVED;
235 	ep->e_flags &= ~TMPNAME;
236 	name = myname(ep);
237 	if (!Nflag && undelete(name) < 0) {
238 		fprintf(stderr, "warning: cannot delete whiteout %s: %s\n",
239 		    name, strerror(errno));
240 		return;
241 	}
242 	vprintf(stdout, "Delete whiteout %s\n", name);
243 }
244 
245 /*
246  * find lowest number file (above "start") that needs to be extracted
247  */
248 ino_t
249 lowerbnd(start)
250 	ino_t start;
251 {
252 	register struct entry *ep;
253 
254 	for ( ; start < maxino; start++) {
255 		ep = lookupino(start);
256 		if (ep == NULL || ep->e_type == NODE)
257 			continue;
258 		if (ep->e_flags & (NEW|EXTRACT))
259 			return (start);
260 	}
261 	return (start);
262 }
263 
264 /*
265  * find highest number file (below "start") that needs to be extracted
266  */
267 ino_t
268 upperbnd(start)
269 	ino_t start;
270 {
271 	register struct entry *ep;
272 
273 	for ( ; start > ROOTINO; start--) {
274 		ep = lookupino(start);
275 		if (ep == NULL || ep->e_type == NODE)
276 			continue;
277 		if (ep->e_flags & (NEW|EXTRACT))
278 			return (start);
279 	}
280 	return (start);
281 }
282 
283 /*
284  * report on a badly formed entry
285  */
286 void
287 badentry(ep, msg)
288 	register struct entry *ep;
289 	char *msg;
290 {
291 
292 	fprintf(stderr, "bad entry: %s\n", msg);
293 	fprintf(stderr, "name: %s\n", myname(ep));
294 	fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
295 	if (ep->e_sibling != NULL)
296 		fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
297 	if (ep->e_entries != NULL)
298 		fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
299 	if (ep->e_links != NULL)
300 		fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
301 	if (ep->e_next != NULL)
302 		fprintf(stderr,
303 		    "next hashchain name: %s\n", myname(ep->e_next));
304 	fprintf(stderr, "entry type: %s\n",
305 		ep->e_type == NODE ? "NODE" : "LEAF");
306 	fprintf(stderr, "inode number: %ld\n", ep->e_ino);
307 	panic("flags: %s\n", flagvalues(ep));
308 }
309 
310 /*
311  * Construct a string indicating the active flag bits of an entry.
312  */
313 char *
314 flagvalues(ep)
315 	register struct entry *ep;
316 {
317 	static char flagbuf[BUFSIZ];
318 
319 	(void) strcpy(flagbuf, "|NIL");
320 	flagbuf[0] = '\0';
321 	if (ep->e_flags & REMOVED)
322 		(void) strcat(flagbuf, "|REMOVED");
323 	if (ep->e_flags & TMPNAME)
324 		(void) strcat(flagbuf, "|TMPNAME");
325 	if (ep->e_flags & EXTRACT)
326 		(void) strcat(flagbuf, "|EXTRACT");
327 	if (ep->e_flags & NEW)
328 		(void) strcat(flagbuf, "|NEW");
329 	if (ep->e_flags & KEEP)
330 		(void) strcat(flagbuf, "|KEEP");
331 	if (ep->e_flags & EXISTED)
332 		(void) strcat(flagbuf, "|EXISTED");
333 	return (&flagbuf[1]);
334 }
335 
336 /*
337  * Check to see if a name is on a dump tape.
338  */
339 ino_t
340 dirlookup(name)
341 	const char *name;
342 {
343 	struct direct *dp;
344 	ino_t ino;
345 
346 	ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
347 
348 	if (ino == 0 || TSTINO(ino, dumpmap) == 0)
349 		fprintf(stderr, "%s is not on the tape\n", name);
350 	return (ino);
351 }
352 
353 /*
354  * Elicit a reply.
355  */
356 int
357 reply(question)
358 	char *question;
359 {
360 	char c;
361 
362 	do	{
363 		fprintf(stderr, "%s? [yn] ", question);
364 		(void) fflush(stderr);
365 		c = getc(terminal);
366 		while (c != '\n' && getc(terminal) != '\n')
367 			if (feof(terminal))
368 				return (FAIL);
369 	} while (c != 'y' && c != 'n');
370 	if (c == 'y')
371 		return (GOOD);
372 	return (FAIL);
373 }
374 
375 /*
376  * handle unexpected inconsistencies
377  */
378 #if __STDC__
379 #include <stdarg.h>
380 #else
381 #include <varargs.h>
382 #endif
383 
384 void
385 #if __STDC__
386 panic(const char *fmt, ...)
387 #else
388 panic(fmt, va_alist)
389 	char *fmt;
390 	va_dcl
391 #endif
392 {
393 	va_list ap;
394 #if __STDC__
395 	va_start(ap, fmt);
396 #else
397 	va_start(ap);
398 #endif
399 
400 	vfprintf(stderr, fmt, ap);
401 	if (yflag)
402 		return;
403 	if (reply("abort") == GOOD) {
404 		if (reply("dump core") == GOOD)
405 			abort();
406 		done(1);
407 	}
408 }
409