xref: /original-bsd/sbin/restore/utilities.c (revision c3e32dec)
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.1 (Berkeley) 06/05/93";
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 			ep = addentry(name, pathsearch(name)->d_ino, NODE);
48 			newnode(ep);
49 		}
50 		ep->e_flags |= NEW|KEEP;
51 		*cp = '/';
52 	}
53 }
54 
55 /*
56  * Change a name to a unique temporary name.
57  */
58 void
59 mktempname(ep)
60 	register struct entry *ep;
61 {
62 	char oldname[MAXPATHLEN];
63 
64 	if (ep->e_flags & TMPNAME)
65 		badentry(ep, "mktempname: called with TMPNAME");
66 	ep->e_flags |= TMPNAME;
67 	(void) strcpy(oldname, myname(ep));
68 	freename(ep->e_name);
69 	ep->e_name = savename(gentempname(ep));
70 	ep->e_namlen = strlen(ep->e_name);
71 	renameit(oldname, myname(ep));
72 }
73 
74 /*
75  * Generate a temporary name for an entry.
76  */
77 char *
78 gentempname(ep)
79 	struct entry *ep;
80 {
81 	static char name[MAXPATHLEN];
82 	struct entry *np;
83 	long i = 0;
84 
85 	for (np = lookupino(ep->e_ino);
86 	    np != NULL && np != ep; np = np->e_links)
87 		i++;
88 	if (np == NULL)
89 		badentry(ep, "not on ino list");
90 	(void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino);
91 	return (name);
92 }
93 
94 /*
95  * Rename a file or directory.
96  */
97 void
98 renameit(from, to)
99 	char *from, *to;
100 {
101 	if (!Nflag && rename(from, to) < 0) {
102 		fprintf(stderr, "warning: cannot rename %s to %s: %s\n",
103 		    from, to, strerror(errno));
104 		return;
105 	}
106 	vprintf(stdout, "rename %s to %s\n", from, to);
107 }
108 
109 /*
110  * Create a new node (directory).
111  */
112 void
113 newnode(np)
114 	struct entry *np;
115 {
116 	char *cp;
117 
118 	if (np->e_type != NODE)
119 		badentry(np, "newnode: not a node");
120 	cp = myname(np);
121 	if (!Nflag && mkdir(cp, 0777) < 0) {
122 		np->e_flags |= EXISTED;
123 		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
124 		return;
125 	}
126 	vprintf(stdout, "Make node %s\n", cp);
127 }
128 
129 /*
130  * Remove an old node (directory).
131  */
132 void
133 removenode(ep)
134 	register struct entry *ep;
135 {
136 	char *cp;
137 
138 	if (ep->e_type != NODE)
139 		badentry(ep, "removenode: not a node");
140 	if (ep->e_entries != NULL)
141 		badentry(ep, "removenode: non-empty directory");
142 	ep->e_flags |= REMOVED;
143 	ep->e_flags &= ~TMPNAME;
144 	cp = myname(ep);
145 	if (!Nflag && rmdir(cp) < 0) {
146 		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
147 		return;
148 	}
149 	vprintf(stdout, "Remove node %s\n", cp);
150 }
151 
152 /*
153  * Remove a leaf.
154  */
155 void
156 removeleaf(ep)
157 	register struct entry *ep;
158 {
159 	char *cp;
160 
161 	if (ep->e_type != LEAF)
162 		badentry(ep, "removeleaf: not a leaf");
163 	ep->e_flags |= REMOVED;
164 	ep->e_flags &= ~TMPNAME;
165 	cp = myname(ep);
166 	if (!Nflag && unlink(cp) < 0) {
167 		fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
168 		return;
169 	}
170 	vprintf(stdout, "Remove leaf %s\n", cp);
171 }
172 
173 /*
174  * Create a link.
175  */
176 int
177 linkit(existing, new, type)
178 	char *existing, *new;
179 	int type;
180 {
181 
182 	if (type == SYMLINK) {
183 		if (!Nflag && symlink(existing, new) < 0) {
184 			fprintf(stderr,
185 			    "warning: cannot create symbolic link %s->%s: %s\n",
186 			    new, existing, strerror(errno));
187 			return (FAIL);
188 		}
189 	} else if (type == HARDLINK) {
190 		if (!Nflag && link(existing, new) < 0) {
191 			fprintf(stderr,
192 			    "warning: cannot create hard link %s->%s: %s\n",
193 			    new, existing, strerror(errno));
194 			return (FAIL);
195 		}
196 	} else {
197 		panic("linkit: unknown type %d\n", type);
198 		return (FAIL);
199 	}
200 	vprintf(stdout, "Create %s link %s->%s\n",
201 		type == SYMLINK ? "symbolic" : "hard", new, existing);
202 	return (GOOD);
203 }
204 
205 /*
206  * find lowest number file (above "start") that needs to be extracted
207  */
208 ino_t
209 lowerbnd(start)
210 	ino_t start;
211 {
212 	register struct entry *ep;
213 
214 	for ( ; start < maxino; start++) {
215 		ep = lookupino(start);
216 		if (ep == NULL || ep->e_type == NODE)
217 			continue;
218 		if (ep->e_flags & (NEW|EXTRACT))
219 			return (start);
220 	}
221 	return (start);
222 }
223 
224 /*
225  * find highest number file (below "start") that needs to be extracted
226  */
227 ino_t
228 upperbnd(start)
229 	ino_t start;
230 {
231 	register struct entry *ep;
232 
233 	for ( ; start > ROOTINO; start--) {
234 		ep = lookupino(start);
235 		if (ep == NULL || ep->e_type == NODE)
236 			continue;
237 		if (ep->e_flags & (NEW|EXTRACT))
238 			return (start);
239 	}
240 	return (start);
241 }
242 
243 /*
244  * report on a badly formed entry
245  */
246 void
247 badentry(ep, msg)
248 	register struct entry *ep;
249 	char *msg;
250 {
251 
252 	fprintf(stderr, "bad entry: %s\n", msg);
253 	fprintf(stderr, "name: %s\n", myname(ep));
254 	fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
255 	if (ep->e_sibling != NULL)
256 		fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
257 	if (ep->e_entries != NULL)
258 		fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
259 	if (ep->e_links != NULL)
260 		fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
261 	if (ep->e_next != NULL)
262 		fprintf(stderr,
263 		    "next hashchain name: %s\n", myname(ep->e_next));
264 	fprintf(stderr, "entry type: %s\n",
265 		ep->e_type == NODE ? "NODE" : "LEAF");
266 	fprintf(stderr, "inode number: %ld\n", ep->e_ino);
267 	panic("flags: %s\n", flagvalues(ep));
268 }
269 
270 /*
271  * Construct a string indicating the active flag bits of an entry.
272  */
273 char *
274 flagvalues(ep)
275 	register struct entry *ep;
276 {
277 	static char flagbuf[BUFSIZ];
278 
279 	(void) strcpy(flagbuf, "|NIL");
280 	flagbuf[0] = '\0';
281 	if (ep->e_flags & REMOVED)
282 		(void) strcat(flagbuf, "|REMOVED");
283 	if (ep->e_flags & TMPNAME)
284 		(void) strcat(flagbuf, "|TMPNAME");
285 	if (ep->e_flags & EXTRACT)
286 		(void) strcat(flagbuf, "|EXTRACT");
287 	if (ep->e_flags & NEW)
288 		(void) strcat(flagbuf, "|NEW");
289 	if (ep->e_flags & KEEP)
290 		(void) strcat(flagbuf, "|KEEP");
291 	if (ep->e_flags & EXISTED)
292 		(void) strcat(flagbuf, "|EXISTED");
293 	return (&flagbuf[1]);
294 }
295 
296 /*
297  * Check to see if a name is on a dump tape.
298  */
299 ino_t
300 dirlookup(name)
301 	const char *name;
302 {
303 	ino_t ino;
304 
305 	ino = pathsearch(name)->d_ino;
306 	if (ino == 0 || TSTINO(ino, dumpmap) == 0)
307 		fprintf(stderr, "%s is not on tape\n", name);
308 	return (ino);
309 }
310 
311 /*
312  * Elicit a reply.
313  */
314 int
315 reply(question)
316 	char *question;
317 {
318 	char c;
319 
320 	do	{
321 		fprintf(stderr, "%s? [yn] ", question);
322 		(void) fflush(stderr);
323 		c = getc(terminal);
324 		while (c != '\n' && getc(terminal) != '\n')
325 			if (feof(terminal))
326 				return (FAIL);
327 	} while (c != 'y' && c != 'n');
328 	if (c == 'y')
329 		return (GOOD);
330 	return (FAIL);
331 }
332 
333 /*
334  * handle unexpected inconsistencies
335  */
336 #if __STDC__
337 #include <stdarg.h>
338 #else
339 #include <varargs.h>
340 #endif
341 
342 void
343 #if __STDC__
344 panic(const char *fmt, ...)
345 #else
346 panic(fmt, va_alist)
347 	char *fmt;
348 	va_dcl
349 #endif
350 {
351 	va_list ap;
352 #if __STDC__
353 	va_start(ap, fmt);
354 #else
355 	va_start(ap);
356 #endif
357 
358 	vfprintf(stderr, fmt, ap);
359 	if (yflag)
360 		return;
361 	if (reply("abort") == GOOD) {
362 		if (reply("dump core") == GOOD)
363 			abort();
364 		done(1);
365 	}
366 }
367