1 |
|
|
/* $OpenBSD: main.c,v 1.59 2016/08/31 21:00:31 deraadt Exp $ */ |
2 |
|
|
/* $NetBSD: main.c,v 1.14 1997/06/05 11:13:24 lukem Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 1980, 1991, 1993, 1994 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/param.h> /* MAXBSIZE DEV_BSIZE roundup */ |
34 |
|
|
#include <sys/mount.h> |
35 |
|
|
#include <sys/stat.h> |
36 |
|
|
#include <sys/time.h> |
37 |
|
|
#include <sys/ioctl.h> |
38 |
|
|
#include <sys/disklabel.h> |
39 |
|
|
#include <sys/dkio.h> |
40 |
|
|
#include <ufs/ffs/fs.h> |
41 |
|
|
#include <ufs/ufs/dinode.h> |
42 |
|
|
|
43 |
|
|
#include <protocols/dumprestore.h> |
44 |
|
|
|
45 |
|
|
#include <ctype.h> |
46 |
|
|
#include <err.h> |
47 |
|
|
#include <errno.h> |
48 |
|
|
#include <fcntl.h> |
49 |
|
|
#include <fstab.h> |
50 |
|
|
#include <paths.h> |
51 |
|
|
#include <signal.h> |
52 |
|
|
#include <stdio.h> |
53 |
|
|
#include <stdlib.h> |
54 |
|
|
#include <string.h> |
55 |
|
|
#include <time.h> |
56 |
|
|
#include <unistd.h> |
57 |
|
|
#include <limits.h> |
58 |
|
|
#include <util.h> |
59 |
|
|
|
60 |
|
|
#include "dump.h" |
61 |
|
|
#include "pathnames.h" |
62 |
|
|
|
63 |
|
|
int notify = 0; /* notify operator flag */ |
64 |
|
|
int64_t blockswritten = 0; /* number of blocks written on current tape */ |
65 |
|
|
int tapeno = 0; /* current tape number */ |
66 |
|
|
int density = 0; /* density in bytes/0.1" */ |
67 |
|
|
int ntrec = NTREC; /* # tape blocks in each tape record */ |
68 |
|
|
int cartridge = 0; /* Assume non-cartridge tape */ |
69 |
|
|
int64_t blocksperfile; /* output blocks per file */ |
70 |
|
|
char *host = NULL; /* remote host (if any) */ |
71 |
|
|
int maxbsize = 64*1024; /* XXX MAXBSIZE from sys/param.h */ |
72 |
|
|
|
73 |
|
|
struct disklabel lab; |
74 |
|
|
|
75 |
|
|
/* |
76 |
|
|
* Possible superblock locations ordered from most to least likely. |
77 |
|
|
*/ |
78 |
|
|
static int sblock_try[] = SBLOCKSEARCH; |
79 |
|
|
|
80 |
|
|
static long long numarg(char *, long long, long long); |
81 |
|
|
static void obsolete(int *, char **[]); |
82 |
|
|
static void usage(void); |
83 |
|
|
|
84 |
|
|
int |
85 |
|
|
main(int argc, char *argv[]) |
86 |
|
|
{ |
87 |
|
|
ino_t ino; |
88 |
|
|
int dirty; |
89 |
|
|
union dinode *dp; |
90 |
|
|
struct fstab *dt; |
91 |
|
|
char *map; |
92 |
|
|
int ch, mode; |
93 |
|
|
struct tm then; |
94 |
|
|
struct statfs fsbuf; |
95 |
|
|
int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1; |
96 |
|
|
ino_t maxino; |
97 |
|
|
time_t t; |
98 |
|
|
int dirlist; |
99 |
|
|
char *toplevel, *str, *mount_point = NULL, *realpath; |
100 |
|
|
int just_estimate = 0; |
101 |
|
|
u_int64_t zero_uid = 0; |
102 |
|
|
|
103 |
|
|
spcl.c_date = (int64_t)time(NULL); |
104 |
|
|
|
105 |
|
|
tsize = 0; /* Default later, based on 'c' option for cart tapes */ |
106 |
|
|
if ((tape = getenv("TAPE")) == NULL) |
107 |
|
|
tape = _PATH_DEFTAPE; |
108 |
|
|
dumpdates = _PATH_DUMPDATES; |
109 |
|
|
temp = _PATH_DTMP; |
110 |
|
|
if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0) |
111 |
|
|
quit("TP_BSIZE must be a multiple of DEV_BSIZE\n"); |
112 |
|
|
level = '0'; |
113 |
|
|
|
114 |
|
|
if (argc < 2) |
115 |
|
|
usage(); |
116 |
|
|
|
117 |
|
|
obsolete(&argc, &argv); |
118 |
|
|
while ((ch = getopt(argc, argv, "0123456789aB:b:cd:f:h:ns:ST:uWw")) != -1) |
119 |
|
|
switch (ch) { |
120 |
|
|
/* dump level */ |
121 |
|
|
case '0': case '1': case '2': case '3': case '4': |
122 |
|
|
case '5': case '6': case '7': case '8': case '9': |
123 |
|
|
level = ch; |
124 |
|
|
break; |
125 |
|
|
|
126 |
|
|
case 'B': /* blocks per output file */ |
127 |
|
|
blocksperfile = numarg("blocks per file", 1, 0); |
128 |
|
|
break; |
129 |
|
|
|
130 |
|
|
case 'b': /* blocks per tape write */ |
131 |
|
|
ntrec = numarg("blocks per write", 1, 1000); |
132 |
|
|
if (ntrec > maxbsize/1024) { |
133 |
|
|
msg("Please choose a blocksize <= %dKB\n", |
134 |
|
|
maxbsize/1024); |
135 |
|
|
exit(X_STARTUP); |
136 |
|
|
} |
137 |
|
|
bflag = 1; |
138 |
|
|
break; |
139 |
|
|
|
140 |
|
|
case 'c': /* Tape is cart. not 9-track */ |
141 |
|
|
cartridge = 1; |
142 |
|
|
break; |
143 |
|
|
|
144 |
|
|
case 'd': /* density, in bits per inch */ |
145 |
|
|
density = numarg("density", 10, 327670) / 10; |
146 |
|
|
if (density >= 625 && !bflag) |
147 |
|
|
ntrec = HIGHDENSITYTREC; |
148 |
|
|
break; |
149 |
|
|
|
150 |
|
|
case 'f': /* output file */ |
151 |
|
|
tape = optarg; |
152 |
|
|
break; |
153 |
|
|
|
154 |
|
|
case 'h': |
155 |
|
|
honorlevel = numarg("honor level", 0, 10); |
156 |
|
|
break; |
157 |
|
|
|
158 |
|
|
case 'n': /* notify operators */ |
159 |
|
|
notify = 1; |
160 |
|
|
break; |
161 |
|
|
|
162 |
|
|
case 's': /* tape size, feet */ |
163 |
|
|
tsize = numarg("tape size", 1, 0) * 12 * 10; |
164 |
|
|
break; |
165 |
|
|
|
166 |
|
|
case 'S': /* estimate blocks and # of tapes */ |
167 |
|
|
just_estimate = 1; |
168 |
|
|
break; |
169 |
|
|
|
170 |
|
|
case 'T': /* time of last dump */ |
171 |
|
|
str = strptime(optarg, "%a %b %e %H:%M:%S %Y", &then); |
172 |
|
|
then.tm_isdst = -1; |
173 |
|
|
if (str == NULL || (*str != '\n' && *str != '\0')) |
174 |
|
|
spcl.c_ddate = -1; |
175 |
|
|
else |
176 |
|
|
spcl.c_ddate = (int64_t)mktime(&then); |
177 |
|
|
if (spcl.c_ddate < 0) { |
178 |
|
|
(void)fprintf(stderr, "bad time \"%s\"\n", |
179 |
|
|
optarg); |
180 |
|
|
exit(X_STARTUP); |
181 |
|
|
} |
182 |
|
|
Tflag = 1; |
183 |
|
|
lastlevel = '?'; |
184 |
|
|
break; |
185 |
|
|
|
186 |
|
|
case 'u': /* update /etc/dumpdates */ |
187 |
|
|
uflag = 1; |
188 |
|
|
break; |
189 |
|
|
|
190 |
|
|
case 'W': /* what to do */ |
191 |
|
|
case 'w': |
192 |
|
|
lastdump(ch); |
193 |
|
|
exit(X_FINOK); /* do nothing else */ |
194 |
|
|
break; |
195 |
|
|
|
196 |
|
|
case 'a': /* `auto-size', Write to EOM. */ |
197 |
|
|
unlimited = 1; |
198 |
|
|
break; |
199 |
|
|
|
200 |
|
|
default: |
201 |
|
|
usage(); |
202 |
|
|
} |
203 |
|
|
argc -= optind; |
204 |
|
|
argv += optind; |
205 |
|
|
|
206 |
|
|
if (argc < 1) { |
207 |
|
|
(void)fprintf(stderr, "Must specify disk or filesystem\n"); |
208 |
|
|
exit(X_STARTUP); |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
/* |
212 |
|
|
* determine if disk is a subdirectory, and setup appropriately |
213 |
|
|
*/ |
214 |
|
|
dirlist = 0; |
215 |
|
|
toplevel = NULL; |
216 |
|
|
for (i = 0; i < argc; i++) { |
217 |
|
|
struct stat sb; |
218 |
|
|
|
219 |
|
|
/* Convert potential duid into a device name */ |
220 |
|
|
if ((diskfd = opendev(argv[i], O_RDONLY | O_NOFOLLOW, 0, |
221 |
|
|
&realpath)) >= 0) { |
222 |
|
|
argv[i] = strdup(realpath); |
223 |
|
|
if (argv[i] == NULL) { |
224 |
|
|
msg("Cannot malloc realpath\n"); |
225 |
|
|
exit(X_STARTUP); |
226 |
|
|
} |
227 |
|
|
(void)close(diskfd); |
228 |
|
|
} |
229 |
|
|
if (lstat(argv[i], &sb) == -1) { |
230 |
|
|
msg("Cannot lstat %s: %s\n", argv[i], strerror(errno)); |
231 |
|
|
exit(X_STARTUP); |
232 |
|
|
} |
233 |
|
|
if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) |
234 |
|
|
break; |
235 |
|
|
if (statfs(argv[i], &fsbuf) == -1) { |
236 |
|
|
msg("Cannot statfs %s: %s\n", argv[i], strerror(errno)); |
237 |
|
|
exit(X_STARTUP); |
238 |
|
|
} |
239 |
|
|
if (strcmp(argv[i], fsbuf.f_mntonname) == 0) { |
240 |
|
|
if (dirlist != 0) { |
241 |
|
|
msg("Can't dump a mountpoint and a filelist\n"); |
242 |
|
|
exit(X_STARTUP); |
243 |
|
|
} |
244 |
|
|
break; /* exit if sole mountpoint */ |
245 |
|
|
} |
246 |
|
|
if (!disk) { |
247 |
|
|
if ((toplevel = strdup(fsbuf.f_mntonname)) == NULL) { |
248 |
|
|
msg("Cannot malloc diskname\n"); |
249 |
|
|
exit(X_STARTUP); |
250 |
|
|
} |
251 |
|
|
disk = toplevel; |
252 |
|
|
if (uflag) { |
253 |
|
|
msg("Ignoring u flag for subdir dump\n"); |
254 |
|
|
uflag = 0; |
255 |
|
|
} |
256 |
|
|
if (level > '0') { |
257 |
|
|
msg("Subdir dump is done at level 0\n"); |
258 |
|
|
level = '0'; |
259 |
|
|
} |
260 |
|
|
msg("Dumping sub files/directories from %s\n", disk); |
261 |
|
|
} else { |
262 |
|
|
if (strcmp(disk, fsbuf.f_mntonname) != 0) { |
263 |
|
|
msg("%s is not on %s\n", argv[i], disk); |
264 |
|
|
exit(X_STARTUP); |
265 |
|
|
} |
266 |
|
|
} |
267 |
|
|
msg("Dumping file/directory %s\n", argv[i]); |
268 |
|
|
dirlist++; |
269 |
|
|
} |
270 |
|
|
if (dirlist == 0) { |
271 |
|
|
disk = *argv++; |
272 |
|
|
if (argc != 1) { |
273 |
|
|
(void)fputs("Excess arguments to dump:", stderr); |
274 |
|
|
while (--argc) { |
275 |
|
|
(void)putc(' ', stderr); |
276 |
|
|
(void)fputs(*argv++, stderr); |
277 |
|
|
} |
278 |
|
|
(void)putc('\n', stderr); |
279 |
|
|
exit(X_STARTUP); |
280 |
|
|
} |
281 |
|
|
} |
282 |
|
|
if (Tflag && uflag) { |
283 |
|
|
(void)fprintf(stderr, |
284 |
|
|
"You cannot use the T and u flags together.\n"); |
285 |
|
|
exit(X_STARTUP); |
286 |
|
|
} |
287 |
|
|
if (strcmp(tape, "-") == 0) { |
288 |
|
|
pipeout++; |
289 |
|
|
tape = "standard output"; |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
if (blocksperfile) |
293 |
|
|
blocksperfile = blocksperfile / ntrec * ntrec; /* round down */ |
294 |
|
|
else if (!unlimited) { |
295 |
|
|
/* |
296 |
|
|
* Determine how to default tape size and density |
297 |
|
|
* |
298 |
|
|
* density tape size |
299 |
|
|
* 9-track 1600 bpi (160 bytes/.1") 2300 ft. |
300 |
|
|
* 9-track 6250 bpi (625 bytes/.1") 2300 ft. |
301 |
|
|
* cartridge 8000 bpi (800 bytes/.1") 1700 ft. |
302 |
|
|
* (450*4 - slop) |
303 |
|
|
*/ |
304 |
|
|
if (density == 0) |
305 |
|
|
density = cartridge ? 100 : 160; |
306 |
|
|
if (tsize == 0) |
307 |
|
|
tsize = cartridge ? 1700L*120L : 2300L*120L; |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
if (strchr(tape, ':')) { |
311 |
|
|
host = tape; |
312 |
|
|
tape = strchr(host, ':'); |
313 |
|
|
*tape++ = '\0'; |
314 |
|
|
#ifdef RDUMP |
315 |
|
|
if (rmthost(host) == 0) |
316 |
|
|
exit(X_STARTUP); |
317 |
|
|
#else |
318 |
|
|
(void)fprintf(stderr, "remote dump not enabled\n"); |
319 |
|
|
exit(X_STARTUP); |
320 |
|
|
#endif |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) |
324 |
|
|
signal(SIGHUP, sig); |
325 |
|
|
if (signal(SIGTERM, SIG_IGN) != SIG_IGN) |
326 |
|
|
signal(SIGTERM, sig); |
327 |
|
|
if (signal(SIGINT, interrupt) == SIG_IGN) |
328 |
|
|
signal(SIGINT, SIG_IGN); |
329 |
|
|
|
330 |
|
|
getfstab(); /* /etc/fstab snarfed */ |
331 |
|
|
|
332 |
|
|
/* |
333 |
|
|
* disk can be either the full special file name, |
334 |
|
|
* the suffix of the special file name, |
335 |
|
|
* the special name missing the leading '/', |
336 |
|
|
* the file system name with or without the leading '/'. |
337 |
|
|
*/ |
338 |
|
|
if (!statfs(disk, &fsbuf) && !strcmp(fsbuf.f_mntonname, disk)) { |
339 |
|
|
/* mounted disk? */ |
340 |
|
|
disk = rawname(fsbuf.f_mntfromname); |
341 |
|
|
if (!disk) { |
342 |
|
|
(void)fprintf(stderr, "cannot get raw name for %s\n", |
343 |
|
|
fsbuf.f_mntfromname); |
344 |
|
|
exit(X_STARTUP); |
345 |
|
|
} |
346 |
|
|
mount_point = fsbuf.f_mntonname; |
347 |
|
|
(void)strlcpy(spcl.c_dev, fsbuf.f_mntfromname, |
348 |
|
|
sizeof(spcl.c_dev)); |
349 |
|
|
if (dirlist != 0) { |
350 |
|
|
(void)snprintf(spcl.c_filesys, sizeof(spcl.c_filesys), |
351 |
|
|
"a subset of %s", mount_point); |
352 |
|
|
} else { |
353 |
|
|
(void)strlcpy(spcl.c_filesys, mount_point, |
354 |
|
|
sizeof(spcl.c_filesys)); |
355 |
|
|
} |
356 |
|
|
} else if ((dt = fstabsearch(disk)) != NULL) { |
357 |
|
|
/* in fstab? */ |
358 |
|
|
if (strchr(dt->fs_spec, '/')) { |
359 |
|
|
/* fs_spec is a /dev/something */ |
360 |
|
|
disk = rawname(dt->fs_spec); |
361 |
|
|
} else { |
362 |
|
|
/* fs_spec is a DUID */ |
363 |
|
|
disk = rawname(disk); |
364 |
|
|
} |
365 |
|
|
mount_point = dt->fs_file; |
366 |
|
|
(void)strlcpy(spcl.c_dev, dt->fs_spec, sizeof(spcl.c_dev)); |
367 |
|
|
if (dirlist != 0) { |
368 |
|
|
(void)snprintf(spcl.c_filesys, sizeof(spcl.c_filesys), |
369 |
|
|
"a subset of %s", mount_point); |
370 |
|
|
} else { |
371 |
|
|
(void)strlcpy(spcl.c_filesys, mount_point, |
372 |
|
|
sizeof(spcl.c_filesys)); |
373 |
|
|
} |
374 |
|
|
} else { |
375 |
|
|
/* must be a device */ |
376 |
|
|
(void)strlcpy(spcl.c_dev, disk, sizeof(spcl.c_dev)); |
377 |
|
|
(void)strlcpy(spcl.c_filesys, "an unlisted file system", |
378 |
|
|
sizeof(spcl.c_filesys)); |
379 |
|
|
} |
380 |
|
|
(void)strlcpy(spcl.c_label, "none", sizeof(spcl.c_label)); |
381 |
|
|
(void)gethostname(spcl.c_host, sizeof(spcl.c_host)); |
382 |
|
|
spcl.c_level = level - '0'; |
383 |
|
|
spcl.c_type = TS_TAPE; |
384 |
|
|
|
385 |
|
|
if ((diskfd = open(disk, O_RDONLY)) < 0) { |
386 |
|
|
msg("Cannot open %s\n", disk); |
387 |
|
|
exit(X_STARTUP); |
388 |
|
|
} |
389 |
|
|
if (ioctl(diskfd, DIOCGDINFO, (char *)&lab) < 0) |
390 |
|
|
err(1, "ioctl (DIOCGDINFO)"); |
391 |
|
|
|
392 |
|
|
if (memcmp(lab.d_uid, &zero_uid, sizeof(lab.d_uid)) != 0) { |
393 |
|
|
if (asprintf(&duid, |
394 |
|
|
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", |
395 |
|
|
lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], |
396 |
|
|
lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7], |
397 |
|
|
disk[strlen(disk)-1]) == -1) { |
398 |
|
|
msg("Cannot malloc duid\n"); |
399 |
|
|
exit(X_STARTUP); |
400 |
|
|
} |
401 |
|
|
} |
402 |
|
|
if (!Tflag) |
403 |
|
|
getdumptime(); /* /etc/dumpdates snarfed */ |
404 |
|
|
|
405 |
|
|
t = (time_t)spcl.c_date; |
406 |
|
|
msg("Date of this level %c dump: %s", level, |
407 |
|
|
t == 0 ? "the epoch\n" : ctime(&t)); |
408 |
|
|
t = (time_t)spcl.c_ddate; |
409 |
|
|
msg("Date of last level %c dump: %s", lastlevel, |
410 |
|
|
t == 0 ? "the epoch\n" : ctime(&t)); |
411 |
|
|
msg("Dumping %s ", disk); |
412 |
|
|
if (mount_point != NULL) |
413 |
|
|
msgtail("(%s) ", mount_point); |
414 |
|
|
if (host) |
415 |
|
|
msgtail("to %s on host %s\n", tape, host); |
416 |
|
|
else |
417 |
|
|
msgtail("to %s\n", tape); |
418 |
|
|
|
419 |
|
|
if (ioctl(diskfd, DIOCGPDINFO, (char *)&lab) < 0) |
420 |
|
|
err(1, "ioctl (DIOCGPDINFO)"); |
421 |
|
|
sync(); |
422 |
|
|
sblock = (struct fs *)sblock_buf; |
423 |
|
|
for (i = 0; sblock_try[i] != -1; i++) { |
424 |
|
|
ssize_t n = pread(diskfd, sblock, SBLOCKSIZE, |
425 |
|
|
(off_t)sblock_try[i]); |
426 |
|
|
if (n == SBLOCKSIZE && (sblock->fs_magic == FS_UFS1_MAGIC || |
427 |
|
|
(sblock->fs_magic == FS_UFS2_MAGIC && |
428 |
|
|
sblock->fs_sblockloc == sblock_try[i])) && |
429 |
|
|
sblock->fs_bsize <= MAXBSIZE && |
430 |
|
|
sblock->fs_bsize >= sizeof(struct fs)) |
431 |
|
|
break; |
432 |
|
|
} |
433 |
|
|
if (sblock_try[i] == -1) |
434 |
|
|
quit("Cannot find filesystem superblock\n"); |
435 |
|
|
tp_bshift = ffs(TP_BSIZE) - 1; |
436 |
|
|
if (TP_BSIZE != (1 << tp_bshift)) |
437 |
|
|
quit("TP_BSIZE (%d) is not a power of 2\n", TP_BSIZE); |
438 |
|
|
#ifdef FS_44INODEFMT |
439 |
|
|
if (sblock->fs_magic == FS_UFS2_MAGIC || |
440 |
|
|
sblock->fs_inodefmt >= FS_44INODEFMT) |
441 |
|
|
spcl.c_flags |= DR_NEWINODEFMT; |
442 |
|
|
#endif |
443 |
|
|
maxino = sblock->fs_ipg * sblock->fs_ncg; |
444 |
|
|
mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE); |
445 |
|
|
usedinomap = calloc((unsigned) mapsize, sizeof(char)); |
446 |
|
|
dumpdirmap = calloc((unsigned) mapsize, sizeof(char)); |
447 |
|
|
dumpinomap = calloc((unsigned) mapsize, sizeof(char)); |
448 |
|
|
tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); |
449 |
|
|
|
450 |
|
|
nonodump = spcl.c_level < honorlevel; |
451 |
|
|
|
452 |
|
|
(void)signal(SIGINFO, statussig); |
453 |
|
|
|
454 |
|
|
msg("mapping (Pass I) [regular files]\n"); |
455 |
|
|
anydirskipped = mapfiles(maxino, &tapesize, toplevel, |
456 |
|
|
(dirlist ? argv : NULL)); |
457 |
|
|
|
458 |
|
|
msg("mapping (Pass II) [directories]\n"); |
459 |
|
|
while (anydirskipped) { |
460 |
|
|
anydirskipped = mapdirs(maxino, &tapesize); |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
if (pipeout || unlimited) { |
464 |
|
|
tapesize += 10; /* 10 trailer blocks */ |
465 |
|
|
msg("estimated %lld tape blocks.\n", tapesize); |
466 |
|
|
} else { |
467 |
|
|
double fetapes; |
468 |
|
|
|
469 |
|
|
if (blocksperfile) |
470 |
|
|
fetapes = (double) tapesize / blocksperfile; |
471 |
|
|
else if (cartridge) { |
472 |
|
|
/* Estimate number of tapes, assuming streaming stops at |
473 |
|
|
the end of each block written, and not in mid-block. |
474 |
|
|
Assume no erroneous blocks; this can be compensated |
475 |
|
|
for with an artificially low tape size. */ |
476 |
|
|
fetapes = |
477 |
|
|
( tapesize /* blocks */ |
478 |
|
|
* TP_BSIZE /* bytes/block */ |
479 |
|
|
* (1.0/density) /* 0.1" / byte */ |
480 |
|
|
+ |
481 |
|
|
tapesize /* blocks */ |
482 |
|
|
* (1.0/ntrec) /* streaming-stops per block */ |
483 |
|
|
* 15.48 /* 0.1" / streaming-stop */ |
484 |
|
|
) * (1.0 / tsize ); /* tape / 0.1" */ |
485 |
|
|
} else { |
486 |
|
|
/* Estimate number of tapes, for old fashioned 9-track |
487 |
|
|
tape */ |
488 |
|
|
int tenthsperirg = (density == 625) ? 3 : 7; |
489 |
|
|
fetapes = |
490 |
|
|
( tapesize /* blocks */ |
491 |
|
|
* TP_BSIZE /* bytes / block */ |
492 |
|
|
* (1.0/density) /* 0.1" / byte */ |
493 |
|
|
+ |
494 |
|
|
tapesize /* blocks */ |
495 |
|
|
* (1.0/ntrec) /* IRG's / block */ |
496 |
|
|
* tenthsperirg /* 0.1" / IRG */ |
497 |
|
|
) * (1.0 / tsize ); /* tape / 0.1" */ |
498 |
|
|
} |
499 |
|
|
etapes = fetapes; /* truncating assignment */ |
500 |
|
|
etapes++; |
501 |
|
|
/* count the dumped inodes map on each additional tape */ |
502 |
|
|
tapesize += (etapes - 1) * |
503 |
|
|
(howmany(mapsize * sizeof(char), TP_BSIZE) + 1); |
504 |
|
|
tapesize += etapes + 10; /* headers + 10 trailer blks */ |
505 |
|
|
msg("estimated %lld tape blocks on %3.2f tape(s).\n", |
506 |
|
|
tapesize, fetapes); |
507 |
|
|
} |
508 |
|
|
|
509 |
|
|
/* |
510 |
|
|
* Exit if user wants an estimate of blocks and # of tapes only. |
511 |
|
|
*/ |
512 |
|
|
if (just_estimate) |
513 |
|
|
exit(X_FINOK); |
514 |
|
|
|
515 |
|
|
/* |
516 |
|
|
* Allocate tape buffer. |
517 |
|
|
*/ |
518 |
|
|
if (!alloctape()) |
519 |
|
|
quit("can't allocate tape buffers - try a smaller blocking factor.\n"); |
520 |
|
|
|
521 |
|
|
startnewtape(1); |
522 |
|
|
(void)time(&tstart_writing); |
523 |
|
|
xferrate = 0; |
524 |
|
|
dumpmap(usedinomap, TS_CLRI, maxino - 1); |
525 |
|
|
|
526 |
|
|
msg("dumping (Pass III) [directories]\n"); |
527 |
|
|
dirty = 0; /* XXX just to get gcc to shut up */ |
528 |
|
|
for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { |
529 |
|
|
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ |
530 |
|
|
dirty = *map++; |
531 |
|
|
else |
532 |
|
|
dirty >>= 1; |
533 |
|
|
if ((dirty & 1) == 0) |
534 |
|
|
continue; |
535 |
|
|
/* |
536 |
|
|
* Skip directory inodes deleted and maybe reallocated |
537 |
|
|
*/ |
538 |
|
|
dp = getino(ino, &mode); |
539 |
|
|
if (mode != IFDIR) |
540 |
|
|
continue; |
541 |
|
|
(void)dumpino(dp, ino); |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
msg("dumping (Pass IV) [regular files]\n"); |
545 |
|
|
for (map = dumpinomap, ino = 1; ino < maxino; ino++) { |
546 |
|
|
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ |
547 |
|
|
dirty = *map++; |
548 |
|
|
else |
549 |
|
|
dirty >>= 1; |
550 |
|
|
if ((dirty & 1) == 0) |
551 |
|
|
continue; |
552 |
|
|
/* |
553 |
|
|
* Skip inodes deleted and reallocated as directories. |
554 |
|
|
*/ |
555 |
|
|
dp = getino(ino, &mode); |
556 |
|
|
if (mode == IFDIR) |
557 |
|
|
continue; |
558 |
|
|
(void)dumpino(dp, ino); |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
spcl.c_type = TS_END; |
562 |
|
|
for (i = 0; i < ntrec; i++) |
563 |
|
|
writeheader(maxino - 1); |
564 |
|
|
if (pipeout) |
565 |
|
|
msg("%lld tape blocks\n", spcl.c_tapea); |
566 |
|
|
else |
567 |
|
|
msg("%lld tape blocks on %d volume%s\n", |
568 |
|
|
spcl.c_tapea, spcl.c_volume, |
569 |
|
|
(spcl.c_volume == 1) ? "" : "s"); |
570 |
|
|
t = (time_t)spcl.c_date; |
571 |
|
|
msg("Date of this level %c dump: %s", level, |
572 |
|
|
t == 0 ? "the epoch\n" : ctime(&t)); |
573 |
|
|
t = do_stats(); |
574 |
|
|
msg("Date this dump completed: %s", ctime(&t)); |
575 |
|
|
msg("Average transfer rate: %ld KB/s\n", xferrate / tapeno); |
576 |
|
|
putdumptime(); |
577 |
|
|
trewind(); |
578 |
|
|
broadcast("DUMP IS DONE!\7\7\n"); |
579 |
|
|
msg("DUMP IS DONE\n"); |
580 |
|
|
Exit(X_FINOK); |
581 |
|
|
/* NOTREACHED */ |
582 |
|
|
} |
583 |
|
|
|
584 |
|
|
static void |
585 |
|
|
usage(void) |
586 |
|
|
{ |
587 |
|
|
extern char *__progname; |
588 |
|
|
|
589 |
|
|
(void)fprintf(stderr, "usage: %s [-0123456789acnSuWw] [-B records] " |
590 |
|
|
"[-b blocksize] [-d density]\n" |
591 |
|
|
"\t[-f file] [-h level] [-s feet] " |
592 |
|
|
"[-T date] files-to-dump\n", |
593 |
|
|
__progname); |
594 |
|
|
exit(X_STARTUP); |
595 |
|
|
} |
596 |
|
|
|
597 |
|
|
/* |
598 |
|
|
* Pick up a numeric argument. It must be nonnegative and in the given |
599 |
|
|
* range (except that a vmax of 0 means unlimited). |
600 |
|
|
*/ |
601 |
|
|
static long long |
602 |
|
|
numarg(char *meaning, long long vmin, long long vmax) |
603 |
|
|
{ |
604 |
|
|
long long val; |
605 |
|
|
const char *errstr; |
606 |
|
|
|
607 |
|
|
if (vmax == 0) |
608 |
|
|
vmax = LLONG_MAX; |
609 |
|
|
val = strtonum(optarg, vmin, vmax, &errstr); |
610 |
|
|
if (errstr) |
611 |
|
|
errx(X_STARTUP, "%s is %s [%lld - %lld]", |
612 |
|
|
meaning, errstr, vmin, vmax); |
613 |
|
|
|
614 |
|
|
return (val); |
615 |
|
|
} |
616 |
|
|
|
617 |
|
|
void |
618 |
|
|
sig(int signo) |
619 |
|
|
{ |
620 |
|
|
switch(signo) { |
621 |
|
|
case SIGALRM: |
622 |
|
|
case SIGHUP: |
623 |
|
|
case SIGTERM: |
624 |
|
|
/* XXX signal race */ |
625 |
|
|
if (pipeout) |
626 |
|
|
quit("Signal on pipe: cannot recover\n"); |
627 |
|
|
msg("Rewriting attempted as response to unknown signal.\n"); |
628 |
|
|
(void)fflush(stderr); |
629 |
|
|
(void)fflush(stdout); |
630 |
|
|
close_rewind(); |
631 |
|
|
exit(X_REWRITE); |
632 |
|
|
/* NOTREACHED */ |
633 |
|
|
} |
634 |
|
|
} |
635 |
|
|
|
636 |
|
|
char * |
637 |
|
|
rawname(char *cp) |
638 |
|
|
{ |
639 |
|
|
static char rawbuf[PATH_MAX]; |
640 |
|
|
char *dp = strrchr(cp, '/'); |
641 |
|
|
char *prefix; |
642 |
|
|
|
643 |
|
|
if (dp == NULL) |
644 |
|
|
return (NULL); |
645 |
|
|
prefix = dp[1] == 'r' ? "" : "r"; |
646 |
|
|
*dp = '\0'; |
647 |
|
|
(void)snprintf(rawbuf, sizeof(rawbuf), "%s/%s%s", cp, prefix, dp + 1); |
648 |
|
|
*dp = '/'; |
649 |
|
|
return (rawbuf); |
650 |
|
|
} |
651 |
|
|
|
652 |
|
|
char * |
653 |
|
|
getduid(char *path) |
654 |
|
|
{ |
655 |
|
|
int fd; |
656 |
|
|
struct disklabel lab; |
657 |
|
|
u_int64_t zero_uid = 0; |
658 |
|
|
char *duid; |
659 |
|
|
|
660 |
|
|
if ((fd = opendev(path, O_RDONLY | O_NOFOLLOW, 0, NULL)) >= 0) { |
661 |
|
|
if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { |
662 |
|
|
close(fd); |
663 |
|
|
warn("ioctl(DIOCGDINFO)"); |
664 |
|
|
return (NULL); |
665 |
|
|
} |
666 |
|
|
close(fd); |
667 |
|
|
|
668 |
|
|
if (memcmp(lab.d_uid, &zero_uid, sizeof(lab.d_uid)) != 0) { |
669 |
|
|
if (asprintf(&duid, |
670 |
|
|
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", |
671 |
|
|
lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], |
672 |
|
|
lab.d_uid[3], lab.d_uid[4], lab.d_uid[5], |
673 |
|
|
lab.d_uid[6], lab.d_uid[7], |
674 |
|
|
path[strlen(path)-1]) == -1) { |
675 |
|
|
warn("Cannot malloc duid"); |
676 |
|
|
return (NULL); |
677 |
|
|
} |
678 |
|
|
return (duid); |
679 |
|
|
} |
680 |
|
|
} |
681 |
|
|
|
682 |
|
|
return (NULL); |
683 |
|
|
} |
684 |
|
|
|
685 |
|
|
/* |
686 |
|
|
* obsolete -- |
687 |
|
|
* Change set of key letters and ordered arguments into something |
688 |
|
|
* getopt(3) will like. |
689 |
|
|
*/ |
690 |
|
|
static void |
691 |
|
|
obsolete(int *argcp, char **argvp[]) |
692 |
|
|
{ |
693 |
|
|
int argc, flags; |
694 |
|
|
char *ap, **argv, *flagsp, **nargv, *p; |
695 |
|
|
size_t len; |
696 |
|
|
|
697 |
|
|
/* Setup. */ |
698 |
|
|
argv = *argvp; |
699 |
|
|
argc = *argcp; |
700 |
|
|
|
701 |
|
|
/* Return if no arguments or first argument has leading dash. */ |
702 |
|
|
ap = argv[1]; |
703 |
|
|
if (argc == 1 || *ap == '-') |
704 |
|
|
return; |
705 |
|
|
|
706 |
|
|
/* Allocate space for new arguments. */ |
707 |
|
|
if ((*argvp = nargv = calloc(argc + 1, sizeof(char *))) == NULL || |
708 |
|
|
(p = flagsp = malloc(strlen(ap) + 2)) == NULL) |
709 |
|
|
err(1, NULL); |
710 |
|
|
|
711 |
|
|
*nargv++ = *argv; |
712 |
|
|
argv += 2; |
713 |
|
|
|
714 |
|
|
for (flags = 0; *ap; ++ap) { |
715 |
|
|
switch (*ap) { |
716 |
|
|
case 'B': |
717 |
|
|
case 'b': |
718 |
|
|
case 'd': |
719 |
|
|
case 'f': |
720 |
|
|
case 'h': |
721 |
|
|
case 's': |
722 |
|
|
case 'T': |
723 |
|
|
if (*argv == NULL) { |
724 |
|
|
warnx("option requires an argument -- %c", *ap); |
725 |
|
|
usage(); |
726 |
|
|
} |
727 |
|
|
len = 2 + strlen(*argv) + 1; |
728 |
|
|
if ((nargv[0] = malloc(len)) == NULL) |
729 |
|
|
err(1, NULL); |
730 |
|
|
nargv[0][0] = '-'; |
731 |
|
|
nargv[0][1] = *ap; |
732 |
|
|
(void)strlcpy(&nargv[0][2], *argv, len - 2); |
733 |
|
|
++argv; |
734 |
|
|
++nargv; |
735 |
|
|
break; |
736 |
|
|
default: |
737 |
|
|
if (!flags) { |
738 |
|
|
*p++ = '-'; |
739 |
|
|
flags = 1; |
740 |
|
|
} |
741 |
|
|
*p++ = *ap; |
742 |
|
|
break; |
743 |
|
|
} |
744 |
|
|
} |
745 |
|
|
|
746 |
|
|
/* Terminate flags, or toss the buffer we did not use. */ |
747 |
|
|
if (flags) { |
748 |
|
|
*p = '\0'; |
749 |
|
|
*nargv++ = flagsp; |
750 |
|
|
} else |
751 |
|
|
free(flagsp); |
752 |
|
|
|
753 |
|
|
/* Copy remaining arguments. */ |
754 |
|
|
while ((*nargv++ = *argv++)) |
755 |
|
|
continue; |
756 |
|
|
|
757 |
|
|
/* Update argument count. */ |
758 |
|
|
*argcp = nargv - *argvp - 1; |
759 |
|
|
} |