diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/backup/dump/dumpitime.c | |
download | illumos-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.c | 447 |
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); +} |