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