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