[PATCH] fixed snaprm command to avoid removing PFS symlinks

Sven Gaerner sgaerner at gmx.net
Tue Aug 9 07:39:14 PDT 2011


* 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 <sgaerner at gmx.net>
---
 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 <path> [<note>]
@@ -200,82 +201,144 @@ hammer_cmd_snapls(char **av, int ac)
 }
 
 /*
- * hammer snaprm <path> ...
- * hammer snaprm <transid> ...
- * hammer snaprm <filesystem> <transid> ...
+ * hammer snaprm <snapshot path> [<snapshot path> ...]
+ * hammer snaprm <transid> [<transid> ...]
+ * hammer snaprm <filesystem> <transid> [<transid> ...]
  */
 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 <filesystem> <transid> [<transid> ...]
+			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 <filesystem> <transid> [<transid> ...]
+				// Call: hammer snaprm <snapshot path> [<snapshot path> ...]
+				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 <filesystem> <transid> [...]
+						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 <snapshot path> [...]
+						// 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 <transid> [<transid> ...]
 
-			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 <path> [<note>]\t\tcreate snapshot & link, points to\n"
 				"\t\t\t\t\ttarget dir\n"
     "hammer snapq <dir> [<note>]\t\tcreate snapshot, output path to stdout\n"
-    "hammer snaprm <path> ...\t\tdelete snapshots; filesystem is CWD\n"
-    "hammer snaprm <transid> ...\t\tdelete snapshots\n"
-    "hammer snaprm <filesystem> <transid> ...\tdelete snapshots\n"
+    "hammer snaprm <symlink> ...\t\tdelete snapshots by symlink\n"
+    "hammer snaprm <transid> ...\t\tdelete snapshots by ID for CWD\n"
+    "hammer snaprm <PFS> <transid> ...\tdelete snapshots by ID on PFS\n"
     "hammer snapls [<path> ...]\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


--QTprm0S8XgL7H0Dt--





More information about the Submit mailing list