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