2 * Copyright 1996-1998, 2002-2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
20 static struct flock fl
;
21 #define flock(fd, flag) (fl.l_type = (flag), fcntl(fd, F_SETLKW, &fl))
22 #define LOCK_EX F_WRLCK
23 #define LOCK_SH F_RDLCK
24 #define LOCK_UN F_UNLCK
28 * Print a date. A date of 0 is the beginning of time (the "epoch").
29 * If the 2nd argument is non-zero, it is ok to format the date in
30 * locale-specific form, otherwise we use ctime. We must use ctime
31 * for dates such as those in the dumpdates file, which must be
43 return (gettext("the epoch"));
46 if (strftime(buf
, sizeof (buf
), "%c", tm
) != 0) {
49 /* Wouldn't fit in buf, fall back */
51 p
[24] = '\0'; /* lose trailing newline */
56 struct idates
**idatev
= 0;
58 static int idates_in
= 0; /* we have read the increment file */
62 static void readitimes(FILE *);
63 static void recout(FILE *, struct idates
*);
64 static int getrecord(FILE *, struct idates
*);
65 static int makeidate(struct idates
*, char *);
67 static void readitimes();
69 static int getrecord();
70 static int makeidate();
85 if (increm
== NULL
|| *increm
== '\0') {
86 msg(gettext("inititimes: No dump record file name defined\n"));
91 * No need to secure this, as increm is hard-coded to NINCREM,
92 * and that file is in /etc. If random people have write-permission
93 * there, then there are more problems than any degree of paranoia
94 * on our part can fix.
96 if ((df
= fopen(increm
, "r")) == NULL
) {
100 "Warning - dump record file `%s' does not exist\n"),
103 msg(gettext("Cannot open dump record file `%s': %s\n"),
104 increm
, strerror(saverr
));
110 if (uflag
&& access(increm
, W_OK
) < 0) {
111 msg(gettext("Cannot access dump record file `%s' for update\n"),
116 (void) flock(fileno(df
), LOCK_SH
);
129 idp
= (struct idates
*)xcalloc(1, sizeof (*idp
));
130 if (getrecord(df
, idp
) < 0) {
135 idatev
= (struct idates
**)xrealloc((void *)idatev
,
136 nidates
* (size_t)sizeof (*idatev
));
137 idatev
[nidates
- 1] = idp
;
139 /* LINTED: assigned value is used in inititimes */
155 * if an alternate name was specified via the N flag, use it instead
165 /* XGETTEXT: #ifdef FDEBUG only */
166 msg(gettext("Looking for name %s in increm = %s for delta = %c\n"),
167 fname
, increm
, (uchar_t
)incno
);
176 * Go find the entry with the same name for a lower increment
180 if (strncmp(fname
, ip
->id_name
, sizeof (ip
->id_name
)) != 0)
182 if (ip
->id_incno
>= incno
)
184 if (ip
->id_ddate
<= spcl
.c_ddate
)
186 spcl
.c_ddate
= ip
->id_ddate
;
187 lastincno
= ip
->id_incno
;
199 struct idates
*itwalk
;
206 if ((df
= safe_fopen(increm
, "r+", 0664)) == (FILE *)NULL
) {
207 msg("%s: %s\n", increm
, strerror(errno
));
208 (void) unlink(increm
);
213 (void) flock(fd
, LOCK_EX
);
216 * if an alternate name was specified via the N flag, use it instead
225 for (i
= 0; i
< nidates
&& idatev
[i
] != 0; i
++)
226 free((char *)idatev
[i
]);
227 free((char *)idatev
);
232 if (fseek(df
, 0L, 0) < 0) { /* rewind() was redefined in dumptape.c */
234 msg(gettext("%s: %s error:\n"),
235 increm
, "fseek", strerror(saverr
));
240 /* LINTED: won't dereference idatev if it is NULL (see readitimes) */
241 ITITERATE(i
, itwalk
) {
242 if (strncmp(fname
, itwalk
->id_name
,
243 sizeof (itwalk
->id_name
)) != 0)
245 if (itwalk
->id_incno
!= incno
)
250 * Add one more entry to idatev
253 idatev
= (struct idates
**)xrealloc((void *)idatev
,
254 nidates
* (size_t)sizeof (struct idates
*));
255 itwalk
= idatev
[nidates
- 1] =
256 (struct idates
*)xcalloc(1, sizeof (*itwalk
));
258 (void) strncpy(itwalk
->id_name
, fname
, sizeof (itwalk
->id_name
));
259 itwalk
->id_name
[sizeof (itwalk
->id_name
) - 1] = '\0';
260 itwalk
->id_incno
= incno
;
261 itwalk
->id_ddate
= spcl
.c_date
;
263 ITITERATE(i
, itwalk
) {
266 if (ftruncate64(fd
, ftello64(df
))) {
268 msg(gettext("%s: %s error:\n"),
269 increm
, "ftruncate64", strerror(saverr
));
274 msg(gettext("Level %c dump on %s\n"),
275 (uchar_t
)incno
, prdate(spcl
.c_date
));
283 time_t ddate
= what
->id_ddate
;
284 /* must use ctime, so we can later use unctime() */
285 (void) fprintf(file
, DUMPOUTFMT
,
287 (uchar_t
)what
->id_incno
,
292 getrecord(df
, idatep
)
294 struct idates
*idatep
;
298 if ((fgets(buf
, BUFSIZ
, df
)) != buf
)
301 if (makeidate(idatep
, buf
) < 0) {
303 "Malformed entry in dump record file `%s', line %d\n"),
305 if (strcmp(increm
, NINCREM
)) {
306 msg(gettext("`%s' not a dump record file\n"), increm
);
314 msg("getrecord: %s %c %s\n",
316 (uchar_t
)idatep
->id_incno
,
317 prdate(idatep
->id_ddate
));
327 char un_buf
[128]; /* size must be >= second one in DUMPINFMT */
330 * MAXNAMLEN has different values in dirent.h and ufs_fsdir.h,
331 * and we need to ensure that the length in DUMPINFMT matches
332 * what we allow for. Can't just use MAXNAMLEN in the test,
333 * because there's no convenient way to substitute it into
335 * XXX There's got to be a better way.
337 /*LINTED [assertion always true]*/
338 assert(sizeof (ip
->id_name
) == (255 + 3));
340 if (sscanf(buf
, DUMPINFMT
, ip
->id_name
, &ip
->id_incno
, un_buf
) != 3)
342 /* LINTED casting from 64-bit to 32-bit time */
343 ip
->id_ddate
= (time32_t
)unctime(un_buf
);
344 if (ip
->id_ddate
< 0)
350 * This is an estimation of the number of tp_bsize blocks in the file.
351 * It estimates the number of blocks in files with holes by assuming
352 * that all of the blocks accounted for by di_blocks are data blocks
353 * (when some of the blocks are usually used for indirect pointers);
354 * hence the estimate may be high.
363 * ip->di_size is the size of the file in bytes.
364 * ip->di_blocks stores the number of sectors actually in the file.
365 * If there are more sectors than the size would indicate, this just
366 * means that there are indirect blocks in the file or unused
367 * sectors in the last file block; we can safely ignore these
369 * If the file is bigger than the number of sectors would indicate,
370 * then the file has holes in it. In this case we must use the
371 * block count to estimate the number of data blocks used, but
372 * we use the actual size for estimating the number of indirect
373 * dump blocks (t vs. s in the indirect block calculation).
376 s
= (unsigned)(ip
->di_blocks
) / (unsigned)(tp_bsize
/ DEV_BSIZE
);
377 /* LINTED: spurious complaint about sign-extending 32 to 64 bits */
378 t
= d_howmany(ip
->di_size
, (unsigned)tp_bsize
);
381 if (ip
->di_size
> (u_offset_t
)((unsigned)(sblock
->fs_bsize
) * NDADDR
)) {
382 /* calculate the number of indirect blocks on the dump tape */
383 /* LINTED: spurious complaint sign-extending 32 to 64 bits */
385 (unsigned)(NDADDR
* sblock
->fs_bsize
/ tp_bsize
),
386 (unsigned)TP_NINDIR
);
397 /* LINTED: spurious complaint sign-extending 32 to 64 bits */
398 f_esize
+= d_howmany(msiz
* sizeof (map
[0]), (unsigned)tp_bsize
);
403 * Check to see if what we are trying to dump is a fs snapshot
404 * If so, we can use the snapshot's create time to populate
405 * the dumpdates file, instead of the time of the dump.
408 is_fssnap_dump(char *disk
)
415 kstat_named_t
*numval
;
417 last
= basename(disk
);
418 if ((strstr(disk
, SNAP_NAME
) == NULL
) || (stat(disk
, &st
) == -1) ||
419 (isdigit(last
[0]) == 0))
422 snapnum
= atoi(last
);
424 if ((kslib
= kstat_open()) == NULL
)
427 ksnum
= kstat_lookup(kslib
, SNAP_NAME
, snapnum
, FSSNAP_KSTAT_NUM
);
429 (void) kstat_close(kslib
);
433 if (kstat_read(kslib
, ksnum
, NULL
) == -1) {
434 (void) kstat_close(kslib
);
438 numval
= kstat_data_lookup(ksnum
, FSSNAP_KSTAT_NUM_CREATETIME
);
439 if (numval
== NULL
) {
440 (void) kstat_close(kslib
);
444 (void) kstat_close(kslib
);
445 /* LINTED casting from long to 32-bit time */
446 return (time32_t
)(numval
->value
.l
& INT_MAX
);