]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
da23017d NS |
2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | |
dfc130f3 | 4 | * |
da23017d NS |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | |
2bd0ea18 | 7 | * published by the Free Software Foundation. |
dfc130f3 | 8 | * |
da23017d NS |
9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
dfc130f3 | 13 | * |
da23017d NS |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
2bd0ea18 NS |
17 | */ |
18 | ||
1d7e80ee NS |
19 | #include <xfs/libxfs.h> |
20 | #include <xfs/libxlog.h> | |
2bd0ea18 | 21 | #include "command.h" |
2bd0ea18 NS |
22 | #include "type.h" |
23 | #include "faddr.h" | |
24 | #include "fprint.h" | |
25 | #include "field.h" | |
26 | #include "io.h" | |
27 | #include "sb.h" | |
28 | #include "bit.h" | |
29 | #include "output.h" | |
4ca431fc | 30 | #include "init.h" |
2bd0ea18 NS |
31 | |
32 | static int sb_f(int argc, char **argv); | |
33 | static void sb_help(void); | |
4ca431fc NS |
34 | static int uuid_f(int argc, char **argv); |
35 | static void uuid_help(void); | |
36 | static int label_f(int argc, char **argv); | |
37 | static void label_help(void); | |
38 | static int version_f(int argc, char **argv); | |
39 | static void version_help(void); | |
2bd0ea18 NS |
40 | |
41 | static const cmdinfo_t sb_cmd = | |
9ee7055c AM |
42 | { "sb", NULL, sb_f, 0, 1, 1, N_("[agno]"), |
43 | N_("set current address to sb header"), sb_help }; | |
4ca431fc | 44 | static const cmdinfo_t uuid_cmd = |
9ee7055c AM |
45 | { "uuid", NULL, uuid_f, 0, 1, 1, N_("[uuid]"), |
46 | N_("write/print FS uuid"), uuid_help }; | |
4ca431fc | 47 | static const cmdinfo_t label_cmd = |
9ee7055c AM |
48 | { "label", NULL, label_f, 0, 1, 1, N_("[label]"), |
49 | N_("write/print FS label"), label_help }; | |
4ca431fc | 50 | static const cmdinfo_t version_cmd = |
9ee7055c AM |
51 | { "version", NULL, version_f, 0, -1, 1, N_("[feature | [vnum fnum]]"), |
52 | N_("set feature bit(s) in the sb version field"), version_help }; | |
2bd0ea18 | 53 | |
4ca431fc NS |
54 | void |
55 | sb_init(void) | |
56 | { | |
57 | add_command(&sb_cmd); | |
58 | add_command(&uuid_cmd); | |
59 | add_command(&label_cmd); | |
60 | add_command(&version_cmd); | |
61 | } | |
2bd0ea18 NS |
62 | |
63 | #define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f)) | |
64 | #define SZC(f) szcount(xfs_sb_t, sb_ ## f) | |
65 | const field_t sb_flds[] = { | |
66 | { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, | |
67 | { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE }, | |
68 | { "dblocks", FLDT_DRFSBNO, OI(OFF(dblocks)), C1, 0, TYP_NONE }, | |
69 | { "rblocks", FLDT_DRFSBNO, OI(OFF(rblocks)), C1, 0, TYP_NONE }, | |
70 | { "rextents", FLDT_DRTBNO, OI(OFF(rextents)), C1, 0, TYP_NONE }, | |
71 | { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, | |
72 | { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG }, | |
73 | { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE }, | |
74 | { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE }, | |
75 | { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE }, | |
76 | { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE }, | |
77 | { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE }, | |
78 | { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE }, | |
79 | { "rbmblocks", FLDT_EXTLEN, OI(OFF(rbmblocks)), C1, 0, TYP_NONE }, | |
80 | { "logblocks", FLDT_EXTLEN, OI(OFF(logblocks)), C1, 0, TYP_NONE }, | |
81 | { "versionnum", FLDT_UINT16X, OI(OFF(versionnum)), C1, 0, TYP_NONE }, | |
82 | { "sectsize", FLDT_UINT16D, OI(OFF(sectsize)), C1, 0, TYP_NONE }, | |
83 | { "inodesize", FLDT_UINT16D, OI(OFF(inodesize)), C1, 0, TYP_NONE }, | |
84 | { "inopblock", FLDT_UINT16D, OI(OFF(inopblock)), C1, 0, TYP_NONE }, | |
85 | { "fname", FLDT_CHARNS, OI(OFF(fname)), CI(SZC(fname)), 0, TYP_NONE }, | |
86 | { "blocklog", FLDT_UINT8D, OI(OFF(blocklog)), C1, 0, TYP_NONE }, | |
87 | { "sectlog", FLDT_UINT8D, OI(OFF(sectlog)), C1, 0, TYP_NONE }, | |
88 | { "inodelog", FLDT_UINT8D, OI(OFF(inodelog)), C1, 0, TYP_NONE }, | |
89 | { "inopblog", FLDT_UINT8D, OI(OFF(inopblog)), C1, 0, TYP_NONE }, | |
90 | { "agblklog", FLDT_UINT8D, OI(OFF(agblklog)), C1, 0, TYP_NONE }, | |
91 | { "rextslog", FLDT_UINT8D, OI(OFF(rextslog)), C1, 0, TYP_NONE }, | |
92 | { "inprogress", FLDT_UINT8D, OI(OFF(inprogress)), C1, 0, TYP_NONE }, | |
93 | { "imax_pct", FLDT_UINT8D, OI(OFF(imax_pct)), C1, 0, TYP_NONE }, | |
94 | { "icount", FLDT_UINT64D, OI(OFF(icount)), C1, 0, TYP_NONE }, | |
95 | { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE }, | |
96 | { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE }, | |
97 | { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE }, | |
98 | { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE }, | |
b36eef04 | 99 | { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE }, |
2bd0ea18 NS |
100 | { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE }, |
101 | { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE }, | |
102 | { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE }, | |
103 | { "inoalignmt", FLDT_EXTLEN, OI(OFF(inoalignmt)), C1, 0, TYP_NONE }, | |
104 | { "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE }, | |
105 | { "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE }, | |
106 | { "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE }, | |
9440d84d NS |
107 | { "logsectlog", FLDT_UINT8D, OI(OFF(logsectlog)), C1, 0, TYP_NONE }, |
108 | { "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE }, | |
73bf5988 | 109 | { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE }, |
465e76a9 | 110 | { "features2", FLDT_UINT32X, OI(OFF(features2)), C1, 0, TYP_NONE }, |
a23fa047 DC |
111 | { "bad_features2", FLDT_UINT32X, OI(OFF(bad_features2)), |
112 | C1, 0, TYP_NONE }, | |
113 | { "features_compat", FLDT_UINT32X, OI(OFF(features_compat)), | |
114 | C1, 0, TYP_NONE }, | |
115 | { "features_ro_compat", FLDT_UINT32X, OI(OFF(features_ro_compat)), | |
116 | C1, 0, TYP_NONE }, | |
117 | { "features_incompat", FLDT_UINT32X, OI(OFF(features_incompat)), | |
118 | C1, 0, TYP_NONE }, | |
119 | { "features_log_incompat", FLDT_UINT32X, OI(OFF(features_log_incompat)), | |
120 | C1, 0, TYP_NONE }, | |
0522f1cc | 121 | { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, |
061e316e | 122 | { "spino_align", FLDT_EXTLEN, OI(OFF(spino_align)), C1, 0, TYP_NONE }, |
a23fa047 DC |
123 | { "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE }, |
124 | { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, | |
2bd0ea18 NS |
125 | { NULL } |
126 | }; | |
127 | ||
4ca431fc NS |
128 | const field_t sb_hfld[] = { |
129 | { "", FLDT_SB, OI(0), C1, 0, TYP_NONE }, | |
130 | { NULL } | |
131 | }; | |
132 | ||
2bd0ea18 NS |
133 | static void |
134 | sb_help(void) | |
135 | { | |
9ee7055c | 136 | dbprintf(_( |
2bd0ea18 NS |
137 | "\n" |
138 | " set allocation group superblock\n" | |
139 | "\n" | |
140 | " Example:\n" | |
141 | "\n" | |
142 | " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n" | |
143 | "\n" | |
9440d84d NS |
144 | " Located in the first sector of each allocation group, the superblock\n" |
145 | " contains the base information for the filesystem.\n" | |
2bd0ea18 NS |
146 | " The superblock in allocation group 0 is the primary. The copies in the\n" |
147 | " remaining allocation groups only serve as backup for filesystem recovery.\n" | |
148 | " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n" | |
149 | "\n" | |
9ee7055c | 150 | )); |
2bd0ea18 NS |
151 | } |
152 | ||
153 | static int | |
154 | sb_f( | |
155 | int argc, | |
156 | char **argv) | |
157 | { | |
158 | xfs_agnumber_t agno; | |
159 | char *p; | |
160 | ||
161 | if (argc > 1) { | |
162 | agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); | |
163 | if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { | |
9ee7055c | 164 | dbprintf(_("bad allocation group number %s\n"), argv[1]); |
2bd0ea18 NS |
165 | return 0; |
166 | } | |
167 | cur_agno = agno; | |
168 | } else if (cur_agno == NULLAGNUMBER) | |
169 | cur_agno = 0; | |
170 | ASSERT(typtab[TYP_SB].typnm == TYP_SB); | |
9440d84d NS |
171 | set_cur(&typtab[TYP_SB], |
172 | XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR), | |
173 | XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL); | |
2bd0ea18 NS |
174 | return 0; |
175 | } | |
176 | ||
2bd0ea18 NS |
177 | /*ARGSUSED*/ |
178 | int | |
179 | sb_size( | |
180 | void *obj, | |
181 | int startoff, | |
182 | int idx) | |
183 | { | |
184 | return bitize(mp->m_sb.sb_sectsize); | |
185 | } | |
4ca431fc NS |
186 | |
187 | static int | |
188 | get_sb(xfs_agnumber_t agno, xfs_sb_t *sb) | |
189 | { | |
190 | push_cur(); | |
191 | set_cur(&typtab[TYP_SB], | |
192 | XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), | |
193 | XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); | |
dfc130f3 | 194 | |
4ca431fc | 195 | if (!iocur_top->data) { |
9ee7055c | 196 | dbprintf(_("can't read superblock for AG %u\n"), agno); |
4ca431fc NS |
197 | pop_cur(); |
198 | return 0; | |
199 | } | |
200 | ||
5e656dbb | 201 | libxfs_sb_from_disk(sb, iocur_top->data); |
dfc130f3 | 202 | |
4ca431fc | 203 | if (sb->sb_magicnum != XFS_SB_MAGIC) { |
9ee7055c | 204 | dbprintf(_("bad sb magic # %#x in AG %u\n"), |
4ca431fc | 205 | sb->sb_magicnum, agno); |
dfc130f3 | 206 | return 0; |
4ca431fc | 207 | } |
5e656dbb | 208 | if (!xfs_sb_good_version(sb)) { |
9ee7055c | 209 | dbprintf(_("bad sb version # %#x in AG %u\n"), |
4ca431fc | 210 | sb->sb_versionnum, agno); |
dfc130f3 | 211 | return 0; |
4ca431fc NS |
212 | } |
213 | if (agno == 0 && sb->sb_inprogress != 0) { | |
9ee7055c | 214 | dbprintf(_("mkfs not completed successfully\n")); |
dfc130f3 | 215 | return 0; |
4ca431fc NS |
216 | } |
217 | return 1; | |
218 | } | |
219 | ||
220 | /* workaround craziness in the xlog routines */ | |
999f0b9c DC |
221 | int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p) |
222 | { | |
223 | return 0; | |
224 | } | |
4ca431fc | 225 | |
add013da NS |
226 | int |
227 | sb_logcheck(void) | |
4ca431fc | 228 | { |
7ac353a9 | 229 | int dirty; |
4ca431fc NS |
230 | |
231 | if (mp->m_sb.sb_logstart) { | |
232 | if (x.logdev && x.logdev != x.ddev) { | |
9ee7055c AM |
233 | dbprintf(_("aborting - external log specified for FS " |
234 | "with an internal log\n")); | |
4ca431fc NS |
235 | return 0; |
236 | } | |
237 | } else { | |
238 | if (!x.logdev || (x.logdev == x.ddev)) { | |
9ee7055c AM |
239 | dbprintf(_("aborting - no external log specified for FS " |
240 | "with an external log\n")); | |
4ca431fc NS |
241 | return 0; |
242 | } | |
243 | } | |
244 | ||
75c8b434 | 245 | libxfs_buftarg_init(mp, x.ddev, x.logdev, x.rtdev); |
999f0b9c | 246 | |
7ac353a9 ES |
247 | dirty = xlog_is_dirty(mp, &x, 0); |
248 | if (dirty == -1) { | |
9ee7055c | 249 | dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n")); |
4ca431fc | 250 | return 0; |
7ac353a9 | 251 | } else if (dirty == 1) { |
9ee7055c | 252 | dbprintf(_( |
4ca431fc NS |
253 | "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" |
254 | "be replayed. Mount the filesystem to replay the log, and unmount it before\n" | |
255 | "re-running %s. If you are unable to mount the filesystem, then use\n" | |
256 | "the xfs_repair -L option to destroy the log and attempt a repair.\n" | |
257 | "Note that destroying the log may cause corruption -- please attempt a mount\n" | |
9ee7055c | 258 | "of the filesystem before doing this.\n"), progname); |
4ca431fc NS |
259 | return 0; |
260 | } | |
7ac353a9 | 261 | /* Log is clean */ |
add013da NS |
262 | return 1; |
263 | } | |
264 | ||
265 | static int | |
266 | sb_logzero(uuid_t *uuidp) | |
267 | { | |
268 | if (!sb_logcheck()) | |
269 | return 0; | |
4ca431fc | 270 | |
9ee7055c | 271 | dbprintf(_("Clearing log and setting UUID\n")); |
4ca431fc | 272 | |
75c8b434 | 273 | if (libxfs_log_clear(mp->m_logdev_targp, |
4ca431fc NS |
274 | XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), |
275 | (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), | |
276 | uuidp, | |
5e656dbb | 277 | xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, |
4ca431fc | 278 | mp->m_sb.sb_logsunit, XLOG_FMT)) { |
9ee7055c | 279 | dbprintf(_("ERROR: cannot clear the log\n")); |
4ca431fc NS |
280 | return 0; |
281 | } | |
282 | return 1; | |
283 | } | |
284 | ||
285 | ||
286 | static void | |
287 | uuid_help(void) | |
288 | { | |
9ee7055c | 289 | dbprintf(_( |
4ca431fc NS |
290 | "\n" |
291 | " write/print FS uuid\n" | |
292 | "\n" | |
293 | " Example:\n" | |
294 | "\n" | |
295 | " 'uuid' - print UUID\n" | |
296 | " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" | |
297 | " 'uuid generate' - generate and write\n" | |
298 | " 'uuid rewrite' - copy UUID from SB 0\n" | |
299 | "\n" | |
300 | "The print function checks the UUID in each SB and will warn if the UUIDs\n" | |
301 | "differ between AGs (the log is not checked). The write commands will\n" | |
302 | "set the uuid in all AGs to either a specified value, a newly generated\n" | |
303 | "value or the value found in the first superblock (SB 0) respectively.\n" | |
304 | "As a side effect of writing the UUID, the log is cleared (which is fine\n" | |
305 | "on a CLEANLY unmounted FS).\n" | |
306 | "\n" | |
9ee7055c | 307 | )); |
4ca431fc NS |
308 | } |
309 | ||
310 | static uuid_t * | |
311 | do_uuid(xfs_agnumber_t agno, uuid_t *uuid) | |
312 | { | |
313 | xfs_sb_t tsb; | |
314 | static uuid_t uu; | |
315 | ||
316 | if (!get_sb(agno, &tsb)) | |
317 | return NULL; | |
318 | ||
319 | if (!uuid) { /* get uuid */ | |
320 | memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t)); | |
321 | pop_cur(); | |
322 | return &uu; | |
323 | } | |
324 | /* set uuid */ | |
325 | memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t)); | |
19ebedcf | 326 | libxfs_sb_to_disk(iocur_top->data, &tsb); |
4ca431fc NS |
327 | write_cur(); |
328 | return uuid; | |
329 | } | |
330 | ||
331 | static int | |
332 | uuid_f( | |
333 | int argc, | |
334 | char **argv) | |
335 | { | |
336 | char bp[40]; | |
337 | xfs_agnumber_t agno; | |
338 | uuid_t uu; | |
339 | uuid_t *uup = NULL; | |
340 | ||
341 | if (argc != 1 && argc != 2) { | |
9ee7055c | 342 | dbprintf(_("invalid parameters\n")); |
4ca431fc NS |
343 | return 0; |
344 | } | |
345 | ||
346 | if (argc == 2) { /* WRITE UUID */ | |
347 | ||
348 | if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { | |
9ee7055c | 349 | dbprintf(_("%s: not in expert mode, writing disabled\n"), |
4ca431fc NS |
350 | progname); |
351 | return 0; | |
352 | } | |
353 | ||
609f6bb2 ES |
354 | /* |
355 | * For now, changing the UUID of V5 superblock filesystems is | |
356 | * not supported; we do not have the infrastructure to fix all | |
357 | * other metadata when a new superblock UUID is generated. | |
358 | */ | |
359 | if (xfs_sb_version_hascrc(&mp->m_sb) && | |
360 | strcasecmp(argv[1], "rewrite")) { | |
361 | dbprintf(_("%s: only 'rewrite' supported on V5 fs\n"), | |
362 | progname); | |
363 | return 0; | |
364 | } | |
365 | ||
4ca431fc | 366 | if (!strcasecmp(argv[1], "generate")) { |
4d32d744 | 367 | platform_uuid_generate(&uu); |
4ca431fc | 368 | } else if (!strcasecmp(argv[1], "nil")) { |
4d32d744 | 369 | platform_uuid_clear(&uu); |
4ca431fc NS |
370 | } else if (!strcasecmp(argv[1], "rewrite")) { |
371 | uup = do_uuid(0, NULL); | |
372 | if (!uup) { | |
9ee7055c | 373 | dbprintf(_("failed to read UUID from AG 0\n")); |
4ca431fc NS |
374 | return 0; |
375 | } | |
6699422d | 376 | memcpy(&uu, uup, sizeof(uuid_t)); |
4d32d744 | 377 | platform_uuid_unparse(&uu, bp); |
9ee7055c | 378 | dbprintf(_("old UUID = %s\n"), bp); |
4ca431fc | 379 | } else { |
4d32d744 | 380 | if (platform_uuid_parse(argv[1], &uu)) { |
9ee7055c | 381 | dbprintf(_("invalid UUID\n")); |
4ca431fc NS |
382 | return 0; |
383 | } | |
384 | } | |
385 | ||
ff1f79a7 | 386 | /* clear the log (setting uuid) if it's not dirty */ |
add013da | 387 | if (!sb_logzero(&uu)) |
4ca431fc NS |
388 | return 0; |
389 | ||
9ee7055c | 390 | dbprintf(_("writing all SBs\n")); |
4ca431fc NS |
391 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) |
392 | if (!do_uuid(agno, &uu)) { | |
9ee7055c | 393 | dbprintf(_("failed to set UUID in AG %d\n"), agno); |
4ca431fc NS |
394 | break; |
395 | } | |
396 | ||
4d32d744 | 397 | platform_uuid_unparse(&uu, bp); |
9ee7055c | 398 | dbprintf(_("new UUID = %s\n"), bp); |
4ca431fc NS |
399 | return 0; |
400 | ||
401 | } else { /* READ+CHECK UUID */ | |
dfc130f3 | 402 | |
4ca431fc NS |
403 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { |
404 | uup = do_uuid(agno, NULL); | |
405 | if (!uup) { | |
9ee7055c | 406 | dbprintf(_("failed to read UUID from AG %d\n"), |
4ca431fc NS |
407 | agno); |
408 | return 0; | |
409 | } | |
410 | if (agno) { | |
411 | if (memcmp(&uu, uup, sizeof(uuid_t))) { | |
9ee7055c AM |
412 | dbprintf(_("warning: UUID in AG %d " |
413 | "differs to the primary SB\n"), | |
4ca431fc NS |
414 | agno); |
415 | break; | |
416 | } | |
417 | } else { | |
6699422d | 418 | memcpy(&uu, uup, sizeof(uuid_t)); |
4ca431fc NS |
419 | } |
420 | } | |
421 | if (mp->m_sb.sb_logstart) { | |
422 | if (x.logdev && x.logdev != x.ddev) | |
9ee7055c AM |
423 | dbprintf(_("warning - external log specified " |
424 | "for FS with an internal log\n")); | |
4ca431fc | 425 | } else if (!x.logdev || (x.logdev == x.ddev)) { |
9ee7055c AM |
426 | dbprintf(_("warning - no external log specified " |
427 | "for FS with an external log\n")); | |
4ca431fc NS |
428 | } |
429 | ||
4d32d744 | 430 | platform_uuid_unparse(&uu, bp); |
9ee7055c | 431 | dbprintf(_("UUID = %s\n"), bp); |
4ca431fc NS |
432 | } |
433 | ||
434 | return 0; | |
435 | } | |
436 | ||
437 | ||
438 | static void | |
439 | label_help(void) | |
440 | { | |
9ee7055c | 441 | dbprintf(_( |
4ca431fc NS |
442 | "\n" |
443 | " write/print FS label\n" | |
444 | "\n" | |
445 | " Example:\n" | |
446 | "\n" | |
447 | " 'label' - print label\n" | |
448 | " 'label 123456789012' - write label\n" | |
449 | " 'label --' - write an empty label\n" | |
450 | "\n" | |
451 | "The print function checks the label in each SB and will warn if the labels\n" | |
452 | "differ between AGs. The write commands will set the label in all AGs to the\n" | |
453 | "specified value. The maximum length of a label is 12 characters - use of a\n" | |
454 | "longer label will result in truncation and a warning will be issued.\n" | |
455 | "\n" | |
9ee7055c | 456 | )); |
4ca431fc NS |
457 | } |
458 | ||
459 | static char * | |
460 | do_label(xfs_agnumber_t agno, char *label) | |
461 | { | |
462 | size_t len; | |
463 | xfs_sb_t tsb; | |
dfc130f3 | 464 | static char lbl[sizeof(tsb.sb_fname) + 1]; |
4ca431fc NS |
465 | |
466 | if (!get_sb(agno, &tsb)) | |
467 | return NULL; | |
468 | ||
469 | memset(&lbl[0], 0, sizeof(lbl)); | |
470 | ||
471 | if (!label) { /* get label */ | |
472 | pop_cur(); | |
473 | memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); | |
474 | return &lbl[0]; | |
475 | } | |
476 | /* set label */ | |
477 | if ((len = strlen(label)) > sizeof(tsb.sb_fname)) { | |
478 | if (agno == 0) | |
9ee7055c | 479 | dbprintf(_("%s: truncating label length from %d to %d\n"), |
4ca431fc NS |
480 | progname, (int)len, (int)sizeof(tsb.sb_fname)); |
481 | len = sizeof(tsb.sb_fname); | |
482 | } | |
483 | if ( len == 2 && | |
484 | (strcmp(label, "\"\"") == 0 || | |
485 | strcmp(label, "''") == 0 || | |
486 | strcmp(label, "--") == 0) ) | |
487 | label[0] = label[1] = '\0'; | |
488 | memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname)); | |
489 | memcpy(&tsb.sb_fname, label, len); | |
490 | memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); | |
19ebedcf | 491 | libxfs_sb_to_disk(iocur_top->data, &tsb); |
4ca431fc NS |
492 | write_cur(); |
493 | return &lbl[0]; | |
494 | } | |
495 | ||
496 | static int | |
497 | label_f( | |
498 | int argc, | |
499 | char **argv) | |
500 | { | |
501 | char *p = NULL; | |
502 | xfs_sb_t sb; | |
503 | xfs_agnumber_t ag; | |
504 | ||
505 | if (argc != 1 && argc != 2) { | |
9ee7055c | 506 | dbprintf(_("invalid parameters\n")); |
4ca431fc NS |
507 | return 0; |
508 | } | |
509 | ||
510 | if (argc == 2) { /* WRITE LABEL */ | |
511 | ||
512 | if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { | |
9ee7055c | 513 | dbprintf(_("%s: not in expert mode, writing disabled\n"), |
4ca431fc NS |
514 | progname); |
515 | return 0; | |
516 | } | |
517 | ||
9ee7055c | 518 | dbprintf(_("writing all SBs\n")); |
4ca431fc NS |
519 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) |
520 | if ((p = do_label(ag, argv[1])) == NULL) { | |
9ee7055c | 521 | dbprintf(_("failed to set label in AG %d\n"), ag); |
4ca431fc NS |
522 | break; |
523 | } | |
9ee7055c | 524 | dbprintf(_("new label = \"%s\"\n"), p); |
4ca431fc NS |
525 | |
526 | } else { /* READ LABEL */ | |
527 | ||
528 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { | |
529 | p = do_label(ag, NULL); | |
530 | if (!p) { | |
9ee7055c | 531 | dbprintf(_("failed to read label in AG %d\n"), ag); |
4ca431fc NS |
532 | return 0; |
533 | } | |
534 | if (!ag) | |
535 | memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname)); | |
536 | else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname))) | |
9ee7055c | 537 | dbprintf(_("warning: AG %d label differs\n"), ag); |
4ca431fc | 538 | } |
9ee7055c | 539 | dbprintf(_("label = \"%s\"\n"), p); |
4ca431fc NS |
540 | } |
541 | return 0; | |
542 | } | |
543 | ||
544 | ||
545 | static void | |
546 | version_help(void) | |
547 | { | |
9ee7055c | 548 | dbprintf(_( |
4ca431fc NS |
549 | "\n" |
550 | " set/print feature bits in sb version\n" | |
551 | "\n" | |
552 | " Example:\n" | |
553 | "\n" | |
554 | " 'version' - print current feature bits\n" | |
555 | " 'version extflg' - enable unwritten extents\n" | |
70476e54 NS |
556 | " 'version attr1' - enable v1 inline extended attributes\n" |
557 | " 'version attr2' - enable v2 inline extended attributes\n" | |
66997473 | 558 | " 'version log2' - enable v2 log format\n" |
4ca431fc NS |
559 | "\n" |
560 | "The version function prints currently enabled features for a filesystem\n" | |
ff1f79a7 | 561 | "according to the version field of its primary superblock.\n" |
4ca431fc | 562 | "It can also be used to enable selected features, such as support for\n" |
ff1f79a7 | 563 | "unwritten extents. The updated version is written into all AGs.\n" |
4ca431fc | 564 | "\n" |
9ee7055c | 565 | )); |
4ca431fc NS |
566 | } |
567 | ||
568 | static int | |
70476e54 | 569 | do_version(xfs_agnumber_t agno, __uint16_t version, __uint32_t features) |
4ca431fc NS |
570 | { |
571 | xfs_sb_t tsb; | |
572 | ||
573 | if (!get_sb(agno, &tsb)) | |
574 | return 0; | |
575 | ||
72f11257 ES |
576 | if (xfs_sb_has_mismatched_features2(&tsb)) { |
577 | dbprintf(_("Superblock has mismatched features2 fields, " | |
578 | "skipping modification\n")); | |
579 | return 0; | |
580 | } | |
581 | ||
66997473 | 582 | if ((version & XFS_SB_VERSION_LOGV2BIT) && |
5e656dbb | 583 | !xfs_sb_version_haslogv2(&tsb)) { |
66997473 | 584 | tsb.sb_logsunit = 1; |
66997473 NS |
585 | } |
586 | ||
70476e54 NS |
587 | tsb.sb_versionnum = version; |
588 | tsb.sb_features2 = features; | |
72f11257 | 589 | tsb.sb_bad_features2 = features; |
19ebedcf | 590 | libxfs_sb_to_disk(iocur_top->data, &tsb); |
4ca431fc NS |
591 | write_cur(); |
592 | return 1; | |
593 | } | |
594 | ||
595 | static char * | |
596 | version_string( | |
597 | xfs_sb_t *sbp) | |
598 | { | |
599 | static char s[1024]; | |
600 | ||
601 | if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1) | |
602 | strcpy(s, "V1"); | |
603 | else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2) | |
604 | strcpy(s, "V2"); | |
605 | else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3) | |
606 | strcpy(s, "V3"); | |
607 | else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) | |
608 | strcpy(s, "V4"); | |
a23fa047 DC |
609 | else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) |
610 | strcpy(s, "V5"); | |
4ca431fc | 611 | |
5f6f3660 DC |
612 | /* |
613 | * We assume the state of these features now, so macros don't exist for | |
614 | * them any more. | |
615 | */ | |
616 | if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT) | |
617 | strcat(s, ",NLINK"); | |
618 | if (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) | |
619 | strcat(s, ",SHARED"); | |
620 | if (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT) | |
621 | strcat(s, ",DIRV2"); | |
622 | ||
5e656dbb | 623 | if (xfs_sb_version_hasattr(sbp)) |
4ca431fc | 624 | strcat(s, ",ATTR"); |
5e656dbb | 625 | if (xfs_sb_version_hasquota(sbp)) |
4ca431fc | 626 | strcat(s, ",QUOTA"); |
5e656dbb | 627 | if (xfs_sb_version_hasalign(sbp)) |
4ca431fc | 628 | strcat(s, ",ALIGN"); |
5e656dbb | 629 | if (xfs_sb_version_hasdalign(sbp)) |
4ca431fc | 630 | strcat(s, ",DALIGN"); |
5e656dbb | 631 | if (xfs_sb_version_haslogv2(sbp)) |
4ca431fc | 632 | strcat(s, ",LOGV2"); |
5e656dbb | 633 | if (xfs_sb_version_hasextflgbit(sbp)) |
4ca431fc | 634 | strcat(s, ",EXTFLG"); |
5e656dbb | 635 | if (xfs_sb_version_hassector(sbp)) |
4ca431fc | 636 | strcat(s, ",SECTOR"); |
51ca7008 BN |
637 | if (xfs_sb_version_hasasciici(sbp)) |
638 | strcat(s, ",ASCII_CI"); | |
5e656dbb | 639 | if (xfs_sb_version_hasmorebits(sbp)) |
ca86e759 | 640 | strcat(s, ",MOREBITS"); |
5e656dbb | 641 | if (xfs_sb_version_hasattr2(sbp)) |
ca86e759 | 642 | strcat(s, ",ATTR2"); |
5e656dbb | 643 | if (xfs_sb_version_haslazysbcount(sbp)) |
cdded3d8 | 644 | strcat(s, ",LAZYSBCOUNT"); |
22bc10ed AM |
645 | if (xfs_sb_version_hasprojid32bit(sbp)) |
646 | strcat(s, ",PROJID32BIT"); | |
a23fa047 DC |
647 | if (xfs_sb_version_hascrc(sbp)) |
648 | strcat(s, ",CRC"); | |
42737f1a MT |
649 | if (xfs_sb_version_hasftype(sbp)) |
650 | strcat(s, ",FTYPE"); | |
b7fc3b36 ES |
651 | if (xfs_sb_version_hasfinobt(sbp)) |
652 | strcat(s, ",FINOBT"); | |
4ca431fc NS |
653 | return s; |
654 | } | |
655 | ||
a23fa047 DC |
656 | /* |
657 | * XXX: this only supports reading and writing to version 4 superblock fields. | |
658 | * V5 superblocks always define certain V4 feature bits - they are blocked from | |
659 | * being changed if a V5 sb is detected, but otherwise v5 superblock features | |
660 | * are not handled here. | |
661 | */ | |
4ca431fc NS |
662 | static int |
663 | version_f( | |
664 | int argc, | |
665 | char **argv) | |
666 | { | |
667 | __uint16_t version = 0; | |
70476e54 | 668 | __uint32_t features = 0; |
4ca431fc NS |
669 | xfs_agnumber_t ag; |
670 | ||
671 | if (argc == 2) { /* WRITE VERSION */ | |
672 | ||
673 | if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { | |
9ee7055c | 674 | dbprintf(_("%s: not in expert mode, writing disabled\n"), |
4ca431fc NS |
675 | progname); |
676 | return 0; | |
677 | } | |
678 | ||
679 | /* Logic here derived from the IRIX xfs_chver(1M) script. */ | |
680 | if (!strcasecmp(argv[1], "extflg")) { | |
681 | switch (XFS_SB_VERSION_NUM(&mp->m_sb)) { | |
682 | case XFS_SB_VERSION_1: | |
683 | version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT; | |
684 | break; | |
685 | case XFS_SB_VERSION_2: | |
686 | version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT; | |
687 | break; | |
688 | case XFS_SB_VERSION_3: | |
689 | version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT; | |
690 | break; | |
691 | case XFS_SB_VERSION_4: | |
5e656dbb | 692 | if (xfs_sb_version_hasextflgbit(&mp->m_sb)) |
a23fa047 DC |
693 | dbprintf( |
694 | _("unwritten extents flag is already enabled\n")); | |
4ca431fc NS |
695 | else |
696 | version = mp->m_sb.sb_versionnum | | |
697 | XFS_SB_VERSION_EXTFLGBIT; | |
698 | break; | |
a23fa047 DC |
699 | case XFS_SB_VERSION_5: |
700 | dbprintf( | |
701 | _("unwritten extents always enabled for v5 superblocks.\n")); | |
702 | break; | |
4ca431fc | 703 | } |
66997473 NS |
704 | } else if (!strcasecmp(argv[1], "log2")) { |
705 | switch (XFS_SB_VERSION_NUM(&mp->m_sb)) { | |
706 | case XFS_SB_VERSION_1: | |
707 | version = 0x0004 | XFS_SB_VERSION_LOGV2BIT; | |
708 | break; | |
709 | case XFS_SB_VERSION_2: | |
710 | version = 0x0014 | XFS_SB_VERSION_LOGV2BIT; | |
711 | break; | |
712 | case XFS_SB_VERSION_3: | |
713 | version = 0x0034 | XFS_SB_VERSION_LOGV2BIT; | |
714 | break; | |
715 | case XFS_SB_VERSION_4: | |
5e656dbb | 716 | if (xfs_sb_version_haslogv2(&mp->m_sb)) |
a23fa047 DC |
717 | dbprintf( |
718 | _("version 2 log format is already in use\n")); | |
66997473 NS |
719 | else |
720 | version = mp->m_sb.sb_versionnum | | |
721 | XFS_SB_VERSION_LOGV2BIT; | |
722 | break; | |
a23fa047 DC |
723 | case XFS_SB_VERSION_5: |
724 | dbprintf( | |
725 | _("Version 2 logs always enabled for v5 superblocks.\n")); | |
726 | break; | |
66997473 | 727 | } |
a23fa047 DC |
728 | } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) { |
729 | dbprintf( | |
730 | _("%s: Cannot change %s on v5 superblocks.\n"), | |
731 | progname, argv[1]); | |
732 | return 0; | |
70476e54 | 733 | } else if (!strcasecmp(argv[1], "attr1")) { |
a23fa047 | 734 | |
5e656dbb | 735 | if (xfs_sb_version_hasattr2(&mp->m_sb)) { |
70476e54 NS |
736 | if (!(mp->m_sb.sb_features2 &= |
737 | ~XFS_SB_VERSION2_ATTR2BIT)) | |
738 | mp->m_sb.sb_versionnum &= | |
739 | ~XFS_SB_VERSION_MOREBITSBIT; | |
740 | } | |
5e656dbb | 741 | xfs_sb_version_addattr(&mp->m_sb); |
70476e54 NS |
742 | version = mp->m_sb.sb_versionnum; |
743 | features = mp->m_sb.sb_features2; | |
744 | } else if (!strcasecmp(argv[1], "attr2")) { | |
5e656dbb BN |
745 | xfs_sb_version_addattr(&mp->m_sb); |
746 | xfs_sb_version_addattr2(&mp->m_sb); | |
22bc10ed AM |
747 | version = mp->m_sb.sb_versionnum; |
748 | features = mp->m_sb.sb_features2; | |
749 | } else if (!strcasecmp(argv[1], "projid32bit")) { | |
750 | xfs_sb_version_addprojid32bit(&mp->m_sb); | |
70476e54 NS |
751 | version = mp->m_sb.sb_versionnum; |
752 | features = mp->m_sb.sb_features2; | |
4ca431fc | 753 | } else { |
9ee7055c | 754 | dbprintf(_("%s: invalid version change command \"%s\"\n"), |
4ca431fc NS |
755 | progname, argv[1]); |
756 | return 0; | |
757 | } | |
758 | ||
759 | if (version) { | |
9ee7055c | 760 | dbprintf(_("writing all SBs\n")); |
4ca431fc | 761 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) |
70476e54 | 762 | if (!do_version(ag, version, features)) { |
9ee7055c AM |
763 | dbprintf(_("failed to set versionnum " |
764 | "in AG %d\n"), ag); | |
4ca431fc NS |
765 | break; |
766 | } | |
767 | mp->m_sb.sb_versionnum = version; | |
70476e54 | 768 | mp->m_sb.sb_features2 = features; |
4ca431fc NS |
769 | } |
770 | } | |
d2df702b NS |
771 | |
772 | if (argc == 3) { /* VERSIONNUM + FEATURES2 */ | |
773 | char *sp; | |
774 | ||
775 | version = mp->m_sb.sb_versionnum; | |
776 | features = mp->m_sb.sb_features2; | |
777 | mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0); | |
778 | mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0); | |
779 | } | |
780 | ||
9ee7055c | 781 | dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum, |
ca86e759 | 782 | mp->m_sb.sb_features2, version_string(&mp->m_sb)); |
d2df702b NS |
783 | |
784 | if (argc == 3) { /* now reset... */ | |
785 | mp->m_sb.sb_versionnum = version; | |
786 | mp->m_sb.sb_features2 = features; | |
787 | return 0; | |
788 | } | |
789 | ||
4ca431fc NS |
790 | return 0; |
791 | } |