]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/mkfs.minix.c
mkfs.cramfs: coding style
[thirdparty/util-linux.git] / disk-utils / mkfs.minix.c
CommitLineData
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
96static char * program_name = "mkfs";
97static char * device_name = NULL;
98static int DEV = -1;
16726585 99static unsigned long long BLOCKS = 0;
6dbe3af9
KZ
100static int check = 0;
101static 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 */
109static int namelen = 30;
fd6b7a7f
KZ
110static int dirsize = 32;
111static int magic = MINIX_SUPER_MAGIC2;
112static int version2 = 0;
6dbe3af9
KZ
113
114static char root_block[BLOCK_SIZE] = "\0";
115
726f69e2 116static char boot_block_buffer[512];
6dbe3af9 117#define Super (*(struct minix_super_block *)super_block_buffer)
6dbe3af9
KZ
118
119static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
120static int used_good_blocks = 0;
121static 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 132static void __attribute__((__noreturn__))
22853e4a 133usage(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 143static 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
160static 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
171static 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 196static 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 203static 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 223static 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
230static 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
242static 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
285end_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
292static 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
341static 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
348static 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 369static 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
392static 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
399static 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
412static 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
427static 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
445static 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 457static 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 531static 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
550static unsigned int currently_testing = 0;
551
50758d0e
DB
552static 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 565static 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 599static 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 625int 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, &sectorsize) == -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}