]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
0d3e0b37 | 2 | * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. |
2bd0ea18 NS |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of version 2 of the GNU General Public License as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it would be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
11 | * | |
12 | * Further, this software is distributed without any warranty that it is | |
13 | * free of the rightful claim of any third person regarding infringement | |
14 | * or the like. Any license provided herein, whether implied or | |
15 | * otherwise, applies only to this software file. Patent licenses, if | |
16 | * any, provided herein do not apply to combinations of this program with | |
17 | * other software, or any other product whatsoever. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; if not, write the Free Software Foundation, Inc., 59 | |
21 | * Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
22 | * | |
23 | * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, | |
24 | * Mountain View, CA 94043, or: | |
25 | * | |
26 | * http://www.sgi.com | |
27 | * | |
28 | * For further information regarding this notice, see: | |
29 | * | |
30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ | |
31 | */ | |
32 | ||
33 | #include <libxfs.h> | |
4ca431fc | 34 | #include <libxlog.h> |
2bd0ea18 | 35 | #include "command.h" |
2bd0ea18 NS |
36 | #include "type.h" |
37 | #include "faddr.h" | |
38 | #include "fprint.h" | |
39 | #include "field.h" | |
40 | #include "io.h" | |
41 | #include "sb.h" | |
42 | #include "bit.h" | |
43 | #include "output.h" | |
4ca431fc | 44 | #include "init.h" |
2bd0ea18 NS |
45 | |
46 | static int sb_f(int argc, char **argv); | |
47 | static void sb_help(void); | |
4ca431fc NS |
48 | static int uuid_f(int argc, char **argv); |
49 | static void uuid_help(void); | |
50 | static int label_f(int argc, char **argv); | |
51 | static void label_help(void); | |
52 | static int version_f(int argc, char **argv); | |
53 | static void version_help(void); | |
2bd0ea18 NS |
54 | |
55 | static const cmdinfo_t sb_cmd = | |
56 | { "sb", NULL, sb_f, 0, 1, 1, "[agno]", | |
57 | "set current address to sb header", sb_help }; | |
4ca431fc NS |
58 | static const cmdinfo_t uuid_cmd = |
59 | { "uuid", NULL, uuid_f, 0, 1, 1, "[uuid]", | |
60 | "write/print FS uuid", uuid_help }; | |
61 | static const cmdinfo_t label_cmd = | |
62 | { "label", NULL, label_f, 0, 1, 1, "[label]", | |
63 | "write/print FS label", label_help }; | |
64 | static const cmdinfo_t version_cmd = | |
65 | { "version", NULL, version_f, 0, 1, 1, "[feature]", | |
66 | "set feature bit(s) in the sb version field", version_help }; | |
2bd0ea18 | 67 | |
4ca431fc NS |
68 | void |
69 | sb_init(void) | |
70 | { | |
71 | add_command(&sb_cmd); | |
72 | add_command(&uuid_cmd); | |
73 | add_command(&label_cmd); | |
74 | add_command(&version_cmd); | |
75 | } | |
2bd0ea18 NS |
76 | |
77 | #define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f)) | |
78 | #define SZC(f) szcount(xfs_sb_t, sb_ ## f) | |
79 | const field_t sb_flds[] = { | |
80 | { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, | |
81 | { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE }, | |
82 | { "dblocks", FLDT_DRFSBNO, OI(OFF(dblocks)), C1, 0, TYP_NONE }, | |
83 | { "rblocks", FLDT_DRFSBNO, OI(OFF(rblocks)), C1, 0, TYP_NONE }, | |
84 | { "rextents", FLDT_DRTBNO, OI(OFF(rextents)), C1, 0, TYP_NONE }, | |
85 | { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, | |
86 | { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG }, | |
87 | { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE }, | |
88 | { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE }, | |
89 | { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE }, | |
90 | { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE }, | |
91 | { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE }, | |
92 | { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE }, | |
93 | { "rbmblocks", FLDT_EXTLEN, OI(OFF(rbmblocks)), C1, 0, TYP_NONE }, | |
94 | { "logblocks", FLDT_EXTLEN, OI(OFF(logblocks)), C1, 0, TYP_NONE }, | |
95 | { "versionnum", FLDT_UINT16X, OI(OFF(versionnum)), C1, 0, TYP_NONE }, | |
96 | { "sectsize", FLDT_UINT16D, OI(OFF(sectsize)), C1, 0, TYP_NONE }, | |
97 | { "inodesize", FLDT_UINT16D, OI(OFF(inodesize)), C1, 0, TYP_NONE }, | |
98 | { "inopblock", FLDT_UINT16D, OI(OFF(inopblock)), C1, 0, TYP_NONE }, | |
99 | { "fname", FLDT_CHARNS, OI(OFF(fname)), CI(SZC(fname)), 0, TYP_NONE }, | |
100 | { "blocklog", FLDT_UINT8D, OI(OFF(blocklog)), C1, 0, TYP_NONE }, | |
101 | { "sectlog", FLDT_UINT8D, OI(OFF(sectlog)), C1, 0, TYP_NONE }, | |
102 | { "inodelog", FLDT_UINT8D, OI(OFF(inodelog)), C1, 0, TYP_NONE }, | |
103 | { "inopblog", FLDT_UINT8D, OI(OFF(inopblog)), C1, 0, TYP_NONE }, | |
104 | { "agblklog", FLDT_UINT8D, OI(OFF(agblklog)), C1, 0, TYP_NONE }, | |
105 | { "rextslog", FLDT_UINT8D, OI(OFF(rextslog)), C1, 0, TYP_NONE }, | |
106 | { "inprogress", FLDT_UINT8D, OI(OFF(inprogress)), C1, 0, TYP_NONE }, | |
107 | { "imax_pct", FLDT_UINT8D, OI(OFF(imax_pct)), C1, 0, TYP_NONE }, | |
108 | { "icount", FLDT_UINT64D, OI(OFF(icount)), C1, 0, TYP_NONE }, | |
109 | { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE }, | |
110 | { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE }, | |
111 | { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE }, | |
112 | { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE }, | |
b36eef04 | 113 | { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE }, |
2bd0ea18 NS |
114 | { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE }, |
115 | { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE }, | |
116 | { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE }, | |
117 | { "inoalignmt", FLDT_EXTLEN, OI(OFF(inoalignmt)), C1, 0, TYP_NONE }, | |
118 | { "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE }, | |
119 | { "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE }, | |
120 | { "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE }, | |
9440d84d NS |
121 | { "logsectlog", FLDT_UINT8D, OI(OFF(logsectlog)), C1, 0, TYP_NONE }, |
122 | { "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE }, | |
73bf5988 | 123 | { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE }, |
2bd0ea18 NS |
124 | { NULL } |
125 | }; | |
126 | ||
4ca431fc NS |
127 | const field_t sb_hfld[] = { |
128 | { "", FLDT_SB, OI(0), C1, 0, TYP_NONE }, | |
129 | { NULL } | |
130 | }; | |
131 | ||
2bd0ea18 NS |
132 | static void |
133 | sb_help(void) | |
134 | { | |
135 | dbprintf( | |
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" | |
149 | ); | |
150 | } | |
151 | ||
152 | static int | |
153 | sb_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) { | |
163 | dbprintf("bad allocation group number %s\n", argv[1]); | |
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*/ |
177 | int | |
178 | sb_size( | |
179 | void *obj, | |
180 | int startoff, | |
181 | int idx) | |
182 | { | |
183 | return bitize(mp->m_sb.sb_sectsize); | |
184 | } | |
4ca431fc NS |
185 | |
186 | static int | |
187 | get_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); | |
193 | ||
194 | if (!iocur_top->data) { | |
195 | dbprintf("can't read superblock for AG %u\n", agno); | |
196 | pop_cur(); | |
197 | return 0; | |
198 | } | |
199 | ||
200 | libxfs_xlate_sb(iocur_top->data, sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); | |
201 | ||
202 | if (sb->sb_magicnum != XFS_SB_MAGIC) { | |
203 | dbprintf("bad sb magic # %#x in AG %u\n", | |
204 | sb->sb_magicnum, agno); | |
205 | return 0; | |
206 | } | |
207 | if (!XFS_SB_GOOD_VERSION(sb)) { | |
208 | dbprintf("bad sb version # %#x in AG %u\n", | |
209 | sb->sb_versionnum, agno); | |
210 | return 0; | |
211 | } | |
212 | if (agno == 0 && sb->sb_inprogress != 0) { | |
213 | dbprintf("mkfs not completed successfully\n"); | |
214 | return 0; | |
215 | } | |
216 | return 1; | |
217 | } | |
218 | ||
219 | /* workaround craziness in the xlog routines */ | |
220 | int xlog_recover_do_trans(xlog_t *log, xlog_recover_t *t, int p) { return 0; } | |
221 | ||
222 | static int | |
223 | zero_log(uuid_t *uuidp) | |
224 | { | |
225 | xlog_t log; | |
226 | xfs_daddr_t head_blk, tail_blk; | |
227 | ||
228 | if (mp->m_sb.sb_logstart) { | |
229 | if (x.logdev && x.logdev != x.ddev) { | |
230 | dbprintf("aborting - external log specified for FS " | |
231 | "with an internal log\n"); | |
232 | return 0; | |
233 | } | |
234 | } else { | |
235 | if (!x.logdev || (x.logdev == x.ddev)) { | |
236 | dbprintf("aborting - no external log specified for FS " | |
237 | "with an external log\n"); | |
238 | return 0; | |
239 | } | |
240 | } | |
241 | ||
242 | memset(&log, 0, sizeof(log)); | |
243 | if (!x.logdev) | |
244 | x.logdev = x.ddev; | |
245 | x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); | |
246 | x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); | |
247 | log.l_dev = (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev; | |
248 | log.l_logsize = BBTOB(log.l_logBBsize); | |
249 | log.l_logBBsize = x.logBBsize; | |
250 | log.l_logBBstart = x.logBBstart; | |
251 | log.l_mp = mp; | |
252 | ||
253 | if (xlog_find_tail(&log, &head_blk, &tail_blk, 0)) { | |
254 | dbprintf("ERROR: cannot find log head/tail, run xfs_repair\n"); | |
255 | return 0; | |
256 | } | |
257 | if (head_blk != tail_blk) { | |
258 | dbprintf( | |
259 | "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" | |
260 | "be replayed. Mount the filesystem to replay the log, and unmount it before\n" | |
261 | "re-running %s. If you are unable to mount the filesystem, then use\n" | |
262 | "the xfs_repair -L option to destroy the log and attempt a repair.\n" | |
263 | "Note that destroying the log may cause corruption -- please attempt a mount\n" | |
264 | "of the filesystem before doing this.\n", progname); | |
265 | return 0; | |
266 | } | |
267 | ||
268 | dbprintf("Clearing log and setting UUID\n"); | |
269 | ||
270 | if (libxfs_log_clear(log.l_dev, | |
271 | XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), | |
272 | (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), | |
273 | uuidp, | |
274 | XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? 2 : 1, | |
275 | mp->m_sb.sb_logsunit, XLOG_FMT)) { | |
276 | dbprintf("ERROR: cannot clear the log\n"); | |
277 | return 0; | |
278 | } | |
279 | return 1; | |
280 | } | |
281 | ||
282 | ||
283 | static void | |
284 | uuid_help(void) | |
285 | { | |
286 | dbprintf( | |
287 | "\n" | |
288 | " write/print FS uuid\n" | |
289 | "\n" | |
290 | " Example:\n" | |
291 | "\n" | |
292 | " 'uuid' - print UUID\n" | |
293 | " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" | |
294 | " 'uuid generate' - generate and write\n" | |
295 | " 'uuid rewrite' - copy UUID from SB 0\n" | |
296 | "\n" | |
297 | "The print function checks the UUID in each SB and will warn if the UUIDs\n" | |
298 | "differ between AGs (the log is not checked). The write commands will\n" | |
299 | "set the uuid in all AGs to either a specified value, a newly generated\n" | |
300 | "value or the value found in the first superblock (SB 0) respectively.\n" | |
301 | "As a side effect of writing the UUID, the log is cleared (which is fine\n" | |
302 | "on a CLEANLY unmounted FS).\n" | |
303 | "\n" | |
304 | ); | |
305 | } | |
306 | ||
307 | static uuid_t * | |
308 | do_uuid(xfs_agnumber_t agno, uuid_t *uuid) | |
309 | { | |
310 | xfs_sb_t tsb; | |
311 | static uuid_t uu; | |
312 | ||
313 | if (!get_sb(agno, &tsb)) | |
314 | return NULL; | |
315 | ||
316 | if (!uuid) { /* get uuid */ | |
317 | memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t)); | |
318 | pop_cur(); | |
319 | return &uu; | |
320 | } | |
321 | /* set uuid */ | |
322 | memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t)); | |
323 | libxfs_xlate_sb(iocur_top->data, &tsb, -1, ARCH_CONVERT, XFS_SB_UUID); | |
324 | write_cur(); | |
325 | return uuid; | |
326 | } | |
327 | ||
328 | static int | |
329 | uuid_f( | |
330 | int argc, | |
331 | char **argv) | |
332 | { | |
333 | char bp[40]; | |
334 | xfs_agnumber_t agno; | |
335 | uuid_t uu; | |
336 | uuid_t *uup = NULL; | |
337 | ||
338 | if (argc != 1 && argc != 2) { | |
339 | dbprintf("invalid parameters\n"); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | if (argc == 2) { /* WRITE UUID */ | |
344 | ||
345 | if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { | |
346 | dbprintf("%s: not in expert mode, writing disabled\n", | |
347 | progname); | |
348 | return 0; | |
349 | } | |
350 | ||
351 | if (!strcasecmp(argv[1], "generate")) { | |
352 | uuid_generate(uu); | |
353 | } else if (!strcasecmp(argv[1], "nil")) { | |
354 | uuid_clear(uu); | |
355 | } else if (!strcasecmp(argv[1], "rewrite")) { | |
356 | uup = do_uuid(0, NULL); | |
357 | if (!uup) { | |
358 | dbprintf("failed to read UUID from AG 0\n"); | |
359 | return 0; | |
360 | } | |
361 | memcpy(&uu, *uup, sizeof(uuid_t)); | |
362 | uuid_unparse(uu, bp); | |
363 | dbprintf("old UUID = %s\n", bp); | |
364 | } else { | |
365 | if (uuid_parse(argv[1], uu)) { | |
366 | dbprintf("invalid UUID\n"); | |
367 | return 0; | |
368 | } | |
369 | } | |
370 | ||
371 | /* clear the log (setting uuid) if its not dirty */ | |
372 | if (!zero_log(&uu)) | |
373 | return 0; | |
374 | ||
375 | dbprintf("writing all SBs\n"); | |
376 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) | |
377 | if (!do_uuid(agno, &uu)) { | |
378 | dbprintf("failed to set UUID in AG %d\n", agno); | |
379 | break; | |
380 | } | |
381 | ||
382 | uuid_unparse(uu, bp); | |
383 | dbprintf("new UUID = %s\n", bp); | |
384 | return 0; | |
385 | ||
386 | } else { /* READ+CHECK UUID */ | |
387 | ||
388 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { | |
389 | uup = do_uuid(agno, NULL); | |
390 | if (!uup) { | |
391 | dbprintf("failed to read UUID from AG %d\n", | |
392 | agno); | |
393 | return 0; | |
394 | } | |
395 | if (agno) { | |
396 | if (memcmp(&uu, uup, sizeof(uuid_t))) { | |
397 | dbprintf("warning: UUID in AG %d " | |
398 | "differs to the primary SB\n", | |
399 | agno); | |
400 | break; | |
401 | } | |
402 | } else { | |
403 | memcpy(uu, uup, sizeof(uuid_t)); | |
404 | } | |
405 | } | |
406 | if (mp->m_sb.sb_logstart) { | |
407 | if (x.logdev && x.logdev != x.ddev) | |
408 | dbprintf("warning - external log specified " | |
409 | "for FS with an internal log\n"); | |
410 | } else if (!x.logdev || (x.logdev == x.ddev)) { | |
411 | dbprintf("warning - no external log specified " | |
412 | "for FS with an external log\n"); | |
413 | } | |
414 | ||
415 | uuid_unparse(uu, bp); | |
416 | dbprintf("UUID = %s\n", bp); | |
417 | } | |
418 | ||
419 | return 0; | |
420 | } | |
421 | ||
422 | ||
423 | static void | |
424 | label_help(void) | |
425 | { | |
426 | dbprintf( | |
427 | "\n" | |
428 | " write/print FS label\n" | |
429 | "\n" | |
430 | " Example:\n" | |
431 | "\n" | |
432 | " 'label' - print label\n" | |
433 | " 'label 123456789012' - write label\n" | |
434 | " 'label --' - write an empty label\n" | |
435 | "\n" | |
436 | "The print function checks the label in each SB and will warn if the labels\n" | |
437 | "differ between AGs. The write commands will set the label in all AGs to the\n" | |
438 | "specified value. The maximum length of a label is 12 characters - use of a\n" | |
439 | "longer label will result in truncation and a warning will be issued.\n" | |
440 | "\n" | |
441 | ); | |
442 | } | |
443 | ||
444 | static char * | |
445 | do_label(xfs_agnumber_t agno, char *label) | |
446 | { | |
447 | size_t len; | |
448 | xfs_sb_t tsb; | |
449 | static char lbl[sizeof(tsb.sb_fname) + 1]; | |
450 | ||
451 | if (!get_sb(agno, &tsb)) | |
452 | return NULL; | |
453 | ||
454 | memset(&lbl[0], 0, sizeof(lbl)); | |
455 | ||
456 | if (!label) { /* get label */ | |
457 | pop_cur(); | |
458 | memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); | |
459 | return &lbl[0]; | |
460 | } | |
461 | /* set label */ | |
462 | if ((len = strlen(label)) > sizeof(tsb.sb_fname)) { | |
463 | if (agno == 0) | |
464 | dbprintf("%s: truncating label length from %d to %d\n", | |
465 | progname, (int)len, (int)sizeof(tsb.sb_fname)); | |
466 | len = sizeof(tsb.sb_fname); | |
467 | } | |
468 | if ( len == 2 && | |
469 | (strcmp(label, "\"\"") == 0 || | |
470 | strcmp(label, "''") == 0 || | |
471 | strcmp(label, "--") == 0) ) | |
472 | label[0] = label[1] = '\0'; | |
473 | memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname)); | |
474 | memcpy(&tsb.sb_fname, label, len); | |
475 | memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); | |
476 | libxfs_xlate_sb(iocur_top->data, &tsb, -1, ARCH_CONVERT, XFS_SB_FNAME); | |
477 | write_cur(); | |
478 | return &lbl[0]; | |
479 | } | |
480 | ||
481 | static int | |
482 | label_f( | |
483 | int argc, | |
484 | char **argv) | |
485 | { | |
486 | char *p = NULL; | |
487 | xfs_sb_t sb; | |
488 | xfs_agnumber_t ag; | |
489 | ||
490 | if (argc != 1 && argc != 2) { | |
491 | dbprintf("invalid parameters\n"); | |
492 | return 0; | |
493 | } | |
494 | ||
495 | if (argc == 2) { /* WRITE LABEL */ | |
496 | ||
497 | if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { | |
498 | dbprintf("%s: not in expert mode, writing disabled\n", | |
499 | progname); | |
500 | return 0; | |
501 | } | |
502 | ||
503 | dbprintf("writing all SBs\n"); | |
504 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) | |
505 | if ((p = do_label(ag, argv[1])) == NULL) { | |
506 | dbprintf("failed to set label in AG %d\n", ag); | |
507 | break; | |
508 | } | |
509 | dbprintf("new label = \"%s\"\n", p); | |
510 | ||
511 | } else { /* READ LABEL */ | |
512 | ||
513 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { | |
514 | p = do_label(ag, NULL); | |
515 | if (!p) { | |
516 | dbprintf("failed to read label in AG %d\n", ag); | |
517 | return 0; | |
518 | } | |
519 | if (!ag) | |
520 | memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname)); | |
521 | else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname))) | |
522 | dbprintf("warning: AG %d label differs\n", ag); | |
523 | } | |
524 | dbprintf("label = \"%s\"\n", p); | |
525 | } | |
526 | return 0; | |
527 | } | |
528 | ||
529 | ||
530 | static void | |
531 | version_help(void) | |
532 | { | |
533 | dbprintf( | |
534 | "\n" | |
535 | " set/print feature bits in sb version\n" | |
536 | "\n" | |
537 | " Example:\n" | |
538 | "\n" | |
539 | " 'version' - print current feature bits\n" | |
540 | " 'version extflg' - enable unwritten extents\n" | |
541 | "\n" | |
542 | "The version function prints currently enabled features for a filesystem\n" | |
543 | "according to its the version field of the primary superblock.\n" | |
544 | "It can also be used to enable selected features, such as support for\n" | |
545 | "unwritten extents. The upated version is written into to all AGs.\n" | |
546 | "\n" | |
547 | ); | |
548 | } | |
549 | ||
550 | static int | |
551 | do_version(xfs_agnumber_t agno, __uint16_t versionnum) | |
552 | { | |
553 | xfs_sb_t tsb; | |
554 | ||
555 | if (!get_sb(agno, &tsb)) | |
556 | return 0; | |
557 | ||
558 | tsb.sb_versionnum = versionnum; | |
559 | libxfs_xlate_sb(iocur_top->data, &tsb, | |
560 | -1, ARCH_CONVERT, XFS_SB_VERSIONNUM); | |
561 | write_cur(); | |
562 | return 1; | |
563 | } | |
564 | ||
565 | static char * | |
566 | version_string( | |
567 | xfs_sb_t *sbp) | |
568 | { | |
569 | static char s[1024]; | |
570 | ||
571 | if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1) | |
572 | strcpy(s, "V1"); | |
573 | else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2) | |
574 | strcpy(s, "V2"); | |
575 | else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3) | |
576 | strcpy(s, "V3"); | |
577 | else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) | |
578 | strcpy(s, "V4"); | |
579 | ||
580 | if (XFS_SB_VERSION_HASATTR(sbp)) | |
581 | strcat(s, ",ATTR"); | |
582 | if (XFS_SB_VERSION_HASNLINK(sbp)) | |
583 | strcat(s, ",NLINK"); | |
584 | if (XFS_SB_VERSION_HASQUOTA(sbp)) | |
585 | strcat(s, ",QUOTA"); | |
586 | if (XFS_SB_VERSION_HASALIGN(sbp)) | |
587 | strcat(s, ",ALIGN"); | |
588 | if (XFS_SB_VERSION_HASDALIGN(sbp)) | |
589 | strcat(s, ",DALIGN"); | |
590 | if (XFS_SB_VERSION_HASSHARED(sbp)) | |
591 | strcat(s, ",SHARED"); | |
592 | if (XFS_SB_VERSION_HASDIRV2(sbp)) | |
593 | strcat(s, ",DIRV2"); | |
594 | if (XFS_SB_VERSION_HASLOGV2(sbp)) | |
595 | strcat(s, ",LOGV2"); | |
596 | if (XFS_SB_VERSION_HASEXTFLGBIT(sbp)) | |
597 | strcat(s, ",EXTFLG"); | |
598 | if (XFS_SB_VERSION_HASSECTOR(sbp)) | |
599 | strcat(s, ",SECTOR"); | |
600 | return s; | |
601 | } | |
602 | ||
603 | static int | |
604 | version_f( | |
605 | int argc, | |
606 | char **argv) | |
607 | { | |
608 | __uint16_t version = 0; | |
609 | xfs_agnumber_t ag; | |
610 | ||
611 | if (argc == 2) { /* WRITE VERSION */ | |
612 | ||
613 | if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { | |
614 | dbprintf("%s: not in expert mode, writing disabled\n", | |
615 | progname); | |
616 | return 0; | |
617 | } | |
618 | ||
619 | /* Logic here derived from the IRIX xfs_chver(1M) script. */ | |
620 | if (!strcasecmp(argv[1], "extflg")) { | |
621 | switch (XFS_SB_VERSION_NUM(&mp->m_sb)) { | |
622 | case XFS_SB_VERSION_1: | |
623 | version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT; | |
624 | break; | |
625 | case XFS_SB_VERSION_2: | |
626 | version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT; | |
627 | break; | |
628 | case XFS_SB_VERSION_3: | |
629 | version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT; | |
630 | break; | |
631 | case XFS_SB_VERSION_4: | |
632 | if (XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) | |
633 | dbprintf("unwritten extents flag" | |
634 | " is already enabled\n"); | |
635 | else | |
636 | version = mp->m_sb.sb_versionnum | | |
637 | XFS_SB_VERSION_EXTFLGBIT; | |
638 | break; | |
639 | } | |
640 | } else { | |
641 | dbprintf("%s: invalid version change command \"%s\"\n", | |
642 | progname, argv[1]); | |
643 | return 0; | |
644 | } | |
645 | ||
646 | if (version) { | |
647 | dbprintf("writing all SBs\n"); | |
648 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) | |
649 | if (!do_version(ag, version)) { | |
650 | dbprintf("failed to set versionnum " | |
651 | "in AG %d\n", ag); | |
652 | break; | |
653 | } | |
654 | mp->m_sb.sb_versionnum = version; | |
655 | } | |
656 | } | |
657 | dbprintf("versionnum [0x%x] = %s\n", mp->m_sb.sb_versionnum, | |
658 | version_string(&mp->m_sb)); | |
659 | return 0; | |
660 | } |