xref: /original-bsd/sbin/restore/utilities.c (revision 90bde559)
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 are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)utilities.c	5.5 (Berkeley) 05/30/90";
20 #endif /* not lint */
21 
22 #include "restore.h"
23 
24 /*
25  * Insure that all the components of a pathname exist.
26  */
27 pathcheck(name)
28 	char *name;
29 {
30 	register char *cp;
31 	struct entry *ep;
32 	char *start;
33 
34 	start = index(name, '/');
35 	if (start == 0)
36 		return;
37 	for (cp = start; *cp != '\0'; cp++) {
38 		if (*cp != '/')
39 			continue;
40 		*cp = '\0';
41 		ep = lookupname(name);
42 		if (ep == NIL) {
43 			ep = addentry(name, psearch(name), NODE);
44 			newnode(ep);
45 		}
46 		ep->e_flags |= NEW|KEEP;
47 		*cp = '/';
48 	}
49 }
50 
51 /*
52  * Change a name to a unique temporary name.
53  */
54 mktempname(ep)
55 	register struct entry *ep;
56 {
57 	char oldname[MAXPATHLEN];
58 
59 	if (ep->e_flags & TMPNAME)
60 		badentry(ep, "mktempname: called with TMPNAME");
61 	ep->e_flags |= TMPNAME;
62 	(void) strcpy(oldname, myname(ep));
63 	freename(ep->e_name);
64 	ep->e_name = savename(gentempname(ep));
65 	ep->e_namlen = strlen(ep->e_name);
66 	renameit(oldname, myname(ep));
67 }
68 
69 /*
70  * Generate a temporary name for an entry.
71  */
72 char *
73 gentempname(ep)
74 	struct entry *ep;
75 {
76 	static char name[MAXPATHLEN];
77 	struct entry *np;
78 	long i = 0;
79 
80 	for (np = lookupino(ep->e_ino); np != NIL && np != ep; np = np->e_links)
81 		i++;
82 	if (np == NIL)
83 		badentry(ep, "not on ino list");
84 	(void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino);
85 	return (name);
86 }
87 
88 /*
89  * Rename a file or directory.
90  */
91 renameit(from, to)
92 	char *from, *to;
93 {
94 	if (!Nflag && rename(from, to) < 0) {
95 		fprintf(stderr, "Warning: cannot rename %s to %s", from, to);
96 		(void) fflush(stderr);
97 		perror("");
98 		return;
99 	}
100 	vprintf(stdout, "rename %s to %s\n", from, to);
101 }
102 
103 /*
104  * Create a new node (directory).
105  */
106 newnode(np)
107 	struct entry *np;
108 {
109 	char *cp;
110 
111 	if (np->e_type != NODE)
112 		badentry(np, "newnode: not a node");
113 	cp = myname(np);
114 	if (!Nflag && mkdir(cp, 0777) < 0) {
115 		np->e_flags |= EXISTED;
116 		fprintf(stderr, "Warning: ");
117 		(void) fflush(stderr);
118 		perror(cp);
119 		return;
120 	}
121 	vprintf(stdout, "Make node %s\n", cp);
122 }
123 
124 /*
125  * Remove an old node (directory).
126  */
127 removenode(ep)
128 	register struct entry *ep;
129 {
130 	char *cp;
131 
132 	if (ep->e_type != NODE)
133 		badentry(ep, "removenode: not a node");
134 	if (ep->e_entries != NIL)
135 		badentry(ep, "removenode: non-empty directory");
136 	ep->e_flags |= REMOVED;
137 	ep->e_flags &= ~TMPNAME;
138 	cp = myname(ep);
139 	if (!Nflag && rmdir(cp) < 0) {
140 		fprintf(stderr, "Warning: ");
141 		(void) fflush(stderr);
142 		perror(cp);
143 		return;
144 	}
145 	vprintf(stdout, "Remove node %s\n", cp);
146 }
147 
148 /*
149  * Remove a leaf.
150  */
151 removeleaf(ep)
152 	register struct entry *ep;
153 {
154 	char *cp;
155 
156 	if (ep->e_type != LEAF)
157 		badentry(ep, "removeleaf: not a leaf");
158 	ep->e_flags |= REMOVED;
159 	ep->e_flags &= ~TMPNAME;
160 	cp = myname(ep);
161 	if (!Nflag && unlink(cp) < 0) {
162 		fprintf(stderr, "Warning: ");
163 		(void) fflush(stderr);
164 		perror(cp);
165 		return;
166 	}
167 	vprintf(stdout, "Remove leaf %s\n", cp);
168 }
169 
170 /*
171  * Create a link.
172  */
173 linkit(existing, new, type)
174 	char *existing, *new;
175 	int type;
176 {
177 
178 	if (type == SYMLINK) {
179 		if (!Nflag && symlink(existing, new) < 0) {
180 			fprintf(stderr,
181 				"Warning: cannot create symbolic link %s->%s: ",
182 				new, existing);
183 			(void) fflush(stderr);
184 			perror("");
185 			return (FAIL);
186 		}
187 	} else if (type == HARDLINK) {
188 		if (!Nflag && link(existing, new) < 0) {
189 			fprintf(stderr,
190 				"Warning: cannot create hard link %s->%s: ",
191 				new, existing);
192 			(void) fflush(stderr);
193 			perror("");
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 == NIL || 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 == NIL || 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 badentry(ep, msg)
247 	register struct entry *ep;
248 	char *msg;
249 {
250 
251 	fprintf(stderr, "bad entry: %s\n", msg);
252 	fprintf(stderr, "name: %s\n", myname(ep));
253 	fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
254 	if (ep->e_sibling != NIL)
255 		fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
256 	if (ep->e_entries != NIL)
257 		fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
258 	if (ep->e_links != NIL)
259 		fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
260 	if (ep->e_next != NIL)
261 		fprintf(stderr, "next hashchain name: %s\n", myname(ep->e_next));
262 	fprintf(stderr, "entry type: %s\n",
263 		ep->e_type == NODE ? "NODE" : "LEAF");
264 	fprintf(stderr, "inode number: %ld\n", ep->e_ino);
265 	panic("flags: %s\n", flagvalues(ep));
266 }
267 
268 /*
269  * Construct a string indicating the active flag bits of an entry.
270  */
271 char *
272 flagvalues(ep)
273 	register struct entry *ep;
274 {
275 	static char flagbuf[BUFSIZ];
276 
277 	(void) strcpy(flagbuf, "|NIL");
278 	flagbuf[0] = '\0';
279 	if (ep->e_flags & REMOVED)
280 		(void) strcat(flagbuf, "|REMOVED");
281 	if (ep->e_flags & TMPNAME)
282 		(void) strcat(flagbuf, "|TMPNAME");
283 	if (ep->e_flags & EXTRACT)
284 		(void) strcat(flagbuf, "|EXTRACT");
285 	if (ep->e_flags & NEW)
286 		(void) strcat(flagbuf, "|NEW");
287 	if (ep->e_flags & KEEP)
288 		(void) strcat(flagbuf, "|KEEP");
289 	if (ep->e_flags & EXISTED)
290 		(void) strcat(flagbuf, "|EXISTED");
291 	return (&flagbuf[1]);
292 }
293 
294 /*
295  * Check to see if a name is on a dump tape.
296  */
297 ino_t
298 dirlookup(name)
299 	char *name;
300 {
301 	ino_t ino;
302 
303 	ino = psearch(name);
304 	if (ino == 0 || BIT(ino, dumpmap) == 0)
305 		fprintf(stderr, "%s is not on tape\n", name);
306 	return (ino);
307 }
308 
309 /*
310  * Elicit a reply.
311  */
312 reply(question)
313 	char *question;
314 {
315 	char c;
316 
317 	do	{
318 		fprintf(stderr, "%s? [yn] ", question);
319 		(void) fflush(stderr);
320 		c = getc(terminal);
321 		while (c != '\n' && getc(terminal) != '\n')
322 			if (feof(terminal))
323 				return (FAIL);
324 	} while (c != 'y' && c != 'n');
325 	if (c == 'y')
326 		return (GOOD);
327 	return (FAIL);
328 }
329 
330 /*
331  * handle unexpected inconsistencies
332  */
333 /* VARARGS1 */
334 panic(msg, d1, d2)
335 	char *msg;
336 	long d1, d2;
337 {
338 
339 	fprintf(stderr, msg, d1, d2);
340 	if (yflag)
341 		return;
342 	if (reply("abort") == GOOD) {
343 		if (reply("dump core") == GOOD)
344 			abort();
345 		done(1);
346 	}
347 }
348