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