]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
xfsprogs: convert to SPDX license tags
[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 */
999f0b9c
DC
212int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
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");
5e656dbb 661 if (xfs_sb_version_hasextflgbit(sbp))
4ca431fc 662 strcat(s, ",EXTFLG");
5e656dbb 663 if (xfs_sb_version_hassector(sbp))
4ca431fc 664 strcat(s, ",SECTOR");
51ca7008
BN
665 if (xfs_sb_version_hasasciici(sbp))
666 strcat(s, ",ASCII_CI");
5e656dbb 667 if (xfs_sb_version_hasmorebits(sbp))
ca86e759 668 strcat(s, ",MOREBITS");
5e656dbb 669 if (xfs_sb_version_hasattr2(sbp))
ca86e759 670 strcat(s, ",ATTR2");
5e656dbb 671 if (xfs_sb_version_haslazysbcount(sbp))
cdded3d8 672 strcat(s, ",LAZYSBCOUNT");
22bc10ed
AM
673 if (xfs_sb_version_hasprojid32bit(sbp))
674 strcat(s, ",PROJID32BIT");
a23fa047
DC
675 if (xfs_sb_version_hascrc(sbp))
676 strcat(s, ",CRC");
42737f1a
MT
677 if (xfs_sb_version_hasftype(sbp))
678 strcat(s, ",FTYPE");
b7fc3b36
ES
679 if (xfs_sb_version_hasfinobt(sbp))
680 strcat(s, ",FINOBT");
b8db0171
BF
681 if (xfs_sb_version_hassparseinodes(sbp))
682 strcat(s, ",SPARSE_INODES");
9c4e12fb
ES
683 if (xfs_sb_version_hasmetauuid(sbp))
684 strcat(s, ",META_UUID");
f810b1bc
ZL
685 if (xfs_sb_version_hasrmapbt(sbp))
686 strcat(s, ",RMAPBT");
9fb2cb27
DW
687 if (xfs_sb_version_hasreflink(sbp))
688 strcat(s, ",REFLINK");
4ca431fc
NS
689 return s;
690}
691
a23fa047
DC
692/*
693 * XXX: this only supports reading and writing to version 4 superblock fields.
694 * V5 superblocks always define certain V4 feature bits - they are blocked from
695 * being changed if a V5 sb is detected, but otherwise v5 superblock features
696 * are not handled here.
697 */
4ca431fc
NS
698static int
699version_f(
700 int argc,
701 char **argv)
702{
14f8b681
DW
703 uint16_t version = 0;
704 uint32_t features = 0;
4ca431fc
NS
705 xfs_agnumber_t ag;
706
707 if (argc == 2) { /* WRITE VERSION */
708
709 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 710 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
711 progname);
712 return 0;
713 }
714
715 /* Logic here derived from the IRIX xfs_chver(1M) script. */
716 if (!strcasecmp(argv[1], "extflg")) {
717 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
718 case XFS_SB_VERSION_1:
719 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
720 break;
721 case XFS_SB_VERSION_2:
722 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
723 break;
724 case XFS_SB_VERSION_3:
725 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
726 break;
727 case XFS_SB_VERSION_4:
5e656dbb 728 if (xfs_sb_version_hasextflgbit(&mp->m_sb))
a23fa047
DC
729 dbprintf(
730 _("unwritten extents flag is already enabled\n"));
4ca431fc
NS
731 else
732 version = mp->m_sb.sb_versionnum |
733 XFS_SB_VERSION_EXTFLGBIT;
734 break;
a23fa047
DC
735 case XFS_SB_VERSION_5:
736 dbprintf(
737 _("unwritten extents always enabled for v5 superblocks.\n"));
738 break;
4ca431fc 739 }
66997473
NS
740 } else if (!strcasecmp(argv[1], "log2")) {
741 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
742 case XFS_SB_VERSION_1:
743 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
744 break;
745 case XFS_SB_VERSION_2:
746 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
747 break;
748 case XFS_SB_VERSION_3:
749 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
750 break;
751 case XFS_SB_VERSION_4:
5e656dbb 752 if (xfs_sb_version_haslogv2(&mp->m_sb))
a23fa047
DC
753 dbprintf(
754 _("version 2 log format is already in use\n"));
66997473
NS
755 else
756 version = mp->m_sb.sb_versionnum |
757 XFS_SB_VERSION_LOGV2BIT;
758 break;
a23fa047
DC
759 case XFS_SB_VERSION_5:
760 dbprintf(
761 _("Version 2 logs always enabled for v5 superblocks.\n"));
762 break;
66997473 763 }
a23fa047
DC
764 } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) {
765 dbprintf(
766 _("%s: Cannot change %s on v5 superblocks.\n"),
767 progname, argv[1]);
768 return 0;
70476e54 769 } else if (!strcasecmp(argv[1], "attr1")) {
a23fa047 770
5e656dbb 771 if (xfs_sb_version_hasattr2(&mp->m_sb)) {
70476e54
NS
772 if (!(mp->m_sb.sb_features2 &=
773 ~XFS_SB_VERSION2_ATTR2BIT))
774 mp->m_sb.sb_versionnum &=
775 ~XFS_SB_VERSION_MOREBITSBIT;
776 }
5e656dbb 777 xfs_sb_version_addattr(&mp->m_sb);
70476e54
NS
778 version = mp->m_sb.sb_versionnum;
779 features = mp->m_sb.sb_features2;
780 } else if (!strcasecmp(argv[1], "attr2")) {
5e656dbb
BN
781 xfs_sb_version_addattr(&mp->m_sb);
782 xfs_sb_version_addattr2(&mp->m_sb);
22bc10ed
AM
783 version = mp->m_sb.sb_versionnum;
784 features = mp->m_sb.sb_features2;
785 } else if (!strcasecmp(argv[1], "projid32bit")) {
786 xfs_sb_version_addprojid32bit(&mp->m_sb);
70476e54
NS
787 version = mp->m_sb.sb_versionnum;
788 features = mp->m_sb.sb_features2;
4ca431fc 789 } else {
9ee7055c 790 dbprintf(_("%s: invalid version change command \"%s\"\n"),
4ca431fc
NS
791 progname, argv[1]);
792 return 0;
793 }
794
795 if (version) {
9ee7055c 796 dbprintf(_("writing all SBs\n"));
4ca431fc 797 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 798 if (!do_version(ag, version, features)) {
9ee7055c
AM
799 dbprintf(_("failed to set versionnum "
800 "in AG %d\n"), ag);
4ca431fc
NS
801 break;
802 }
803 mp->m_sb.sb_versionnum = version;
70476e54 804 mp->m_sb.sb_features2 = features;
4ca431fc
NS
805 }
806 }
d2df702b
NS
807
808 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
809 char *sp;
810
811 version = mp->m_sb.sb_versionnum;
812 features = mp->m_sb.sb_features2;
813 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
814 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
815 }
816
9ee7055c 817 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum,
ca86e759 818 mp->m_sb.sb_features2, version_string(&mp->m_sb));
d2df702b
NS
819
820 if (argc == 3) { /* now reset... */
821 mp->m_sb.sb_versionnum = version;
822 mp->m_sb.sb_features2 = features;
823 return 0;
824 }
825
4ca431fc
NS
826 return 0;
827}