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