xref: /original-bsd/sbin/restore/utilities.c (revision babae2df)
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.2 (Berkeley) 03/25/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  * find lowest number file (above "start") that needs to be extracted
208  */
209 ino_t
210 lowerbnd(start)
211 	ino_t start;
212 {
213 	register struct entry *ep;
214 
215 	for ( ; start < maxino; start++) {
216 		ep = lookupino(start);
217 		if (ep == NULL || ep->e_type == NODE)
218 			continue;
219 		if (ep->e_flags & (NEW|EXTRACT))
220 			return (start);
221 	}
222 	return (start);
223 }
224 
225 /*
226  * find highest number file (below "start") that needs to be extracted
227  */
228 ino_t
229 upperbnd(start)
230 	ino_t start;
231 {
232 	register struct entry *ep;
233 
234 	for ( ; start > ROOTINO; start--) {
235 		ep = lookupino(start);
236 		if (ep == NULL || ep->e_type == NODE)
237 			continue;
238 		if (ep->e_flags & (NEW|EXTRACT))
239 			return (start);
240 	}
241 	return (start);
242 }
243 
244 /*
245  * report on a badly formed entry
246  */
247 void
248 badentry(ep, msg)
249 	register struct entry *ep;
250 	char *msg;
251 {
252 
253 	fprintf(stderr, "bad entry: %s\n", msg);
254 	fprintf(stderr, "name: %s\n", myname(ep));
255 	fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
256 	if (ep->e_sibling != NULL)
257 		fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
258 	if (ep->e_entries != NULL)
259 		fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
260 	if (ep->e_links != NULL)
261 		fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
262 	if (ep->e_next != NULL)
263 		fprintf(stderr,
264 		    "next hashchain name: %s\n", myname(ep->e_next));
265 	fprintf(stderr, "entry type: %s\n",
266 		ep->e_type == NODE ? "NODE" : "LEAF");
267 	fprintf(stderr, "inode number: %ld\n", ep->e_ino);
268 	panic("flags: %s\n", flagvalues(ep));
269 }
270 
271 /*
272  * Construct a string indicating the active flag bits of an entry.
273  */
274 char *
275 flagvalues(ep)
276 	register struct entry *ep;
277 {
278 	static char flagbuf[BUFSIZ];
279 
280 	(void) strcpy(flagbuf, "|NIL");
281 	flagbuf[0] = '\0';
282 	if (ep->e_flags & REMOVED)
283 		(void) strcat(flagbuf, "|REMOVED");
284 	if (ep->e_flags & TMPNAME)
285 		(void) strcat(flagbuf, "|TMPNAME");
286 	if (ep->e_flags & EXTRACT)
287 		(void) strcat(flagbuf, "|EXTRACT");
288 	if (ep->e_flags & NEW)
289 		(void) strcat(flagbuf, "|NEW");
290 	if (ep->e_flags & KEEP)
291 		(void) strcat(flagbuf, "|KEEP");
292 	if (ep->e_flags & EXISTED)
293 		(void) strcat(flagbuf, "|EXISTED");
294 	return (&flagbuf[1]);
295 }
296 
297 /*
298  * Check to see if a name is on a dump tape.
299  */
300 ino_t
301 dirlookup(name)
302 	const char *name;
303 {
304 	struct direct *dp;
305 	ino_t ino;
306 
307 	ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
308 
309 	if (ino == 0 || TSTINO(ino, dumpmap) == 0)
310 		fprintf(stderr, "%s is not on the tape\n", name);
311 	return (ino);
312 }
313 
314 /*
315  * Elicit a reply.
316  */
317 int
318 reply(question)
319 	char *question;
320 {
321 	char c;
322 
323 	do	{
324 		fprintf(stderr, "%s? [yn] ", question);
325 		(void) fflush(stderr);
326 		c = getc(terminal);
327 		while (c != '\n' && getc(terminal) != '\n')
328 			if (feof(terminal))
329 				return (FAIL);
330 	} while (c != 'y' && c != 'n');
331 	if (c == 'y')
332 		return (GOOD);
333 	return (FAIL);
334 }
335 
336 /*
337  * handle unexpected inconsistencies
338  */
339 #if __STDC__
340 #include <stdarg.h>
341 #else
342 #include <varargs.h>
343 #endif
344 
345 void
346 #if __STDC__
347 panic(const char *fmt, ...)
348 #else
349 panic(fmt, va_alist)
350 	char *fmt;
351 	va_dcl
352 #endif
353 {
354 	va_list ap;
355 #if __STDC__
356 	va_start(ap, fmt);
357 #else
358 	va_start(ap);
359 #endif
360 
361 	vfprintf(stderr, fmt, ap);
362 	if (yflag)
363 		return;
364 	if (reply("abort") == GOOD) {
365 		if (reply("dump core") == GOOD)
366 			abort();
367 		done(1);
368 	}
369 }
370