]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/restore/utilities.c
This commit was generated by cvs2svn to compensate for changes in r43007,
[FreeBSD/FreeBSD.git] / sbin / restore / utilities.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  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 #if 0
36 static char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95";
37 #endif
38 static const char rcsid[] =
39         "$Id$";
40 #endif /* not lint */
41
42 #include <sys/param.h>
43 #include <sys/stat.h>
44
45 #include <ufs/ufs/dinode.h>
46 #include <ufs/ufs/dir.h>
47
48 #include <errno.h>
49 #include <stdio.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         register 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         register 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) sprintf(name, "%s%ld%lu", TMPHDR, i, (u_long)ep->e_ino);
121         return (name);
122 }
123
124 /*
125  * Rename a file or directory.
126  */
127 void
128 renameit(from, to)
129         char *from, *to;
130 {
131         if (!Nflag && rename(from, to) < 0) {
132                 fprintf(stderr, "warning: cannot rename %s to %s: %s\n",
133                     from, to, strerror(errno));
134                 return;
135         }
136         vprintf(stdout, "rename %s to %s\n", from, to);
137 }
138
139 /*
140  * Create a new node (directory).
141  */
142 void
143 newnode(np)
144         struct entry *np;
145 {
146         char *cp;
147
148         if (np->e_type != NODE)
149                 badentry(np, "newnode: not a node");
150         cp = myname(np);
151         if (!Nflag && mkdir(cp, 0777) < 0 && !uflag) {
152                 np->e_flags |= EXISTED;
153                 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
154                 return;
155         }
156         vprintf(stdout, "Make node %s\n", cp);
157 }
158
159 /*
160  * Remove an old node (directory).
161  */
162 void
163 removenode(ep)
164         register struct entry *ep;
165 {
166         char *cp;
167
168         if (ep->e_type != NODE)
169                 badentry(ep, "removenode: not a node");
170         if (ep->e_entries != NULL)
171                 badentry(ep, "removenode: non-empty directory");
172         ep->e_flags |= REMOVED;
173         ep->e_flags &= ~TMPNAME;
174         cp = myname(ep);
175         if (!Nflag && rmdir(cp) < 0) {
176                 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
177                 return;
178         }
179         vprintf(stdout, "Remove node %s\n", cp);
180 }
181
182 /*
183  * Remove a leaf.
184  */
185 void
186 removeleaf(ep)
187         register struct entry *ep;
188 {
189         char *cp;
190
191         if (ep->e_type != LEAF)
192                 badentry(ep, "removeleaf: not a leaf");
193         ep->e_flags |= REMOVED;
194         ep->e_flags &= ~TMPNAME;
195         cp = myname(ep);
196         if (!Nflag && unlink(cp) < 0) {
197                 fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
198                 return;
199         }
200         vprintf(stdout, "Remove leaf %s\n", cp);
201 }
202
203 /*
204  * Create a link.
205  */
206 int
207 linkit(existing, new, type)
208         char *existing, *new;
209         int type;
210 {
211
212         /* if we want to unlink first, do it now so *link() won't fail */
213         if (uflag && !Nflag)
214                 (void)unlink(new);
215
216         if (type == SYMLINK) {
217                 if (!Nflag && symlink(existing, new) < 0) {
218                         fprintf(stderr,
219                             "warning: cannot create symbolic link %s->%s: %s\n",
220                             new, existing, strerror(errno));
221                         return (FAIL);
222                 }
223         } else if (type == HARDLINK) {
224                 int ret;
225
226                 if (!Nflag && (ret = link(existing, new)) < 0) {
227                         struct stat s;
228
229                         /*
230                          * Most likely, the schg flag is set.  Clear the
231                          * flags and try again.
232                          */
233                         if (stat(existing, &s) == 0 && s.st_flags != 0 &&
234                             chflags(existing, 0) == 0) {
235                                 ret = link(existing, new);
236                                 chflags(existing, s.st_flags);
237                         }
238                         if (ret < 0) {
239                                 fprintf(stderr, "warning: cannot create "
240                                     "hard link %s->%s: %s\n",
241                                     new, existing, strerror(errno));
242                                 return (FAIL);
243                         }
244                 }
245         } else {
246                 panic("linkit: unknown type %d\n", type);
247                 return (FAIL);
248         }
249         vprintf(stdout, "Create %s link %s->%s\n",
250                 type == SYMLINK ? "symbolic" : "hard", new, existing);
251         return (GOOD);
252 }
253
254 /*
255  * Create a whiteout.
256  */
257 int
258 addwhiteout(name)
259         char *name;
260 {
261
262         if (!Nflag && mknod(name, S_IFWHT, 0) < 0) {
263                 fprintf(stderr, "warning: cannot create whiteout %s: %s\n",
264                     name, strerror(errno));
265                 return (FAIL);
266         }
267         vprintf(stdout, "Create whiteout %s\n", name);
268         return (GOOD);
269 }
270
271 /*
272  * Delete a whiteout.
273  */
274 void
275 delwhiteout(ep)
276         register struct entry *ep;
277 {
278         char *name;
279
280         if (ep->e_type != LEAF)
281                 badentry(ep, "delwhiteout: not a leaf");
282         ep->e_flags |= REMOVED;
283         ep->e_flags &= ~TMPNAME;
284         name = myname(ep);
285         if (!Nflag && undelete(name) < 0) {
286                 fprintf(stderr, "warning: cannot delete whiteout %s: %s\n",
287                     name, strerror(errno));
288                 return;
289         }
290         vprintf(stdout, "Delete whiteout %s\n", name);
291 }
292
293 /*
294  * find lowest number file (above "start") that needs to be extracted
295  */
296 ino_t
297 lowerbnd(start)
298         ino_t start;
299 {
300         register struct entry *ep;
301
302         for ( ; start < maxino; start++) {
303                 ep = lookupino(start);
304                 if (ep == NULL || ep->e_type == NODE)
305                         continue;
306                 if (ep->e_flags & (NEW|EXTRACT))
307                         return (start);
308         }
309         return (start);
310 }
311
312 /*
313  * find highest number file (below "start") that needs to be extracted
314  */
315 ino_t
316 upperbnd(start)
317         ino_t start;
318 {
319         register struct entry *ep;
320
321         for ( ; start > ROOTINO; start--) {
322                 ep = lookupino(start);
323                 if (ep == NULL || ep->e_type == NODE)
324                         continue;
325                 if (ep->e_flags & (NEW|EXTRACT))
326                         return (start);
327         }
328         return (start);
329 }
330
331 /*
332  * report on a badly formed entry
333  */
334 void
335 badentry(ep, msg)
336         register struct entry *ep;
337         char *msg;
338 {
339
340         fprintf(stderr, "bad entry: %s\n", msg);
341         fprintf(stderr, "name: %s\n", myname(ep));
342         fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
343         if (ep->e_sibling != NULL)
344                 fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
345         if (ep->e_entries != NULL)
346                 fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
347         if (ep->e_links != NULL)
348                 fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
349         if (ep->e_next != NULL)
350                 fprintf(stderr,
351                     "next hashchain name: %s\n", myname(ep->e_next));
352         fprintf(stderr, "entry type: %s\n",
353                 ep->e_type == NODE ? "NODE" : "LEAF");
354         fprintf(stderr, "inode number: %lu\n", (u_long)ep->e_ino);
355         panic("flags: %s\n", flagvalues(ep));
356 }
357
358 /*
359  * Construct a string indicating the active flag bits of an entry.
360  */
361 char *
362 flagvalues(ep)
363         register struct entry *ep;
364 {
365         static char flagbuf[BUFSIZ];
366
367         (void) strcpy(flagbuf, "|NIL");
368         flagbuf[0] = '\0';
369         if (ep->e_flags & REMOVED)
370                 (void) strcat(flagbuf, "|REMOVED");
371         if (ep->e_flags & TMPNAME)
372                 (void) strcat(flagbuf, "|TMPNAME");
373         if (ep->e_flags & EXTRACT)
374                 (void) strcat(flagbuf, "|EXTRACT");
375         if (ep->e_flags & NEW)
376                 (void) strcat(flagbuf, "|NEW");
377         if (ep->e_flags & KEEP)
378                 (void) strcat(flagbuf, "|KEEP");
379         if (ep->e_flags & EXISTED)
380                 (void) strcat(flagbuf, "|EXISTED");
381         return (&flagbuf[1]);
382 }
383
384 /*
385  * Check to see if a name is on a dump tape.
386  */
387 ino_t
388 dirlookup(name)
389         const char *name;
390 {
391         struct direct *dp;
392         ino_t ino;
393
394         ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
395
396         if (ino == 0 || TSTINO(ino, dumpmap) == 0)
397                 fprintf(stderr, "%s is not on the tape\n", name);
398         return (ino);
399 }
400
401 /*
402  * Elicit a reply.
403  */
404 int
405 reply(question)
406         char *question;
407 {
408         char c;
409
410         do      {
411                 fprintf(stderr, "%s? [yn] ", question);
412                 (void) fflush(stderr);
413                 c = getc(terminal);
414                 while (c != '\n' && getc(terminal) != '\n')
415                         if (feof(terminal))
416                                 return (FAIL);
417         } while (c != 'y' && c != 'n');
418         if (c == 'y')
419                 return (GOOD);
420         return (FAIL);
421 }
422
423 /*
424  * handle unexpected inconsistencies
425  */
426 #if __STDC__
427 #include <stdarg.h>
428 #else
429 #include <varargs.h>
430 #endif
431
432 void
433 #if __STDC__
434 panic(const char *fmt, ...)
435 #else
436 panic(fmt, va_alist)
437         char *fmt;
438         va_dcl
439 #endif
440 {
441         va_list ap;
442 #if __STDC__
443         va_start(ap, fmt);
444 #else
445         va_start(ap);
446 #endif
447
448         vfprintf(stderr, fmt, ap);
449         if (yflag)
450                 return;
451         if (reply("abort") == GOOD) {
452                 if (reply("dump core") == GOOD)
453                         abort();
454                 done(1);
455         }
456 }