]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
xfs_db: report FINOBT in version output
[thirdparty/xfsprogs-dev.git] / db / sb.c
CommitLineData
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
32static int sb_f(int argc, char **argv);
33static void sb_help(void);
4ca431fc
NS
34static int uuid_f(int argc, char **argv);
35static void uuid_help(void);
36static int label_f(int argc, char **argv);
37static void label_help(void);
38static int version_f(int argc, char **argv);
39static void version_help(void);
2bd0ea18
NS
40
41static 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 44static 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 47static 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 50static 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
54void
55sb_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)
65const 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 },
a23fa047
DC
122 { "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE },
123 { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
2bd0ea18
NS
124 { NULL }
125};
126
4ca431fc
NS
127const field_t sb_hfld[] = {
128 { "", FLDT_SB, OI(0), C1, 0, TYP_NONE },
129 { NULL }
130};
131
2bd0ea18
NS
132static void
133sb_help(void)
134{
9ee7055c 135 dbprintf(_(
2bd0ea18
NS
136"\n"
137" set allocation group superblock\n"
138"\n"
139" Example:\n"
140"\n"
141" 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
142"\n"
9440d84d
NS
143" Located in the first sector of each allocation group, the superblock\n"
144" contains the base information for the filesystem.\n"
2bd0ea18
NS
145" The superblock in allocation group 0 is the primary. The copies in the\n"
146" remaining allocation groups only serve as backup for filesystem recovery.\n"
147" The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
148"\n"
9ee7055c 149));
2bd0ea18
NS
150}
151
152static int
153sb_f(
154 int argc,
155 char **argv)
156{
157 xfs_agnumber_t agno;
158 char *p;
159
160 if (argc > 1) {
161 agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0);
162 if (*p != '\0' || agno >= mp->m_sb.sb_agcount) {
9ee7055c 163 dbprintf(_("bad allocation group number %s\n"), argv[1]);
2bd0ea18
NS
164 return 0;
165 }
166 cur_agno = agno;
167 } else if (cur_agno == NULLAGNUMBER)
168 cur_agno = 0;
169 ASSERT(typtab[TYP_SB].typnm == TYP_SB);
9440d84d
NS
170 set_cur(&typtab[TYP_SB],
171 XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR),
172 XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL);
2bd0ea18
NS
173 return 0;
174}
175
2bd0ea18
NS
176/*ARGSUSED*/
177int
178sb_size(
179 void *obj,
180 int startoff,
181 int idx)
182{
183 return bitize(mp->m_sb.sb_sectsize);
184}
4ca431fc
NS
185
186static int
187get_sb(xfs_agnumber_t agno, xfs_sb_t *sb)
188{
189 push_cur();
190 set_cur(&typtab[TYP_SB],
191 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
192 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 193
4ca431fc 194 if (!iocur_top->data) {
9ee7055c 195 dbprintf(_("can't read superblock for AG %u\n"), agno);
4ca431fc
NS
196 pop_cur();
197 return 0;
198 }
199
5e656dbb 200 libxfs_sb_from_disk(sb, iocur_top->data);
dfc130f3 201
4ca431fc 202 if (sb->sb_magicnum != XFS_SB_MAGIC) {
9ee7055c 203 dbprintf(_("bad sb magic # %#x in AG %u\n"),
4ca431fc 204 sb->sb_magicnum, agno);
dfc130f3 205 return 0;
4ca431fc 206 }
5e656dbb 207 if (!xfs_sb_good_version(sb)) {
9ee7055c 208 dbprintf(_("bad sb version # %#x in AG %u\n"),
4ca431fc 209 sb->sb_versionnum, agno);
dfc130f3 210 return 0;
4ca431fc
NS
211 }
212 if (agno == 0 && sb->sb_inprogress != 0) {
9ee7055c 213 dbprintf(_("mkfs not completed successfully\n"));
dfc130f3 214 return 0;
4ca431fc
NS
215 }
216 return 1;
217}
218
219/* workaround craziness in the xlog routines */
999f0b9c
DC
220int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
221{
222 return 0;
223}
4ca431fc 224
add013da
NS
225int
226sb_logcheck(void)
4ca431fc 227{
999f0b9c 228 struct xlog log;
4ca431fc
NS
229 xfs_daddr_t head_blk, tail_blk;
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
245 memset(&log, 0, sizeof(log));
75c8b434 246 libxfs_buftarg_init(mp, x.ddev, x.logdev, x.rtdev);
4ca431fc
NS
247 x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
248 x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
999f0b9c
DC
249 x.lbsize = BBSIZE;
250 if (xfs_sb_version_hassector(&mp->m_sb))
251 x.lbsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT);
252
75c8b434 253 log.l_dev = mp->m_logdev_targp;
4ca431fc
NS
254 log.l_logsize = BBTOB(log.l_logBBsize);
255 log.l_logBBsize = x.logBBsize;
256 log.l_logBBstart = x.logBBstart;
999f0b9c 257 log.l_sectBBsize = BTOBB(x.lbsize);
4ca431fc
NS
258 log.l_mp = mp;
259
5e656dbb 260 if (xlog_find_tail(&log, &head_blk, &tail_blk)) {
9ee7055c 261 dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
4ca431fc
NS
262 return 0;
263 }
264 if (head_blk != tail_blk) {
9ee7055c 265 dbprintf(_(
4ca431fc
NS
266"ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
267"be replayed. Mount the filesystem to replay the log, and unmount it before\n"
268"re-running %s. If you are unable to mount the filesystem, then use\n"
269"the xfs_repair -L option to destroy the log and attempt a repair.\n"
270"Note that destroying the log may cause corruption -- please attempt a mount\n"
9ee7055c 271"of the filesystem before doing this.\n"), progname);
4ca431fc
NS
272 return 0;
273 }
add013da
NS
274 return 1;
275}
276
277static int
278sb_logzero(uuid_t *uuidp)
279{
280 if (!sb_logcheck())
281 return 0;
4ca431fc 282
9ee7055c 283 dbprintf(_("Clearing log and setting UUID\n"));
4ca431fc 284
75c8b434 285 if (libxfs_log_clear(mp->m_logdev_targp,
4ca431fc
NS
286 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
287 (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
288 uuidp,
5e656dbb 289 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
4ca431fc 290 mp->m_sb.sb_logsunit, XLOG_FMT)) {
9ee7055c 291 dbprintf(_("ERROR: cannot clear the log\n"));
4ca431fc
NS
292 return 0;
293 }
294 return 1;
295}
296
297
298static void
299uuid_help(void)
300{
9ee7055c 301 dbprintf(_(
4ca431fc
NS
302"\n"
303" write/print FS uuid\n"
304"\n"
305" Example:\n"
306"\n"
307" 'uuid' - print UUID\n"
308" 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
309" 'uuid generate' - generate and write\n"
310" 'uuid rewrite' - copy UUID from SB 0\n"
311"\n"
312"The print function checks the UUID in each SB and will warn if the UUIDs\n"
313"differ between AGs (the log is not checked). The write commands will\n"
314"set the uuid in all AGs to either a specified value, a newly generated\n"
315"value or the value found in the first superblock (SB 0) respectively.\n"
316"As a side effect of writing the UUID, the log is cleared (which is fine\n"
317"on a CLEANLY unmounted FS).\n"
318"\n"
9ee7055c 319));
4ca431fc
NS
320}
321
322static uuid_t *
323do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
324{
325 xfs_sb_t tsb;
326 static uuid_t uu;
327
328 if (!get_sb(agno, &tsb))
329 return NULL;
330
331 if (!uuid) { /* get uuid */
332 memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t));
333 pop_cur();
334 return &uu;
335 }
336 /* set uuid */
337 memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
5e656dbb 338 libxfs_sb_to_disk(iocur_top->data, &tsb, XFS_SB_UUID);
4ca431fc
NS
339 write_cur();
340 return uuid;
341}
342
343static int
344uuid_f(
345 int argc,
346 char **argv)
347{
348 char bp[40];
349 xfs_agnumber_t agno;
350 uuid_t uu;
351 uuid_t *uup = NULL;
352
353 if (argc != 1 && argc != 2) {
9ee7055c 354 dbprintf(_("invalid parameters\n"));
4ca431fc
NS
355 return 0;
356 }
357
358 if (argc == 2) { /* WRITE UUID */
359
360 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 361 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
362 progname);
363 return 0;
364 }
365
609f6bb2
ES
366 /*
367 * For now, changing the UUID of V5 superblock filesystems is
368 * not supported; we do not have the infrastructure to fix all
369 * other metadata when a new superblock UUID is generated.
370 */
371 if (xfs_sb_version_hascrc(&mp->m_sb) &&
372 strcasecmp(argv[1], "rewrite")) {
373 dbprintf(_("%s: only 'rewrite' supported on V5 fs\n"),
374 progname);
375 return 0;
376 }
377
4ca431fc 378 if (!strcasecmp(argv[1], "generate")) {
4d32d744 379 platform_uuid_generate(&uu);
4ca431fc 380 } else if (!strcasecmp(argv[1], "nil")) {
4d32d744 381 platform_uuid_clear(&uu);
4ca431fc
NS
382 } else if (!strcasecmp(argv[1], "rewrite")) {
383 uup = do_uuid(0, NULL);
384 if (!uup) {
9ee7055c 385 dbprintf(_("failed to read UUID from AG 0\n"));
4ca431fc
NS
386 return 0;
387 }
6699422d 388 memcpy(&uu, uup, sizeof(uuid_t));
4d32d744 389 platform_uuid_unparse(&uu, bp);
9ee7055c 390 dbprintf(_("old UUID = %s\n"), bp);
4ca431fc 391 } else {
4d32d744 392 if (platform_uuid_parse(argv[1], &uu)) {
9ee7055c 393 dbprintf(_("invalid UUID\n"));
4ca431fc
NS
394 return 0;
395 }
396 }
397
ff1f79a7 398 /* clear the log (setting uuid) if it's not dirty */
add013da 399 if (!sb_logzero(&uu))
4ca431fc
NS
400 return 0;
401
9ee7055c 402 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
403 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
404 if (!do_uuid(agno, &uu)) {
9ee7055c 405 dbprintf(_("failed to set UUID in AG %d\n"), agno);
4ca431fc
NS
406 break;
407 }
408
4d32d744 409 platform_uuid_unparse(&uu, bp);
9ee7055c 410 dbprintf(_("new UUID = %s\n"), bp);
4ca431fc
NS
411 return 0;
412
413 } else { /* READ+CHECK UUID */
dfc130f3 414
4ca431fc
NS
415 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
416 uup = do_uuid(agno, NULL);
417 if (!uup) {
9ee7055c 418 dbprintf(_("failed to read UUID from AG %d\n"),
4ca431fc
NS
419 agno);
420 return 0;
421 }
422 if (agno) {
423 if (memcmp(&uu, uup, sizeof(uuid_t))) {
9ee7055c
AM
424 dbprintf(_("warning: UUID in AG %d "
425 "differs to the primary SB\n"),
4ca431fc
NS
426 agno);
427 break;
428 }
429 } else {
6699422d 430 memcpy(&uu, uup, sizeof(uuid_t));
4ca431fc
NS
431 }
432 }
433 if (mp->m_sb.sb_logstart) {
434 if (x.logdev && x.logdev != x.ddev)
9ee7055c
AM
435 dbprintf(_("warning - external log specified "
436 "for FS with an internal log\n"));
4ca431fc 437 } else if (!x.logdev || (x.logdev == x.ddev)) {
9ee7055c
AM
438 dbprintf(_("warning - no external log specified "
439 "for FS with an external log\n"));
4ca431fc
NS
440 }
441
4d32d744 442 platform_uuid_unparse(&uu, bp);
9ee7055c 443 dbprintf(_("UUID = %s\n"), bp);
4ca431fc
NS
444 }
445
446 return 0;
447}
448
449
450static void
451label_help(void)
452{
9ee7055c 453 dbprintf(_(
4ca431fc
NS
454"\n"
455" write/print FS label\n"
456"\n"
457" Example:\n"
458"\n"
459" 'label' - print label\n"
460" 'label 123456789012' - write label\n"
461" 'label --' - write an empty label\n"
462"\n"
463"The print function checks the label in each SB and will warn if the labels\n"
464"differ between AGs. The write commands will set the label in all AGs to the\n"
465"specified value. The maximum length of a label is 12 characters - use of a\n"
466"longer label will result in truncation and a warning will be issued.\n"
467"\n"
9ee7055c 468));
4ca431fc
NS
469}
470
471static char *
472do_label(xfs_agnumber_t agno, char *label)
473{
474 size_t len;
475 xfs_sb_t tsb;
dfc130f3 476 static char lbl[sizeof(tsb.sb_fname) + 1];
4ca431fc
NS
477
478 if (!get_sb(agno, &tsb))
479 return NULL;
480
481 memset(&lbl[0], 0, sizeof(lbl));
482
483 if (!label) { /* get label */
484 pop_cur();
485 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
486 return &lbl[0];
487 }
488 /* set label */
489 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
490 if (agno == 0)
9ee7055c 491 dbprintf(_("%s: truncating label length from %d to %d\n"),
4ca431fc
NS
492 progname, (int)len, (int)sizeof(tsb.sb_fname));
493 len = sizeof(tsb.sb_fname);
494 }
495 if ( len == 2 &&
496 (strcmp(label, "\"\"") == 0 ||
497 strcmp(label, "''") == 0 ||
498 strcmp(label, "--") == 0) )
499 label[0] = label[1] = '\0';
500 memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname));
501 memcpy(&tsb.sb_fname, label, len);
502 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
5e656dbb 503 libxfs_sb_to_disk(iocur_top->data, &tsb, XFS_SB_FNAME);
4ca431fc
NS
504 write_cur();
505 return &lbl[0];
506}
507
508static int
509label_f(
510 int argc,
511 char **argv)
512{
513 char *p = NULL;
514 xfs_sb_t sb;
515 xfs_agnumber_t ag;
516
517 if (argc != 1 && argc != 2) {
9ee7055c 518 dbprintf(_("invalid parameters\n"));
4ca431fc
NS
519 return 0;
520 }
521
522 if (argc == 2) { /* WRITE LABEL */
523
524 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 525 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
526 progname);
527 return 0;
528 }
529
9ee7055c 530 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
531 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
532 if ((p = do_label(ag, argv[1])) == NULL) {
9ee7055c 533 dbprintf(_("failed to set label in AG %d\n"), ag);
4ca431fc
NS
534 break;
535 }
9ee7055c 536 dbprintf(_("new label = \"%s\"\n"), p);
4ca431fc
NS
537
538 } else { /* READ LABEL */
539
540 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
541 p = do_label(ag, NULL);
542 if (!p) {
9ee7055c 543 dbprintf(_("failed to read label in AG %d\n"), ag);
4ca431fc
NS
544 return 0;
545 }
546 if (!ag)
547 memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname));
548 else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname)))
9ee7055c 549 dbprintf(_("warning: AG %d label differs\n"), ag);
4ca431fc 550 }
9ee7055c 551 dbprintf(_("label = \"%s\"\n"), p);
4ca431fc
NS
552 }
553 return 0;
554}
555
556
557static void
558version_help(void)
559{
9ee7055c 560 dbprintf(_(
4ca431fc
NS
561"\n"
562" set/print feature bits in sb version\n"
563"\n"
564" Example:\n"
565"\n"
566" 'version' - print current feature bits\n"
567" 'version extflg' - enable unwritten extents\n"
70476e54
NS
568" 'version attr1' - enable v1 inline extended attributes\n"
569" 'version attr2' - enable v2 inline extended attributes\n"
66997473 570" 'version log2' - enable v2 log format\n"
4ca431fc
NS
571"\n"
572"The version function prints currently enabled features for a filesystem\n"
ff1f79a7 573"according to the version field of its primary superblock.\n"
4ca431fc 574"It can also be used to enable selected features, such as support for\n"
ff1f79a7 575"unwritten extents. The updated version is written into all AGs.\n"
4ca431fc 576"\n"
9ee7055c 577));
4ca431fc
NS
578}
579
580static int
70476e54 581do_version(xfs_agnumber_t agno, __uint16_t version, __uint32_t features)
4ca431fc
NS
582{
583 xfs_sb_t tsb;
66997473 584 __int64_t fields = 0;
4ca431fc
NS
585
586 if (!get_sb(agno, &tsb))
587 return 0;
588
72f11257
ES
589 if (xfs_sb_has_mismatched_features2(&tsb)) {
590 dbprintf(_("Superblock has mismatched features2 fields, "
591 "skipping modification\n"));
592 return 0;
593 }
594
66997473 595 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
5e656dbb 596 !xfs_sb_version_haslogv2(&tsb)) {
66997473
NS
597 tsb.sb_logsunit = 1;
598 fields |= (1LL << XFS_SBS_LOGSUNIT);
599 }
600
70476e54
NS
601 tsb.sb_versionnum = version;
602 tsb.sb_features2 = features;
72f11257
ES
603 tsb.sb_bad_features2 = features;
604 fields |= XFS_SB_VERSIONNUM | XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
5e656dbb 605 libxfs_sb_to_disk(iocur_top->data, &tsb, fields);
4ca431fc
NS
606 write_cur();
607 return 1;
608}
609
610static char *
611version_string(
612 xfs_sb_t *sbp)
613{
614 static char s[1024];
615
616 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
617 strcpy(s, "V1");
618 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
619 strcpy(s, "V2");
620 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
621 strcpy(s, "V3");
622 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
623 strcpy(s, "V4");
a23fa047
DC
624 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5)
625 strcpy(s, "V5");
4ca431fc 626
5e656dbb 627 if (xfs_sb_version_hasattr(sbp))
4ca431fc 628 strcat(s, ",ATTR");
5e656dbb 629 if (xfs_sb_version_hasnlink(sbp))
4ca431fc 630 strcat(s, ",NLINK");
5e656dbb 631 if (xfs_sb_version_hasquota(sbp))
4ca431fc 632 strcat(s, ",QUOTA");
5e656dbb 633 if (xfs_sb_version_hasalign(sbp))
4ca431fc 634 strcat(s, ",ALIGN");
5e656dbb 635 if (xfs_sb_version_hasdalign(sbp))
4ca431fc 636 strcat(s, ",DALIGN");
5e656dbb 637 if (xfs_sb_version_hasshared(sbp))
4ca431fc 638 strcat(s, ",SHARED");
5e656dbb 639 if (xfs_sb_version_hasdirv2(sbp))
4ca431fc 640 strcat(s, ",DIRV2");
5e656dbb 641 if (xfs_sb_version_haslogv2(sbp))
4ca431fc 642 strcat(s, ",LOGV2");
5e656dbb 643 if (xfs_sb_version_hasextflgbit(sbp))
4ca431fc 644 strcat(s, ",EXTFLG");
5e656dbb 645 if (xfs_sb_version_hassector(sbp))
4ca431fc 646 strcat(s, ",SECTOR");
51ca7008
BN
647 if (xfs_sb_version_hasasciici(sbp))
648 strcat(s, ",ASCII_CI");
5e656dbb 649 if (xfs_sb_version_hasmorebits(sbp))
ca86e759 650 strcat(s, ",MOREBITS");
5e656dbb 651 if (xfs_sb_version_hasattr2(sbp))
ca86e759 652 strcat(s, ",ATTR2");
5e656dbb 653 if (xfs_sb_version_haslazysbcount(sbp))
cdded3d8 654 strcat(s, ",LAZYSBCOUNT");
22bc10ed
AM
655 if (xfs_sb_version_hasprojid32bit(sbp))
656 strcat(s, ",PROJID32BIT");
a23fa047
DC
657 if (xfs_sb_version_hascrc(sbp))
658 strcat(s, ",CRC");
42737f1a
MT
659 if (xfs_sb_version_hasftype(sbp))
660 strcat(s, ",FTYPE");
b7fc3b36
ES
661 if (xfs_sb_version_hasfinobt(sbp))
662 strcat(s, ",FINOBT");
4ca431fc
NS
663 return s;
664}
665
a23fa047
DC
666/*
667 * XXX: this only supports reading and writing to version 4 superblock fields.
668 * V5 superblocks always define certain V4 feature bits - they are blocked from
669 * being changed if a V5 sb is detected, but otherwise v5 superblock features
670 * are not handled here.
671 */
4ca431fc
NS
672static int
673version_f(
674 int argc,
675 char **argv)
676{
677 __uint16_t version = 0;
70476e54 678 __uint32_t features = 0;
4ca431fc
NS
679 xfs_agnumber_t ag;
680
681 if (argc == 2) { /* WRITE VERSION */
682
683 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 684 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
685 progname);
686 return 0;
687 }
688
689 /* Logic here derived from the IRIX xfs_chver(1M) script. */
690 if (!strcasecmp(argv[1], "extflg")) {
691 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
692 case XFS_SB_VERSION_1:
693 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
694 break;
695 case XFS_SB_VERSION_2:
696 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
697 break;
698 case XFS_SB_VERSION_3:
699 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
700 break;
701 case XFS_SB_VERSION_4:
5e656dbb 702 if (xfs_sb_version_hasextflgbit(&mp->m_sb))
a23fa047
DC
703 dbprintf(
704 _("unwritten extents flag is already enabled\n"));
4ca431fc
NS
705 else
706 version = mp->m_sb.sb_versionnum |
707 XFS_SB_VERSION_EXTFLGBIT;
708 break;
a23fa047
DC
709 case XFS_SB_VERSION_5:
710 dbprintf(
711 _("unwritten extents always enabled for v5 superblocks.\n"));
712 break;
4ca431fc 713 }
66997473
NS
714 } else if (!strcasecmp(argv[1], "log2")) {
715 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
716 case XFS_SB_VERSION_1:
717 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
718 break;
719 case XFS_SB_VERSION_2:
720 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
721 break;
722 case XFS_SB_VERSION_3:
723 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
724 break;
725 case XFS_SB_VERSION_4:
5e656dbb 726 if (xfs_sb_version_haslogv2(&mp->m_sb))
a23fa047
DC
727 dbprintf(
728 _("version 2 log format is already in use\n"));
66997473
NS
729 else
730 version = mp->m_sb.sb_versionnum |
731 XFS_SB_VERSION_LOGV2BIT;
732 break;
a23fa047
DC
733 case XFS_SB_VERSION_5:
734 dbprintf(
735 _("Version 2 logs always enabled for v5 superblocks.\n"));
736 break;
66997473 737 }
a23fa047
DC
738 } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) {
739 dbprintf(
740 _("%s: Cannot change %s on v5 superblocks.\n"),
741 progname, argv[1]);
742 return 0;
70476e54 743 } else if (!strcasecmp(argv[1], "attr1")) {
a23fa047 744
5e656dbb 745 if (xfs_sb_version_hasattr2(&mp->m_sb)) {
70476e54
NS
746 if (!(mp->m_sb.sb_features2 &=
747 ~XFS_SB_VERSION2_ATTR2BIT))
748 mp->m_sb.sb_versionnum &=
749 ~XFS_SB_VERSION_MOREBITSBIT;
750 }
5e656dbb 751 xfs_sb_version_addattr(&mp->m_sb);
70476e54
NS
752 version = mp->m_sb.sb_versionnum;
753 features = mp->m_sb.sb_features2;
754 } else if (!strcasecmp(argv[1], "attr2")) {
5e656dbb
BN
755 xfs_sb_version_addattr(&mp->m_sb);
756 xfs_sb_version_addattr2(&mp->m_sb);
22bc10ed
AM
757 version = mp->m_sb.sb_versionnum;
758 features = mp->m_sb.sb_features2;
759 } else if (!strcasecmp(argv[1], "projid32bit")) {
760 xfs_sb_version_addprojid32bit(&mp->m_sb);
70476e54
NS
761 version = mp->m_sb.sb_versionnum;
762 features = mp->m_sb.sb_features2;
4ca431fc 763 } else {
9ee7055c 764 dbprintf(_("%s: invalid version change command \"%s\"\n"),
4ca431fc
NS
765 progname, argv[1]);
766 return 0;
767 }
768
769 if (version) {
9ee7055c 770 dbprintf(_("writing all SBs\n"));
4ca431fc 771 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 772 if (!do_version(ag, version, features)) {
9ee7055c
AM
773 dbprintf(_("failed to set versionnum "
774 "in AG %d\n"), ag);
4ca431fc
NS
775 break;
776 }
777 mp->m_sb.sb_versionnum = version;
70476e54 778 mp->m_sb.sb_features2 = features;
4ca431fc
NS
779 }
780 }
d2df702b
NS
781
782 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
783 char *sp;
784
785 version = mp->m_sb.sb_versionnum;
786 features = mp->m_sb.sb_features2;
787 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
788 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
789 }
790
9ee7055c 791 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum,
ca86e759 792 mp->m_sb.sb_features2, version_string(&mp->m_sb));
d2df702b
NS
793
794 if (argc == 3) { /* now reset... */
795 mp->m_sb.sb_versionnum = version;
796 mp->m_sb.sb_features2 = features;
797 return 0;
798 }
799
4ca431fc
NS
800 return 0;
801}