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