btrfs-progs: fix btrfs-image old_restore fsck failure
[platform/upstream/btrfs-progs.git] / cmds-rescue.c
1 /*
2  * Copyright (C) 2013 SUSE.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include "kerncompat.h"
20
21 #include <getopt.h>
22 #include "commands.h"
23 #include "utils.h"
24
25 static const char * const rescue_cmd_group_usage[] = {
26         "btrfs rescue <command> [options] <path>",
27         NULL
28 };
29
30 int btrfs_recover_chunk_tree(char *path, int verbose, int yes);
31 int btrfs_recover_superblocks(char *path, int verbose, int yes);
32
33 const char * const cmd_chunk_recover_usage[] = {
34         "btrfs rescue chunk-recover [options] <device>",
35         "Recover the chunk tree by scanning the devices one by one.",
36         "",
37         "-y     Assume an answer of `yes' to all questions",
38         "-v     Verbose mode",
39         "-h     Help",
40         NULL
41 };
42
43 const char * const cmd_super_recover_usage[] = {
44         "btrfs rescue super-recover [options] <device>",
45         "Recover bad superblocks from good copies",
46         "",
47         "-y     Assume an answer of `yes' to all questions",
48         "-v     Verbose mode",
49         NULL
50 };
51
52 int cmd_chunk_recover(int argc, char *argv[])
53 {
54         int ret = 0;
55         char *file;
56         int yes = 0;
57         int verbose = 0;
58
59         while (1) {
60                 int c = getopt(argc, argv, "yvh");
61                 if (c < 0)
62                         break;
63                 switch (c) {
64                 case 'y':
65                         yes = 1;
66                         break;
67                 case 'v':
68                         verbose = 1;
69                         break;
70                 case 'h':
71                 default:
72                         usage(cmd_chunk_recover_usage);
73                 }
74         }
75
76         argc = argc - optind;
77         if (check_argc_exact(argc, 1))
78                 usage(cmd_chunk_recover_usage);
79
80         file = argv[optind];
81
82         ret = check_mounted(file);
83         if (ret < 0) {
84                 fprintf(stderr, "Could not check mount status: %s\n",
85                         strerror(-ret));
86                 return 1;
87         } else if (ret) {
88                 fprintf(stderr, "the device is busy\n");
89                 return 1;
90         }
91
92         ret = btrfs_recover_chunk_tree(file, verbose, yes);
93         if (!ret) {
94                 fprintf(stdout, "Recover the chunk tree successfully.\n");
95         } else if (ret > 0) {
96                 ret = 0;
97                 fprintf(stdout, "Abort to rebuild the on-disk chunk tree.\n");
98         } else {
99                 fprintf(stdout, "Fail to recover the chunk tree.\n");
100         }
101         return ret;
102 }
103
104 /*
105  * return codes:
106  *   0 : All superblocks are valid, no need to recover
107  *   1 : Usage or syntax error
108  *   2 : Recover all bad superblocks successfully
109  *   3 : Fail to Recover bad supeblocks
110  *   4 : Abort to recover bad superblocks
111  */
112 int cmd_super_recover(int argc, char **argv)
113 {
114         int ret;
115         int verbose = 0;
116         int yes = 0;
117         char *dname;
118
119         while (1) {
120                 int c = getopt(argc, argv, "vy");
121                 if (c < 0)
122                         break;
123                 switch (c) {
124                 case 'v':
125                         verbose = 1;
126                         break;
127                 case 'y':
128                         yes = 1;
129                         break;
130                 default:
131                         usage(cmd_super_recover_usage);
132                 }
133         }
134         argc = argc - optind;
135         if (check_argc_exact(argc, 1))
136                 usage(cmd_super_recover_usage);
137
138         dname = argv[optind];
139         ret = check_mounted(dname);
140         if (ret < 0) {
141                 fprintf(stderr, "Could not check mount status: %s\n",
142                         strerror(-ret));
143                 return 1;
144         } else if (ret) {
145                 fprintf(stderr, "the device is busy\n");
146                 return 1;
147         }
148         ret = btrfs_recover_superblocks(dname, verbose, yes);
149         return ret;
150 }
151
152 const struct cmd_group rescue_cmd_group = {
153         rescue_cmd_group_usage, NULL, {
154                 { "chunk-recover", cmd_chunk_recover, cmd_chunk_recover_usage, NULL, 0},
155                 { "super-recover", cmd_super_recover, cmd_super_recover_usage, NULL, 0},
156                 { 0, 0, 0, 0, 0 }
157         }
158 };
159
160 int cmd_rescue(int argc, char **argv)
161 {
162         return handle_command_group(&rescue_cmd_group, argc, argv);
163 }