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