[Ocfs2-tools-commits] zab commits r325 - in trunk/fsck.ocfs2: .
include
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Mon Oct 11 15:17:54 CDT 2004
Author: zab
Date: 2004-10-11 15:17:52 -0500 (Mon, 11 Oct 2004)
New Revision: 325
Modified:
trunk/fsck.ocfs2/Makefile
trunk/fsck.ocfs2/include/problem.h
trunk/fsck.ocfs2/pass1.c
trunk/fsck.ocfs2/pass2.c
trunk/fsck.ocfs2/pass3.c
trunk/fsck.ocfs2/pass4.c
trunk/fsck.ocfs2/problem.c
Log:
clean up fsck's prompting:
o callers more carefully form their prompt
o rename 'should_fix' to 'prompt', duh.
o cleanly exit from ctl-c without hosing the terminal, just like a grown up.
o random beautification of output and newlines and stuff
Modified: trunk/fsck.ocfs2/Makefile
===================================================================
--- trunk/fsck.ocfs2/Makefile 2004-10-11 19:00:18 UTC (rev 324)
+++ trunk/fsck.ocfs2/Makefile 2004-10-11 20:17:52 UTC (rev 325)
@@ -7,7 +7,8 @@
INCLUDES = -Iinclude -I$(TOPDIR)/libocfs2/include
LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2
-CFLAGS := -g -Wall -Wstrict-prototypes -Wmissing-prototypes \
+# -O2 to get uninitialized warnings from gcc.
+CFLAGS := -O2 -g -Wall -Wstrict-prototypes -Wmissing-prototypes \
-Wmissing-declarations
DEFINES = -DOCFS2_FLAT_INCLUDES
Modified: trunk/fsck.ocfs2/include/problem.h
===================================================================
--- trunk/fsck.ocfs2/include/problem.h 2004-10-11 19:00:18 UTC (rev 324)
+++ trunk/fsck.ocfs2/include/problem.h 2004-10-11 20:17:52 UTC (rev 325)
@@ -24,12 +24,16 @@
#ifndef __O2FSCK_PROBLEM_H__
#define __O2FSCK_PROBLEM_H__
-#define FIX_DEFYES (1 << 0)
-#define FIX_DEFNO (1 << 1)
+/* prompt flags. */
+#define PY (1 << 0) /* default to yes when asked and no answer forced */
+#define PN (1 << 1) /* default to no when asked and no answer forced */
#include "fsck.h"
-int should_fix(o2fsck_state *ost, unsigned flags, const char *fmt, ...);
+/* returns non-zero for yes and zero for no. The caller is expected to
+ * provide a thorough description of the state and the action that will
+ * be taken depending on the answer. Without \n termination. */
+int prompt(o2fsck_state *ost, unsigned flags, const char *fmt, ...);
#endif /* __O2FSCK_PROBLEM_H__ */
Modified: trunk/fsck.ocfs2/pass1.c
===================================================================
--- trunk/fsck.ocfs2/pass1.c 2004-10-11 19:00:18 UTC (rev 324)
+++ trunk/fsck.ocfs2/pass1.c 2004-10-11 20:17:52 UTC (rev 325)
@@ -80,7 +80,8 @@
/* offer to clear a non-directory root inode so that
* pass3:check_root() can re-create it */
if ((di->i_blkno == fs->fs_root_blkno) && !S_ISDIR(di->i_mode) &&
- should_fix(ost, FIX_DEFYES, "Root inode isn't a directory.")) {
+ prompt(ost, PY, "Root inode isn't a directory. Clear it in "
+ "preparation for fixing it?")) {
di->i_dtime = 0ULL;
di->i_links_count = 0ULL;
o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno,
@@ -89,14 +90,11 @@
o2fsck_write_inode(fs, blkno, di);
}
- if (di->i_dtime) {
- if (should_fix(ost, FIX_DEFYES,
- "Inode %llu is in use but has a non-zero dtime.",
- di->i_blkno)) {
-
- di->i_dtime = 0ULL;
- o2fsck_write_inode(fs, blkno, di);
- }
+ if (di->i_dtime && prompt(ost, PY, "Inode %"PRIu64" is in use but has "
+ "a non-zero dtime. Reset the dtime to 0?",
+ di->i_blkno)) {
+ di->i_dtime = 0ULL;
+ o2fsck_write_inode(fs, blkno, di);
}
ocfs2_bitmap_set(ost->ost_used_inodes, blkno, &was_set);
@@ -159,11 +157,10 @@
vb->vb_errors++;
#if 0 /* ext2 does this by returning a value to libext2 which clears the
block from the inode's allocation */
- if (should_fix(ost, FIX_DEFYES,
- "inode %"PRIu64" references bad physical block"
- " %"PRIu64" at logical block %"PRIu64
- ", should it be cleared?",
- di->i_blkno, bklno, bcount)) {
+ if (prompt(ost, PY, "inode %"PRIu64" references bad physical "
+ "block %"PRIu64" at logical block %"PRIu64", "
+ "should it be cleared?", di->i_blkno, bklno,
+ bcount)) {
}
#endif
}
@@ -171,9 +168,8 @@
/* XXX this logic should be more sophisticated. It's not really clear
* what ext2 is trying to do in theirs. */
if (vb->vb_errors == 12) {
- if (should_fix(ost, FIX_DEFYES,
- "inode %"PRIu64" has seen many errors, should it "
- "be cleared?", di->i_blkno)) {
+ if (prompt(ost, PY, "inode %"PRIu64" has seen many errors, "
+ "should it be cleared?", di->i_blkno)) {
vb->vb_clear = 1;
return OCFS2_BLOCK_ABORT;
}
@@ -258,9 +254,8 @@
}
if (S_ISDIR(di->i_mode) && vb.vb_num_blocks == 0) {
- if (should_fix(ost, FIX_DEFYES,
- "inode %"PRIu64" is a zero length directory, "
- "clear it?", di->i_blkno)) {
+ if (prompt(ost, PY, "Inode %"PRIu64" is a zero length "
+ "directory, clear it?", di->i_blkno)) {
vb.vb_clear = 1;
}
}
@@ -286,10 +281,9 @@
/* i_size is checked for symlinks elsewhere */
if (!S_ISLNK(di->i_mode) && di->i_size > expected &&
- should_fix(ost, FIX_DEFYES, "inode %"PRIu64" has a size of "
- "%"PRIu64" but has %"PRIu64" bytes of actual data. "
- " Correct the file size?", di->i_blkno, di->i_size,
- expected)) {
+ prompt(ost, PY, "Inode %"PRIu64" has a size of %"PRIu64" but has "
+ "%"PRIu64" bytes of actual data. Correct the file size?",
+ di->i_blkno, di->i_size, expected)) {
di->i_size = expected;
o2fsck_write_inode(fs, blkno, di);
}
@@ -299,10 +293,9 @@
expected = clusters_holding_blocks(fs, vb.vb_last_block + 1);
if (di->i_clusters < expected &&
- should_fix(ost, FIX_DEFYES, "inode %"PRIu64" has %"PRIu64" "
- "clusters but its blocks fit in %"PRIu64" clusters. "
- " Correct the number of clusters?", di->i_blkno,
- di->i_clusters, expected)) {
+ prompt(ost, PY, "inode %"PRIu64" has %"PRIu64" clusters but its "
+ "blocks fit in %"PRIu64" clusters. Correct the number of "
+ "clusters?", di->i_blkno, di->i_clusters, expected)) {
di->i_clusters = expected;
o2fsck_write_inode(fs, blkno, di);
}
Modified: trunk/fsck.ocfs2/pass2.c
===================================================================
--- trunk/fsck.ocfs2/pass2.c 2004-10-11 19:00:18 UTC (rev 324)
+++ trunk/fsck.ocfs2/pass2.c 2004-10-11 20:17:52 UTC (rev 325)
@@ -66,7 +66,6 @@
return 0;
}
-/* XXX this needs much stronger messages */
static int fix_dirent_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
struct ocfs2_dir_entry *dirent, int offset,
int left)
@@ -79,18 +78,20 @@
if (!expect_dots) {
if (!dirent_has_dots(dirent, 1) && !dirent_has_dots(dirent, 2))
return 0;
- if (should_fix(ost, FIX_DEFYES,
- "Duplicate '%.*s' directory found, remove?",
- dirent->name_len, dirent->name)) {
- /* XXX I don't understand the inode = 0 clearing */
+ if (prompt(ost, PY, "Duplicate '%.*s' directory entry found, "
+ "remove it?", dirent->name_len, dirent->name)) {
dirent->inode = 0;
return OCFS2_DIRENT_CHANGED;
}
}
if (!dirent_has_dots(dirent, expect_dots) &&
- should_fix(ost, FIX_DEFYES,
- "didn't find dots when expecting them")) {
+ prompt(ost, PY, "The %s directory entry in directory inode "
+ "%"PRIu64" is '%.*s' instead of '%.*s'. Clobber the "
+ "current name with the expected dot name?",
+ expect_dots == 1 ? "first" : "second", dbe->e_ino,
+ dirent->name_len, dirent->name, expect_dots, "..")) {
+
dirent->name_len = expect_dots;
memset(dirent->name, '.', expect_dots);
changed_len = 1;
@@ -114,7 +115,9 @@
}
if ((dirent->inode != dbe->e_ino) &&
- should_fix(ost, FIX_DEFYES, "invalid . directory, replace?")) {
+ prompt(ost, PY, "The '.' entry in directory inode %"PRIu64" "
+ "points to inode %"PRIu64" instead of itself. Fix "
+ "the '.' entry?", dbe->e_ino, dirent->inode)) {
dirent->inode = dbe->e_ino;
ret_flags = OCFS2_DIRENT_CHANGED;
}
@@ -126,8 +129,10 @@
*/
new_len = OCFS2_DIR_REC_LEN(dirent->name_len) - dirent->rec_len;
if (new_len && (changed_len ||
- should_fix(ost, FIX_DEFNO,
- "'.' entry is too big, split?"))) {
+ prompt(ost, PY, "The '.' entry in directory inode "
+ "%"PRIu64" is too long. Try to create another "
+ "directory entry from the excess?",
+ dbe->e_ino))) {
dirent->rec_len = OCFS2_DIR_REC_LEN(dirent->name_len);
next = (struct ocfs2_dir_entry *)((char *)dirent +
@@ -152,10 +157,10 @@
(OCFS2_DIR_REC_LEN(dirent->name_len) <= dirent->rec_len))
return 0;
- if (!should_fix(ost, FIX_DEFYES,
- "Directory inode %"PRIu64" corrupted in logical "
- "block %"PRIu64" physical block %"PRIu64" offset %d",
- dbe->e_ino, dbe->e_blkcount, dbe->e_blkno, offset))
+ if (!prompt(ost, PY, "Directory inode %"PRIu64" corrupted in logical "
+ "block %"PRIu64" physical block %"PRIu64" offset %d. "
+ "Attempt to repair this block's directory entries?",
+ dbe->e_ino, dbe->e_blkcount, dbe->e_blkno, offset))
fatal_error(OCFS2_ET_DIR_CORRUPTED, "in pass2");
/* special casing an empty dirent that doesn't include the
@@ -200,8 +205,8 @@
int len = dirent->name_len, fix = 0, ret_flags = 0;
if (len == 0) {
- if (should_fix(ost, FIX_DEFYES, "Directory entry has a "
- "zero-length name, clear it?")) {
+ if (prompt(ost, PY, "Directory entry has a zero-length name, "
+ "clear it?")) {
dirent->inode = 0;
ret_flags = OCFS2_DIRENT_CHANGED;
}
@@ -210,10 +215,10 @@
for(; len-- > 0 && (*chr == '/' || *chr == '\0'); chr++) {
/* XXX in %s parent name */
if (!fix) {
- fix = should_fix(ost, FIX_DEFYES, "Entry '%.*s' "
- "contains invalid characters, replace "
- "with dots?", dirent->name_len,
- dirent->name);
+ fix = prompt(ost, PY, "Directory entry '%.*s' "
+ "contains invalid characters, replace "
+ "them with dots?", dirent->name_len,
+ dirent->name);
if (!fix)
return 0;
}
@@ -239,10 +244,10 @@
int was_set;
if (inode_out_of_range(ost->ost_fs, dirent->inode)) {
- if (should_fix(ost, FIX_DEFYES, "Entry '%.*s' refers to inode "
- "number %"PRIu64" which is out of range, "
- "clear it?", dirent->name_len, dirent->name,
- dirent->inode)) {
+ if (prompt(ost, PY, "Directory entry '%.*s' refers to inode "
+ "number %"PRIu64" which is out of range, "
+ "clear the entry?", dirent->name_len, dirent->name,
+ dirent->inode)) {
dirent->inode = 0;
return OCFS2_DIRENT_CHANGED;
}
@@ -251,10 +256,10 @@
/* XXX Do I care about possible bitmap_test errors here? */
ocfs2_bitmap_test(ost->ost_used_inodes, dirent->inode, &was_set);
if (!was_set) {
- if (should_fix(ost, FIX_DEFYES, "Entry '%.*s' refers to inode "
- "number %"PRIu64" which is unused, clear it?",
- dirent->name_len, dirent->name,
- dirent->inode)) {
+ if (prompt(ost, PY, "Directory entry '%.*s' refers to inode "
+ "number %"PRIu64" which is unused, clear the "
+ "entry?", dirent->name_len, dirent->name,
+ dirent->inode)) {
dirent->inode = 0;
return OCFS2_DIRENT_CHANGED;
}
@@ -327,11 +332,10 @@
ocfs2_free(&buf);
check:
- /* XXX do we care to have expected 0 -> lead to "set" rather than
- * "fix" language? */
if ((dirent->file_type != expected_type) &&
- should_fix(ost, FIX_DEFYES, "entry %.*s contains file type %s (%u) "
- "but its inode %"PRIu64" leads to type %s (%u)",
+ prompt(ost, PY, "Directory entry %.*s contains file type %s (%u) "
+ "but its inode %"PRIu64" leads to type %s (%u). Reset the "
+ "entry's type to match the inode's?",
dirent->name_len, dirent->name,
file_type_string(dirent->file_type), dirent->file_type,
dirent->inode,
@@ -378,11 +382,11 @@
return 0;
}
- if (should_fix(ost, 0, "directory inode %"PRIu64" is not the first to "
- "claim to be the parent of subdir '%.*s' (%"PRIu64"). Forget "
- "this linkage and leave the previous parent of '%.*s' intact?",
- dbe->e_ino, dirent->name_len, dirent->name, dirent->inode,
- dirent->name_len, dirent->name)) {
+ if (prompt(ost, 0, "Directory inode %"PRIu64" is not the first to "
+ "claim to be the parent of subdir '%.*s' (inode %"PRIu64"). "
+ "Clear this directory entry and leave the previous parent of "
+ "the subdir's inode intact?", dbe->e_ino,
+ dirent->name_len, dirent->name, dirent->inode)) {
dirent->inode = 0;
return OCFS2_DIRENT_CHANGED;
Modified: trunk/fsck.ocfs2/pass3.c
===================================================================
--- trunk/fsck.ocfs2/pass3.c 2004-10-11 19:00:18 UTC (rev 324)
+++ trunk/fsck.ocfs2/pass3.c 2004-10-11 20:17:52 UTC (rev 325)
@@ -52,8 +52,8 @@
return;
}
- if (!should_fix(ost, FIX_DEFYES, "The root inode doesn't exist. "
- "Should it be created? If not, fsck will exit.")) {
+ if (!prompt(ost, PY, "The root inode %"PRIu64" doesn't exist. "
+ "Should it be created?", ost->ost_fs->fs_root_blkno)) {
printf("Aborting.\n");
exit(FSCK_ERROR);
}
@@ -181,9 +181,9 @@
/* ok, we hit an orphan subtree with no parent or are at
* the dir in a subtree that is the first to try to reference
* a dir in its children */
- fix = should_fix(ost, FIX_DEFYES, "directory inode %"PRIu64" "
- "isn't connected to the filesystem. Move it "
- "to lost+found?", dp->dp_ino);
+ fix = prompt(ost, PY, "Directory inode %"PRIu64" isn't "
+ "connected to the filesystem. Move it to "
+ "lost+found?", dp->dp_ino);
if (fix)
o2fsck_reconnect_file(ost, dp->dp_ino);
@@ -191,13 +191,12 @@
}
if (dir->dp_dirent != dir->dp_dot_dot) {
- fix = should_fix(ost, FIX_DEFYES, "directory inode %"PRIu64" "
- "is referenced by a dirent in directory "
- "%"PRIu64" but its '..' entry points to "
- "inode %"PRIu64". Fix the '..' entry to "
- "reference %"PRIu64"?", dir->dp_ino,
- dir->dp_dirent, dir->dp_dot_dot,
- dir->dp_dirent);
+ fix = prompt(ost, PY, "Directory inode %"PRIu64" is "
+ "referenced by a dirent in directory %"PRIu64" "
+ "but its '..' entry points to inode %"PRIu64". "
+ "Fix the '..' entry to reference %"PRIu64"?",
+ dir->dp_ino, dir->dp_dirent, dir->dp_dot_dot,
+ dir->dp_dirent);
if (fix)
fix_dot_dot(ost, dir);
}
Modified: trunk/fsck.ocfs2/pass4.c
===================================================================
--- trunk/fsck.ocfs2/pass4.c 2004-10-11 19:00:18 UTC (rev 324)
+++ trunk/fsck.ocfs2/pass4.c 2004-10-11 20:17:52 UTC (rev 325)
@@ -60,9 +60,9 @@
if (refs == 0) {
/* XXX offer to remove files/dirs with no data? */
- if (should_fix(ost, FIX_DEFYES, "Inode %"PRIu64" "
- "isn't referenced by any directory "
- "entries. Move it to lost+found?")) {
+ if (prompt(ost, PY, "Inode %"PRIu64" isn't referenced "
+ "by any directory entries. Move it to "
+ "lost+found?")) {
o2fsck_reconnect_file(ost, ino);
refs = o2fsck_icount_get(ost->ost_icount_refs,
ino);
@@ -94,11 +94,10 @@
"%"PRIu16, ino, in_inode,
di->i_links_count);
- if (should_fix(ost, FIX_DEFYES, "Inode %"PRIu64" has a link "
- "count of %"PRIu16" on disk but directory "
- "entry references come to %"PRIu16", update "
- "the count on disk to match?", ino,
- in_inode, refs)) {
+ if (prompt(ost, PY, "Inode %"PRIu64" has a link count of "
+ "%"PRIu16" on disk but directory entry references "
+ "come to %"PRIu16". Update the count on disk to "
+ "match?", ino, in_inode, refs)) {
di->i_links_count = refs;
o2fsck_icount_set(ost->ost_icount_in_inodes, ino,
refs);
Modified: trunk/fsck.ocfs2/problem.c
===================================================================
--- trunk/fsck.ocfs2/problem.c 2004-10-11 19:00:18 UTC (rev 324)
+++ trunk/fsck.ocfs2/problem.c 2004-10-11 20:17:52 UTC (rev 325)
@@ -28,26 +28,37 @@
#include <string.h>
#include <stdarg.h>
#include <termios.h>
+#include <ctype.h>
+#include <signal.h>
#include "ocfs2.h"
#include "problem.h"
#include "util.h"
+/* XXX more of fsck will want this.. */
+static sig_atomic_t interrupted = 0;
+static void handle_sigint(int sig)
+{
+ interrupted = 1;
+}
+
/*
* when a caller cares why read() failed we can bother to communicate
* the error.
- *
- * XXX I wonder this termios junk is really the best way. I bet we want
- * to at least make a passing attempt to not be killed while we have
- * the terminal all messed up.
*/
static int read_a_char(int fd)
{
struct termios orig, new;
char c;
ssize_t ret;
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handle_sigint;
+ sa.sa_flags = SA_ONESHOT; /* !SA_RESTART */
+ sigaction(SIGINT, &sa, NULL);
+
/* turn off buffering and echoing and encourage single character
* reads */
tcgetattr(0, &orig);
@@ -61,6 +72,9 @@
tcsetattr (0, TCSANOW, &orig);
+ if (interrupted)
+ return 3;
+
if (ret != sizeof(c))
return EOF;
@@ -69,65 +83,73 @@
/*
* this checks the user's intent. someday soon it will check command line flags
- * and have a notion of grouping, as well
+ * and have a notion of grouping, as well. The caller is expected to provide
+ * a fully formed question that isn't terminated with a newline.
*/
-int should_fix(o2fsck_state *ost, unsigned flags, const char *fmt, ...)
+int prompt(o2fsck_state *ost, unsigned flags, const char *fmt, ...)
{
va_list ap;
- int c;
+ int c, ans = 0;
/* paranoia for jokers that claim to default to both */
- if((flags & FIX_DEFYES) && (flags & FIX_DEFNO))
- flags &= ~(FIX_DEFYES|FIX_DEFNO);
+ if((flags & PY) && (flags & PN))
+ flags &= ~(PY|PN);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
if (!ost->ost_ask) {
- if (ost->ost_answer)
- printf(" Fixing.\n");
- else
- printf(" Ignoring\n");
- return ost->ost_answer;
+ ans = ost->ost_answer ? 'y' : 'n';
+ } else {
+ if (flags & PY)
+ printf(" <y> ");
+ else if (flags & PN)
+ printf(" <n> ");
+ fflush(stdout);
}
- printf(" Fix? ");
- if (flags & FIX_DEFYES)
- printf(" <y> ");
- else if (flags & FIX_DEFNO)
- printf(" <n> ");
-
- fflush(stdout);
-
/* no curses, no nothin. overly regressive? */
- while ((c = read_a_char(fileno(stdin))) != EOF) {
+ while (!ans && (c = read_a_char(fileno(stdin))) != EOF) {
- /* XXX control-c, we're done? */
if (c == 3) {
- printf("cancelled!\n");
+ printf("ctl-c pressed, aborting.\n");
exit(FSCK_ERROR);
}
- /* straight answers */
- if (c == 'y' || c == 'Y')
- return 1;
- if (c == 'n' || c == 'N')
- return 0;
+ if (c == 27) {
+ printf("ESC pressed, aborting.\n");
+ exit(FSCK_ERROR);
+ }
+ c = tolower(c);
+
/* space or CR lead to applying the optional default */
if (c == ' ' || c == '\n') {
- if (flags & FIX_DEFYES)
- return 1;
- if (flags & FIX_DEFNO)
- return 0;
+ if (flags & PY)
+ c = 'y';
+ else if (flags & PN)
+ c = 'n';
}
+ if (c == 'y' || c == 'n') {
+ ans = c;
+ break;
+ }
+
/* otherwise keep asking */
}
- printf("input failed?\n");
- exit(FSCK_ERROR);
+ if (!ans) {
+ printf("input failed, aborting.\n");
+ exit(FSCK_ERROR);
+ }
- return 0;
+ /* this is totally silly. */
+ if (!ost->ost_ask)
+ printf(" %c\n", ans);
+ else
+ printf("%c\n", ans);
+
+ return ans == 'y';
}
More information about the Ocfs2-tools-commits
mailing list