source: MondoRescue/branches/3.3/mindi-busybox/util-linux/mkfs_reiser.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 13.3 KB
RevLine 
[2725]1/* vi: set sw=4 ts=4: */
2/*
3 * mkfs_reiser: utility to create ReiserFS filesystem
4 *
5 * Busybox'ed (2009) by Vladimir Dronnikov <dronnikov@gmail.com>
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
[3232]9
10//usage:#define mkfs_reiser_trivial_usage
11//usage: "[-f] [-l LABEL] BLOCKDEV [4K-BLOCKS]"
12//usage:#define mkfs_reiser_full_usage "\n\n"
13//usage: "Make a ReiserFS V3 filesystem\n"
14//usage: "\n -f Force"
15//usage: "\n -l LBL Volume label"
16
[2725]17#include "libbb.h"
18#include <linux/fs.h>
19
20char BUG_wrong_field_size(void);
21#define STORE_LE(field, value) \
22do { \
23 if (sizeof(field) == 4) \
24 field = SWAP_LE32(value); \
25 else if (sizeof(field) == 2) \
26 field = SWAP_LE16(value); \
27 else if (sizeof(field) == 1) \
28 field = (value); \
29 else \
30 BUG_wrong_field_size(); \
31} while (0)
32
33#define FETCH_LE32(field) \
34 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
35
36struct journal_params {
37 uint32_t jp_journal_1st_block; /* where does journal start from on its device */
38 uint32_t jp_journal_dev; /* journal device st_rdev */
39 uint32_t jp_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */
40 uint32_t jp_journal_trans_max; /* max number of blocks in a transaction. */
41 uint32_t jp_journal_magic; /* random value made on fs creation (this was sb_journal_block_count) */
42 uint32_t jp_journal_max_batch; /* max number of blocks to batch into a trans */
43 uint32_t jp_journal_max_commit_age; /* in seconds, how old can an async commit be */
44 uint32_t jp_journal_max_trans_age; /* in seconds, how old can a transaction be */
45};
46
47struct reiserfs_journal_header {
48 uint32_t jh_last_flush_trans_id; /* id of last fully flushed transaction */
49 uint32_t jh_first_unflushed_offset; /* offset in the log of where to start replay after a crash */
50 uint32_t jh_mount_id;
51 struct journal_params jh_journal;
52 uint32_t jh_last_check_mount_id; /* the mount id of the fs during the last reiserfsck --check. */
53};
54
55struct reiserfs_super_block {
56 uint32_t sb_block_count; /* 0 number of block on data device */
57 uint32_t sb_free_blocks; /* 4 free blocks count */
58 uint32_t sb_root_block; /* 8 root of the tree */
59
60 struct journal_params sb_journal; /* 12 */
61
62 uint16_t sb_blocksize; /* 44 */
63 uint16_t sb_oid_maxsize; /* 46 max size of object id array, see get_objectid() commentary */
64 uint16_t sb_oid_cursize; /* 48 current size of object id array */
65 uint16_t sb_umount_state; /* 50 this is set to 1 when filesystem was umounted, to 2 - when not */
66
67 char s_magic[10]; /* 52 "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
68 uint16_t sb_fs_state; /* 62 it is set to used by fsck to mark which phase of rebuilding is done (used for fsck debugging) */
[3621]69 uint32_t sb_hash_function_code; /* 64 code of function which was/is/will be used to sort names in a directory. See codes in above */
[2725]70 uint16_t sb_tree_height; /* 68 height of filesytem tree. Tree consisting of only one root block has 2 here */
71 uint16_t sb_bmap_nr; /* 70 amount of bitmap blocks needed to address each block of file system */
72 uint16_t sb_version; /* 72 this field is only reliable on filesystem with non-standard journal */
73 uint16_t sb_reserved_for_journal; /* 74 size in blocks of journal area on main device, we need to keep after non-standard journal relocation */
74 uint32_t sb_inode_generation; /* 76 */
75 uint32_t sb_flags; /* 80 Right now used only by inode-attributes, if enabled */
76 unsigned char s_uuid[16]; /* 84 filesystem unique identifier */
77 unsigned char s_label[16]; /* 100 filesystem volume label */
78 uint16_t sb_mnt_count; /* 116 */
79 uint16_t sb_max_mnt_count; /* 118 */
80 uint32_t sb_lastcheck; /* 120 */
81 uint32_t sb_check_interval; /* 124 */
82/* zero filled by mkreiserfs and reiserfs_convert_objectid_map_v1() so any additions must be updated there as well. */
83 char s_unused[76]; /* 128 */
84 /* 204 */
85};
86
87/* Header of a disk block. More precisely, header of a formatted leaf
88 or internal node, and not the header of an unformatted node. */
89struct block_head {
90 uint16_t blk2_level; /* Level of a block in the tree. */
91 uint16_t blk2_nr_item; /* Number of keys/items in a block. */
92 uint16_t blk2_free_space; /* Block free space in bytes. */
93 uint16_t blk_reserved;
94 uint32_t reserved[4];
95};
96
97#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
98
99#define REISERFS_3_6_SUPER_MAGIC_STRING "ReIsEr2Fs"
100#define REISERFS_FORMAT_3_6 2
101#define DEFAULT_MAX_MNT_COUNT 30 /* 30 mounts */
102#define DEFAULT_CHECK_INTERVAL (180 * 60 * 60 * 24) /* 180 days */
103
104#define FS_CLEANLY_UMOUNTED 1 /* this was REISERFS_VALID_FS */
105
106#define JOURNAL_MIN_SIZE 512
107/* biggest possible single transaction, don't change for now (8/3/99) */
108#define JOURNAL_TRANS_MAX 1024
109#define JOURNAL_TRANS_MIN 256 /* need to check whether it works */
110#define JOURNAL_DEFAULT_RATIO 8 /* default journal size / max trans length */
111#define JOURNAL_MIN_RATIO 2
112/* max blocks to batch into one transaction, don't make this any bigger than 900 */
113#define JOURNAL_MAX_BATCH 900
114#define JOURNAL_MAX_COMMIT_AGE 30
115
116
117// Standard mkreiserfs 3.6.21:
118// -b | --block-size N size of file-system block, in bytes
119// -j | --journal-device FILE path to separate device to hold journal
120// -s | --journal-size N size of the journal in blocks
121// -o | --journal-offset N offset of the journal from the start of
122// the separate device, in blocks
123// -t | --transaction-max-size N maximal size of transaction, in blocks
124// -B | --badblocks file store all bad blocks given in file on the fs
125// -h | --hash rupasov|tea|r5 hash function to use by default
126// -u | --uuid UUID store UUID in the superblock
127// -l | --label LABEL store LABEL in the superblock
128// --format 3.5|3.6 old 3.5 format or newer 3.6
129// -f | --force specified once, make mkreiserfs the whole
130// disk, not block device or mounted partition;
131// specified twice, do not ask for confirmation
132// -q | --quiet quiet work without messages, progress and
133// questions. Useful if run in a script. For use
134// by end users only.
135// -d | --debug print debugging information during mkreiser
136// -V print version and exit
137
138// Options not commented below are taken but silently ignored:
139enum {
140 OPT_b = 1 << 0,
141 OPT_j = 1 << 1,
142 OPT_s = 1 << 2,
143 OPT_o = 1 << 3,
144 OPT_t = 1 << 4,
145 OPT_B = 1 << 5,
146 OPT_h = 1 << 6,
147 OPT_u = 1 << 7,
148 OPT_l = 1 << 8, // label
149 OPT_f = 1 << 9, // ask no questions
150 OPT_q = 1 << 10,
151 OPT_d = 1 << 11,
152 //OPT_V = 1 << 12, // -V version. bbox applets don't support that
153};
154
155int mkfs_reiser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
156int mkfs_reiser_main(int argc UNUSED_PARAM, char **argv)
157{
158 unsigned blocksize = 4096;
159 unsigned journal_blocks = 8192;
160 unsigned blocks, bitmap_blocks, i, block;
161 time_t timestamp;
162 const char *label = "";
163 struct stat st;
164 int fd;
165 uint8_t *buf;
166 struct reiserfs_super_block *sb;
167 struct journal_params *jp;
168 struct block_head *root;
169
170 // using global "option_mask32" instead of local "opts":
171 // we are register starved here
172 opt_complementary = "-1:b+";
173 /*opts =*/ getopt32(argv, "b:j:s:o:t:B:h:u:l:fqd",
174 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &label);
175 argv += optind; // argv[0] -- device
176
177 // check the device is a block device
178 fd = xopen(argv[0], O_WRONLY | O_EXCL);
179 xfstat(fd, &st, argv[0]);
180 if (!S_ISBLK(st.st_mode) && !(option_mask32 & OPT_f))
181 bb_error_msg_and_die("%s: not a block device", argv[0]);
182
183 // check if it is mounted
184 // N.B. what if we format a file? find_mount_point will return false negative since
185 // it is loop block device which is mounted!
186 if (find_mount_point(argv[0], 0))
187 bb_error_msg_and_die("can't format mounted filesystem");
188
189 // open the device, get size in blocks
190 blocks = get_volume_size_in_bytes(fd, argv[1], blocksize, /*extend:*/ 1) / blocksize;
191
192 // block number sanity check
193 // we have a limit: skipped area, super block, journal and root block
194 // all have to be addressed by one first bitmap
195 block = REISERFS_DISK_OFFSET_IN_BYTES / blocksize // boot area
196 + 1 // sb
197 + 1 // bitmap#0
198 + journal_blocks+1 // journal
199 ;
200
201 // count overhead
202 bitmap_blocks = (blocks - 1) / (blocksize * 8) + 1;
203 i = block + bitmap_blocks;
204
205 // check overhead
206 if (MIN(blocksize * 8, blocks) < i)
207 bb_error_msg_and_die("need >= %u blocks", i);
208
209 // ask confirmation?
210 // TODO: ???
211
212 // wipe out first REISERFS_DISK_OFFSET_IN_BYTES of device
213 // TODO: do we really need to wipe?!
214 xlseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET);
215
216 // fill superblock
217 sb = (struct reiserfs_super_block *)xzalloc(blocksize);
218 // block count
219 STORE_LE(sb->sb_block_count, blocks);
220 STORE_LE(sb->sb_free_blocks, blocks - i);
221 // TODO: decypher!
222 STORE_LE(sb->sb_root_block, block);
223 // fill journal related fields
224 jp = &sb->sb_journal;
225 STORE_LE(jp->jp_journal_1st_block, REISERFS_DISK_OFFSET_IN_BYTES / blocksize + 1/*sb*/ + 1/*bmp#0*/);
226 timestamp = time(NULL);
[3621]227 srand(timestamp);
228 STORE_LE(jp->jp_journal_magic, rand());
[2725]229 STORE_LE(jp->jp_journal_size, journal_blocks);
230 STORE_LE(jp->jp_journal_trans_max, JOURNAL_TRANS_MAX);
231 STORE_LE(jp->jp_journal_max_batch, JOURNAL_MAX_BATCH);
232 STORE_LE(jp->jp_journal_max_commit_age, JOURNAL_MAX_COMMIT_AGE);
233 // sizes
234 STORE_LE(sb->sb_blocksize, blocksize);
235 STORE_LE(sb->sb_oid_maxsize, (blocksize - sizeof(*sb)) / sizeof(uint32_t) / 2 * 2);
236 STORE_LE(sb->sb_oid_cursize, 2); // "." and ".."
237 strcpy(sb->s_magic, REISERFS_3_6_SUPER_MAGIC_STRING);
238 STORE_LE(sb->sb_bmap_nr, (bitmap_blocks > ((1LL << 16) - 1)) ? 0 : bitmap_blocks);
239 // misc
240 STORE_LE(sb->sb_version, REISERFS_FORMAT_3_6);
241 STORE_LE(sb->sb_lastcheck, timestamp);
242 STORE_LE(sb->sb_check_interval, DEFAULT_CHECK_INTERVAL);
243 STORE_LE(sb->sb_mnt_count, 1);
244 STORE_LE(sb->sb_max_mnt_count, DEFAULT_MAX_MNT_COUNT);
245 STORE_LE(sb->sb_umount_state, FS_CLEANLY_UMOUNTED);
246 STORE_LE(sb->sb_tree_height, 2);
247 STORE_LE(sb->sb_hash_function_code, 3); // R5_HASH
248 STORE_LE(sb->sb_flags, 1);
249 //STORE_LE(sb->sb_reserved_for_journal, 0);
250 // create UUID
251 generate_uuid(sb->s_uuid);
252 // write the label
253 safe_strncpy((char *)sb->s_label, label, sizeof(sb->s_label));
254
255 // TODO: EMPIRIC! ENDIANNESS!
256 // superblock has only 204 bytes. What are these?
257 buf = (uint8_t *)sb;
258 buf[205] = 1;
259 buf[209] = 3;
260
261 // put superblock
262 xwrite(fd, sb, blocksize);
263
264 // create bitmaps
265 buf = xzalloc(blocksize);
266
267 // bitmap #0 uses initial "block"+1 blocks
268 i = block + 1;
269 memset(buf, 0xFF, i / 8);
270 buf[i / 8] = (1 << (i & 7)) - 1; //0..7 => 00000000..01111111
271 // mark trailing absent blocks, if any
272 if (blocks < 8*blocksize) {
273 unsigned n = 8*blocksize - blocks;
274 i = n / 8;
275 buf[blocksize - i - 1] |= 0x7F00 >> (n & 7); //0..7 => 00000000..11111110
276 memset(buf + blocksize - i, 0xFF, i); // N.B. no overflow here!
277 }
278 // put bitmap #0
279 xwrite(fd, buf, blocksize);
280
281 // now go journal blocks
282 memset(buf, 0, blocksize);
283 for (i = 0; i < journal_blocks; i++)
284 xwrite(fd, buf, blocksize);
285 // dump journal control block
286 memcpy(&((struct reiserfs_journal_header *)buf)->jh_journal, &sb->sb_journal, sizeof(sb->sb_journal));
287 xwrite(fd, buf, blocksize);
288
289 // other bitmaps are in every (8*blocksize)-th block
290 // N.B. they use the only block -- namely bitmap itself!
291 buf[0] = 0x01;
292 // put bitmaps
293 for (i = 1; i < bitmap_blocks; i++) {
294 xlseek(fd, i*8*blocksize * blocksize, SEEK_SET);
295 // mark trailing absent blocks, if any
296 if (i == bitmap_blocks - 1 && (blocks % (8*blocksize))) {
297 unsigned n = 8*blocksize - blocks % (8*blocksize);
298 unsigned j = n / 8;
299 buf[blocksize - j - 1] |= 0x7F00 >> (n & 7); //0..7 => 00000000..11111110
300 memset(buf + blocksize - j, 0xFF, j); // N.B. no overflow here!
301 }
302 xwrite(fd, buf, blocksize);
303 }
304
305 // fill root block
306 // block head
307 memset(buf, 0, blocksize);
308 root = (struct block_head *)buf;
309 STORE_LE(root->blk2_level, 1); // leaf node
310 STORE_LE(root->blk2_nr_item, 2); // "." and ".."
311 STORE_LE(root->blk2_free_space, blocksize - sizeof(struct block_head));
312 // item head
313 // root directory
314 // TODO: EMPIRIC! ENDIANNESS!
315 // TODO: indented assignments seem to be timestamps
316buf[4] = 0134;
317buf[24] = 01;
318buf[28] = 02;
319buf[42] = 054;
320buf[44] = 0324;
321buf[45] = 017;
322buf[46] = 01;
323buf[48] = 01;
324buf[52] = 02;
325buf[56] = 01;
326buf[60] = 0364;
327buf[61] = 01;
328buf[64] = 02;
329buf[66] = 060;
330buf[68] = 0244;
331buf[69] = 017;
332buf[4004] = 01;
333buf[4008] = 01;
334buf[4012] = 02;
335buf[4016] = 050;
336buf[4018] = 04;
337buf[4020] = 02;
338buf[4028] = 01;
339buf[4032] = 040;
340buf[4034] = 04;
341
342buf[4036] = 056; buf[4037] = 056; // ".."
343buf[4044] = 056; // "."
344
345buf[4052] = 0355;
346buf[4053] = 0101;
347buf[4056] = 03;
348buf[4060] = 060;
349 buf[4076] = 0173;
350 buf[4077] = 0240;
351 buf[4078] = 0344;
352 buf[4079] = 0112;
353 buf[4080] = 0173;
354 buf[4081] = 0240;
355 buf[4082] = 0344;
356 buf[4083] = 0112;
357 buf[4084] = 0173;
358 buf[4085] = 0240;
359 buf[4086] = 0344;
360 buf[4087] = 0112;
361buf[4088] = 01;
362
363 // put root block
364 xlseek(fd, block * blocksize, SEEK_SET);
365 xwrite(fd, buf, blocksize);
366
367 // cleanup
368 if (ENABLE_FEATURE_CLEAN_UP) {
369 free(buf);
370 free(sb);
371 }
372
373 xclose(fd);
374 return EXIT_SUCCESS;
375}
Note: See TracBrowser for help on using the repository browser.