git » libjio » commit 041ce8c

After the journal has been checked with jfsck(), what should be done is to remove the journal entirely in order to start with a clean one.

author Alberto Bertogli
2004-05-05 18:08:20 UTC
committer Alberto Bertogli
2007-07-15 12:44:27 UTC
parent 68e1b10eaa64da6462437f5c1ba2a8700baf77d6

After the journal has been checked with jfsck(), what should be done is to remove the journal entirely in order to start with a clean one.

After the journal has been checked with jfsck(), what should be done is to
remove the journal entirely in order to start with a clean one.

This function does that: remove every transaction file inside the journal
directory, leaving it clean and ready to use.

doc/libjio.3 +18 -7
jiofsck.c +35 -8
libjio.c +41 -0
libjio.h +1 -0

diff --git a/doc/libjio.3 b/doc/libjio.3
index 4a8132b..64078a6 100644
--- a/doc/libjio.3
+++ b/doc/libjio.3
@@ -34,6 +34,8 @@ libjio - A library for Journaled I/O
 
 .BI "int jfsck(const char *" name ", struct jfsck_result *" res " );
 
+.BI "int jfsck_cleanup(const char *" name" );"
+
 .SH STRUCTURES
 .PP
 .RS
@@ -109,13 +111,22 @@ jfs. To close a file, use jclose(). They're exactly like the open() and
 close() functions but use a struct jfs instead of a file descriptor; take a
 look at their manpages if you have any doubts about how to use them.
 
-There is one function that differs from the rest, which is jfsck(). It is used
-to perform journal checking and recovery in case of a crash. It must be
-performed when nobody else is using the file (like in the case of a filesystem
-which can't be mounted), and it returns 0 if success or -1 in case of a
-failure. If it succeed, a structure jfsck_result that summarizes the outcome
-of the operation. There is also a program named jiofsck which is just a simple
-human frontend to this function.
+There are two functions that differs from the rest, which are jfsck() and
+jfsck_cleanup().
+
+The first one, jfsck(), is used to perform journal checking and recovery in
+case of a crash. It must be performed when nobody else is using the file (like
+in the case of a filesystem which can't be mounted), and it returns 0 if
+success or -1 in case of a failure. If it succeed, a structure jfsck_result
+that summarizes the outcome of the operation. There is also a program named
+jiofsck which is just a simple human frontend to this function.
+
+The second, jfsck_cleanup(), is intended to be used after jfsck() by programs
+wanting to remove all the stall transaction files and leave the journal
+directory ready to use. After calling jfsck(), the transaction files will no
+longer be needed, so by cleaning up the directory you make sure you're
+starting over with a clean journal. It returns 0 if there was an error, or 1
+if it succeeded.
 
 .SH HIGH LEVEL API
 
diff --git a/jiofsck.c b/jiofsck.c
index b48600d..c7df0f0 100644
--- a/jiofsck.c
+++ b/jiofsck.c
@@ -11,23 +11,36 @@
 
 void usage()
 {
-	printf("Use: jiofsck FILE\n\n");
-	printf("Where FILE is the name of the file"
-			"which you want to check the journal from.\n");
+	printf("Use: jiofsck [clean] FILE\n\n");
+	printf("Where \"FILE\" is the name of the file "
+			"which you want to check the journal from,\n"
+			"and the optional parameter \"clean\" makes "
+			"jiofsck to clean up the journal after\n"
+			"recovery.\n");
 }
 
 int main(int argc, char **argv)
 {
-	int rv;
+	int rv, do_cleanup;
 	char *file;
 	struct jfsck_result res;
 	
-	if (argc != 2) {
+	if (argc != 2 && argc != 3) {
 		usage();
 		return 1;
 	}
 
-	file = argv[1];
+	if (argc == 3) {
+		if (strcmp("clean", argv[1]) != 0 ) {
+			usage();
+			return 1;
+		}
+		file = argv[2];
+		do_cleanup = 1;
+	} else {
+		file = argv[1];
+		do_cleanup = 0;
+	}
 
 	memset(&res, 0, sizeof(res));
 	
@@ -45,6 +58,16 @@ int main(int argc, char **argv)
 
 	printf("done\n");
 
+	if (do_cleanup) {
+		printf("Cleaning journal: ");
+		if (!jfsck_cleanup(file)) {
+			printf("Error cleaning journal\n");
+			return 1;
+		}
+
+		printf("done\n");
+	}
+
 	printf("Journal checking results\n");
 	printf("------------------------\n\n");
 
@@ -58,8 +81,12 @@ int main(int argc, char **argv)
 	printf("Rollbacked:\t %d\n", res.rollbacked);
 	printf("\n");
 	
-	printf("You can now safely remove the journal directory completely\n"
-			"to start a new journal.\n");
+	if (!do_cleanup) {
+		printf("You can now safely remove the journal directory "
+				"completely\nto start a new journal.\n");
+	} else {
+		printf("The journal has been checked and cleaned up.\n");
+	}
 
 	return 0;
 }
diff --git a/libjio.c b/libjio.c
index a530c6c..e6f88fc 100644
--- a/libjio.c
+++ b/libjio.c
@@ -15,6 +15,7 @@
 #include <stdio.h>
 #include <dirent.h>
 #include <sys/uio.h>
+#include <errno.h>
 
 #include "libjio.h"
 
@@ -868,4 +869,44 @@ loop:
 
 }
 
+/* remove all the files in the journal directory (if any) */
+int jfsck_cleanup(const char *name)
+{
+	char jdir[PATH_MAX], tfile[PATH_MAX*3];
+	DIR *dir;
+	struct dirent *dent;
+
+	if (!get_jdir(name, jdir))
+		return 0;
+
+	dir = opendir(jdir);
+	if (dir == NULL && errno == ENOENT)
+		/* it doesn't exist, so it's clean */
+		return 1;
+	else if (dir == NULL)
+		return 0;
+
+	for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+		/* we only care about transactions (named as numbers > 0) and
+		 * the lockfile (named "lock"); ignore everything else */
+		if (strcmp(dent->d_name, "lock") && atoi(dent->d_name) <= 0)
+			continue;
+
+		/* build the full path to the transaction file */
+		memset(tfile, 0, PATH_MAX * 3);
+		strcat(tfile, jdir);
+		strcat(tfile, "/");
+		strcat(tfile, dent->d_name);
+
+		/* the full filename is too large */
+		if (strlen(tfile) > PATH_MAX)
+			return 0;
+
+		/* and remove it */
+		unlink(tfile);
+	}
+	closedir(dir);
+
+	return 1;
+}
 
diff --git a/libjio.h b/libjio.h
index 012905b..343bc69 100644
--- a/libjio.h
+++ b/libjio.h
@@ -87,6 +87,7 @@ void jtrans_free(struct jtrans *ts);
 
 /* journal checker */
 int jfsck(const char *name, struct jfsck_result *res);
+int jfsck_cleanup(const char *name);
 
 
 /* jfs constants */