summaryrefslogtreecommitdiff
path: root/usr/src/cmd/backup/dump/dumpitime.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/backup/dump/dumpitime.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/backup/dump/dumpitime.c')
-rw-r--r--usr/src/cmd/backup/dump/dumpitime.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/usr/src/cmd/backup/dump/dumpitime.c b/usr/src/cmd/backup/dump/dumpitime.c
new file mode 100644
index 0000000000..41ba0e0d16
--- /dev/null
+++ b/usr/src/cmd/backup/dump/dumpitime.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright 1996-1998, 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "dump.h"
+
+#ifndef LOCK_EX
+static struct flock fl;
+#define flock(fd, flag) (fl.l_type = (flag), fcntl(fd, F_SETLKW, &fl))
+#define LOCK_EX F_WRLCK
+#define LOCK_SH F_RDLCK
+#define LOCK_UN F_UNLCK
+#endif
+
+/*
+ * Print a date. A date of 0 is the beginning of time (the "epoch").
+ * If the 2nd argument is non-zero, it is ok to format the date in
+ * locale-specific form, otherwise we use ctime. We must use ctime
+ * for dates such as those in the dumpdates file, which must be
+ * locale-independent.
+ */
+char *
+prdate(d)
+ time_t d;
+{
+ static char buf[256];
+ struct tm *tm;
+ char *p;
+
+ if (d == 0)
+ return (gettext("the epoch"));
+
+ tm = localtime(&d);
+ if (strftime(buf, sizeof (buf), "%c", tm) != 0) {
+ p = buf;
+ } else {
+ /* Wouldn't fit in buf, fall back */
+ p = ctime(&d);
+ p[24] = '\0'; /* lose trailing newline */
+ }
+ return (p);
+}
+
+struct idates **idatev = 0;
+size_t nidates = 0;
+static int idates_in = 0; /* we have read the increment file */
+static int recno;
+
+#ifdef __STDC__
+static void readitimes(FILE *);
+static void recout(FILE *, struct idates *);
+static int getrecord(FILE *, struct idates *);
+static int makeidate(struct idates *, char *);
+#else
+static void readitimes();
+static void recout();
+static int getrecord();
+static int makeidate();
+#endif
+
+void
+#ifdef __STDC__
+inititimes(void)
+#else
+inititimes()
+#endif
+{
+ FILE *df;
+ int saverr;
+
+ if (idates_in)
+ return;
+ if (increm == NULL || *increm == '\0') {
+ msg(gettext("inititimes: No dump record file name defined\n"));
+ dumpabort();
+ /*NOTREACHED*/
+ }
+ /*
+ * No need to secure this, as increm is hard-coded to NINCREM,
+ * and that file is in /etc. If random people have write-permission
+ * there, then there are more problems than any degree of paranoia
+ * on our part can fix.
+ */
+ if ((df = fopen(increm, "r")) == NULL) {
+ saverr = errno;
+ if (errno == ENOENT)
+ msg(gettext(
+ "Warning - dump record file `%s' does not exist\n"),
+ increm);
+ else {
+ msg(gettext("Cannot open dump record file `%s': %s\n"),
+ increm, strerror(saverr));
+ dumpabort();
+ /*NOTREACHED*/
+ }
+ return;
+ }
+ if (uflag && access(increm, W_OK) < 0) {
+ msg(gettext("Cannot access dump record file `%s' for update\n"),
+ increm);
+ dumpabort();
+ /*NOTREACHED*/
+ }
+ (void) flock(fileno(df), LOCK_SH);
+ readitimes(df);
+ (void) fclose(df);
+}
+
+static void
+readitimes(df)
+ FILE *df;
+{
+ struct idates *idp;
+
+ recno = 0;
+ for (;;) {
+ idp = (struct idates *)xcalloc(1, sizeof (*idp));
+ if (getrecord(df, idp) < 0) {
+ free((char *)idp);
+ break;
+ }
+ nidates++;
+ idatev = (struct idates **)xrealloc((void *)idatev,
+ nidates * (size_t)sizeof (*idatev));
+ idatev[nidates - 1] = idp;
+ }
+ /* LINTED: assigned value is used in inititimes */
+ idates_in = 1;
+}
+
+void
+#ifdef __STDC__
+getitime(void)
+#else
+getitime()
+#endif
+{
+ struct idates *ip;
+ int i;
+ char *fname;
+
+ /*
+ * if an alternate name was specified via the N flag, use it instead
+ * of the disk name.
+ */
+ if (dname != NULL)
+ fname = dname;
+ else
+ fname = disk;
+
+#ifdef FDEBUG
+
+ /* XGETTEXT: #ifdef FDEBUG only */
+ msg(gettext("Looking for name %s in increm = %s for delta = %c\n"),
+ fname, increm, (uchar_t)incno);
+#endif
+ spcl.c_ddate = 0;
+ lastincno = '0';
+
+ inititimes();
+ if (idatev == 0)
+ return;
+ /*
+ * Go find the entry with the same name for a lower increment
+ * and older date
+ */
+ ITITERATE(i, ip) {
+ if (strncmp(fname, ip->id_name, sizeof (ip->id_name)) != 0)
+ continue;
+ if (ip->id_incno >= incno)
+ continue;
+ if (ip->id_ddate <= spcl.c_ddate)
+ continue;
+ spcl.c_ddate = ip->id_ddate;
+ lastincno = ip->id_incno;
+ }
+}
+
+void
+#ifdef __STDC__
+putitime(void)
+#else
+putitime()
+#endif
+{
+ FILE *df;
+ struct idates *itwalk;
+ int i;
+ int fd, saverr;
+ char *fname;
+
+ if (uflag == 0)
+ return;
+ if ((df = safe_fopen(increm, "r+", 0664)) == (FILE *)NULL) {
+ msg("%s: %s\n", increm, strerror(errno));
+ (void) unlink(increm);
+ dumpabort();
+ /*NOTREACHED*/
+ }
+ fd = fileno(df);
+ (void) flock(fd, LOCK_EX);
+
+ /*
+ * if an alternate name was specified via the N flag, use it instead
+ * of the disk name.
+ */
+ if (dname != NULL)
+ fname = dname;
+ else
+ fname = disk;
+
+ if (idatev != 0) {
+ for (i = 0; i < nidates && idatev[i] != 0; i++)
+ free((char *)idatev[i]);
+ free((char *)idatev);
+ }
+ idatev = 0;
+ nidates = 0;
+ readitimes(df);
+ if (fseek(df, 0L, 0) < 0) { /* rewind() was redefined in dumptape.c */
+ saverr = errno;
+ msg(gettext("%s: %s error:\n"),
+ increm, "fseek", strerror(saverr));
+ dumpabort();
+ /*NOTREACHED*/
+ }
+ spcl.c_ddate = 0;
+ /* LINTED: won't dereference idatev if it is NULL (see readitimes) */
+ ITITERATE(i, itwalk) {
+ if (strncmp(fname, itwalk->id_name,
+ sizeof (itwalk->id_name)) != 0)
+ continue;
+ if (itwalk->id_incno != incno)
+ continue;
+ goto found;
+ }
+ /*
+ * Add one more entry to idatev
+ */
+ nidates++;
+ idatev = (struct idates **)xrealloc((void *)idatev,
+ nidates * (size_t)sizeof (struct idates *));
+ itwalk = idatev[nidates - 1] =
+ (struct idates *)xcalloc(1, sizeof (*itwalk));
+found:
+ (void) strncpy(itwalk->id_name, fname, sizeof (itwalk->id_name));
+ itwalk->id_name[sizeof (itwalk->id_name) - 1] = '\0';
+ itwalk->id_incno = incno;
+ itwalk->id_ddate = spcl.c_date;
+
+ ITITERATE(i, itwalk) {
+ recout(df, itwalk);
+ }
+ if (ftruncate64(fd, ftello64(df))) {
+ saverr = errno;
+ msg(gettext("%s: %s error:\n"),
+ increm, "ftruncate64", strerror(saverr));
+ dumpabort();
+ /*NOTREACHED*/
+ }
+ (void) fclose(df);
+ msg(gettext("Level %c dump on %s\n"),
+ (uchar_t)incno, prdate(spcl.c_date));
+}
+
+static void
+recout(file, what)
+ FILE *file;
+ struct idates *what;
+{
+ time_t ddate = what->id_ddate;
+ /* must use ctime, so we can later use unctime() */
+ (void) fprintf(file, DUMPOUTFMT,
+ what->id_name,
+ (uchar_t)what->id_incno,
+ ctime(&ddate));
+}
+
+static int
+getrecord(df, idatep)
+ FILE *df;
+ struct idates *idatep;
+{
+ char buf[BUFSIZ];
+
+ if ((fgets(buf, BUFSIZ, df)) != buf)
+ return (-1);
+ recno++;
+ if (makeidate(idatep, buf) < 0) {
+ msg(gettext(
+ "Malformed entry in dump record file `%s', line %d\n"),
+ increm, recno);
+ if (strcmp(increm, NINCREM)) {
+ msg(gettext("`%s' not a dump record file\n"), increm);
+ dumpabort();
+ /*NOTREACHED*/
+ }
+ return (-1);
+ }
+
+#ifdef FDEBUG
+ msg("getrecord: %s %c %s\n",
+ idatep->id_name,
+ (uchar_t)idatep->id_incno,
+ prdate(idatep->id_ddate));
+#endif
+ return (0);
+}
+
+static int
+makeidate(ip, buf)
+ struct idates *ip;
+ char *buf;
+{
+ char un_buf[128]; /* size must be >= second one in DUMPINFMT */
+
+ /*
+ * MAXNAMLEN has different values in dirent.h and ufs_fsdir.h,
+ * and we need to ensure that the length in DUMPINFMT matches
+ * what we allow for. Can't just use MAXNAMLEN in the test,
+ * because there's no convenient way to substitute it into
+ * DUMPINFMT.
+ * XXX There's got to be a better way.
+ */
+ /*LINTED [assertion always true]*/
+ assert(sizeof (ip->id_name) == (255 + 3));
+
+ if (sscanf(buf, DUMPINFMT, ip->id_name, &ip->id_incno, un_buf) != 3)
+ return (-1);
+ /* LINTED casting from 64-bit to 32-bit time */
+ ip->id_ddate = (time32_t)unctime(un_buf);
+ if (ip->id_ddate < 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * This is an estimation of the number of tp_bsize blocks in the file.
+ * It estimates the number of blocks in files with holes by assuming
+ * that all of the blocks accounted for by di_blocks are data blocks
+ * (when some of the blocks are usually used for indirect pointers);
+ * hence the estimate may be high.
+ */
+void
+est(ip)
+ struct dinode *ip;
+{
+ u_offset_t s, t;
+
+ /*
+ * ip->di_size is the size of the file in bytes.
+ * ip->di_blocks stores the number of sectors actually in the file.
+ * If there are more sectors than the size would indicate, this just
+ * means that there are indirect blocks in the file or unused
+ * sectors in the last file block; we can safely ignore these
+ * (s = t below).
+ * If the file is bigger than the number of sectors would indicate,
+ * then the file has holes in it. In this case we must use the
+ * block count to estimate the number of data blocks used, but
+ * we use the actual size for estimating the number of indirect
+ * dump blocks (t vs. s in the indirect block calculation).
+ */
+ o_esize++;
+ s = (unsigned)(ip->di_blocks) / (unsigned)(tp_bsize / DEV_BSIZE);
+ /* LINTED: spurious complaint about sign-extending 32 to 64 bits */
+ t = d_howmany(ip->di_size, (unsigned)tp_bsize);
+ if (s > t)
+ s = t;
+ if (ip->di_size > (u_offset_t)((unsigned)(sblock->fs_bsize) * NDADDR)) {
+ /* calculate the number of indirect blocks on the dump tape */
+ /* LINTED: spurious complaint sign-extending 32 to 64 bits */
+ s += d_howmany(t -
+ (unsigned)(NDADDR * sblock->fs_bsize / tp_bsize),
+ (unsigned)TP_NINDIR);
+ }
+ f_esize += s;
+}
+
+/*ARGSUSED*/
+void
+bmapest(map)
+ uchar_t *map;
+{
+ o_esize++;
+ /* LINTED: spurious complaint sign-extending 32 to 64 bits */
+ f_esize += d_howmany(msiz * sizeof (map[0]), (unsigned)tp_bsize);
+}
+
+
+/*
+ * Check to see if what we are trying to dump is a fs snapshot
+ * If so, we can use the snapshot's create time to populate
+ * the dumpdates file, instead of the time of the dump.
+ */
+time32_t
+is_fssnap_dump(char *disk)
+{
+ struct stat st;
+ char *last;
+ int snapnum;
+ kstat_ctl_t *kslib;
+ kstat_t *ksnum;
+ kstat_named_t *numval;
+
+ last = basename(disk);
+ if ((strstr(disk, SNAP_NAME) == NULL) || (stat(disk, &st) == -1) ||
+ (isdigit(last[0]) == 0))
+ return (0);
+
+ snapnum = atoi(last);
+
+ if ((kslib = kstat_open()) == NULL)
+ return (0);
+
+ ksnum = kstat_lookup(kslib, SNAP_NAME, snapnum, FSSNAP_KSTAT_NUM);
+ if (ksnum == NULL) {
+ (void) kstat_close(kslib);
+ return (0);
+ }
+
+ if (kstat_read(kslib, ksnum, NULL) == -1) {
+ (void) kstat_close(kslib);
+ return (0);
+ }
+
+ numval = kstat_data_lookup(ksnum, FSSNAP_KSTAT_NUM_CREATETIME);
+ if (numval == NULL) {
+ (void) kstat_close(kslib);
+ return (0);
+ }
+
+ (void) kstat_close(kslib);
+ /* LINTED casting from long to 32-bit time */
+ return (time32_t)(numval->value.l & INT_MAX);
+}