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