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