summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZach Brown <zab@redhat.com>2013-08-06 11:49:04 -0700
committerDavid Sterba <dsterba@suse.cz>2013-09-03 19:40:52 +0200
commit6a0af4e57b58e9756e246db6967423ea6fa83265 (patch)
tree1eb84334ca9622d73ede5c72aaf01b012cea1dcc
parent689ad3e362c1e6d54ef7b6876dbb64e1e51b8cf1 (diff)
btrfs-progs: don't overrun "answer" array in cmds-chunk.c
Eric noticed the trivial stack overflow bug in ask_user(). I went to see the context for that fix and found that ask_user() was a bit much. This fixes the overflow bug that Eric found, endless spinning on scanf() errors, removes dead code, and leaves us with a trivial helper. Signed-off-by: Zach Brown <zab@redhat.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r--cmds-chunk.c65
1 files changed, 14 insertions, 51 deletions
diff --git a/cmds-chunk.c b/cmds-chunk.c
index c40d620b..fdc01727 100644
--- a/cmds-chunk.c
+++ b/cmds-chunk.c
@@ -1307,58 +1307,22 @@ fail_close_fd:
return ret;
}
-static int ask_user(char *question, int defval)
+/*
+ * This reads a line from the stdin and only returns non-zero if the
+ * first whitespace delimited token is a case insensitive match with yes
+ * or y.
+ */
+static int ask_user(char *question)
{
- char answer[5];
- char *defstr;
- int i;
-
- if (defval == 1)
- defstr = "[Y/n]";
- else if (defval == 0)
- defstr = "[y/N]";
- else if (defval == -1)
- defstr = "[y/n]";
- else
- BUG_ON(1);
-again:
- printf("%s%s? ", question, defstr);
-
- i = 0;
- while (i < 4 && scanf("%c", &answer[i])) {
- if (answer[i] == '\n') {
- answer[i] = '\0';
- break;
- } else if (answer[i] == ' '){
- answer[i] = '\0';
- if (i == 0)
- continue;
- else
- break;
- } else if (answer[i] >= 'A' && answer[i] <= 'Z') {
- answer[i] += 'a' - 'A';
- }
- i++;
- }
- answer[5] = '\0';
- __fpurge(stdin);
-
- if (strlen(answer) == 0) {
- if (defval != -1)
- return defval;
- else
- goto again;
- }
+ char buf[30] = {0,};
+ char *saveptr = NULL;
+ char *answer;
- if (!strcmp(answer, "yes") ||
- !strcmp(answer, "y"))
- return 1;
-
- if (!strcmp(answer, "no") ||
- !strcmp(answer, "n"))
- return 0;
+ printf("%s [y/N]: ", question);
- goto again;
+ return fgets(buf, sizeof(buf) - 1, stdin) &&
+ (answer = strtok_r(buf, " \t\n\r", &saveptr)) &&
+ (!strcasecmp(answer, "yes") || !strcasecmp(answer, "y"));
}
static int btrfs_get_device_extents(u64 chunk_object,
@@ -1752,8 +1716,7 @@ static int btrfs_recover_chunk_tree(char *path, int verbose, int yes)
}
if (!rc.yes) {
- ret = ask_user("We are going to rebuild the chunk tree on disk, it might destroy the old metadata on the disk, Are you sure",
- 0);
+ ret = ask_user("We are going to rebuild the chunk tree on disk, it might destroy the old metadata on the disk, Are you sure?");
if (!ret) {
ret = BTRFS_CHUNK_TREE_REBUILD_ABORTED;
goto fail_close_ctree;