diff -ur dump.ORG/dump.h dump/dump.h --- dump.ORG/dump.h Tue Jul 14 18:19:45 1998 +++ dump/dump.h Tue Sep 26 12:29:01 2000 @@ -105,7 +105,9 @@ /* mapping rouintes */ struct dinode; long blockest __P((struct dinode *dp)); -int mapfiles __P((ino_t maxino, long *tapesize)); +void mapfileino __P((ino_t, long *, int *)); +int mapfiles __P((ino_t maxino, long *tapesize, char *disk, + char * const *dirv)); int mapdirs __P((ino_t maxino, long *tapesize)); /* file dumping routines */ @@ -181,6 +183,15 @@ for (ddp = ddatev[i = 0]; i < nddates; ddp = ddatev[++i]) void sig __P((int signo)); + +/* + * Dump tag extention. + */ +#define DUMPTAGPREFIX '@' +#define MAX_DUMPTAG 64 +char *dumptags; /* name of the file containing dump set */ +char *dumptag; /* labelname for a set of files/dirrectories */ +char **readdumptag __P((int *ac)); /* * Compatibility with old systems. diff -ur dump.ORG/itime.c dump/itime.c --- dump.ORG/itime.c Sat Aug 28 09:12:38 1999 +++ dump/itime.c Wed Sep 27 10:26:16 2000 @@ -60,8 +60,10 @@ #include #include #endif +#include #include "dump.h" +#include "pathnames.h" struct dumpdates **ddatev = 0; int nddates = 0; @@ -140,7 +142,7 @@ register int i; char *fname; - fname = disk; + fname = dumptag ? dumptag : disk; #ifdef FDEBUG msg("Looking for name %s in dumpdates = %s for level = %c\n", fname, dumpdates, level); @@ -180,7 +182,7 @@ quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno)); fd = fileno(df); (void) flock(fd, LOCK_EX); - fname = disk; + fname = dumptag ? dumptag : disk; free((char *)ddatev); ddatev = 0; nddates = 0; @@ -271,4 +273,41 @@ if (ddp->dd_ddate < 0) return(-1); return(0); +} + + +/* + * read dumptag + */ + +char ** +readdumptag(ac) + int *ac; +{ + FILE *df; + static char line[LINE_MAX]; + static char *path[MAX_DUMPTAG]; + char **p, *linep; + char **av = NULL; + + if ((df = fopen(dumptags, "r")) == NULL) { + quit("cannot read %s: %s\n", dumptags, strerror(errno)); + } + (void) flock(fileno(df), LOCK_SH); + while ((fgets(line, sizeof(line), df)) == line) { + if (line[0] != DUMPTAGPREFIX) + continue; + linep = line; + for (p = path; (*p = strsep(&linep, " \t\n")) != NULL;) + if (**p && (++p >= &path[MAX_DUMPTAG])) + break; + if (strcmp(dumptag, path[0]) == 0) { + av = &path[1]; + for (*ac = 0; av[*ac] != NULL;++*ac) + ; + break; + } + } + (void) fclose(df); + return av; } diff -ur dump.ORG/main.c dump/main.c --- dump.ORG/main.c Mon Apr 24 23:41:54 2000 +++ dump/main.c Wed Sep 27 11:16:22 2000 @@ -48,6 +48,8 @@ #include #include #include +#include +#include #ifdef sunos #include @@ -105,6 +107,8 @@ register int ch; int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1; ino_t maxino; + int dirlist; + char *toplevel; spcl.c_date = 0; (void)time((time_t *)&spcl.c_date); @@ -113,6 +117,7 @@ if ((tape = getenv("TAPE")) == NULL) tape = _PATH_DEFTAPE; dumpdates = _PATH_DUMPDATES; + dumptags = _PATH_DUMPTAGS; temp = _PATH_DTMP; if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0) quit("TP_BSIZE must be a multiple of DEV_BSIZE\n"); @@ -214,14 +219,93 @@ (void)fprintf(stderr, "Must specify disk or filesystem\n"); exit(X_STARTUP); } - disk = *argv++; - argc--; - if (argc >= 1) { - (void)fprintf(stderr, "Unknown arguments to dump:"); - while (argc--) + + if (argv[0][0] == DUMPTAGPREFIX) { + if (argc > 1) { + msg("Can't use a tagname with other filelists\n"); + exit(X_ABORT); + } + dumptag = argv[0]; + if ((argv = readdumptag(&argc)) == NULL) { + msg("Unknown dumptag name\n"); + exit(X_ABORT); + } + if (argc < 1) { + (void)fprintf(stderr, "%s has no argument in %s\n", dumptag, dumptags); + exit(X_STARTUP); + } + } + + /* + * determine if disk is a subdirectory, and setup appropriately + */ + dirlist = 0; + toplevel = NULL; + for (i = 0; i < argc; i++) { + struct stat sb; + struct statfs fsbuf; + + if (argv[i][0] == DUMPTAGPREFIX) { + msg("Can't use a tagname with other filelists\n"); + exit(X_ABORT); + } + if (lstat(argv[i], &sb) == -1) { + msg("Cannot lstat %s: %s\n", argv[i], strerror(errno)); + exit(X_ABORT); + } + if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) { + if (dirlist != 0) { + msg("Can't dump a mountpoint and a filelist\n"); + exit(X_ABORT); + } + break; + } + if (statfs(argv[i], &fsbuf) == -1) { + msg("Cannot statfs %s: %s\n", argv[i], strerror(errno)); + exit(X_ABORT); + } + if (strcmp(argv[i], fsbuf.f_mntonname) == 0) { + if (dirlist != 0) { + msg("Can't dump a mountpoint and a filelist\n"); + exit(X_ABORT); + } + break; /* exit if sole mountpoint */ + } + if (!disk) { + if ((toplevel = strdup(fsbuf.f_mntonname)) == NULL) { + msg("Cannot malloc diskname\n"); + exit(X_ABORT); + } + disk = toplevel; + if (!dumptag) { + if (uflag) { + msg("Ignoring u flag for subdir dump\n"); + uflag = 0; + } + if (level > '0') { + msg("Subdir dump is done at level 0\n"); + level = '0'; + } + } + msg("Dumping sub files/directories from %s\n", disk); + } else { + if (strcmp(disk, fsbuf.f_mntonname) != 0) { + msg("%s is not on %s\n", argv[i], disk); + exit(X_ABORT); + } + } + msg("Dumping file/directory %s\n", argv[i]); + dirlist++; + } + if (dirlist == 0) { + disk = *argv++; + if (argc != 1) { + (void)fprintf(stderr, "Excess arguments to dump:"); + while (--argc) (void)fprintf(stderr, " %s", *argv++); (void)fprintf(stderr, "\n"); exit(X_STARTUP); + } } if (Tflag && uflag) { (void)fprintf(stderr, @@ -287,6 +371,7 @@ set_operators(); /* /etc/group snarfed */ getfstab(); /* /etc/fstab snarfed */ + /* * disk can be either the full special file name, * the suffix of the special file name, @@ -297,6 +382,10 @@ if (dt != NULL) { disk = rawname(dt->fs_spec); (void)strncpy(spcl.c_dev, dt->fs_spec, NAMELEN); + if (dirlist != 0) + (void)snprintf(spcl.c_filesys, NAMELEN, + "a subset of %s", dt->fs_file); + else (void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN); } else { (void)strncpy(spcl.c_dev, disk, NAMELEN); @@ -354,7 +443,8 @@ nonodump = spcl.c_level < honorlevel; msg("mapping (Pass I) [regular files]\n"); - anydirskipped = mapfiles(maxino, &tapesize); + anydirskipped = mapfiles(maxino, &tapesize, toplevel, + (dirlist ? argv : NULL)); msg("mapping (Pass II) [directories]\n"); while (anydirskipped) { @@ -599,7 +689,7 @@ /* Allocate space for new arguments. */ if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL || (p = flagsp = malloc(strlen(ap) + 2)) == NULL) - err(1, NULL); + err(1, "malloc"); *nargv++ = *argv; argv += 2; @@ -618,7 +708,7 @@ usage(); } if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL) - err(1, NULL); + err(1, "malloc"); nargv[0][0] = '-'; nargv[0][1] = *ap; (void)strcpy(&nargv[0][2], *argv); diff -ur dump.ORG/pathnames.h dump/pathnames.h --- dump.ORG/pathnames.h Tue Sep 22 19:05:17 1998 +++ dump/pathnames.h Tue Sep 26 11:46:38 2000 @@ -38,5 +38,6 @@ #define _PATH_DEFTAPE "/dev/rsa0" #define _PATH_DTMP "/etc/dtmp" #define _PATH_DUMPDATES "/etc/dumpdates" +#define _PATH_DUMPTAGS "/etc/dump.tag" #define _PATH_LOCK "/tmp/dumplockXXXXXX" #define _PATH_RMT "/etc/rmt" /* path on remote host */ diff -ur dump.ORG/traverse.c dump/traverse.c --- dump.ORG/traverse.c Sat Jul 1 15:31:52 2000 +++ dump/traverse.c Mon Sep 25 10:42:41 2000 @@ -56,6 +56,8 @@ #include #include +#include +#include #include #ifdef __STDC__ #include @@ -132,26 +134,20 @@ #endif /* - * Dump pass 1. - * - * Walk the inode list for a filesystem to find all allocated inodes - * that have been modified since the previous dump time. Also, find all - * the directories in the filesystem. + * Determine if given inode should be dumped */ -int -mapfiles(maxino, tapesize) - ino_t maxino; +void +mapfileino(ino, tapesize, dirskipped) + ino_t ino; long *tapesize; + int *dirskipped; { register int mode; - register ino_t ino; register struct dinode *dp; - int anydirskipped = 0; - for (ino = ROOTINO; ino < maxino; ino++) { dp = getino(ino); if ((mode = (dp->di_mode & IFMT)) == 0) - continue; + return; SETINO(ino, usedinomap); if (mode == IFDIR) SETINO(ino, dumpdirmap); @@ -161,10 +157,101 @@ *tapesize += 1; else *tapesize += blockest(dp); - continue; + return; } if (mode == IFDIR) - anydirskipped = 1; + *dirskipped = 1; +} + +/* + * Dump pass 1. + * + * Walk the inode list for a filesystem to find all allocated inodes + * that have been modified since the previous dump time. Also, find all + * the directories in the filesystem. + */ +int +mapfiles(maxino, tapesize, disk, dirv) + ino_t maxino; + long *tapesize; + char *disk; + char * const *dirv; +{ + int anydirskipped = 0; + + if (dirv != NULL) { + char curdir[MAXPATHLEN]; + FTS *dirh; + FTSENT *entry; + int d; + + if (getcwd(curdir, sizeof(curdir)) == NULL) { + msg("Can't determine cwd: %s\n", strerror(errno)); + dumpabort(0); + } + if ((dirh = fts_open(dirv, FTS_PHYSICAL|FTS_SEEDOT|FTS_XDEV, + (int (*)())NULL)) == NULL) { + msg("fts_open failed: %s\n", strerror(errno)); + dumpabort(0); + } + while ((entry = fts_read(dirh)) != NULL) { + switch (entry->fts_info) { + case FTS_DNR: /* an error */ + case FTS_ERR: + case FTS_NS: + msg("Can't fts_read %s: %s\n", entry->fts_path, + strerror(errno)); + case FTS_DP: /* already seen dir */ + continue; + } + mapfileino(entry->fts_statp->st_ino, tapesize, + &anydirskipped); + } + (void)fts_close(dirh); + + /* + * Add any parent directories + */ + for (d = 0 ; dirv[d] != NULL ; d++) { + char path[MAXPATHLEN]; + + if (dirv[d][0] != '/') + (void)snprintf(path, sizeof(path), "%s/%s", + curdir, dirv[d]); + else + (void)snprintf(path, sizeof(path), "%s", + dirv[d]); + while (strcmp(path, disk) != 0) { + char *p; + struct stat sb; + + if (*path == '\0') + break; + if ((p = strrchr(path, '/')) == NULL) + break; + if (p == path) + break; + *p = '\0'; + if (stat(path, &sb) == -1) { + msg("Can't stat %s: %s\n", path, + strerror(errno)); + break; + } + mapfileino(sb.st_ino, tapesize, &anydirskipped); + } + } + + /* + * Ensure that the root inode actually appears in the + * file list for a subdir + */ + mapfileino(ROOTINO, tapesize, &anydirskipped); + } else { + ino_t ino; + + for (ino = ROOTINO; ino < maxino; ino++) { + mapfileino(ino, tapesize, &anydirskipped); + } } /* * Restore gets very upset if the root is not dumped,