Btrfs-progs: add super-recover to recover bad supers
[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 (argc == 0)
78                 usage(cmd_chunk_recover_usage);
79
80         file = argv[optind];
81
82         ret = check_mounted(file);
83         if (ret) {
84                 fprintf(stderr, "the device is busy\n");
85                 return ret;
86         }
87
88         ret = btrfs_recover_chunk_tree(file, verbose, yes);
89         if (!ret) {
90                 fprintf(stdout, "Recover the chunk tree successfully.\n");
91         } else if (ret > 0) {
92                 ret = 0;
93                 fprintf(stdout, "Abort to rebuild the on-disk chunk tree.\n");
94         } else {
95                 fprintf(stdout, "Fail to recover the chunk tree.\n");
96         }
97         return ret;
98 }
99
100 /*
101  * return codes:
102  *   0 : All superblocks are valid, no need to recover
103  *   1 : Usage or syntax error
104  *   2 : Recover all bad superblocks successfully
105  *   3 : Fail to Recover bad supeblocks
106  *   4 : Abort to recover bad superblocks
107  */
108 int cmd_super_recover(int argc, char **argv)
109 {
110         int ret;
111         int verbose = 0;
112         int yes = 0;
113         char *dname;
114
115         while (1) {
116                 int c = getopt(argc, argv, "vy");
117                 if (c < 0)
118                         break;
119                 switch (c) {
120                 case 'v':
121                         verbose = 1;
122                         break;
123                 case 'y':
124                         yes = 1;
125                         break;
126                 default:
127                         usage(cmd_super_recover_usage);
128                 }
129         }
130         argc = argc - optind;
131         if (argc != 1)
132                 usage(cmd_super_recover_usage);
133
134         dname = argv[optind];
135         ret = check_mounted(dname);
136         if (ret) {
137                 fprintf(stderr, "the device is busy\n");
138                 return 1;
139         }
140         ret = btrfs_recover_superblocks(dname, verbose, yes);
141         return ret;
142 }
143
144 const struct cmd_group rescue_cmd_group = {
145         rescue_cmd_group_usage, NULL, {
146                 { "chunk-recover", cmd_chunk_recover, cmd_chunk_recover_usage, NULL, 0},
147                 { "super-recover", cmd_super_recover, cmd_super_recover_usage, NULL, 0},
148                 { 0, 0, 0, 0, 0 }
149         }
150 };
151
152 int cmd_rescue(int argc, char **argv)
153 {
154         return handle_command_group(&rescue_cmd_group, argc, argv);
155 }