From ba0cbce8b6fdb2fcbb02e14aaf9e7d536dd72d55 Mon Sep 17 00:00:00 2001 From: Sven Gaerner Date: Tue, 9 Aug 2011 16:39:14 +0200 Subject: [PATCH] fixed snaprm command to avoid removing PFS symlinks * Calling 'hammer snaprm /pfs/some.pfs 0x0000000123456789' removed the PFS link /pfs/some.pfs. This has been fixed. * Re-implemented function to detect if a symlink points to a transid or to a PSF. * Allow passing more arguments to each call, updated the usage as well. Each call can now remove more than one snapshot. Signed-off-by: Sven Gaerner --- sbin/hammer/cmd_snapshot.c | 211 ++++++++++++++++++++++++++++++++------------ 1 files changed, 153 insertions(+), 58 deletions(-) diff --git a/sbin/hammer/cmd_snapshot.c b/sbin/hammer/cmd_snapshot.c index 796c38b..cf65071 100644 --- a/sbin/hammer/cmd_snapshot.c +++ b/sbin/hammer/cmd_snapshot.c @@ -53,6 +53,7 @@ static void snapshot_add(int fd, const char *fsym, const char *tsym, static void snapshot_ls(const char *path); static void snapshot_del(int fsfd, hammer_tid_t tid); static char *dirpart(const char *path); +static void snapshot_snaprm_by_tid(char **av, int ac, int fsfd); /* * hammer snap [] @@ -200,82 +201,144 @@ hammer_cmd_snapls(char **av, int ac) } /* - * hammer snaprm ... - * hammer snaprm ... - * hammer snaprm ... + * hammer snaprm [ ...] + * hammer snaprm [ ...] + * hammer snaprm [ ...] */ void hammer_cmd_snaprm(char **av, int ac) { struct stat st; - char linkbuf[1024]; + char linkbuf[1024] = { 0 }; intmax_t tid; int fsfd = -1; - int i; + int i = 0; char *dirpath; char *ptr; + uint8_t remove_symlinks = 0; - for (i = 0; i < ac; ++i) { - if (lstat(av[i], &st) < 0) { - tid = strtoull(av[i], &ptr, 16); - if (*ptr) { - err(2, "hammer snaprm: not a file or tid: %s", - av[i]); - /* not reached */ + // leave if no arg + if(ac == 0) { + err(EINVAL, "hammer snaprm: at least one argument is " + "required"); + /* not reached */ + } + + do { + // inspect arguments + if (lstat(av[i], &st) == 0) { + // argument is either a link or a path, get + // associated PFS + // Call: hammer snaprm [ ...] + if(S_ISDIR(st.st_mode)) { + if(remove_symlinks) { + err(EINVAL, + "hammer snaprm: invalid argument " + "passed, snapshot symlink " + "expected"); + /* not reached */ + } + assert(fsfd == -1); + assert(i == 0); + fsfd = open(av[0], O_RDONLY); + if(fsfd >= 0) { + // skip first argument + snapshot_snaprm_by_tid(av + 1, ac - 1, fsfd); + } } - if (fsfd < 0) - fsfd = open(".", O_RDONLY); - snapshot_del(fsfd, tid); - } else if (S_ISDIR(st.st_mode)) { - if (fsfd >= 0) - close(fsfd); - fsfd = open(av[i], O_RDONLY); - if (fsfd < 0) { - err(2, "hammer snaprm: cannot open dir %s", - av[i]); - /* not reached */ + else if(S_ISLNK(st.st_mode)) { + // check if link points to a version or to a PFS + if (readlink(av[i], linkbuf, sizeof(linkbuf) - 1) < 0) { + err(ENOENT, "hammer snaprm: cannot read softlink: " + "%s", av[i]); + /* not reached */ + } + + // snapshot link looks like /path/to/pfs/@@0x0000000123456789 + // PFS link looks like /path/to/@@-1:00001 + + // Call: hammer snaprm [ ...] + // Call: hammer snaprm [ ...] + dirpath = strrchr(linkbuf, '@'); + if((dirpath != NULL) && + (dirpath > linkbuf) && + (*(--dirpath) == '@')) { + // dirpath points to link target without path + // skip leading @@ + dirpath += 2; + tid = strtoull(dirpath, &ptr, 16); + if(*ptr) { + // Call: hammer snaprm [...] + if(remove_symlinks) { + err(ENOENT, + "hammer snaprm: invalid argument passed, " + "expect snapshot symlink"); + /* not reached */ + } + + assert(fsfd == -1); + assert(i == 0); + // remove snapshot, at least one transid is required + if(ac == 1) { + err(EINVAL, "hammer snaprm: at least on " + "transid is required"); + /* not reached */ + } + fsfd = open(av[0], O_RDONLY); + if(fsfd >= 0) { + // skip first argument + snapshot_snaprm_by_tid(av + 1, ac - 1, fsfd); + } + } + else { + // Call: hammer snaprm [...] + // remove symlink and snapshot + printf("Deleting snapshot 0x%016jx %s\n", + tid, av[i]); + fsfd = open(av[i], O_RDONLY); + if(fsfd >= 0) { + snapshot_del(fsfd, tid); + remove(av[0]); + } + // adjust flag and counter to remove more + // snapshots by symlink + if((ac > 1) && (i < (ac - 1))) { + ++i; + remove_symlinks = 1; + } + else { + remove_symlinks = 0; + } + } + } } - } else if (S_ISLNK(st.st_mode)) { - dirpath = dirpart(av[i]); - bzero(linkbuf, sizeof(linkbuf)); - if (readlink(av[i], linkbuf, sizeof(linkbuf) - 1) < 0) { - err(2, "hammer snaprm: cannot read softlink: " - "%s", av[i]); + else { + err(EINVAL, "hammer snaprm: invalid parameter passed"); /* not reached */ } - if (linkbuf[0] == '/') { - free(dirpath); - dirpath = dirpart(linkbuf); - } else { - asprintf(&ptr, "%s/%s", dirpath, linkbuf); - free(dirpath); - dirpath = dirpart(ptr); - } + } + else { + // Call: hammer snaprm [ ...] - if (fsfd >= 0) - close(fsfd); - fsfd = open(dirpath, O_RDONLY); - if (fsfd < 0) { - err(2, "hammer snaprm: cannot open dir %s", - dirpath); + // handle list of transids + if(remove_symlinks) { + err(EINVAL, "hammer snaprm: invalid argument passed, " + "expect snapshot symlink"); /* not reached */ } - if ((ptr = strrchr(linkbuf, '@')) && - ptr > linkbuf && ptr[-1] == '@') { - tid = strtoull(ptr + 1, NULL, 16); - snapshot_del(fsfd, tid); + assert(fsfd == -1); + assert(i == 0); + fsfd = open(".", O_RDONLY); + if(fsfd >= 0) { + snapshot_snaprm_by_tid(av, ac, fsfd); } - remove(av[i]); - free(dirpath); - } else { - err(2, "hammer snaprm: not directory or snapshot " - "softlink: %s", av[i]); - /* not reached */ } - } - if (fsfd >= 0) + } while(remove_symlinks); + + if(fsfd >= 0) { close(fsfd); + } } /* @@ -565,9 +628,9 @@ snapshot_usage(int exit_code) "hammer snaplo []\t\tcreate snapshot & link, points to\n" "\t\t\t\t\ttarget dir\n" "hammer snapq []\t\tcreate snapshot, output path to stdout\n" - "hammer snaprm ...\t\tdelete snapshots; filesystem is CWD\n" - "hammer snaprm ...\t\tdelete snapshots\n" - "hammer snaprm ...\tdelete snapshots\n" + "hammer snaprm ...\t\tdelete snapshots by symlink\n" + "hammer snaprm ...\t\tdelete snapshots by ID for CWD\n" + "hammer snaprm ...\tdelete snapshots by ID on PFS\n" "hammer snapls [ ...]\t\tlist available snapshots\n" "\n" "NOTE: Snapshots are created in filesystem meta-data, any directory\n" @@ -611,3 +674,35 @@ dirpart(const char *path) res[ptr - path] = 0; return(res); } + +/** + * Remove all snapshots that are passed as arguments. + * + * Expect each argument to be a transid. + */ +static +void +snapshot_snaprm_by_tid(char **av, int ac, int fsfd) +{ + int i; + intmax_t tid; + char *ptr; + + assert(fsfd >= 0); + assert(ac > 0); + + for(i = 0; i < ac; ++i) { + tid = strtoull(av[i], &ptr, 16); + if(*ptr) { + // conversion failed + if(fsfd >= 0) { + close(fsfd); + } + err(ENOENT, "hammer snaprm: not a file or tid: %s", + av[i]); + /* not reached */ + } + printf("Deleting snapshot 0x%016jx\n", tid); + snapshot_del(fsfd, tid); + } +} -- 1.7.5.4