btrfs-progs: check: introduce function to check inode_extref
[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 "ctree.h"
23 #include "transaction.h"
24 #include "disk-io.h"
25 #include "commands.h"
26 #include "utils.h"
27
28 static const char * const rescue_cmd_group_usage[] = {
29         "btrfs rescue <command> [options] <path>",
30         NULL
31 };
32
33 int btrfs_recover_chunk_tree(char *path, int verbose, int yes);
34 int btrfs_recover_superblocks(char *path, int verbose, int yes);
35
36 static const char * const cmd_rescue_chunk_recover_usage[] = {
37         "btrfs rescue chunk-recover [options] <device>",
38         "Recover the chunk tree by scanning the devices one by one.",
39         "",
40         "-y     Assume an answer of `yes' to all questions",
41         "-v     Verbose mode",
42         "-h     Help",
43         NULL
44 };
45
46 static int cmd_rescue_chunk_recover(int argc, char *argv[])
47 {
48         int ret = 0;
49         char *file;
50         int yes = 0;
51         int verbose = 0;
52
53         while (1) {
54                 int c = getopt(argc, argv, "yvh");
55                 if (c < 0)
56                         break;
57                 switch (c) {
58                 case 'y':
59                         yes = 1;
60                         break;
61                 case 'v':
62                         verbose = 1;
63                         break;
64                 case 'h':
65                 default:
66                         usage(cmd_rescue_chunk_recover_usage);
67                 }
68         }
69
70         if (check_argc_exact(argc - optind, 1))
71                 usage(cmd_rescue_chunk_recover_usage);
72
73         file = argv[optind];
74
75         ret = check_mounted(file);
76         if (ret < 0) {
77                 error("could not check mount status: %s", strerror(-ret));
78                 return 1;
79         } else if (ret) {
80                 error("the device is busy");
81                 return 1;
82         }
83
84         ret = btrfs_recover_chunk_tree(file, verbose, yes);
85         if (!ret) {
86                 fprintf(stdout, "Chunk tree recovered successfully\n");
87         } else if (ret > 0) {
88                 ret = 0;
89                 fprintf(stdout, "Chunk tree recovery aborted\n");
90         } else {
91                 fprintf(stdout, "Chunk tree recovery failed\n");
92         }
93         return ret;
94 }
95
96 static const char * const cmd_rescue_super_recover_usage[] = {
97         "btrfs rescue super-recover [options] <device>",
98         "Recover bad superblocks from good copies",
99         "",
100         "-y     Assume an answer of `yes' to all questions",
101         "-v     Verbose mode",
102         NULL
103 };
104
105 /*
106  * return codes:
107  *   0 : All superblocks are valid, no need to recover
108  *   1 : Usage or syntax error
109  *   2 : Recover all bad superblocks successfully
110  *   3 : Fail to Recover bad supeblocks
111  *   4 : Abort to recover bad superblocks
112  */
113 static int cmd_rescue_super_recover(int argc, char **argv)
114 {
115         int ret;
116         int verbose = 0;
117         int yes = 0;
118         char *dname;
119
120         while (1) {
121                 int c = getopt(argc, argv, "vy");
122                 if (c < 0)
123                         break;
124                 switch (c) {
125                 case 'v':
126                         verbose = 1;
127                         break;
128                 case 'y':
129                         yes = 1;
130                         break;
131                 default:
132                         usage(cmd_rescue_super_recover_usage);
133                 }
134         }
135         if (check_argc_exact(argc - optind, 1))
136                 usage(cmd_rescue_super_recover_usage);
137
138         dname = argv[optind];
139         ret = check_mounted(dname);
140         if (ret < 0) {
141                 error("could not check mount status: %s", strerror(-ret));
142                 return 1;
143         } else if (ret) {
144                 error("the device is busy");
145                 return 1;
146         }
147         ret = btrfs_recover_superblocks(dname, verbose, yes);
148         return ret;
149 }
150
151 static const char * const cmd_rescue_zero_log_usage[] = {
152         "btrfs rescue zero-log <device>",
153         "Clear the tree log. Usable if it's corrupted and prevents mount.",
154         "",
155         NULL
156 };
157
158 static int cmd_rescue_zero_log(int argc, char **argv)
159 {
160         struct btrfs_root *root;
161         struct btrfs_trans_handle *trans;
162         struct btrfs_super_block *sb;
163         char *devname;
164         int ret;
165
166         clean_args_no_options(argc, argv, cmd_rescue_zero_log_usage);
167
168         if (check_argc_exact(argc, 2))
169                 usage(cmd_rescue_zero_log_usage);
170
171         devname = argv[optind];
172         ret = check_mounted(devname);
173         if (ret < 0) {
174                 error("could not check mount status: %s", strerror(-ret));
175                 goto out;
176         } else if (ret) {
177                 error("%s is currently mounted", devname);
178                 ret = -EBUSY;
179         }
180
181         root = open_ctree(devname, 0, OPEN_CTREE_WRITES | OPEN_CTREE_PARTIAL);
182         if (!root) {
183                 error("could not open ctree");
184                 return 1;
185         }
186
187         sb = root->fs_info->super_copy;
188         printf("Clearing log on %s, previous log_root %llu, level %u\n",
189                         devname,
190                         (unsigned long long)btrfs_super_log_root(sb),
191                         (unsigned)btrfs_super_log_root_level(sb));
192         trans = btrfs_start_transaction(root, 1);
193         btrfs_set_super_log_root(sb, 0);
194         btrfs_set_super_log_root_level(sb, 0);
195         btrfs_commit_transaction(trans, root);
196         close_ctree(root);
197
198 out:
199         return !!ret;
200 }
201
202 static const char rescue_cmd_group_info[] =
203 "toolbox for specific rescue operations";
204
205 const struct cmd_group rescue_cmd_group = {
206         rescue_cmd_group_usage, rescue_cmd_group_info, {
207                 { "chunk-recover", cmd_rescue_chunk_recover,
208                         cmd_rescue_chunk_recover_usage, NULL, 0},
209                 { "super-recover", cmd_rescue_super_recover,
210                         cmd_rescue_super_recover_usage, NULL, 0},
211                 { "zero-log", cmd_rescue_zero_log, cmd_rescue_zero_log_usage, NULL, 0},
212                 NULL_CMD_STRUCT
213         }
214 };
215
216 int cmd_rescue(int argc, char **argv)
217 {
218         return handle_command_group(&rescue_cmd_group, argc, argv);
219 }