]>
Commit | Line | Data |
---|---|---|
6dbe3af9 KZ |
1 | /* |
2 | * mkfs.c - make a linux (minix) file-system. | |
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 | * | |
49 | * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] | |
6dbe3af9 KZ |
50 | * |
51 | * -c for readablility checking (SLOW!) | |
52 | * -l for getting a list of bad blocks from a file. | |
53 | * -n for namelength (currently the kernel only uses 14 or 30) | |
54 | * -i for number of inodes | |
fd6b7a7f | 55 | * -v for v2 filesystem |
6dbe3af9 KZ |
56 | * |
57 | * The device may be a block device or a image of one, but this isn't | |
58 | * enforced (but it's not much fun on a character device :-). | |
59 | */ | |
60 | ||
61 | #include <stdio.h> | |
62 | #include <time.h> | |
63 | #include <unistd.h> | |
64 | #include <string.h> | |
65 | #include <signal.h> | |
66 | #include <fcntl.h> | |
67 | #include <ctype.h> | |
68 | #include <stdlib.h> | |
69 | #include <termios.h> | |
70 | #include <sys/stat.h> | |
fd6b7a7f | 71 | #include <sys/ioctl.h> |
6dbe3af9 | 72 | #include <mntent.h> |
7eda085c | 73 | #include <getopt.h> |
6dbe3af9 | 74 | |
22853e4a | 75 | #include "minix.h" |
7eda085c | 76 | #include "nls.h" |
7eda085c | 77 | |
22853e4a KZ |
78 | #ifndef BLKGETSIZE |
79 | #define BLKGETSIZE _IO(0x12,96) /* return device size */ | |
80 | #endif | |
81 | ||
fd6b7a7f KZ |
82 | #ifdef MINIX2_SUPER_MAGIC2 |
83 | #define HAVE_MINIX2 1 | |
84 | #endif | |
85 | ||
6dbe3af9 KZ |
86 | #ifndef __GNUC__ |
87 | #error "needs gcc for the bitop-__asm__'s" | |
88 | #endif | |
89 | ||
6dbe3af9 KZ |
90 | #define MINIX_ROOT_INO 1 |
91 | #define MINIX_BAD_INO 2 | |
92 | ||
93 | #define TEST_BUFFER_BLOCKS 16 | |
94 | #define MAX_GOOD_BLOCKS 512 | |
95 | ||
96 | #define UPPER(size,n) ((size+((n)-1))/(n)) | |
97 | #define INODE_SIZE (sizeof(struct minix_inode)) | |
fd6b7a7f KZ |
98 | #ifdef HAVE_MINIX2 |
99 | #define INODE_SIZE2 (sizeof(struct minix2_inode)) | |
100 | #define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ | |
101 | : MINIX_INODES_PER_BLOCK)) | |
102 | #else | |
103 | #define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK)) | |
104 | #endif | |
6dbe3af9 KZ |
105 | #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) |
106 | ||
107 | #define BITS_PER_BLOCK (BLOCK_SIZE<<3) | |
108 | ||
109 | static char * program_name = "mkfs"; | |
110 | static char * device_name = NULL; | |
111 | static int DEV = -1; | |
112 | static long BLOCKS = 0; | |
113 | static int check = 0; | |
114 | static int badblocks = 0; | |
115 | static int namelen = 30; /* default (changed to 30, per Linus's | |
116 | suggestion, Sun Nov 21 08:05:07 1993) */ | |
fd6b7a7f KZ |
117 | static int dirsize = 32; |
118 | static int magic = MINIX_SUPER_MAGIC2; | |
119 | static int version2 = 0; | |
6dbe3af9 KZ |
120 | |
121 | static char root_block[BLOCK_SIZE] = "\0"; | |
122 | ||
123 | static char * inode_buffer = NULL; | |
124 | #define Inode (((struct minix_inode *) inode_buffer)-1) | |
fd6b7a7f KZ |
125 | #ifdef HAVE_MINIX2 |
126 | #define Inode2 (((struct minix2_inode *) inode_buffer)-1) | |
127 | #endif | |
6dbe3af9 | 128 | static char super_block_buffer[BLOCK_SIZE]; |
726f69e2 | 129 | static char boot_block_buffer[512]; |
6dbe3af9 KZ |
130 | #define Super (*(struct minix_super_block *)super_block_buffer) |
131 | #define INODES ((unsigned long)Super.s_ninodes) | |
fd6b7a7f KZ |
132 | #ifdef HAVE_MINIX2 |
133 | #define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) | |
134 | #else | |
135 | #define ZONES ((unsigned long)(Super.s_nzones)) | |
136 | #endif | |
6dbe3af9 KZ |
137 | #define IMAPS ((unsigned long)Super.s_imap_blocks) |
138 | #define ZMAPS ((unsigned long)Super.s_zmap_blocks) | |
139 | #define FIRSTZONE ((unsigned long)Super.s_firstdatazone) | |
140 | #define ZONESIZE ((unsigned long)Super.s_log_zone_size) | |
141 | #define MAXSIZE ((unsigned long)Super.s_max_size) | |
142 | #define MAGIC (Super.s_magic) | |
143 | #define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS) | |
144 | ||
2b6fc908 KZ |
145 | static char *inode_map; |
146 | static char *zone_map; | |
6dbe3af9 KZ |
147 | |
148 | static unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; | |
149 | static int used_good_blocks = 0; | |
150 | static unsigned long req_nr_inodes = 0; | |
151 | ||
fd6b7a7f | 152 | #include "bitops.h" |
6dbe3af9 KZ |
153 | |
154 | #define inode_in_use(x) (bit(inode_map,(x))) | |
155 | #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) | |
156 | ||
157 | #define mark_inode(x) (setbit(inode_map,(x))) | |
158 | #define unmark_inode(x) (clrbit(inode_map,(x))) | |
159 | ||
160 | #define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1)) | |
161 | #define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1)) | |
162 | ||
22853e4a KZ |
163 | static void |
164 | die(char *str) { | |
95f1bdee KZ |
165 | fprintf(stderr, "%s: ", program_name); |
166 | fprintf(stderr, str, device_name); | |
167 | fprintf(stderr, "\n"); | |
7eda085c KZ |
168 | exit(8); |
169 | } | |
170 | ||
22853e4a KZ |
171 | static void |
172 | usage(void) { | |
7eda085c KZ |
173 | fprintf(stderr, "%s (%s)\n", program_name, util_linux_version); |
174 | fprintf(stderr, | |
175 | _("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]\n"), | |
176 | program_name); | |
177 | exit(16); | |
178 | } | |
6dbe3af9 KZ |
179 | |
180 | /* | |
181 | * Check to make certain that our new filesystem won't be created on | |
182 | * an already mounted partition. Code adapted from mke2fs, Copyright | |
183 | * (C) 1994 Theodore Ts'o. Also licensed under GPL. | |
184 | */ | |
22853e4a KZ |
185 | static void |
186 | check_mount(void) { | |
6dbe3af9 KZ |
187 | FILE * f; |
188 | struct mntent * mnt; | |
189 | ||
190 | if ((f = setmntent (MOUNTED, "r")) == NULL) | |
191 | return; | |
192 | while ((mnt = getmntent (f)) != NULL) | |
193 | if (strcmp (device_name, mnt->mnt_fsname) == 0) | |
194 | break; | |
195 | endmntent (f); | |
196 | if (!mnt) | |
197 | return; | |
198 | ||
7eda085c | 199 | die(_("%s is mounted; will not make a filesystem here!")); |
6dbe3af9 KZ |
200 | } |
201 | ||
22853e4a KZ |
202 | static long |
203 | valid_offset (int fd, int offset) { | |
fd6b7a7f KZ |
204 | char ch; |
205 | ||
206 | if (lseek (fd, offset, 0) < 0) | |
207 | return 0; | |
208 | if (read (fd, &ch, 1) < 1) | |
209 | return 0; | |
210 | return 1; | |
211 | } | |
212 | ||
22853e4a KZ |
213 | static int |
214 | count_blocks (int fd) { | |
fd6b7a7f KZ |
215 | int high, low; |
216 | ||
217 | low = 0; | |
218 | for (high = 1; valid_offset (fd, high); high *= 2) | |
219 | low = high; | |
220 | while (low < high - 1) | |
221 | { | |
222 | const int mid = (low + high) / 2; | |
223 | ||
224 | if (valid_offset (fd, mid)) | |
225 | low = mid; | |
226 | else | |
227 | high = mid; | |
228 | } | |
229 | valid_offset (fd, 0); | |
230 | return (low + 1); | |
231 | } | |
232 | ||
22853e4a KZ |
233 | static int |
234 | get_size(const char *file) { | |
fd6b7a7f | 235 | int fd; |
7eda085c | 236 | long size; |
fd6b7a7f KZ |
237 | |
238 | fd = open(file, O_RDWR); | |
239 | if (fd < 0) { | |
240 | perror(file); | |
241 | exit(1); | |
242 | } | |
243 | if (ioctl(fd, BLKGETSIZE, &size) >= 0) { | |
244 | close(fd); | |
245 | return (size * 512); | |
246 | } | |
247 | ||
248 | size = count_blocks(fd); | |
249 | close(fd); | |
250 | return size; | |
251 | } | |
252 | ||
22853e4a KZ |
253 | static void |
254 | write_tables(void) { | |
6dbe3af9 KZ |
255 | /* Mark the super block valid. */ |
256 | Super.s_state |= MINIX_VALID_FS; | |
257 | Super.s_state &= ~MINIX_ERROR_FS; | |
258 | ||
726f69e2 | 259 | if (lseek(DEV, 0, SEEK_SET)) |
7eda085c | 260 | die(_("seek to boot block failed in write_tables")); |
726f69e2 | 261 | if (512 != write(DEV, boot_block_buffer, 512)) |
7eda085c | 262 | die(_("unable to clear boot sector")); |
6dbe3af9 | 263 | if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET)) |
7eda085c | 264 | die(_("seek failed in write_tables")); |
6dbe3af9 | 265 | if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE)) |
7eda085c | 266 | die(_("unable to write super-block")); |
6dbe3af9 | 267 | if (IMAPS*BLOCK_SIZE != write(DEV,inode_map,IMAPS*BLOCK_SIZE)) |
7eda085c | 268 | die(_("unable to write inode map")); |
6dbe3af9 | 269 | if (ZMAPS*BLOCK_SIZE != write(DEV,zone_map,ZMAPS*BLOCK_SIZE)) |
7eda085c | 270 | die(_("unable to write zone map")); |
6dbe3af9 | 271 | if (INODE_BUFFER_SIZE != write(DEV,inode_buffer,INODE_BUFFER_SIZE)) |
7eda085c | 272 | die(_("unable to write inodes")); |
726f69e2 | 273 | |
6dbe3af9 KZ |
274 | } |
275 | ||
22853e4a KZ |
276 | static void |
277 | write_block(int blk, char * buffer) { | |
6dbe3af9 | 278 | if (blk*BLOCK_SIZE != lseek(DEV, blk*BLOCK_SIZE, SEEK_SET)) |
7eda085c | 279 | die(_("seek failed in write_block")); |
6dbe3af9 | 280 | if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE)) |
7eda085c | 281 | die(_("write failed in write_block")); |
6dbe3af9 KZ |
282 | } |
283 | ||
22853e4a KZ |
284 | static int |
285 | get_free_block(void) { | |
6dbe3af9 KZ |
286 | int blk; |
287 | ||
288 | if (used_good_blocks+1 >= MAX_GOOD_BLOCKS) | |
7eda085c | 289 | die(_("too many bad blocks")); |
6dbe3af9 KZ |
290 | if (used_good_blocks) |
291 | blk = good_blocks_table[used_good_blocks-1]+1; | |
292 | else | |
293 | blk = FIRSTZONE; | |
294 | while (blk < ZONES && zone_in_use(blk)) | |
295 | blk++; | |
296 | if (blk >= ZONES) | |
7eda085c | 297 | die(_("not enough good blocks")); |
6dbe3af9 KZ |
298 | good_blocks_table[used_good_blocks] = blk; |
299 | used_good_blocks++; | |
300 | return blk; | |
301 | } | |
302 | ||
22853e4a KZ |
303 | static void |
304 | mark_good_blocks(void) { | |
6dbe3af9 KZ |
305 | int blk; |
306 | ||
307 | for (blk=0 ; blk < used_good_blocks ; blk++) | |
308 | mark_zone(good_blocks_table[blk]); | |
309 | } | |
310 | ||
22853e4a KZ |
311 | static inline int |
312 | next(int zone) { | |
6dbe3af9 KZ |
313 | if (!zone) |
314 | zone = FIRSTZONE-1; | |
315 | while (++zone < ZONES) | |
316 | if (zone_in_use(zone)) | |
317 | return zone; | |
318 | return 0; | |
319 | } | |
320 | ||
22853e4a KZ |
321 | static void |
322 | make_bad_inode(void) { | |
6dbe3af9 KZ |
323 | struct minix_inode * inode = &Inode[MINIX_BAD_INO]; |
324 | int i,j,zone; | |
325 | int ind=0,dind=0; | |
326 | unsigned short ind_block[BLOCK_SIZE>>1]; | |
327 | unsigned short dind_block[BLOCK_SIZE>>1]; | |
328 | ||
329 | #define NEXT_BAD (zone = next(zone)) | |
330 | ||
331 | if (!badblocks) | |
332 | return; | |
333 | mark_inode(MINIX_BAD_INO); | |
334 | inode->i_nlinks = 1; | |
335 | inode->i_time = time(NULL); | |
336 | inode->i_mode = S_IFREG + 0000; | |
337 | inode->i_size = badblocks*BLOCK_SIZE; | |
338 | zone = next(0); | |
339 | for (i=0 ; i<7 ; i++) { | |
340 | inode->i_zone[i] = zone; | |
341 | if (!NEXT_BAD) | |
342 | goto end_bad; | |
343 | } | |
344 | inode->i_zone[7] = ind = get_free_block(); | |
345 | memset(ind_block,0,BLOCK_SIZE); | |
346 | for (i=0 ; i<512 ; i++) { | |
347 | ind_block[i] = zone; | |
348 | if (!NEXT_BAD) | |
349 | goto end_bad; | |
350 | } | |
351 | inode->i_zone[8] = dind = get_free_block(); | |
352 | memset(dind_block,0,BLOCK_SIZE); | |
353 | for (i=0 ; i<512 ; i++) { | |
354 | write_block(ind,(char *) ind_block); | |
355 | dind_block[i] = ind = get_free_block(); | |
356 | memset(ind_block,0,BLOCK_SIZE); | |
357 | for (j=0 ; j<512 ; j++) { | |
358 | ind_block[j] = zone; | |
359 | if (!NEXT_BAD) | |
360 | goto end_bad; | |
361 | } | |
362 | } | |
7eda085c | 363 | die(_("too many bad blocks")); |
6dbe3af9 KZ |
364 | end_bad: |
365 | if (ind) | |
366 | write_block(ind, (char *) ind_block); | |
367 | if (dind) | |
368 | write_block(dind, (char *) dind_block); | |
369 | } | |
370 | ||
fd6b7a7f | 371 | #ifdef HAVE_MINIX2 |
22853e4a KZ |
372 | static void |
373 | make_bad_inode2 (void) { | |
fd6b7a7f KZ |
374 | struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; |
375 | int i, j, zone; | |
376 | int ind = 0, dind = 0; | |
377 | unsigned long ind_block[BLOCK_SIZE >> 2]; | |
378 | unsigned long dind_block[BLOCK_SIZE >> 2]; | |
379 | ||
380 | if (!badblocks) | |
381 | return; | |
382 | mark_inode (MINIX_BAD_INO); | |
383 | inode->i_nlinks = 1; | |
384 | inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); | |
385 | inode->i_mode = S_IFREG + 0000; | |
386 | inode->i_size = badblocks * BLOCK_SIZE; | |
387 | zone = next (0); | |
388 | for (i = 0; i < 7; i++) { | |
389 | inode->i_zone[i] = zone; | |
390 | if (!NEXT_BAD) | |
391 | goto end_bad; | |
392 | } | |
393 | inode->i_zone[7] = ind = get_free_block (); | |
394 | memset (ind_block, 0, BLOCK_SIZE); | |
395 | for (i = 0; i < 256; i++) { | |
396 | ind_block[i] = zone; | |
397 | if (!NEXT_BAD) | |
398 | goto end_bad; | |
399 | } | |
400 | inode->i_zone[8] = dind = get_free_block (); | |
401 | memset (dind_block, 0, BLOCK_SIZE); | |
402 | for (i = 0; i < 256; i++) { | |
403 | write_block (ind, (char *) ind_block); | |
404 | dind_block[i] = ind = get_free_block (); | |
405 | memset (ind_block, 0, BLOCK_SIZE); | |
406 | for (j = 0; j < 256; j++) { | |
407 | ind_block[j] = zone; | |
408 | if (!NEXT_BAD) | |
409 | goto end_bad; | |
410 | } | |
411 | } | |
412 | /* Could make triple indirect block here */ | |
7eda085c | 413 | die (_("too many bad blocks")); |
fd6b7a7f KZ |
414 | end_bad: |
415 | if (ind) | |
416 | write_block (ind, (char *) ind_block); | |
417 | if (dind) | |
418 | write_block (dind, (char *) dind_block); | |
419 | } | |
420 | #endif | |
421 | ||
22853e4a KZ |
422 | static void |
423 | make_root_inode(void) { | |
6dbe3af9 KZ |
424 | struct minix_inode * inode = &Inode[MINIX_ROOT_INO]; |
425 | ||
426 | mark_inode(MINIX_ROOT_INO); | |
427 | inode->i_zone[0] = get_free_block(); | |
428 | inode->i_nlinks = 2; | |
429 | inode->i_time = time(NULL); | |
430 | if (badblocks) | |
431 | inode->i_size = 3*dirsize; | |
432 | else { | |
433 | root_block[2*dirsize] = '\0'; | |
434 | root_block[2*dirsize+1] = '\0'; | |
435 | inode->i_size = 2*dirsize; | |
436 | } | |
437 | inode->i_mode = S_IFDIR + 0755; | |
2b6fc908 KZ |
438 | inode->i_uid = getuid(); |
439 | if (inode->i_uid) | |
440 | inode->i_gid = getgid(); | |
6dbe3af9 KZ |
441 | write_block(inode->i_zone[0],root_block); |
442 | } | |
443 | ||
fd6b7a7f | 444 | #ifdef HAVE_MINIX2 |
22853e4a KZ |
445 | static void |
446 | make_root_inode2 (void) { | |
fd6b7a7f KZ |
447 | struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; |
448 | ||
449 | mark_inode (MINIX_ROOT_INO); | |
450 | inode->i_zone[0] = get_free_block (); | |
451 | inode->i_nlinks = 2; | |
452 | inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); | |
453 | if (badblocks) | |
454 | inode->i_size = 3 * dirsize; | |
455 | else { | |
456 | root_block[2 * dirsize] = '\0'; | |
457 | root_block[2 * dirsize + 1] = '\0'; | |
458 | inode->i_size = 2 * dirsize; | |
459 | } | |
460 | inode->i_mode = S_IFDIR + 0755; | |
2b6fc908 KZ |
461 | inode->i_uid = getuid(); |
462 | if (inode->i_uid) | |
463 | inode->i_gid = getgid(); | |
fd6b7a7f KZ |
464 | write_block (inode->i_zone[0], root_block); |
465 | } | |
466 | #endif | |
467 | ||
22853e4a KZ |
468 | static void |
469 | setup_tables(void) { | |
6dbe3af9 | 470 | int i; |
fd6b7a7f | 471 | unsigned long inodes; |
6dbe3af9 | 472 | |
6dbe3af9 | 473 | memset(super_block_buffer,0,BLOCK_SIZE); |
726f69e2 | 474 | memset(boot_block_buffer,0,512); |
6dbe3af9 KZ |
475 | MAGIC = magic; |
476 | ZONESIZE = 0; | |
fd6b7a7f | 477 | MAXSIZE = version2 ? 0x7fffffff : (7+512+512*512)*1024; |
6dbe3af9 | 478 | ZONES = BLOCKS; |
eb63b9b8 | 479 | |
6dbe3af9 KZ |
480 | /* some magic nrs: 1 inode / 3 blocks */ |
481 | if ( req_nr_inodes == 0 ) | |
fd6b7a7f | 482 | inodes = BLOCKS/3; |
6dbe3af9 | 483 | else |
fd6b7a7f | 484 | inodes = req_nr_inodes; |
2b6fc908 KZ |
485 | /* Round up inode count to fill block size */ |
486 | #ifdef HAVE_MINIX2 | |
487 | if (version2) | |
488 | inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & | |
489 | ~(MINIX2_INODES_PER_BLOCK - 1)); | |
490 | else | |
491 | #endif | |
492 | inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) & | |
493 | ~(MINIX_INODES_PER_BLOCK - 1)); | |
fd6b7a7f KZ |
494 | if (inodes > 65535) |
495 | inodes = 65535; | |
496 | INODES = inodes; | |
2b6fc908 | 497 | IMAPS = UPPER(INODES + 1,BITS_PER_BLOCK); |
eb63b9b8 KZ |
498 | ZMAPS = UPPER(BLOCKS - (1+IMAPS+INODE_BLOCKS), BITS_PER_BLOCK+1); |
499 | /* The old code here | |
500 | * ZMAPS = 0; | |
501 | * while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE + 1,BITS_PER_BLOCK)) | |
502 | * ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE + 1,BITS_PER_BLOCK); | |
503 | * was no good, since it may loop. - aeb | |
504 | */ | |
6dbe3af9 | 505 | FIRSTZONE = NORM_FIRSTZONE; |
2b6fc908 KZ |
506 | inode_map = malloc(IMAPS * BLOCK_SIZE); |
507 | zone_map = malloc(ZMAPS * BLOCK_SIZE); | |
508 | if (!inode_map || !zone_map) | |
7eda085c | 509 | die(_("unable to allocate buffers for maps")); |
2b6fc908 KZ |
510 | memset(inode_map,0xff,IMAPS * BLOCK_SIZE); |
511 | memset(zone_map,0xff,ZMAPS * BLOCK_SIZE); | |
6dbe3af9 KZ |
512 | for (i = FIRSTZONE ; i<ZONES ; i++) |
513 | unmark_zone(i); | |
2b6fc908 | 514 | for (i = MINIX_ROOT_INO ; i<=INODES ; i++) |
6dbe3af9 KZ |
515 | unmark_inode(i); |
516 | inode_buffer = malloc(INODE_BUFFER_SIZE); | |
517 | if (!inode_buffer) | |
7eda085c | 518 | die(_("unable to allocate buffer for inodes")); |
6dbe3af9 | 519 | memset(inode_buffer,0,INODE_BUFFER_SIZE); |
7eda085c KZ |
520 | printf(_("%ld inodes\n"),INODES); |
521 | printf(_("%ld blocks\n"),ZONES); | |
522 | printf(_("Firstdatazone=%ld (%ld)\n"),FIRSTZONE,NORM_FIRSTZONE); | |
523 | printf(_("Zonesize=%d\n"),BLOCK_SIZE<<ZONESIZE); | |
524 | printf(_("Maxsize=%ld\n\n"),MAXSIZE); | |
6dbe3af9 KZ |
525 | } |
526 | ||
527 | /* | |
528 | * Perform a test of a block; return the number of | |
529 | * blocks readable/writeable. | |
530 | */ | |
22853e4a KZ |
531 | static long |
532 | do_check(char * buffer, int try, unsigned int current_block) { | |
6dbe3af9 KZ |
533 | long got; |
534 | ||
535 | /* Seek to the correct loc. */ | |
536 | if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) != | |
66ee8158 KZ |
537 | current_block * BLOCK_SIZE ) { |
538 | die(_("seek failed during testing of blocks")); | |
6dbe3af9 KZ |
539 | } |
540 | ||
541 | ||
542 | /* Try the read */ | |
543 | got = read(DEV, buffer, try * BLOCK_SIZE); | |
544 | if (got < 0) got = 0; | |
545 | if (got & (BLOCK_SIZE - 1 )) { | |
7eda085c | 546 | printf(_("Weird values in do_check: probably bugs\n")); |
6dbe3af9 KZ |
547 | } |
548 | got /= BLOCK_SIZE; | |
549 | return got; | |
550 | } | |
551 | ||
552 | static unsigned int currently_testing = 0; | |
553 | ||
22853e4a KZ |
554 | static void |
555 | alarm_intr(int alnum) { | |
6dbe3af9 KZ |
556 | if (currently_testing >= ZONES) |
557 | return; | |
558 | signal(SIGALRM,alarm_intr); | |
559 | alarm(5); | |
560 | if (!currently_testing) | |
561 | return; | |
562 | printf("%d ...", currently_testing); | |
563 | fflush(stdout); | |
564 | } | |
565 | ||
22853e4a KZ |
566 | static void |
567 | check_blocks(void) { | |
6dbe3af9 KZ |
568 | int try,got; |
569 | static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; | |
570 | ||
571 | currently_testing=0; | |
572 | signal(SIGALRM,alarm_intr); | |
573 | alarm(5); | |
574 | while (currently_testing < ZONES) { | |
575 | if (lseek(DEV,currently_testing*BLOCK_SIZE,SEEK_SET) != | |
576 | currently_testing*BLOCK_SIZE) | |
7eda085c | 577 | die(_("seek failed in check_blocks")); |
6dbe3af9 KZ |
578 | try = TEST_BUFFER_BLOCKS; |
579 | if (currently_testing + try > ZONES) | |
580 | try = ZONES-currently_testing; | |
581 | got = do_check(buffer, try, currently_testing); | |
582 | currently_testing += got; | |
583 | if (got == try) | |
584 | continue; | |
585 | if (currently_testing < FIRSTZONE) | |
7eda085c | 586 | die(_("bad blocks before data-area: cannot make fs")); |
6dbe3af9 KZ |
587 | mark_zone(currently_testing); |
588 | badblocks++; | |
589 | currently_testing++; | |
590 | } | |
7eda085c KZ |
591 | if (badblocks > 1) |
592 | printf(_("%d bad blocks\n"), badblocks); | |
593 | else if (badblocks == 1) | |
594 | printf(_("one bad block\n")); | |
6dbe3af9 KZ |
595 | } |
596 | ||
22853e4a KZ |
597 | static void |
598 | get_list_blocks(char *filename) { | |
e8f26419 KZ |
599 | FILE *listfile; |
600 | unsigned long blockno; | |
fd6b7a7f | 601 | |
e8f26419 KZ |
602 | listfile = fopen(filename,"r"); |
603 | if (listfile == NULL) | |
604 | die(_("can't open file of bad blocks")); | |
605 | ||
606 | while (!feof(listfile)) { | |
607 | fscanf(listfile,"%ld\n", &blockno); | |
608 | mark_zone(blockno); | |
609 | badblocks++; | |
610 | } | |
611 | fclose(listfile); | |
612 | ||
613 | if(badblocks > 1) | |
614 | printf(_("%d bad blocks\n"), badblocks); | |
615 | else if (badblocks == 1) | |
616 | printf(_("one bad block\n")); | |
6dbe3af9 KZ |
617 | } |
618 | ||
22853e4a KZ |
619 | int |
620 | main(int argc, char ** argv) { | |
fd6b7a7f KZ |
621 | int i; |
622 | char * tmp; | |
623 | struct stat statbuf; | |
624 | char * listfile = NULL; | |
eb63b9b8 | 625 | char * p; |
fd6b7a7f KZ |
626 | |
627 | if (argc && *argv) | |
628 | program_name = *argv; | |
eb63b9b8 KZ |
629 | if ((p = strrchr(program_name, '/')) != NULL) |
630 | program_name = p+1; | |
631 | ||
632 | setlocale(LC_ALL, ""); | |
633 | bindtextdomain(PACKAGE, LOCALEDIR); | |
634 | textdomain(PACKAGE); | |
635 | ||
636 | if (argc == 2 && | |
637 | (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) { | |
638 | printf(_("%s from %s\n"), program_name, util_linux_version); | |
639 | exit(0); | |
640 | } | |
641 | ||
fd6b7a7f | 642 | if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) |
7eda085c | 643 | die(_("bad inode size")); |
fd6b7a7f KZ |
644 | #ifdef HAVE_MINIX2 |
645 | if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) | |
7eda085c | 646 | die(_("bad inode size")); |
fd6b7a7f | 647 | #endif |
7eda085c | 648 | opterr = 0; |
ffc43748 | 649 | while ((i = getopt(argc, argv, "ci:l:n:v")) != -1) |
7eda085c KZ |
650 | switch (i) { |
651 | case 'c': | |
652 | check=1; break; | |
653 | case 'i': | |
66ee8158 | 654 | req_nr_inodes = (unsigned long) atol(optarg); |
7eda085c KZ |
655 | break; |
656 | case 'l': | |
657 | listfile = optarg; break; | |
658 | case 'n': | |
659 | i = strtoul(optarg,&tmp,0); | |
660 | if (*tmp) | |
fd6b7a7f | 661 | usage(); |
7eda085c KZ |
662 | if (i == 14) |
663 | magic = MINIX_SUPER_MAGIC; | |
664 | else if (i == 30) | |
665 | magic = MINIX_SUPER_MAGIC2; | |
666 | else | |
fd6b7a7f | 667 | usage(); |
7eda085c KZ |
668 | namelen = i; |
669 | dirsize = i+2; | |
670 | break; | |
671 | case 'v': | |
95f1bdee KZ |
672 | #ifndef HAVE_MINIX2 |
673 | fprintf(stderr, | |
674 | _("%s: not compiled with minix v2 support\n"), | |
675 | program_name); | |
676 | exit(-1); | |
fd6b7a7f | 677 | #endif |
95f1bdee | 678 | version2 = 1; |
7eda085c KZ |
679 | break; |
680 | default: | |
681 | usage(); | |
fd6b7a7f | 682 | } |
7eda085c KZ |
683 | argc -= optind; |
684 | argv += optind; | |
685 | if (argc > 0 && !device_name) { | |
686 | device_name = argv[0]; | |
687 | argc--; | |
688 | argv++; | |
689 | } | |
690 | if (argc > 0) { | |
691 | BLOCKS = strtol(argv[0],&tmp,0); | |
692 | if (*tmp) { | |
693 | printf(_("strtol error: number of blocks not specified")); | |
694 | usage(); | |
695 | } | |
fd6b7a7f | 696 | } |
7eda085c | 697 | |
fd6b7a7f KZ |
698 | if (device_name && !BLOCKS) |
699 | BLOCKS = get_size (device_name) / 1024; | |
700 | if (!device_name || BLOCKS<10) { | |
701 | usage(); | |
702 | } | |
703 | #ifdef HAVE_MINIX2 | |
704 | if (version2) { | |
705 | if (namelen == 14) | |
706 | magic = MINIX2_SUPER_MAGIC; | |
707 | else | |
708 | magic = MINIX2_SUPER_MAGIC2; | |
709 | } else | |
710 | #endif | |
711 | if (BLOCKS > 65535) | |
712 | BLOCKS = 65535; | |
713 | check_mount(); /* is it already mounted? */ | |
714 | tmp = root_block; | |
715 | *(short *)tmp = 1; | |
716 | strcpy(tmp+2,"."); | |
717 | tmp += dirsize; | |
718 | *(short *)tmp = 1; | |
719 | strcpy(tmp+2,".."); | |
720 | tmp += dirsize; | |
721 | *(short *)tmp = 2; | |
722 | strcpy(tmp+2,".badblocks"); | |
723 | DEV = open(device_name,O_RDWR ); | |
724 | if (DEV<0) | |
7eda085c | 725 | die(_("unable to open %s")); |
fd6b7a7f | 726 | if (fstat(DEV,&statbuf)<0) |
7eda085c | 727 | die(_("unable to stat %s")); |
fd6b7a7f KZ |
728 | if (!S_ISBLK(statbuf.st_mode)) |
729 | check=0; | |
730 | else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) | |
7eda085c | 731 | die(_("will not try to make filesystem on '%s'")); |
fd6b7a7f KZ |
732 | setup_tables(); |
733 | if (check) | |
734 | check_blocks(); | |
735 | else if (listfile) | |
736 | get_list_blocks(listfile); | |
737 | #ifdef HAVE_MINIX2 | |
738 | if (version2) { | |
739 | make_root_inode2 (); | |
740 | make_bad_inode2 (); | |
741 | } else | |
742 | #endif | |
743 | { | |
744 | make_root_inode(); | |
745 | make_bad_inode(); | |
746 | } | |
747 | mark_good_blocks(); | |
748 | write_tables(); | |
749 | return 0; | |
6dbe3af9 | 750 | } |