]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * util.c --- miscellaneous utilities | |
efc6f628 | 3 | * |
21c84b71 TT |
4 | * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. |
5 | * | |
6 | * %Begin-Header% | |
7 | * This file may be redistributed under the terms of the GNU Public | |
8 | * License. | |
9 | * %End-Header% | |
3839e657 TT |
10 | */ |
11 | ||
12 | #include <stdlib.h> | |
80875db5 | 13 | #include <stdio.h> |
3839e657 TT |
14 | #include <unistd.h> |
15 | #include <string.h> | |
16 | #include <ctype.h> | |
80875db5 TT |
17 | #ifdef __linux__ |
18 | #include <sys/utsname.h> | |
19 | #endif | |
9ecd8bec TT |
20 | |
21 | #ifdef HAVE_CONIO_H | |
22 | #undef HAVE_TERMIOS_H | |
23 | #include <conio.h> | |
e6597048 | 24 | #define read_a_char() getch() |
9ecd8bec TT |
25 | #else |
26 | #ifdef HAVE_TERMIOS_H | |
3839e657 | 27 | #include <termios.h> |
9ecd8bec TT |
28 | #endif |
29 | #endif | |
30 | ||
4a9f5936 TT |
31 | #ifdef HAVE_MALLOC_H |
32 | #include <malloc.h> | |
33 | #endif | |
3839e657 | 34 | |
49a7360b JS |
35 | #ifdef HAVE_ERRNO_H |
36 | #include <errno.h> | |
37 | #endif | |
38 | ||
3839e657 TT |
39 | #include "e2fsck.h" |
40 | ||
aa75eccc | 41 | extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ |
542867fb | 42 | |
50e1e10f TT |
43 | #include <sys/time.h> |
44 | #include <sys/resource.h> | |
45 | ||
f8188fff | 46 | void fatal_error(e2fsck_t ctx, const char *msg) |
3839e657 | 47 | { |
efc6f628 | 48 | if (msg) |
1b6bf175 | 49 | fprintf (stderr, "e2fsck: %s\n", msg); |
58a75177 | 50 | if (ctx->fs && ctx->fs->io) { |
e39ac922 | 51 | if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL) |
58a75177 TT |
52 | io_channel_flush(ctx->fs->io); |
53 | else | |
54 | fprintf(stderr, "e2fsck: io manager magic bad!\n"); | |
55 | } | |
f8188fff TT |
56 | ctx->flags |= E2F_FLAG_ABORT; |
57 | if (ctx->flags & E2F_FLAG_SETJMP_OK) | |
58 | longjmp(ctx->abort_loc, 1); | |
3839e657 TT |
59 | exit(FSCK_ERROR); |
60 | } | |
61 | ||
f8188fff TT |
62 | void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, |
63 | const char *description) | |
3839e657 TT |
64 | { |
65 | void *ret; | |
66 | char buf[256]; | |
67 | ||
68 | #ifdef DEBUG_ALLOCATE_MEMORY | |
611378fe | 69 | printf("Allocating %u bytes for %s...\n", size, description); |
3839e657 TT |
70 | #endif |
71 | ret = malloc(size); | |
72 | if (!ret) { | |
7f88b043 | 73 | sprintf(buf, "Can't allocate %s\n", description); |
f8188fff | 74 | fatal_error(ctx, buf); |
3839e657 TT |
75 | } |
76 | memset(ret, 0, size); | |
77 | return ret; | |
78 | } | |
79 | ||
efc6f628 | 80 | char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)), |
54434927 | 81 | const char *str, int len) |
f364093b TT |
82 | { |
83 | char *ret; | |
efc6f628 | 84 | |
f364093b TT |
85 | if (!str) |
86 | return NULL; | |
87 | if (!len) | |
88 | len = strlen(str); | |
89 | ret = malloc(len+1); | |
90 | if (ret) { | |
91 | strncpy(ret, str, len); | |
92 | ret[len] = 0; | |
93 | } | |
94 | return ret; | |
95 | } | |
96 | ||
97 | #ifndef HAVE_STRNLEN | |
98 | /* | |
99 | * Incredibly, libc5 doesn't appear to have strnlen. So we have to | |
100 | * provide our own. | |
101 | */ | |
102 | int e2fsck_strnlen(const char * s, int count) | |
103 | { | |
104 | const char *cp = s; | |
105 | ||
106 | while (count-- && *cp) | |
107 | cp++; | |
108 | return cp - s; | |
109 | } | |
110 | #endif | |
111 | ||
542867fb | 112 | #ifndef HAVE_CONIO_H |
3e699064 | 113 | static int read_a_char(void) |
542867fb TT |
114 | { |
115 | char c; | |
116 | int r; | |
117 | int fail = 0; | |
118 | ||
119 | while(1) { | |
120 | if (e2fsck_global_ctx && | |
121 | (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) { | |
122 | return 3; | |
123 | } | |
124 | r = read(0, &c, 1); | |
125 | if (r == 1) | |
126 | return c; | |
127 | if (fail++ > 100) | |
128 | break; | |
129 | } | |
130 | return EOF; | |
131 | } | |
132 | #endif | |
133 | ||
3839e657 TT |
134 | int ask_yn(const char * string, int def) |
135 | { | |
136 | int c; | |
3839e657 | 137 | const char *defstr; |
53ef44c4 TT |
138 | const char *short_yes = _("yY"); |
139 | const char *short_no = _("nN"); | |
3839e657 | 140 | |
9ecd8bec TT |
141 | #ifdef HAVE_TERMIOS_H |
142 | struct termios termios, tmp; | |
143 | ||
3839e657 TT |
144 | tcgetattr (0, &termios); |
145 | tmp = termios; | |
146 | tmp.c_lflag &= ~(ICANON | ECHO); | |
50e1e10f TT |
147 | tmp.c_cc[VMIN] = 1; |
148 | tmp.c_cc[VTIME] = 0; | |
3839e657 | 149 | tcsetattr (0, TCSANOW, &tmp); |
9ecd8bec | 150 | #endif |
3839e657 TT |
151 | |
152 | if (def == 1) | |
542867fb | 153 | defstr = _(_("<y>")); |
3839e657 | 154 | else if (def == 0) |
542867fb | 155 | defstr = _(_("<n>")); |
3839e657 | 156 | else |
0c4a0726 | 157 | defstr = _(" (y/n)"); |
3839e657 TT |
158 | printf("%s%s? ", string, defstr); |
159 | while (1) { | |
160 | fflush (stdout); | |
e6597048 | 161 | if ((c = read_a_char()) == EOF) |
3839e657 | 162 | break; |
542867fb TT |
163 | if (c == 3) { |
164 | #ifdef HAVE_TERMIOS_H | |
165 | tcsetattr (0, TCSANOW, &termios); | |
166 | #endif | |
167 | if (e2fsck_global_ctx && | |
168 | e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) { | |
169 | puts("\n"); | |
170 | longjmp(e2fsck_global_ctx->abort_loc, 1); | |
171 | } | |
172 | puts(_("cancelled!\n")); | |
173 | return 0; | |
174 | } | |
0c4a0726 | 175 | if (strchr(short_yes, (char) c)) { |
3839e657 TT |
176 | def = 1; |
177 | break; | |
178 | } | |
0c4a0726 | 179 | else if (strchr(short_no, (char) c)) { |
3839e657 TT |
180 | def = 0; |
181 | break; | |
182 | } | |
183 | else if ((c == ' ' || c == '\n') && (def != -1)) | |
184 | break; | |
185 | } | |
186 | if (def) | |
542867fb | 187 | puts(_("yes\n")); |
3839e657 | 188 | else |
542867fb | 189 | puts (_("no\n")); |
9ecd8bec | 190 | #ifdef HAVE_TERMIOS_H |
3839e657 | 191 | tcsetattr (0, TCSANOW, &termios); |
9ecd8bec | 192 | #endif |
3839e657 TT |
193 | return def; |
194 | } | |
195 | ||
1b6bf175 | 196 | int ask (e2fsck_t ctx, const char * string, int def) |
3839e657 | 197 | { |
1b6bf175 | 198 | if (ctx->options & E2F_OPT_NO) { |
0c4a0726 | 199 | printf (_("%s? no\n\n"), string); |
3839e657 TT |
200 | return 0; |
201 | } | |
1b6bf175 | 202 | if (ctx->options & E2F_OPT_YES) { |
0c4a0726 | 203 | printf (_("%s? yes\n\n"), string); |
3839e657 TT |
204 | return 1; |
205 | } | |
1b6bf175 | 206 | if (ctx->options & E2F_OPT_PREEN) { |
0c4a0726 | 207 | printf ("%s? %s\n\n", string, def ? _("yes") : _("no")); |
3839e657 TT |
208 | return def; |
209 | } | |
210 | return ask_yn(string, def); | |
211 | } | |
212 | ||
f8188fff | 213 | void e2fsck_read_bitmaps(e2fsck_t ctx) |
3839e657 | 214 | { |
1b6bf175 | 215 | ext2_filsys fs = ctx->fs; |
3839e657 | 216 | errcode_t retval; |
e94bc631 | 217 | const char *old_op; |
3839e657 | 218 | |
1b6bf175 TT |
219 | if (ctx->invalid_bitmaps) { |
220 | com_err(ctx->program_name, 0, | |
0c4a0726 | 221 | _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"), |
1b6bf175 | 222 | ctx->device_name); |
f8188fff | 223 | fatal_error(ctx, 0); |
3839e657 | 224 | } |
f3db3566 | 225 | |
e94bc631 | 226 | old_op = ehandler_operation(_("reading inode and block bitmaps")); |
f3db3566 | 227 | retval = ext2fs_read_bitmaps(fs); |
e94bc631 | 228 | ehandler_operation(old_op); |
f3db3566 | 229 | if (retval) { |
1b6bf175 | 230 | com_err(ctx->program_name, retval, |
0c4a0726 | 231 | _("while retrying to read bitmaps for %s"), |
1b6bf175 | 232 | ctx->device_name); |
f8188fff | 233 | fatal_error(ctx, 0); |
3839e657 TT |
234 | } |
235 | } | |
236 | ||
f8188fff | 237 | void e2fsck_write_bitmaps(e2fsck_t ctx) |
3839e657 | 238 | { |
1b6bf175 | 239 | ext2_filsys fs = ctx->fs; |
3839e657 | 240 | errcode_t retval; |
e94bc631 | 241 | const char *old_op; |
3839e657 | 242 | |
1bb6f6c8 AD |
243 | old_op = ehandler_operation(_("writing block and inode bitmaps")); |
244 | retval = ext2fs_write_bitmaps(fs); | |
245 | ehandler_operation(old_op); | |
246 | if (retval) { | |
247 | com_err(ctx->program_name, retval, | |
248 | _("while rewriting block and inode bitmaps for %s"), | |
249 | ctx->device_name); | |
250 | fatal_error(ctx, 0); | |
3839e657 TT |
251 | } |
252 | } | |
253 | ||
1b6bf175 | 254 | void preenhalt(e2fsck_t ctx) |
3839e657 | 255 | { |
1b6bf175 TT |
256 | ext2_filsys fs = ctx->fs; |
257 | ||
258 | if (!(ctx->options & E2F_OPT_PREEN)) | |
3839e657 | 259 | return; |
0c4a0726 TT |
260 | fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; " |
261 | "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"), | |
1b6bf175 | 262 | ctx->device_name); |
79cc3362 | 263 | ctx->flags |= E2F_FLAG_EXITING; |
50e1e10f TT |
264 | if (fs != NULL) { |
265 | fs->super->s_state |= EXT2_ERROR_FS; | |
266 | ext2fs_mark_super_dirty(fs); | |
267 | ext2fs_close(fs); | |
268 | } | |
3839e657 TT |
269 | exit(FSCK_UNCORRECTED); |
270 | } | |
271 | ||
8bf191e8 | 272 | #ifdef RESOURCE_TRACK |
6d96b00d | 273 | void init_resource_track(struct resource_track *track, io_channel channel) |
3839e657 | 274 | { |
50e1e10f | 275 | #ifdef HAVE_GETRUSAGE |
3839e657 | 276 | struct rusage r; |
50e1e10f | 277 | #endif |
6d96b00d | 278 | io_stats io_start = 0; |
efc6f628 | 279 | |
3839e657 TT |
280 | track->brk_start = sbrk(0); |
281 | gettimeofday(&track->time_start, 0); | |
50e1e10f | 282 | #ifdef HAVE_GETRUSAGE |
53ef44c4 TT |
283 | #ifdef sun |
284 | memset(&r, 0, sizeof(struct rusage)); | |
1b6bf175 | 285 | #endif |
3839e657 TT |
286 | getrusage(RUSAGE_SELF, &r); |
287 | track->user_start = r.ru_utime; | |
288 | track->system_start = r.ru_stime; | |
50e1e10f TT |
289 | #else |
290 | track->user_start.tv_sec = track->user_start.tv_usec = 0; | |
291 | track->system_start.tv_sec = track->system_start.tv_usec = 0; | |
292 | #endif | |
6d96b00d TT |
293 | track->bytes_read = 0; |
294 | track->bytes_written = 0; | |
295 | if (channel && channel->manager && channel->manager->get_stats) | |
296 | channel->manager->get_stats(channel, &io_start); | |
297 | if (io_start) { | |
298 | track->bytes_read = io_start->bytes_read; | |
299 | track->bytes_written = io_start->bytes_written; | |
300 | } | |
3839e657 TT |
301 | } |
302 | ||
21c84b71 TT |
303 | #ifdef __GNUC__ |
304 | #define _INLINE_ __inline__ | |
305 | #else | |
306 | #define _INLINE_ | |
307 | #endif | |
308 | ||
309 | static _INLINE_ float timeval_subtract(struct timeval *tv1, | |
310 | struct timeval *tv2) | |
3839e657 TT |
311 | { |
312 | return ((tv1->tv_sec - tv2->tv_sec) + | |
313 | ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); | |
314 | } | |
315 | ||
9facd076 KC |
316 | void print_resource_track(e2fsck_t ctx, const char *desc, |
317 | struct resource_track *track, io_channel channel) | |
3839e657 | 318 | { |
50e1e10f | 319 | #ifdef HAVE_GETRUSAGE |
3839e657 | 320 | struct rusage r; |
4a9f5936 TT |
321 | #endif |
322 | #ifdef HAVE_MALLINFO | |
323 | struct mallinfo malloc_info; | |
50e1e10f | 324 | #endif |
3839e657 TT |
325 | struct timeval time_end; |
326 | ||
9facd076 KC |
327 | if ((desc && !(ctx->options & E2F_OPT_TIME2)) || |
328 | (!desc && !(ctx->options & E2F_OPT_TIME))) | |
329 | return; | |
330 | ||
331 | e2fsck_clear_progbar(ctx); | |
3839e657 | 332 | gettimeofday(&time_end, 0); |
1b6bf175 TT |
333 | |
334 | if (desc) | |
7fdfabd3 | 335 | printf("%s: ", desc); |
4a9f5936 TT |
336 | |
337 | #ifdef HAVE_MALLINFO | |
70eabde9 | 338 | #define kbytes(x) (((unsigned long)(x) + 1023) / 1024) |
efc6f628 | 339 | |
4a9f5936 | 340 | malloc_info = mallinfo(); |
70eabde9 | 341 | printf(_("Memory used: %luk/%luk (%luk/%luk), "), |
80c5d7e4 TT |
342 | kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd), |
343 | kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks)); | |
4a9f5936 | 344 | #else |
70eabde9 AD |
345 | printf(_("Memory used: %lu, "), |
346 | (unsigned long) (((char *) sbrk(0)) - | |
347 | ((char *) track->brk_start))); | |
efc6f628 | 348 | #endif |
50e1e10f | 349 | #ifdef HAVE_GETRUSAGE |
3839e657 TT |
350 | getrusage(RUSAGE_SELF, &r); |
351 | ||
80c5d7e4 | 352 | printf(_("time: %5.2f/%5.2f/%5.2f\n"), |
3839e657 TT |
353 | timeval_subtract(&time_end, &track->time_start), |
354 | timeval_subtract(&r.ru_utime, &track->user_start), | |
355 | timeval_subtract(&r.ru_stime, &track->system_start)); | |
50e1e10f | 356 | #else |
0c4a0726 | 357 | printf(_("elapsed time: %6.3f\n"), |
50e1e10f TT |
358 | timeval_subtract(&time_end, &track->time_start)); |
359 | #endif | |
6d96b00d TT |
360 | #define mbytes(x) (((x) + 1048575) / 1048576) |
361 | if (channel && channel->manager && channel->manager->get_stats) { | |
362 | io_stats delta = 0; | |
363 | unsigned long long bytes_read = 0; | |
364 | unsigned long long bytes_written = 0; | |
365 | ||
366 | if (desc) | |
367 | printf("%s: ", desc); | |
368 | ||
369 | channel->manager->get_stats(channel, &delta); | |
370 | if (delta) { | |
371 | bytes_read = delta->bytes_read - track->bytes_read; | |
efc6f628 | 372 | bytes_written = delta->bytes_written - |
6d96b00d TT |
373 | track->bytes_written; |
374 | } | |
375 | printf("I/O read: %lluMB, write: %lluMB, rate: %.2fMB/s\n", | |
376 | mbytes(bytes_read), mbytes(bytes_written), | |
377 | (double)mbytes(bytes_read + bytes_written) / | |
378 | timeval_subtract(&time_end, &track->time_start)); | |
379 | } | |
3839e657 | 380 | } |
8bf191e8 | 381 | #endif /* RESOURCE_TRACK */ |
3839e657 | 382 | |
08b21301 | 383 | void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino, |
f3db3566 TT |
384 | struct ext2_inode * inode, const char *proc) |
385 | { | |
386 | int retval; | |
387 | ||
08b21301 | 388 | retval = ext2fs_read_inode(ctx->fs, ino, inode); |
f3db3566 TT |
389 | if (retval) { |
390 | com_err("ext2fs_read_inode", retval, | |
611378fe | 391 | _("while reading inode %lu in %s"), ino, proc); |
f8188fff | 392 | fatal_error(ctx, 0); |
f3db3566 TT |
393 | } |
394 | } | |
395 | ||
fefaef39 AD |
396 | void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino, |
397 | struct ext2_inode *inode, int bufsize, | |
398 | const char *proc) | |
399 | { | |
400 | int retval; | |
401 | ||
402 | retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize); | |
403 | if (retval) { | |
404 | com_err("ext2fs_read_inode_full", retval, | |
611378fe | 405 | _("while reading inode %lu in %s"), ino, proc); |
fefaef39 AD |
406 | fatal_error(ctx, 0); |
407 | } | |
408 | } | |
409 | ||
cebe48a1 TT |
410 | extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino, |
411 | struct ext2_inode * inode, int bufsize, | |
412 | const char *proc) | |
413 | { | |
414 | int retval; | |
415 | ||
416 | retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize); | |
417 | if (retval) { | |
418 | com_err("ext2fs_write_inode", retval, | |
611378fe | 419 | _("while writing inode %lu in %s"), ino, proc); |
cebe48a1 TT |
420 | fatal_error(ctx, 0); |
421 | } | |
422 | } | |
423 | ||
08b21301 | 424 | extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino, |
f3db3566 TT |
425 | struct ext2_inode * inode, const char *proc) |
426 | { | |
427 | int retval; | |
428 | ||
08b21301 | 429 | retval = ext2fs_write_inode(ctx->fs, ino, inode); |
f3db3566 TT |
430 | if (retval) { |
431 | com_err("ext2fs_write_inode", retval, | |
611378fe | 432 | _("while writing inode %lu in %s"), ino, proc); |
f8188fff | 433 | fatal_error(ctx, 0); |
f3db3566 TT |
434 | } |
435 | } | |
436 | ||
3839e657 TT |
437 | #ifdef MTRACE |
438 | void mtrace_print(char *mesg) | |
439 | { | |
440 | FILE *malloc_get_mallstream(); | |
441 | FILE *f = malloc_get_mallstream(); | |
442 | ||
443 | if (f) | |
444 | fprintf(f, "============= %s\n", mesg); | |
445 | } | |
446 | #endif | |
447 | ||
f1a1761d TT |
448 | blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name, |
449 | io_manager manager) | |
1b6bf175 | 450 | { |
f1a1761d TT |
451 | struct ext2_super_block *sb; |
452 | io_channel io = NULL; | |
fae9bfaa | 453 | void *buf = NULL; |
f1a1761d TT |
454 | int blocksize; |
455 | blk_t superblock, ret_sb = 8193; | |
efc6f628 | 456 | |
f1a1761d TT |
457 | if (fs && fs->super) { |
458 | ret_sb = (fs->super->s_blocks_per_group + | |
459 | fs->super->s_first_data_block); | |
460 | if (ctx) { | |
461 | ctx->superblock = ret_sb; | |
462 | ctx->blocksize = fs->blocksize; | |
463 | } | |
464 | return ret_sb; | |
465 | } | |
efc6f628 | 466 | |
f1a1761d TT |
467 | if (ctx) { |
468 | if (ctx->blocksize) { | |
469 | ret_sb = ctx->blocksize * 8; | |
470 | if (ctx->blocksize == 1024) | |
471 | ret_sb++; | |
472 | ctx->superblock = ret_sb; | |
473 | return ret_sb; | |
474 | } | |
475 | ctx->superblock = ret_sb; | |
476 | ctx->blocksize = 1024; | |
477 | } | |
478 | ||
479 | if (!name || !manager) | |
480 | goto cleanup; | |
481 | ||
482 | if (manager->open(name, 0, &io) != 0) | |
483 | goto cleanup; | |
484 | ||
485 | if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf)) | |
486 | goto cleanup; | |
487 | sb = (struct ext2_super_block *) buf; | |
488 | ||
932a489c AD |
489 | for (blocksize = EXT2_MIN_BLOCK_SIZE; |
490 | blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) { | |
f1a1761d TT |
491 | superblock = blocksize*8; |
492 | if (blocksize == 1024) | |
493 | superblock++; | |
494 | io_channel_set_blksize(io, blocksize); | |
495 | if (io_channel_read_blk(io, superblock, | |
496 | -SUPERBLOCK_SIZE, buf)) | |
497 | continue; | |
2eae0930 | 498 | #ifdef WORDS_BIGENDIAN |
f1a1761d TT |
499 | if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) |
500 | ext2fs_swap_super(sb); | |
501 | #endif | |
e7b5d3c0 DD |
502 | if ((sb->s_magic == EXT2_SUPER_MAGIC) && |
503 | (EXT2_BLOCK_SIZE(sb) == blocksize)) { | |
557ddb2f TT |
504 | ret_sb = superblock; |
505 | if (ctx) { | |
506 | ctx->superblock = superblock; | |
507 | ctx->blocksize = blocksize; | |
508 | } | |
f1a1761d TT |
509 | break; |
510 | } | |
511 | } | |
512 | ||
513 | cleanup: | |
514 | if (io) | |
515 | io_channel_close(io); | |
516 | if (buf) | |
517 | ext2fs_free_mem(&buf); | |
518 | return (ret_sb); | |
1b6bf175 | 519 | } |
3839e657 | 520 | |
6fdc7a32 TT |
521 | /* |
522 | * Given a mode, return the ext2 file type | |
523 | */ | |
524 | int ext2_file_type(unsigned int mode) | |
525 | { | |
526 | if (LINUX_S_ISREG(mode)) | |
527 | return EXT2_FT_REG_FILE; | |
528 | ||
529 | if (LINUX_S_ISDIR(mode)) | |
530 | return EXT2_FT_DIR; | |
efc6f628 | 531 | |
6fdc7a32 TT |
532 | if (LINUX_S_ISCHR(mode)) |
533 | return EXT2_FT_CHRDEV; | |
efc6f628 | 534 | |
6fdc7a32 TT |
535 | if (LINUX_S_ISBLK(mode)) |
536 | return EXT2_FT_BLKDEV; | |
efc6f628 | 537 | |
6fdc7a32 TT |
538 | if (LINUX_S_ISLNK(mode)) |
539 | return EXT2_FT_SYMLINK; | |
540 | ||
541 | if (LINUX_S_ISFIFO(mode)) | |
542 | return EXT2_FT_FIFO; | |
efc6f628 | 543 | |
6fdc7a32 TT |
544 | if (LINUX_S_ISSOCK(mode)) |
545 | return EXT2_FT_SOCK; | |
efc6f628 | 546 | |
6fdc7a32 TT |
547 | return 0; |
548 | } | |
49a7360b JS |
549 | |
550 | #define STRIDE_LENGTH 8 | |
551 | /* | |
552 | * Helper function which zeros out _num_ blocks starting at _blk_. In | |
553 | * case of an error, the details of the error is returned via _ret_blk_ | |
554 | * and _ret_count_ if they are non-NULL pointers. Returns 0 on | |
555 | * success, and an error code on an error. | |
556 | * | |
557 | * As a special case, if the first argument is NULL, then it will | |
558 | * attempt to free the static zeroizing buffer. (This is to keep | |
559 | * programs that check for memory leaks happy.) | |
560 | */ | |
561 | errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num, | |
562 | blk_t *ret_blk, int *ret_count) | |
563 | { | |
564 | int j, count, next_update, next_update_incr; | |
565 | static char *buf; | |
566 | errcode_t retval; | |
567 | ||
568 | /* If fs is null, clean up the static buffer and return */ | |
569 | if (!fs) { | |
570 | if (buf) { | |
571 | free(buf); | |
572 | buf = 0; | |
573 | } | |
574 | return 0; | |
575 | } | |
576 | /* Allocate the zeroizing buffer if necessary */ | |
577 | if (!buf) { | |
578 | buf = malloc(fs->blocksize * STRIDE_LENGTH); | |
579 | if (!buf) { | |
580 | com_err("malloc", ENOMEM, | |
581 | _("while allocating zeroizing buffer")); | |
582 | exit(1); | |
583 | } | |
584 | memset(buf, 0, fs->blocksize * STRIDE_LENGTH); | |
585 | } | |
586 | /* OK, do the write loop */ | |
587 | next_update = 0; | |
588 | next_update_incr = num / 100; | |
589 | if (next_update_incr < 1) | |
590 | next_update_incr = 1; | |
591 | for (j = 0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { | |
592 | count = num - j; | |
593 | if (count > STRIDE_LENGTH) | |
594 | count = STRIDE_LENGTH; | |
595 | retval = io_channel_write_blk(fs->io, blk, count, buf); | |
596 | if (retval) { | |
597 | if (ret_count) | |
598 | *ret_count = count; | |
599 | if (ret_blk) | |
600 | *ret_blk = blk; | |
601 | return retval; | |
602 | } | |
603 | } | |
604 | return 0; | |
605 | } | |
80875db5 TT |
606 | |
607 | /* | |
608 | * Check to see if a filesystem is in /proc/filesystems. | |
609 | * Returns 1 if found, 0 if not | |
610 | */ | |
611 | int fs_proc_check(const char *fs_name) | |
612 | { | |
613 | FILE *f; | |
614 | char buf[80], *cp, *t; | |
615 | ||
616 | f = fopen("/proc/filesystems", "r"); | |
617 | if (!f) | |
618 | return (0); | |
619 | while (!feof(f)) { | |
620 | if (!fgets(buf, sizeof(buf), f)) | |
621 | break; | |
622 | cp = buf; | |
623 | if (!isspace(*cp)) { | |
624 | while (*cp && !isspace(*cp)) | |
625 | cp++; | |
626 | } | |
627 | while (*cp && isspace(*cp)) | |
628 | cp++; | |
629 | if ((t = strchr(cp, '\n')) != NULL) | |
630 | *t = 0; | |
631 | if ((t = strchr(cp, '\t')) != NULL) | |
632 | *t = 0; | |
633 | if ((t = strchr(cp, ' ')) != NULL) | |
634 | *t = 0; | |
635 | if (!strcmp(fs_name, cp)) { | |
636 | fclose(f); | |
637 | return (1); | |
638 | } | |
639 | } | |
640 | fclose(f); | |
641 | return (0); | |
642 | } | |
643 | ||
644 | /* | |
645 | * Check to see if a filesystem is available as a module | |
646 | * Returns 1 if found, 0 if not | |
647 | */ | |
648 | int check_for_modules(const char *fs_name) | |
649 | { | |
650 | #ifdef __linux__ | |
651 | struct utsname uts; | |
652 | FILE *f; | |
653 | char buf[1024], *cp, *t; | |
654 | int i; | |
655 | ||
656 | if (uname(&uts)) | |
657 | return (0); | |
658 | snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release); | |
659 | ||
660 | f = fopen(buf, "r"); | |
661 | if (!f) | |
662 | return (0); | |
663 | while (!feof(f)) { | |
664 | if (!fgets(buf, sizeof(buf), f)) | |
665 | break; | |
666 | if ((cp = strchr(buf, ':')) != NULL) | |
667 | *cp = 0; | |
668 | else | |
669 | continue; | |
670 | if ((cp = strrchr(buf, '/')) != NULL) | |
671 | cp++; | |
f2fe5da3 ES |
672 | else |
673 | cp = buf; | |
80875db5 TT |
674 | i = strlen(cp); |
675 | if (i > 3) { | |
676 | t = cp + i - 3; | |
677 | if (!strcmp(t, ".ko")) | |
678 | *t = 0; | |
679 | } | |
680 | if (!strcmp(cp, fs_name)) { | |
681 | fclose(f); | |
682 | return (1); | |
683 | } | |
684 | } | |
685 | fclose(f); | |
686 | #endif /* __linux__ */ | |
687 | return (0); | |
688 | } | |
b0258cbc TT |
689 | |
690 | /* | |
691 | * Helper function that does the right thing if write returns a | |
692 | * partial write, or an EGAIN/EINTR error. | |
693 | */ | |
694 | int write_all(int fd, char *buf, size_t count) | |
695 | { | |
696 | ssize_t ret; | |
697 | int c = 0; | |
698 | ||
699 | while (count > 0) { | |
700 | ret = write(fd, buf, count); | |
701 | if (ret < 0) { | |
702 | if ((errno == EAGAIN) || (errno == EINTR)) | |
703 | continue; | |
704 | return -1; | |
705 | } | |
706 | count -= ret; | |
707 | buf += ret; | |
708 | c += ret; | |
709 | } | |
710 | return c; | |
711 | } |