]>
Commit | Line | Data |
---|---|---|
6dbe3af9 | 1 | /* |
727b3c2f | 2 | * mkfs.minix.c - make a linux (minix) file-system. |
6dbe3af9 KZ |
3 | * |
4 | * (C) 1991 Linus Torvalds. This file may be redistributed as per | |
5 | * the Linux copyright. | |
6 | */ | |
7 | ||
8 | /* | |
726f69e2 | 9 | * DD.MM.YY |
6dbe3af9 | 10 | * |
726f69e2 KZ |
11 | * 24.11.91 - Time began. Used the fsck sources to get started. |
12 | * | |
13 | * 25.11.91 - Corrected some bugs. Added support for ".badblocks" | |
6dbe3af9 KZ |
14 | * The algorithm for ".badblocks" is a bit weird, but |
15 | * it should work. Oh, well. | |
16 | * | |
726f69e2 KZ |
17 | * 25.01.92 - Added the -l option for getting the list of bad blocks |
18 | * out of a named file. (Dave Rivers, rivers@ponds.uucp) | |
6dbe3af9 | 19 | * |
726f69e2 | 20 | * 28.02.92 - Added %-information when using -c. |
6dbe3af9 | 21 | * |
726f69e2 | 22 | * 28.02.93 - Added support for other namelengths than the original |
6dbe3af9 KZ |
23 | * 14 characters so that I can test the new kernel routines.. |
24 | * | |
726f69e2 KZ |
25 | * 09.10.93 - Make exit status conform to that required by fsutil |
26 | * (Rik Faith, faith@cs.unc.edu) | |
6dbe3af9 | 27 | * |
726f69e2 KZ |
28 | * 31.10.93 - Added inode request feature, for backup floppies: use |
29 | * 32 inodes, for a news partition use more. | |
30 | * (Scott Heavner, sdh@po.cwru.edu) | |
6dbe3af9 | 31 | * |
726f69e2 KZ |
32 | * 03.01.94 - Added support for file system valid flag. |
33 | * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) | |
fd6b7a7f | 34 | * |
66ee8158 KZ |
35 | * 30.10.94 - Added support for v2 filesystem |
36 | * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) | |
6dbe3af9 | 37 | * |
726f69e2 KZ |
38 | * 09.11.94 - Added test to prevent overwrite of mounted fs adapted |
39 | * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs | |
40 | * program. (Daniel Quinlan, quinlan@yggdrasil.com) | |
41 | * | |
42 | * 03.20.95 - Clear first 512 bytes of filesystem to make certain that | |
43 | * the filesystem is not misidentified as a MS-DOS FAT filesystem. | |
44 | * (Daniel Quinlan, quinlan@yggdrasil.com) | |
6dbe3af9 | 45 | * |
fd6b7a7f KZ |
46 | * 02.07.96 - Added small patch from Russell King to make the program a |
47 | * good deal more portable (janl@math.uio.no) | |
48 | * | |
a2657ae3 DB |
49 | * 06.29.11 - Overall cleanups for util-linux and v3 support |
50 | * Davidlohr Bueso <dave@gnu.org> | |
51 | * | |
52 | * Usage: mkfs [-c | -l filename ] [-12v3] [-nXX] [-iXX] device [size-in-blocks] | |
6dbe3af9 KZ |
53 | * |
54 | * -c for readablility checking (SLOW!) | |
55 | * -l for getting a list of bad blocks from a file. | |
56 | * -n for namelength (currently the kernel only uses 14 or 30) | |
57 | * -i for number of inodes | |
a2657ae3 DB |
58 | * -1 for v1 filesystem |
59 | * -2,-v for v2 filesystem | |
60 | * -3 for v3 filesystem | |
6dbe3af9 KZ |
61 | * |
62 | * The device may be a block device or a image of one, but this isn't | |
63 | * enforced (but it's not much fun on a character device :-). | |
64 | */ | |
65 | ||
66 | #include <stdio.h> | |
67 | #include <time.h> | |
68 | #include <unistd.h> | |
69 | #include <string.h> | |
70 | #include <signal.h> | |
71 | #include <fcntl.h> | |
72 | #include <ctype.h> | |
73 | #include <stdlib.h> | |
74 | #include <termios.h> | |
75 | #include <sys/stat.h> | |
76 | #include <mntent.h> | |
7eda085c | 77 | #include <getopt.h> |
c8079044 | 78 | #include <err.h> |
6dbe3af9 | 79 | |
a28a3ad2 | 80 | #include "blkdev.h" |
22853e4a | 81 | #include "minix.h" |
7eda085c | 82 | #include "nls.h" |
fc68cd49 | 83 | #include "pathnames.h" |
e98754d6 | 84 | #include "bitops.h" |
9fae6c27 | 85 | #include "mkfs.h" |
a2657ae3 | 86 | #include "strutils.h" |
7eda085c | 87 | |
6dbe3af9 KZ |
88 | #define MINIX_ROOT_INO 1 |
89 | #define MINIX_BAD_INO 2 | |
90 | ||
91 | #define TEST_BUFFER_BLOCKS 16 | |
92 | #define MAX_GOOD_BLOCKS 512 | |
93 | ||
c8079044 DB |
94 | #define MAX_INODES 65535 |
95 | ||
6dbe3af9 KZ |
96 | static char * program_name = "mkfs"; |
97 | static char * device_name = NULL; | |
98 | static int DEV = -1; | |
16726585 | 99 | static unsigned long long BLOCKS = 0; |
6dbe3af9 KZ |
100 | static int check = 0; |
101 | static int badblocks = 0; | |
a2657ae3 DB |
102 | |
103 | /* | |
104 | * default (changed to 30, per Linus's | |
105 | * suggestion, Sun Nov 21 08:05:07 1993) | |
106 | * This should be changed in the future to 60, | |
107 | * since v3 needs to be the default nowadays (2011) | |
108 | */ | |
109 | static int namelen = 30; | |
fd6b7a7f KZ |
110 | static int dirsize = 32; |
111 | static int magic = MINIX_SUPER_MAGIC2; | |
112 | static int version2 = 0; | |
6dbe3af9 KZ |
113 | |
114 | static char root_block[BLOCK_SIZE] = "\0"; | |
115 | ||
726f69e2 | 116 | static char boot_block_buffer[512]; |
6dbe3af9 | 117 | #define Super (*(struct minix_super_block *)super_block_buffer) |
6dbe3af9 KZ |
118 | |
119 | static unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; | |
120 | static int used_good_blocks = 0; | |
121 | static unsigned long req_nr_inodes = 0; | |
122 | ||
50758d0e | 123 | #define zone_in_use(x) (isset(zone_map,(x)-get_first_zone()+1) != 0) |
6dbe3af9 KZ |
124 | |
125 | #define mark_inode(x) (setbit(inode_map,(x))) | |
126 | #define unmark_inode(x) (clrbit(inode_map,(x))) | |
127 | ||
50758d0e DB |
128 | #define mark_zone(x) (setbit(zone_map,(x)-get_first_zone()+1)) |
129 | #define unmark_zone(x) (clrbit(zone_map,(x)-get_first_zone()+1)) | |
6dbe3af9 | 130 | |
7eda085c | 131 | |
c8079044 | 132 | static void __attribute__((__noreturn__)) |
22853e4a | 133 | usage(void) { |
9fae6c27 | 134 | errx(MKFS_USAGE, _("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]"), |
c8079044 | 135 | program_name); |
7eda085c | 136 | } |
6dbe3af9 KZ |
137 | |
138 | /* | |
139 | * Check to make certain that our new filesystem won't be created on | |
140 | * an already mounted partition. Code adapted from mke2fs, Copyright | |
141 | * (C) 1994 Theodore Ts'o. Also licensed under GPL. | |
142 | */ | |
50758d0e | 143 | static void check_mount(void) { |
6dbe3af9 KZ |
144 | FILE * f; |
145 | struct mntent * mnt; | |
146 | ||
fc68cd49 | 147 | if ((f = setmntent (_PATH_MOUNTED, "r")) == NULL) |
6dbe3af9 KZ |
148 | return; |
149 | while ((mnt = getmntent (f)) != NULL) | |
150 | if (strcmp (device_name, mnt->mnt_fsname) == 0) | |
151 | break; | |
152 | endmntent (f); | |
153 | if (!mnt) | |
154 | return; | |
155 | ||
9fae6c27 DB |
156 | errx(MKFS_ERROR, _("%s is mounted; will not make a filesystem here!"), |
157 | device_name); | |
6dbe3af9 KZ |
158 | } |
159 | ||
a2657ae3 DB |
160 | static void super_set_state(void) |
161 | { | |
162 | switch (fs_version) { | |
3ca43386 DB |
163 | case 1: |
164 | case 2: | |
a2657ae3 DB |
165 | Super.s_state |= MINIX_VALID_FS; |
166 | Super.s_state &= ~MINIX_ERROR_FS; | |
167 | break; | |
168 | } | |
169 | } | |
170 | ||
50758d0e DB |
171 | static void write_tables(void) { |
172 | unsigned long imaps = get_nimaps(); | |
173 | unsigned long zmaps = get_nzmaps(); | |
174 | unsigned long buffsz = get_inode_buffer_size(); | |
175 | ||
6dbe3af9 | 176 | /* Mark the super block valid. */ |
a2657ae3 | 177 | super_set_state(); |
6dbe3af9 | 178 | |
726f69e2 | 179 | if (lseek(DEV, 0, SEEK_SET)) |
9fae6c27 DB |
180 | err(MKFS_ERROR, _("%s: seek to boot block failed " |
181 | " in write_tables"), device_name); | |
726f69e2 | 182 | if (512 != write(DEV, boot_block_buffer, 512)) |
9fae6c27 | 183 | err(MKFS_ERROR, _("%s: unable to clear boot sector"), device_name); |
6dbe3af9 | 184 | if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET)) |
9fae6c27 | 185 | err(MKFS_ERROR, _("%s: seek failed in write_tables"), device_name); |
6dbe3af9 | 186 | if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE)) |
9fae6c27 | 187 | err(MKFS_ERROR, _("%s: unable to write super-block"), device_name); |
50758d0e | 188 | if (imaps*BLOCK_SIZE != write(DEV,inode_map, imaps*BLOCK_SIZE)) |
9fae6c27 | 189 | err(MKFS_ERROR, _("%s: unable to write inode map"), device_name); |
50758d0e | 190 | if (zmaps*BLOCK_SIZE != write(DEV,zone_map, zmaps*BLOCK_SIZE)) |
9fae6c27 | 191 | err(MKFS_ERROR, _("%s: unable to write zone map"), device_name); |
50758d0e | 192 | if (buffsz != write(DEV,inode_buffer, buffsz)) |
9fae6c27 | 193 | err(MKFS_ERROR, _("%s: unable to write inodes"), device_name); |
6dbe3af9 KZ |
194 | } |
195 | ||
50758d0e | 196 | static void write_block(int blk, char * buffer) { |
6dbe3af9 | 197 | if (blk*BLOCK_SIZE != lseek(DEV, blk*BLOCK_SIZE, SEEK_SET)) |
9fae6c27 | 198 | errx(MKFS_ERROR, _("%s: seek failed in write_block"), device_name); |
6dbe3af9 | 199 | if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE)) |
9fae6c27 | 200 | errx(MKFS_ERROR, _("%s: write failed in write_block"), device_name); |
6dbe3af9 KZ |
201 | } |
202 | ||
50758d0e | 203 | static int get_free_block(void) { |
6dbe3af9 | 204 | int blk; |
50758d0e DB |
205 | unsigned int zones = get_nzones(); |
206 | unsigned int first_zone = get_first_zone(); | |
6dbe3af9 KZ |
207 | |
208 | if (used_good_blocks+1 >= MAX_GOOD_BLOCKS) | |
9fae6c27 | 209 | errx(MKFS_ERROR, _("%s: too many bad blocks"), device_name); |
6dbe3af9 KZ |
210 | if (used_good_blocks) |
211 | blk = good_blocks_table[used_good_blocks-1]+1; | |
212 | else | |
50758d0e DB |
213 | blk = first_zone; |
214 | while (blk < zones && zone_in_use(blk)) | |
6dbe3af9 | 215 | blk++; |
50758d0e | 216 | if (blk >= zones) |
9fae6c27 | 217 | errx(MKFS_ERROR, _("%s: not enough good blocks"), device_name); |
6dbe3af9 KZ |
218 | good_blocks_table[used_good_blocks] = blk; |
219 | used_good_blocks++; | |
220 | return blk; | |
221 | } | |
222 | ||
50758d0e | 223 | static void mark_good_blocks(void) { |
6dbe3af9 KZ |
224 | int blk; |
225 | ||
226 | for (blk=0 ; blk < used_good_blocks ; blk++) | |
227 | mark_zone(good_blocks_table[blk]); | |
228 | } | |
229 | ||
50758d0e DB |
230 | static inline int next(int zone) { |
231 | unsigned int zones = get_nzones(); | |
232 | unsigned int first_zone = get_first_zone(); | |
233 | ||
6dbe3af9 | 234 | if (!zone) |
50758d0e DB |
235 | zone = first_zone-1; |
236 | while (++zone < zones) | |
6dbe3af9 KZ |
237 | if (zone_in_use(zone)) |
238 | return zone; | |
239 | return 0; | |
240 | } | |
241 | ||
a2657ae3 DB |
242 | static void make_bad_inode_v1(void) |
243 | { | |
6dbe3af9 KZ |
244 | struct minix_inode * inode = &Inode[MINIX_BAD_INO]; |
245 | int i,j,zone; | |
246 | int ind=0,dind=0; | |
247 | unsigned short ind_block[BLOCK_SIZE>>1]; | |
248 | unsigned short dind_block[BLOCK_SIZE>>1]; | |
249 | ||
250 | #define NEXT_BAD (zone = next(zone)) | |
251 | ||
252 | if (!badblocks) | |
253 | return; | |
254 | mark_inode(MINIX_BAD_INO); | |
255 | inode->i_nlinks = 1; | |
256 | inode->i_time = time(NULL); | |
257 | inode->i_mode = S_IFREG + 0000; | |
258 | inode->i_size = badblocks*BLOCK_SIZE; | |
259 | zone = next(0); | |
260 | for (i=0 ; i<7 ; i++) { | |
261 | inode->i_zone[i] = zone; | |
262 | if (!NEXT_BAD) | |
263 | goto end_bad; | |
264 | } | |
265 | inode->i_zone[7] = ind = get_free_block(); | |
266 | memset(ind_block,0,BLOCK_SIZE); | |
267 | for (i=0 ; i<512 ; i++) { | |
268 | ind_block[i] = zone; | |
269 | if (!NEXT_BAD) | |
270 | goto end_bad; | |
271 | } | |
272 | inode->i_zone[8] = dind = get_free_block(); | |
273 | memset(dind_block,0,BLOCK_SIZE); | |
274 | for (i=0 ; i<512 ; i++) { | |
275 | write_block(ind,(char *) ind_block); | |
276 | dind_block[i] = ind = get_free_block(); | |
277 | memset(ind_block,0,BLOCK_SIZE); | |
278 | for (j=0 ; j<512 ; j++) { | |
279 | ind_block[j] = zone; | |
280 | if (!NEXT_BAD) | |
281 | goto end_bad; | |
282 | } | |
283 | } | |
9fae6c27 | 284 | errx(MKFS_ERROR, _("%s: too many bad blocks"), device_name); |
6dbe3af9 KZ |
285 | end_bad: |
286 | if (ind) | |
287 | write_block(ind, (char *) ind_block); | |
288 | if (dind) | |
289 | write_block(dind, (char *) dind_block); | |
290 | } | |
291 | ||
a2657ae3 DB |
292 | static void make_bad_inode_v2_v3 (void) |
293 | { | |
fd6b7a7f KZ |
294 | struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; |
295 | int i, j, zone; | |
296 | int ind = 0, dind = 0; | |
297 | unsigned long ind_block[BLOCK_SIZE >> 2]; | |
298 | unsigned long dind_block[BLOCK_SIZE >> 2]; | |
299 | ||
300 | if (!badblocks) | |
301 | return; | |
302 | mark_inode (MINIX_BAD_INO); | |
303 | inode->i_nlinks = 1; | |
304 | inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); | |
305 | inode->i_mode = S_IFREG + 0000; | |
306 | inode->i_size = badblocks * BLOCK_SIZE; | |
307 | zone = next (0); | |
308 | for (i = 0; i < 7; i++) { | |
309 | inode->i_zone[i] = zone; | |
310 | if (!NEXT_BAD) | |
311 | goto end_bad; | |
312 | } | |
313 | inode->i_zone[7] = ind = get_free_block (); | |
314 | memset (ind_block, 0, BLOCK_SIZE); | |
315 | for (i = 0; i < 256; i++) { | |
316 | ind_block[i] = zone; | |
317 | if (!NEXT_BAD) | |
318 | goto end_bad; | |
319 | } | |
320 | inode->i_zone[8] = dind = get_free_block (); | |
321 | memset (dind_block, 0, BLOCK_SIZE); | |
322 | for (i = 0; i < 256; i++) { | |
323 | write_block (ind, (char *) ind_block); | |
324 | dind_block[i] = ind = get_free_block (); | |
325 | memset (ind_block, 0, BLOCK_SIZE); | |
326 | for (j = 0; j < 256; j++) { | |
327 | ind_block[j] = zone; | |
328 | if (!NEXT_BAD) | |
329 | goto end_bad; | |
330 | } | |
331 | } | |
332 | /* Could make triple indirect block here */ | |
9fae6c27 | 333 | errx(MKFS_ERROR, _("%s: too many bad blocks"), device_name); |
fd6b7a7f KZ |
334 | end_bad: |
335 | if (ind) | |
336 | write_block (ind, (char *) ind_block); | |
337 | if (dind) | |
338 | write_block (dind, (char *) dind_block); | |
339 | } | |
fd6b7a7f | 340 | |
37ebb48b DB |
341 | static void make_bad_inode(void) |
342 | { | |
343 | if (fs_version < 2) | |
344 | return make_bad_inode_v1(); | |
a2657ae3 | 345 | return make_bad_inode_v2_v3(); |
37ebb48b DB |
346 | } |
347 | ||
348 | static void make_root_inode_v1(void) { | |
6dbe3af9 KZ |
349 | struct minix_inode * inode = &Inode[MINIX_ROOT_INO]; |
350 | ||
351 | mark_inode(MINIX_ROOT_INO); | |
352 | inode->i_zone[0] = get_free_block(); | |
353 | inode->i_nlinks = 2; | |
354 | inode->i_time = time(NULL); | |
355 | if (badblocks) | |
356 | inode->i_size = 3*dirsize; | |
357 | else { | |
358 | root_block[2*dirsize] = '\0'; | |
359 | root_block[2*dirsize+1] = '\0'; | |
360 | inode->i_size = 2*dirsize; | |
361 | } | |
362 | inode->i_mode = S_IFDIR + 0755; | |
2b6fc908 KZ |
363 | inode->i_uid = getuid(); |
364 | if (inode->i_uid) | |
365 | inode->i_gid = getgid(); | |
6dbe3af9 KZ |
366 | write_block(inode->i_zone[0],root_block); |
367 | } | |
368 | ||
a2657ae3 | 369 | static void make_root_inode_v2_v3 (void) { |
fd6b7a7f KZ |
370 | struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; |
371 | ||
372 | mark_inode (MINIX_ROOT_INO); | |
373 | inode->i_zone[0] = get_free_block (); | |
374 | inode->i_nlinks = 2; | |
375 | inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); | |
a2657ae3 | 376 | |
fd6b7a7f KZ |
377 | if (badblocks) |
378 | inode->i_size = 3 * dirsize; | |
379 | else { | |
380 | root_block[2 * dirsize] = '\0'; | |
a2657ae3 DB |
381 | if (fs_version == 2) |
382 | inode->i_size = 2 * dirsize; | |
fd6b7a7f | 383 | } |
a2657ae3 | 384 | |
fd6b7a7f | 385 | inode->i_mode = S_IFDIR + 0755; |
2b6fc908 KZ |
386 | inode->i_uid = getuid(); |
387 | if (inode->i_uid) | |
388 | inode->i_gid = getgid(); | |
fd6b7a7f KZ |
389 | write_block (inode->i_zone[0], root_block); |
390 | } | |
fd6b7a7f | 391 | |
37ebb48b DB |
392 | static void make_root_inode(void) |
393 | { | |
394 | if (fs_version < 2) | |
395 | return make_root_inode_v1(); | |
a2657ae3 | 396 | return make_root_inode_v2_v3(); |
37ebb48b DB |
397 | } |
398 | ||
7a173d7f DB |
399 | static void super_set_nzones(void) |
400 | { | |
401 | switch (fs_version) { | |
a2657ae3 | 402 | case 3: |
7a173d7f DB |
403 | case 2: |
404 | Super.s_zones = BLOCKS; | |
405 | break; | |
406 | default: /* v1 */ | |
407 | Super.s_nzones = BLOCKS; | |
408 | break; | |
409 | } | |
410 | } | |
411 | ||
412 | static void super_init_maxsize(void) | |
413 | { | |
414 | switch (fs_version) { | |
a2657ae3 DB |
415 | case 3: |
416 | Super3.s_max_size = 2147483647L; | |
417 | break; | |
7a173d7f DB |
418 | case 2: |
419 | Super.s_max_size = 0x7fffffff; | |
a2657ae3 | 420 | break; |
7a173d7f DB |
421 | default: /* v1 */ |
422 | Super.s_max_size = (7+512+512*512)*1024; | |
423 | break; | |
424 | } | |
425 | } | |
426 | ||
a2657ae3 DB |
427 | static void super_set_map_blocks(unsigned long inodes) |
428 | { | |
429 | switch (fs_version) { | |
430 | case 3: | |
431 | Super3.s_imap_blocks = UPPER(inodes + 1, BITS_PER_BLOCK); | |
432 | Super3.s_zmap_blocks = UPPER(BLOCKS - (1+get_nimaps()+inode_blocks()), | |
433 | BITS_PER_BLOCK+1); | |
434 | Super3.s_firstdatazone = first_zone_data(); | |
435 | break; | |
436 | default: | |
437 | Super.s_imap_blocks = UPPER(inodes + 1, BITS_PER_BLOCK); | |
438 | Super.s_zmap_blocks = UPPER(BLOCKS - (1+get_nimaps()+inode_blocks()), | |
439 | BITS_PER_BLOCK+1); | |
440 | Super.s_firstdatazone = first_zone_data(); | |
441 | break; | |
442 | } | |
443 | } | |
444 | ||
445 | static void super_set_magic(void) | |
446 | { | |
447 | switch (fs_version) { | |
448 | case 3: | |
449 | Super3.s_magic = magic; | |
450 | break; | |
451 | default: | |
452 | Super.s_magic = magic; | |
453 | break; | |
454 | } | |
455 | } | |
456 | ||
50758d0e | 457 | static void setup_tables(void) { |
6dbe3af9 | 458 | int i; |
50758d0e | 459 | unsigned long inodes, zmaps, imaps, zones; |
6dbe3af9 | 460 | |
dfea2569 KZ |
461 | super_block_buffer = calloc(1, BLOCK_SIZE); |
462 | if (!super_block_buffer) | |
9fae6c27 DB |
463 | err(MKFS_ERROR, _("%s: unable to alloc buffer for superblock"), |
464 | device_name); | |
dfea2569 | 465 | |
726f69e2 | 466 | memset(boot_block_buffer,0,512); |
a2657ae3 DB |
467 | super_set_magic(); |
468 | ||
469 | if (fs_version == 3) { | |
470 | Super3.s_log_zone_size = 0; | |
471 | Super3.s_blocksize = BLOCKS; | |
472 | } | |
473 | else { | |
474 | Super.s_log_zone_size = 0; | |
475 | } | |
7a173d7f DB |
476 | |
477 | super_init_maxsize(); | |
478 | super_set_nzones(); | |
479 | zones = get_nzones(); | |
eb63b9b8 | 480 | |
a2657ae3 | 481 | /* some magic nrs: 1 inode / 3 blocks */ |
6dbe3af9 | 482 | if ( req_nr_inodes == 0 ) |
fd6b7a7f | 483 | inodes = BLOCKS/3; |
6dbe3af9 | 484 | else |
fd6b7a7f | 485 | inodes = req_nr_inodes; |
2b6fc908 | 486 | /* Round up inode count to fill block size */ |
a2657ae3 | 487 | if (fs_version == 2 || fs_version == 3) |
2b6fc908 KZ |
488 | inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & |
489 | ~(MINIX2_INODES_PER_BLOCK - 1)); | |
490 | else | |
2b6fc908 KZ |
491 | inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) & |
492 | ~(MINIX_INODES_PER_BLOCK - 1)); | |
a2657ae3 DB |
493 | if (inodes > MAX_INODES) |
494 | inodes = MAX_INODES; | |
495 | if (fs_version == 3) | |
496 | Super3.s_ninodes = inodes; | |
497 | else | |
498 | Super.s_ninodes = inodes; | |
499 | ||
500 | super_set_map_blocks(inodes); | |
501 | imaps = get_nimaps(); | |
502 | zmaps = get_nzmaps(); | |
c129767e | 503 | |
50758d0e DB |
504 | inode_map = malloc(imaps * BLOCK_SIZE); |
505 | zone_map = malloc(zmaps * BLOCK_SIZE); | |
2b6fc908 | 506 | if (!inode_map || !zone_map) |
9fae6c27 DB |
507 | err(MKFS_ERROR, _("%s: unable to allocate buffers for maps"), |
508 | device_name); | |
50758d0e DB |
509 | memset(inode_map,0xff,imaps * BLOCK_SIZE); |
510 | memset(zone_map,0xff,zmaps * BLOCK_SIZE); | |
511 | for (i = get_first_zone() ; i<zones ; i++) | |
6dbe3af9 | 512 | unmark_zone(i); |
50758d0e | 513 | for (i = MINIX_ROOT_INO ; i<=inodes; i++) |
6dbe3af9 | 514 | unmark_inode(i); |
50758d0e | 515 | inode_buffer = malloc(get_inode_buffer_size()); |
6dbe3af9 | 516 | if (!inode_buffer) |
9fae6c27 DB |
517 | err(MKFS_ERROR, _("%s: unable to allocate buffer for inodes"), |
518 | device_name); | |
50758d0e DB |
519 | memset(inode_buffer,0, get_inode_buffer_size()); |
520 | printf(_("%ld inodes\n"), inodes); | |
521 | printf(_("%ld blocks\n"), zones); | |
522 | printf(_("Firstdatazone=%ld (%ld)\n"), get_first_zone(), first_zone_data()); | |
523 | printf(_("Zonesize=%d\n"),BLOCK_SIZE<<get_zone_size()); | |
524 | printf(_("Maxsize=%ld\n\n"),get_max_size()); | |
6dbe3af9 KZ |
525 | } |
526 | ||
527 | /* | |
528 | * Perform a test of a block; return the number of | |
529 | * blocks readable/writeable. | |
530 | */ | |
50758d0e | 531 | static long do_check(char * buffer, int try, unsigned int current_block) { |
6dbe3af9 KZ |
532 | long got; |
533 | ||
534 | /* Seek to the correct loc. */ | |
535 | if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) != | |
9fae6c27 DB |
536 | current_block * BLOCK_SIZE ) |
537 | err(MKFS_ERROR, _("%s: seek failed during testing of blocks"), | |
538 | device_name); | |
6dbe3af9 KZ |
539 | |
540 | /* Try the read */ | |
541 | got = read(DEV, buffer, try * BLOCK_SIZE); | |
542 | if (got < 0) got = 0; | |
543 | if (got & (BLOCK_SIZE - 1 )) { | |
7eda085c | 544 | printf(_("Weird values in do_check: probably bugs\n")); |
6dbe3af9 KZ |
545 | } |
546 | got /= BLOCK_SIZE; | |
547 | return got; | |
548 | } | |
549 | ||
550 | static unsigned int currently_testing = 0; | |
551 | ||
50758d0e DB |
552 | static void alarm_intr(int alnum) { |
553 | unsigned long zones = get_nzones(); | |
554 | ||
555 | if (currently_testing >= zones) | |
6dbe3af9 KZ |
556 | return; |
557 | signal(SIGALRM,alarm_intr); | |
558 | alarm(5); | |
559 | if (!currently_testing) | |
560 | return; | |
561 | printf("%d ...", currently_testing); | |
562 | fflush(stdout); | |
563 | } | |
564 | ||
50758d0e | 565 | static void check_blocks(void) { |
6dbe3af9 KZ |
566 | int try,got; |
567 | static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; | |
50758d0e DB |
568 | unsigned long zones = get_nzones(); |
569 | unsigned long first_zone = get_first_zone(); | |
6dbe3af9 KZ |
570 | |
571 | currently_testing=0; | |
572 | signal(SIGALRM,alarm_intr); | |
573 | alarm(5); | |
50758d0e | 574 | while (currently_testing < zones) { |
6dbe3af9 | 575 | if (lseek(DEV,currently_testing*BLOCK_SIZE,SEEK_SET) != |
9fae6c27 DB |
576 | currently_testing*BLOCK_SIZE) |
577 | errx(MKFS_ERROR, _("%s: seek failed in check_blocks"), | |
578 | device_name); | |
6dbe3af9 | 579 | try = TEST_BUFFER_BLOCKS; |
50758d0e DB |
580 | if (currently_testing + try > zones) |
581 | try = zones-currently_testing; | |
6dbe3af9 KZ |
582 | got = do_check(buffer, try, currently_testing); |
583 | currently_testing += got; | |
584 | if (got == try) | |
585 | continue; | |
50758d0e | 586 | if (currently_testing < first_zone) |
9fae6c27 DB |
587 | errx(MKFS_ERROR, _("%s: bad blocks before data-area: " |
588 | "cannot make fs"), device_name); | |
6dbe3af9 KZ |
589 | mark_zone(currently_testing); |
590 | badblocks++; | |
591 | currently_testing++; | |
592 | } | |
7eda085c KZ |
593 | if (badblocks > 1) |
594 | printf(_("%d bad blocks\n"), badblocks); | |
595 | else if (badblocks == 1) | |
596 | printf(_("one bad block\n")); | |
6dbe3af9 KZ |
597 | } |
598 | ||
50758d0e | 599 | static void get_list_blocks(char *filename) { |
e8f26419 KZ |
600 | FILE *listfile; |
601 | unsigned long blockno; | |
fd6b7a7f | 602 | |
e8f26419 KZ |
603 | listfile = fopen(filename,"r"); |
604 | if (listfile == NULL) | |
9fae6c27 DB |
605 | err(MKFS_ERROR, _("%s: can't open file of bad blocks"), |
606 | device_name); | |
e8f26419 KZ |
607 | |
608 | while (!feof(listfile)) { | |
e30cb0ed RD |
609 | if (fscanf(listfile,"%ld\n", &blockno) != 1) { |
610 | printf(_("badblock number input error on line %d\n"), badblocks + 1); | |
9fae6c27 DB |
611 | errx(MKFS_ERROR, _("%s: cannot read badblocks file"), |
612 | device_name); | |
e30cb0ed | 613 | } |
e8f26419 KZ |
614 | mark_zone(blockno); |
615 | badblocks++; | |
616 | } | |
617 | fclose(listfile); | |
618 | ||
619 | if(badblocks > 1) | |
620 | printf(_("%d bad blocks\n"), badblocks); | |
621 | else if (badblocks == 1) | |
622 | printf(_("one bad block\n")); | |
6dbe3af9 KZ |
623 | } |
624 | ||
50758d0e | 625 | int main(int argc, char ** argv) { |
c8079044 DB |
626 | int i; |
627 | char * tmp; | |
628 | struct stat statbuf; | |
629 | char * listfile = NULL; | |
630 | char * p; | |
631 | ||
632 | if (argc && *argv) | |
633 | program_name = *argv; | |
634 | if ((p = strrchr(program_name, '/')) != NULL) | |
635 | program_name = p+1; | |
636 | ||
637 | setlocale(LC_ALL, ""); | |
638 | bindtextdomain(PACKAGE, LOCALEDIR); | |
639 | textdomain(PACKAGE); | |
640 | ||
641 | if (argc == 2 && | |
642 | (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) { | |
643 | printf(_("%s (%s)\n"), program_name, PACKAGE_STRING); | |
644 | exit(0); | |
645 | } | |
646 | ||
647 | if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) | |
9fae6c27 | 648 | errx(MKFS_ERROR, _("%s: bad inode size"), device_name); |
50758d0e | 649 | if (INODE2_SIZE * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) |
9fae6c27 | 650 | errx(MKFS_ERROR, _("%s: bad inode size"), device_name); |
c8079044 DB |
651 | |
652 | opterr = 0; | |
a2657ae3 | 653 | while ((i = getopt(argc, argv, "ci:l:n:v123")) != -1) |
c8079044 DB |
654 | switch (i) { |
655 | case 'c': | |
656 | check=1; break; | |
657 | case 'i': | |
658 | req_nr_inodes = (unsigned long) atol(optarg); | |
659 | break; | |
660 | case 'l': | |
661 | listfile = optarg; break; | |
662 | case 'n': | |
663 | i = strtoul(optarg,&tmp,0); | |
664 | if (*tmp) | |
665 | usage(); | |
666 | if (i == 14) | |
667 | magic = MINIX_SUPER_MAGIC; | |
668 | else if (i == 30) | |
669 | magic = MINIX_SUPER_MAGIC2; | |
670 | else | |
671 | usage(); | |
672 | namelen = i; | |
673 | dirsize = i+2; | |
674 | break; | |
4bc4653e DB |
675 | case '1': |
676 | fs_version = 1; | |
677 | break; | |
678 | case '2': | |
679 | case 'v': /* kept for backwards compatiblitly */ | |
50758d0e | 680 | fs_version = 2; |
c8079044 DB |
681 | version2 = 1; |
682 | break; | |
a2657ae3 DB |
683 | case '3': |
684 | fs_version = 3; | |
685 | break; | |
c8079044 DB |
686 | default: |
687 | usage(); | |
688 | } | |
689 | argc -= optind; | |
690 | argv += optind; | |
691 | if (argc > 0 && !device_name) { | |
692 | device_name = argv[0]; | |
693 | argc--; | |
694 | argv++; | |
695 | } | |
696 | if (argc > 0) { | |
697 | BLOCKS = strtol(argv[0],&tmp,0); | |
698 | if (*tmp) { | |
699 | printf(_("strtol error: number of blocks not specified")); | |
700 | usage(); | |
701 | } | |
702 | } | |
703 | ||
704 | if (!device_name) { | |
705 | usage(); | |
706 | } | |
707 | check_mount(); /* is it already mounted? */ | |
708 | tmp = root_block; | |
709 | *(short *)tmp = 1; | |
710 | strcpy(tmp+2,"."); | |
711 | tmp += dirsize; | |
712 | *(short *)tmp = 1; | |
713 | strcpy(tmp+2,".."); | |
714 | tmp += dirsize; | |
715 | *(short *)tmp = 2; | |
716 | strcpy(tmp+2,".badblocks"); | |
717 | if (stat(device_name, &statbuf) < 0) | |
9fae6c27 | 718 | err(MKFS_ERROR, _("%s: stat failed"), device_name); |
c8079044 DB |
719 | if (S_ISBLK(statbuf.st_mode)) |
720 | DEV = open(device_name,O_RDWR | O_EXCL); | |
7eda085c | 721 | else |
c8079044 | 722 | DEV = open(device_name,O_RDWR); |
4f138435 | 723 | |
c8079044 | 724 | if (DEV<0) |
9fae6c27 | 725 | err(MKFS_ERROR, _("%s: open failed"), device_name); |
a2657ae3 | 726 | |
c8079044 DB |
727 | if (S_ISBLK(statbuf.st_mode)) { |
728 | int sectorsize; | |
729 | ||
730 | if (blkdev_get_sector_size(DEV, §orsize) == -1) | |
c2e05a49 | 731 | sectorsize = DEFAULT_SECTOR_SIZE; /* kernel < 2.3.3 */ |
4f138435 DB |
732 | |
733 | if (blkdev_is_misaligned(DEV)) | |
734 | warnx(_("%s: device is misaligned"), device_name); | |
735 | ||
c8079044 | 736 | if (BLOCK_SIZE < sectorsize) |
9fae6c27 DB |
737 | errx(MKFS_ERROR, _("block size smaller than physical " |
738 | "sector size of %s"), device_name); | |
c8079044 DB |
739 | if (!BLOCKS) { |
740 | if (blkdev_get_size(DEV, &BLOCKS) == -1) | |
9fae6c27 DB |
741 | errx(MKFS_ERROR, _("cannot determine size of %s"), |
742 | device_name); | |
c8079044 DB |
743 | BLOCKS /= BLOCK_SIZE; |
744 | } | |
745 | } else if (!S_ISBLK(statbuf.st_mode)) { | |
746 | if (!BLOCKS) | |
747 | BLOCKS = statbuf.st_size / BLOCK_SIZE; | |
748 | check=0; | |
749 | } else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) | |
9fae6c27 | 750 | errx(MKFS_ERROR, _("will not try to make filesystem on '%s'"), device_name); |
c8079044 | 751 | if (BLOCKS < 10) |
9fae6c27 | 752 | errx(MKFS_ERROR, _("%s: number of blocks too small"), device_name); |
a2657ae3 DB |
753 | |
754 | if (fs_version == 3) | |
755 | magic = MINIX3_SUPER_MAGIC; | |
756 | ||
50758d0e | 757 | if (fs_version == 2) { |
c8079044 DB |
758 | if (namelen == 14) |
759 | magic = MINIX2_SUPER_MAGIC; | |
760 | else | |
761 | magic = MINIX2_SUPER_MAGIC2; | |
762 | } else | |
763 | if (BLOCKS > MAX_INODES) | |
764 | BLOCKS = MAX_INODES; | |
765 | setup_tables(); | |
766 | if (check) | |
767 | check_blocks(); | |
768 | else if (listfile) | |
769 | get_list_blocks(listfile); | |
37ebb48b DB |
770 | |
771 | make_root_inode(); | |
772 | make_bad_inode(); | |
c8079044 DB |
773 | |
774 | mark_good_blocks(); | |
775 | write_tables(); | |
776 | close(DEV); | |
777 | ||
778 | return 0; | |
6dbe3af9 | 779 | } |