]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/sb.c
xfsprogs: Add verifiers to libxfs buffer interfaces.
[thirdparty/xfsprogs-dev.git] / db / sb.c
1 /*
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #include <xfs/libxfs.h>
20 #include <xfs/libxlog.h>
21 #include "command.h"
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"
30 #include "init.h"
31
32 static int sb_f(int argc, char **argv);
33 static void sb_help(void);
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);
40
41 static const cmdinfo_t sb_cmd =
42 { "sb", NULL, sb_f, 0, 1, 1, N_("[agno]"),
43 N_("set current address to sb header"), sb_help };
44 static const cmdinfo_t uuid_cmd =
45 { "uuid", NULL, uuid_f, 0, 1, 1, N_("[uuid]"),
46 N_("write/print FS uuid"), uuid_help };
47 static const cmdinfo_t label_cmd =
48 { "label", NULL, label_f, 0, 1, 1, N_("[label]"),
49 N_("write/print FS label"), label_help };
50 static const cmdinfo_t version_cmd =
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 };
53
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 }
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 },
99 { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE },
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 },
107 { "logsectlog", FLDT_UINT8D, OI(OFF(logsectlog)), C1, 0, TYP_NONE },
108 { "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE },
109 { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE },
110 { "features2", FLDT_UINT32X, OI(OFF(features2)), C1, 0, TYP_NONE },
111 { "bad_features2", FLDT_UINT32X, OI(OFF(bad_features2)), C1, 0, TYP_NONE },
112 { NULL }
113 };
114
115 const field_t sb_hfld[] = {
116 { "", FLDT_SB, OI(0), C1, 0, TYP_NONE },
117 { NULL }
118 };
119
120 static void
121 sb_help(void)
122 {
123 dbprintf(_(
124 "\n"
125 " set allocation group superblock\n"
126 "\n"
127 " Example:\n"
128 "\n"
129 " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
130 "\n"
131 " Located in the first sector of each allocation group, the superblock\n"
132 " contains the base information for the filesystem.\n"
133 " The superblock in allocation group 0 is the primary. The copies in the\n"
134 " remaining allocation groups only serve as backup for filesystem recovery.\n"
135 " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
136 "\n"
137 ));
138 }
139
140 static int
141 sb_f(
142 int argc,
143 char **argv)
144 {
145 xfs_agnumber_t agno;
146 char *p;
147
148 if (argc > 1) {
149 agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0);
150 if (*p != '\0' || agno >= mp->m_sb.sb_agcount) {
151 dbprintf(_("bad allocation group number %s\n"), argv[1]);
152 return 0;
153 }
154 cur_agno = agno;
155 } else if (cur_agno == NULLAGNUMBER)
156 cur_agno = 0;
157 ASSERT(typtab[TYP_SB].typnm == TYP_SB);
158 set_cur(&typtab[TYP_SB],
159 XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR),
160 XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL);
161 return 0;
162 }
163
164 /*ARGSUSED*/
165 int
166 sb_size(
167 void *obj,
168 int startoff,
169 int idx)
170 {
171 return bitize(mp->m_sb.sb_sectsize);
172 }
173
174 static int
175 get_sb(xfs_agnumber_t agno, xfs_sb_t *sb)
176 {
177 push_cur();
178 set_cur(&typtab[TYP_SB],
179 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
180 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
181
182 if (!iocur_top->data) {
183 dbprintf(_("can't read superblock for AG %u\n"), agno);
184 pop_cur();
185 return 0;
186 }
187
188 libxfs_sb_from_disk(sb, iocur_top->data);
189
190 if (sb->sb_magicnum != XFS_SB_MAGIC) {
191 dbprintf(_("bad sb magic # %#x in AG %u\n"),
192 sb->sb_magicnum, agno);
193 return 0;
194 }
195 if (!xfs_sb_good_version(sb)) {
196 dbprintf(_("bad sb version # %#x in AG %u\n"),
197 sb->sb_versionnum, agno);
198 return 0;
199 }
200 if (agno == 0 && sb->sb_inprogress != 0) {
201 dbprintf(_("mkfs not completed successfully\n"));
202 return 0;
203 }
204 return 1;
205 }
206
207 /* workaround craziness in the xlog routines */
208 int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
209 {
210 return 0;
211 }
212
213 int
214 sb_logcheck(void)
215 {
216 struct xlog log;
217 xfs_daddr_t head_blk, tail_blk;
218
219 if (mp->m_sb.sb_logstart) {
220 if (x.logdev && x.logdev != x.ddev) {
221 dbprintf(_("aborting - external log specified for FS "
222 "with an internal log\n"));
223 return 0;
224 }
225 } else {
226 if (!x.logdev || (x.logdev == x.ddev)) {
227 dbprintf(_("aborting - no external log specified for FS "
228 "with an external log\n"));
229 return 0;
230 }
231 }
232
233 memset(&log, 0, sizeof(log));
234 libxfs_buftarg_init(mp, x.ddev, x.logdev, x.rtdev);
235 x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
236 x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
237 x.lbsize = BBSIZE;
238 if (xfs_sb_version_hassector(&mp->m_sb))
239 x.lbsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT);
240
241 log.l_dev = mp->m_logdev_targp;
242 log.l_logsize = BBTOB(log.l_logBBsize);
243 log.l_logBBsize = x.logBBsize;
244 log.l_logBBstart = x.logBBstart;
245 log.l_sectBBsize = BTOBB(x.lbsize);
246 log.l_mp = mp;
247
248 if (xlog_find_tail(&log, &head_blk, &tail_blk)) {
249 dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
250 return 0;
251 }
252 if (head_blk != tail_blk) {
253 dbprintf(_(
254 "ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
255 "be replayed. Mount the filesystem to replay the log, and unmount it before\n"
256 "re-running %s. If you are unable to mount the filesystem, then use\n"
257 "the xfs_repair -L option to destroy the log and attempt a repair.\n"
258 "Note that destroying the log may cause corruption -- please attempt a mount\n"
259 "of the filesystem before doing this.\n"), progname);
260 return 0;
261 }
262 return 1;
263 }
264
265 static int
266 sb_logzero(uuid_t *uuidp)
267 {
268 if (!sb_logcheck())
269 return 0;
270
271 dbprintf(_("Clearing log and setting UUID\n"));
272
273 if (libxfs_log_clear(mp->m_logdev_targp,
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,
277 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
278 mp->m_sb.sb_logsunit, XLOG_FMT)) {
279 dbprintf(_("ERROR: cannot clear the log\n"));
280 return 0;
281 }
282 return 1;
283 }
284
285
286 static void
287 uuid_help(void)
288 {
289 dbprintf(_(
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"
307 ));
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));
326 libxfs_sb_to_disk(iocur_top->data, &tsb, XFS_SB_UUID);
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) {
342 dbprintf(_("invalid parameters\n"));
343 return 0;
344 }
345
346 if (argc == 2) { /* WRITE UUID */
347
348 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
349 dbprintf(_("%s: not in expert mode, writing disabled\n"),
350 progname);
351 return 0;
352 }
353
354 if (!strcasecmp(argv[1], "generate")) {
355 platform_uuid_generate(&uu);
356 } else if (!strcasecmp(argv[1], "nil")) {
357 platform_uuid_clear(&uu);
358 } else if (!strcasecmp(argv[1], "rewrite")) {
359 uup = do_uuid(0, NULL);
360 if (!uup) {
361 dbprintf(_("failed to read UUID from AG 0\n"));
362 return 0;
363 }
364 memcpy(&uu, uup, sizeof(uuid_t));
365 platform_uuid_unparse(&uu, bp);
366 dbprintf(_("old UUID = %s\n"), bp);
367 } else {
368 if (platform_uuid_parse(argv[1], &uu)) {
369 dbprintf(_("invalid UUID\n"));
370 return 0;
371 }
372 }
373
374 /* clear the log (setting uuid) if it's not dirty */
375 if (!sb_logzero(&uu))
376 return 0;
377
378 dbprintf(_("writing all SBs\n"));
379 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
380 if (!do_uuid(agno, &uu)) {
381 dbprintf(_("failed to set UUID in AG %d\n"), agno);
382 break;
383 }
384
385 platform_uuid_unparse(&uu, bp);
386 dbprintf(_("new UUID = %s\n"), bp);
387 return 0;
388
389 } else { /* READ+CHECK UUID */
390
391 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
392 uup = do_uuid(agno, NULL);
393 if (!uup) {
394 dbprintf(_("failed to read UUID from AG %d\n"),
395 agno);
396 return 0;
397 }
398 if (agno) {
399 if (memcmp(&uu, uup, sizeof(uuid_t))) {
400 dbprintf(_("warning: UUID in AG %d "
401 "differs to the primary SB\n"),
402 agno);
403 break;
404 }
405 } else {
406 memcpy(&uu, uup, sizeof(uuid_t));
407 }
408 }
409 if (mp->m_sb.sb_logstart) {
410 if (x.logdev && x.logdev != x.ddev)
411 dbprintf(_("warning - external log specified "
412 "for FS with an internal log\n"));
413 } else if (!x.logdev || (x.logdev == x.ddev)) {
414 dbprintf(_("warning - no external log specified "
415 "for FS with an external log\n"));
416 }
417
418 platform_uuid_unparse(&uu, bp);
419 dbprintf(_("UUID = %s\n"), bp);
420 }
421
422 return 0;
423 }
424
425
426 static void
427 label_help(void)
428 {
429 dbprintf(_(
430 "\n"
431 " write/print FS label\n"
432 "\n"
433 " Example:\n"
434 "\n"
435 " 'label' - print label\n"
436 " 'label 123456789012' - write label\n"
437 " 'label --' - write an empty label\n"
438 "\n"
439 "The print function checks the label in each SB and will warn if the labels\n"
440 "differ between AGs. The write commands will set the label in all AGs to the\n"
441 "specified value. The maximum length of a label is 12 characters - use of a\n"
442 "longer label will result in truncation and a warning will be issued.\n"
443 "\n"
444 ));
445 }
446
447 static char *
448 do_label(xfs_agnumber_t agno, char *label)
449 {
450 size_t len;
451 xfs_sb_t tsb;
452 static char lbl[sizeof(tsb.sb_fname) + 1];
453
454 if (!get_sb(agno, &tsb))
455 return NULL;
456
457 memset(&lbl[0], 0, sizeof(lbl));
458
459 if (!label) { /* get label */
460 pop_cur();
461 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
462 return &lbl[0];
463 }
464 /* set label */
465 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
466 if (agno == 0)
467 dbprintf(_("%s: truncating label length from %d to %d\n"),
468 progname, (int)len, (int)sizeof(tsb.sb_fname));
469 len = sizeof(tsb.sb_fname);
470 }
471 if ( len == 2 &&
472 (strcmp(label, "\"\"") == 0 ||
473 strcmp(label, "''") == 0 ||
474 strcmp(label, "--") == 0) )
475 label[0] = label[1] = '\0';
476 memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname));
477 memcpy(&tsb.sb_fname, label, len);
478 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
479 libxfs_sb_to_disk(iocur_top->data, &tsb, XFS_SB_FNAME);
480 write_cur();
481 return &lbl[0];
482 }
483
484 static int
485 label_f(
486 int argc,
487 char **argv)
488 {
489 char *p = NULL;
490 xfs_sb_t sb;
491 xfs_agnumber_t ag;
492
493 if (argc != 1 && argc != 2) {
494 dbprintf(_("invalid parameters\n"));
495 return 0;
496 }
497
498 if (argc == 2) { /* WRITE LABEL */
499
500 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
501 dbprintf(_("%s: not in expert mode, writing disabled\n"),
502 progname);
503 return 0;
504 }
505
506 dbprintf(_("writing all SBs\n"));
507 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
508 if ((p = do_label(ag, argv[1])) == NULL) {
509 dbprintf(_("failed to set label in AG %d\n"), ag);
510 break;
511 }
512 dbprintf(_("new label = \"%s\"\n"), p);
513
514 } else { /* READ LABEL */
515
516 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
517 p = do_label(ag, NULL);
518 if (!p) {
519 dbprintf(_("failed to read label in AG %d\n"), ag);
520 return 0;
521 }
522 if (!ag)
523 memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname));
524 else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname)))
525 dbprintf(_("warning: AG %d label differs\n"), ag);
526 }
527 dbprintf(_("label = \"%s\"\n"), p);
528 }
529 return 0;
530 }
531
532
533 static void
534 version_help(void)
535 {
536 dbprintf(_(
537 "\n"
538 " set/print feature bits in sb version\n"
539 "\n"
540 " Example:\n"
541 "\n"
542 " 'version' - print current feature bits\n"
543 " 'version extflg' - enable unwritten extents\n"
544 " 'version attr1' - enable v1 inline extended attributes\n"
545 " 'version attr2' - enable v2 inline extended attributes\n"
546 " 'version log2' - enable v2 log format\n"
547 "\n"
548 "The version function prints currently enabled features for a filesystem\n"
549 "according to the version field of its primary superblock.\n"
550 "It can also be used to enable selected features, such as support for\n"
551 "unwritten extents. The updated version is written into all AGs.\n"
552 "\n"
553 ));
554 }
555
556 static int
557 do_version(xfs_agnumber_t agno, __uint16_t version, __uint32_t features)
558 {
559 xfs_sb_t tsb;
560 __int64_t fields = 0;
561
562 if (!get_sb(agno, &tsb))
563 return 0;
564
565 if (xfs_sb_has_mismatched_features2(&tsb)) {
566 dbprintf(_("Superblock has mismatched features2 fields, "
567 "skipping modification\n"));
568 return 0;
569 }
570
571 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
572 !xfs_sb_version_haslogv2(&tsb)) {
573 tsb.sb_logsunit = 1;
574 fields |= (1LL << XFS_SBS_LOGSUNIT);
575 }
576
577 tsb.sb_versionnum = version;
578 tsb.sb_features2 = features;
579 tsb.sb_bad_features2 = features;
580 fields |= XFS_SB_VERSIONNUM | XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
581 libxfs_sb_to_disk(iocur_top->data, &tsb, fields);
582 write_cur();
583 return 1;
584 }
585
586 static char *
587 version_string(
588 xfs_sb_t *sbp)
589 {
590 static char s[1024];
591
592 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
593 strcpy(s, "V1");
594 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
595 strcpy(s, "V2");
596 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
597 strcpy(s, "V3");
598 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
599 strcpy(s, "V4");
600
601 if (xfs_sb_version_hasattr(sbp))
602 strcat(s, ",ATTR");
603 if (xfs_sb_version_hasnlink(sbp))
604 strcat(s, ",NLINK");
605 if (xfs_sb_version_hasquota(sbp))
606 strcat(s, ",QUOTA");
607 if (xfs_sb_version_hasalign(sbp))
608 strcat(s, ",ALIGN");
609 if (xfs_sb_version_hasdalign(sbp))
610 strcat(s, ",DALIGN");
611 if (xfs_sb_version_hasshared(sbp))
612 strcat(s, ",SHARED");
613 if (xfs_sb_version_hasdirv2(sbp))
614 strcat(s, ",DIRV2");
615 if (xfs_sb_version_haslogv2(sbp))
616 strcat(s, ",LOGV2");
617 if (xfs_sb_version_hasextflgbit(sbp))
618 strcat(s, ",EXTFLG");
619 if (xfs_sb_version_hassector(sbp))
620 strcat(s, ",SECTOR");
621 if (xfs_sb_version_hasasciici(sbp))
622 strcat(s, ",ASCII_CI");
623 if (xfs_sb_version_hasmorebits(sbp))
624 strcat(s, ",MOREBITS");
625 if (xfs_sb_version_hasattr2(sbp))
626 strcat(s, ",ATTR2");
627 if (xfs_sb_version_haslazysbcount(sbp))
628 strcat(s, ",LAZYSBCOUNT");
629 if (xfs_sb_version_hasprojid32bit(sbp))
630 strcat(s, ",PROJID32BIT");
631 return s;
632 }
633
634 static int
635 version_f(
636 int argc,
637 char **argv)
638 {
639 __uint16_t version = 0;
640 __uint32_t features = 0;
641 xfs_agnumber_t ag;
642
643 if (argc == 2) { /* WRITE VERSION */
644
645 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
646 dbprintf(_("%s: not in expert mode, writing disabled\n"),
647 progname);
648 return 0;
649 }
650
651 /* Logic here derived from the IRIX xfs_chver(1M) script. */
652 if (!strcasecmp(argv[1], "extflg")) {
653 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
654 case XFS_SB_VERSION_1:
655 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
656 break;
657 case XFS_SB_VERSION_2:
658 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
659 break;
660 case XFS_SB_VERSION_3:
661 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
662 break;
663 case XFS_SB_VERSION_4:
664 if (xfs_sb_version_hasextflgbit(&mp->m_sb))
665 dbprintf(_("unwritten extents flag"
666 " is already enabled\n"));
667 else
668 version = mp->m_sb.sb_versionnum |
669 XFS_SB_VERSION_EXTFLGBIT;
670 break;
671 }
672 } else if (!strcasecmp(argv[1], "log2")) {
673 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
674 case XFS_SB_VERSION_1:
675 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
676 break;
677 case XFS_SB_VERSION_2:
678 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
679 break;
680 case XFS_SB_VERSION_3:
681 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
682 break;
683 case XFS_SB_VERSION_4:
684 if (xfs_sb_version_haslogv2(&mp->m_sb))
685 dbprintf(_("version 2 log format"
686 " is already in use\n"));
687 else
688 version = mp->m_sb.sb_versionnum |
689 XFS_SB_VERSION_LOGV2BIT;
690 break;
691 }
692 } else if (!strcasecmp(argv[1], "attr1")) {
693 if (xfs_sb_version_hasattr2(&mp->m_sb)) {
694 if (!(mp->m_sb.sb_features2 &=
695 ~XFS_SB_VERSION2_ATTR2BIT))
696 mp->m_sb.sb_versionnum &=
697 ~XFS_SB_VERSION_MOREBITSBIT;
698 }
699 xfs_sb_version_addattr(&mp->m_sb);
700 version = mp->m_sb.sb_versionnum;
701 features = mp->m_sb.sb_features2;
702 } else if (!strcasecmp(argv[1], "attr2")) {
703 xfs_sb_version_addattr(&mp->m_sb);
704 xfs_sb_version_addattr2(&mp->m_sb);
705 version = mp->m_sb.sb_versionnum;
706 features = mp->m_sb.sb_features2;
707 } else if (!strcasecmp(argv[1], "projid32bit")) {
708 xfs_sb_version_addprojid32bit(&mp->m_sb);
709 version = mp->m_sb.sb_versionnum;
710 features = mp->m_sb.sb_features2;
711 } else {
712 dbprintf(_("%s: invalid version change command \"%s\"\n"),
713 progname, argv[1]);
714 return 0;
715 }
716
717 if (version) {
718 dbprintf(_("writing all SBs\n"));
719 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
720 if (!do_version(ag, version, features)) {
721 dbprintf(_("failed to set versionnum "
722 "in AG %d\n"), ag);
723 break;
724 }
725 mp->m_sb.sb_versionnum = version;
726 mp->m_sb.sb_features2 = features;
727 }
728 }
729
730 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
731 char *sp;
732
733 version = mp->m_sb.sb_versionnum;
734 features = mp->m_sb.sb_features2;
735 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
736 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
737 }
738
739 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum,
740 mp->m_sb.sb_features2, version_string(&mp->m_sb));
741
742 if (argc == 3) { /* now reset... */
743 mp->m_sb.sb_versionnum = version;
744 mp->m_sb.sb_features2 = features;
745 return 0;
746 }
747
748 return 0;
749 }