1 /* $NetBSD: utilities.c,v 1.21 2005/06/27 02:03:28 christos Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95";
37 __RCSID("$NetBSD: utilities.c,v 1.21 2005/06/27 02:03:28 christos Exp $");
41 #include <sys/param.h>
44 #include <ufs/ufs/dinode.h>
45 #include <ufs/ufs/dir.h>
58 * Insure that all the components of a pathname exist.
67 start
= strchr(name
, '/');
70 for (cp
= start
; *cp
!= '\0'; cp
++) {
74 ep
= lookupname(name
);
76 /* Safe; we know the pathname exists in the dump. */
77 ep
= addentry(name
, pathsearch(name
)->d_ino
, NODE
);
80 ep
->e_flags
|= NEW
|KEEP
;
86 * Change a name to a unique temporary name.
89 mktempname(struct entry
*ep
)
91 char oldname
[MAXPATHLEN
];
93 if (ep
->e_flags
& TMPNAME
)
94 badentry(ep
, "mktempname: called with TMPNAME");
95 ep
->e_flags
|= TMPNAME
;
96 (void) strcpy(oldname
, myname(ep
));
98 ep
->e_name
= savename(gentempname(ep
));
99 ep
->e_namlen
= strlen(ep
->e_name
);
100 renameit(oldname
, myname(ep
));
104 * Generate a temporary name for an entry.
107 gentempname(struct entry
*ep
)
109 static char name
[MAXPATHLEN
];
113 for (np
= lookupino(ep
->e_ino
);
114 np
!= NULL
&& np
!= ep
; np
= np
->e_links
)
117 badentry(ep
, "not on ino list");
118 (void)snprintf(name
, sizeof(name
), "%s%ld%llu", TMPHDR
, (long) i
,
119 (unsigned long long)ep
->e_ino
);
124 * Rename a file or directory.
127 renameit(char *from
, const char *to
)
129 if (!Nflag
&& rename(from
, to
) < 0) {
130 fprintf(stderr
, "warning: cannot rename %s to %s: %s\n",
131 from
, to
, strerror(errno
));
134 vprintf(stdout
, "rename %s to %s\n", from
, to
);
138 * Create a new node (directory).
141 newnode(struct entry
*np
)
145 if (np
->e_type
!= NODE
)
146 badentry(np
, "newnode: not a node");
148 if (!Nflag
&& mkdir(cp
, 0777) < 0) {
149 np
->e_flags
|= EXISTED
;
150 fprintf(stderr
, "warning: %s: %s\n", cp
, strerror(errno
));
153 vprintf(stdout
, "Make node %s\n", cp
);
157 * Remove an old node (directory).
160 removenode(struct entry
*ep
)
164 if (ep
->e_type
!= NODE
)
165 badentry(ep
, "removenode: not a node");
166 if (ep
->e_entries
!= NULL
)
167 badentry(ep
, "removenode: non-empty directory");
168 ep
->e_flags
|= REMOVED
;
169 ep
->e_flags
&= ~TMPNAME
;
171 if (!Nflag
&& rmdir(cp
) < 0) {
172 fprintf(stderr
, "warning: %s: %s\n", cp
, strerror(errno
));
175 vprintf(stdout
, "Remove node %s\n", cp
);
182 removeleaf(struct entry
*ep
)
186 if (ep
->e_type
!= LEAF
)
187 badentry(ep
, "removeleaf: not a leaf");
188 ep
->e_flags
|= REMOVED
;
189 ep
->e_flags
&= ~TMPNAME
;
191 if (!Nflag
&& unlink(cp
) < 0) {
192 fprintf(stderr
, "warning: %s: %s\n", cp
, strerror(errno
));
195 vprintf(stdout
, "Remove leaf %s\n", cp
);
202 linkit(char *existing
, char *new, int type
)
205 if (type
== SYMLINK
) {
206 if (!Nflag
&& symlink(existing
, new) < 0) {
208 "warning: cannot create symbolic link %s->%s: %s\n",
209 new, existing
, strerror(errno
));
212 } else if (type
== HARDLINK
) {
213 if (!Nflag
&& link(existing
, new) < 0) {
215 "warning: cannot create hard link %s->%s: %s\n",
216 new, existing
, strerror(errno
));
220 panic("linkit: unknown type %d\n", type
);
223 vprintf(stdout
, "Create %s link %s->%s\n",
224 type
== SYMLINK
? "symbolic" : "hard", new, existing
);
232 addwhiteout(char *name
)
235 if (!Nflag
&& mknod(name
, S_IFWHT
, 0) < 0) {
236 fprintf(stderr
, "warning: cannot create whiteout %s: %s\n",
237 name
, strerror(errno
));
240 vprintf(stdout
, "Create whiteout %s\n", name
);
248 delwhiteout(struct entry
*ep
)
252 if (ep
->e_type
!= LEAF
)
253 badentry(ep
, "delwhiteout: not a leaf");
254 ep
->e_flags
|= REMOVED
;
255 ep
->e_flags
&= ~TMPNAME
;
257 if (!Nflag
&& undelete(name
) < 0) {
258 fprintf(stderr
, "warning: cannot delete whiteout %s: %s\n",
259 name
, strerror(errno
));
262 vprintf(stdout
, "Delete whiteout %s\n", name
);
266 * find lowest number file (above "start") that needs to be extracted
269 lowerbnd(ino_t start
)
273 for ( ; start
< maxino
; start
++) {
274 ep
= lookupino(start
);
275 if (ep
== NULL
|| ep
->e_type
== NODE
)
277 if (ep
->e_flags
& (NEW
|EXTRACT
))
284 * find highest number file (below "start") that needs to be extracted
287 upperbnd(ino_t start
)
291 for ( ; start
> ROOTINO
; start
--) {
292 ep
= lookupino(start
);
293 if (ep
== NULL
|| ep
->e_type
== NODE
)
295 if (ep
->e_flags
& (NEW
|EXTRACT
))
302 * report on a badly formed entry
305 badentry(struct entry
*ep
, const char *message
)
308 fprintf(stderr
, "bad entry: %s\n", message
);
309 fprintf(stderr
, "name: %s\n", myname(ep
));
310 fprintf(stderr
, "parent name %s\n", myname(ep
->e_parent
));
311 if (ep
->e_sibling
!= NULL
)
312 fprintf(stderr
, "sibling name: %s\n", myname(ep
->e_sibling
));
313 if (ep
->e_entries
!= NULL
)
314 fprintf(stderr
, "next entry name: %s\n", myname(ep
->e_entries
));
315 if (ep
->e_links
!= NULL
)
316 fprintf(stderr
, "next link name: %s\n", myname(ep
->e_links
));
317 if (ep
->e_next
!= NULL
)
319 "next hashchain name: %s\n", myname(ep
->e_next
));
320 fprintf(stderr
, "entry type: %s\n",
321 ep
->e_type
== NODE
? "NODE" : "LEAF");
322 fprintf(stderr
, "inode number: %ld\n", (long)ep
->e_ino
);
323 panic("flags: %s\n", flagvalues(ep
));
327 * Construct a string indicating the active flag bits of an entry.
330 flagvalues(struct entry
*ep
)
332 static char flagbuf
[BUFSIZ
];
334 (void) strcpy(flagbuf
, "|NIL");
336 if (ep
->e_flags
& REMOVED
)
337 (void) strcat(flagbuf
, "|REMOVED");
338 if (ep
->e_flags
& TMPNAME
)
339 (void) strcat(flagbuf
, "|TMPNAME");
340 if (ep
->e_flags
& EXTRACT
)
341 (void) strcat(flagbuf
, "|EXTRACT");
342 if (ep
->e_flags
& NEW
)
343 (void) strcat(flagbuf
, "|NEW");
344 if (ep
->e_flags
& KEEP
)
345 (void) strcat(flagbuf
, "|KEEP");
346 if (ep
->e_flags
& EXISTED
)
347 (void) strcat(flagbuf
, "|EXISTED");
348 return (&flagbuf
[1]);
352 * Check to see if a name is on a dump tape.
355 dirlookup(const char *name
)
360 ino
= ((dp
= pathsearch(name
)) == NULL
) ? 0 : dp
->d_ino
;
362 if (ino
== 0 || TSTINO(ino
, dumpmap
) == 0)
363 fprintf(stderr
, "%s is not on the tape\n", name
);
371 reply(const char *question
)
376 fprintf(stderr
, "%s? [yn] ", question
);
377 (void) fflush(stderr
);
379 while (c
!= '\n' && getc(terminal
) != '\n')
382 } while (c
!= 'y' && c
!= 'n');
389 * handle unexpected inconsistencies
394 panic(const char *fmt
, ...)
399 vfprintf(stderr
, fmt
, ap
);
403 if (reply("abort") == GOOD
) {
404 if (reply("dump core") == GOOD
)
411 writemtree(const char *name
, const char *type
,
412 const uid_t uid
, const gid_t gid
, const mode_t mode
, const u_long flags
)
414 const char *sep
= "";
415 if ((name
[0] != '.') || (name
[1] != '/' && name
[1] != '\0'))
416 fprintf(Mtreefile
, "./");
417 fprintf(Mtreefile
, "%s type=%s uid=%d gid=%d mode=%#4.4o",
418 name
, type
, uid
, gid
,
419 mode
& (S_IRWXU
| S_IRWXG
| S_IRWXO
| S_ISUID
| S_ISGID
| S_ISTXT
));
421 fprintf(Mtreefile
, " flags=");
422 if (flags
& UF_NODUMP
) {
423 fprintf(Mtreefile
, "nodump");
426 if (flags
& UF_IMMUTABLE
) {
427 fprintf(Mtreefile
, "%suchg", sep
);
430 if (flags
& UF_APPEND
) {
431 fprintf(Mtreefile
, "%suappnd", sep
);
434 if (flags
& UF_OPAQUE
) {
435 fprintf(Mtreefile
, "%sopaque", sep
);
438 if (flags
& SF_ARCHIVED
) {
439 fprintf(Mtreefile
, "%sarch", sep
);
442 if (flags
& SF_IMMUTABLE
) {
443 fprintf(Mtreefile
, "%sschg", sep
);
446 if (flags
& SF_APPEND
) {
447 fprintf(Mtreefile
, "%ssappnd", sep
);
450 fprintf(Mtreefile
, "\n");
451 if (ferror(Mtreefile
))
452 err(1, "error writing to mtree file");