Whamcloud - gitweb
util.c (ask_yn, read_a_char): Note when the user has typed ^C,
[tools/e2fsprogs.git] / e2fsck / util.c
1 /*
2  * util.c --- miscellaneous utilities
3  * 
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%
10  */
11
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <ctype.h>
16
17 #ifdef HAVE_CONIO_H
18 #undef HAVE_TERMIOS_H
19 #include <conio.h>
20 #define read_a_char()   getch()
21 #else
22 #ifdef HAVE_TERMIOS_H
23 #include <termios.h>
24 #endif
25 #include <stdio.h>
26 #endif
27
28 #ifdef HAVE_MALLOC_H
29 #include <malloc.h>
30 #endif
31
32 #include "e2fsck.h"
33
34 e2fsck_t e2fsck_global_ctx;     /* Try your very best not to use this! */
35
36 #include <sys/time.h>
37 #include <sys/resource.h>
38
39 void fatal_error(e2fsck_t ctx, const char *msg)
40 {
41         if (msg) 
42                 fprintf (stderr, "e2fsck: %s\n", msg);
43         if (ctx->fs && ctx->fs->io) {
44                 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
45                         io_channel_flush(ctx->fs->io);
46                 else
47                         fprintf(stderr, "e2fsck: io manager magic bad!\n");
48         }
49         ctx->flags |= E2F_FLAG_ABORT;
50         if (ctx->flags & E2F_FLAG_SETJMP_OK)
51                 longjmp(ctx->abort_loc, 1);
52         exit(FSCK_ERROR);
53 }
54
55 void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
56                              const char *description)
57 {
58         void *ret;
59         char buf[256];
60
61 #ifdef DEBUG_ALLOCATE_MEMORY
62         printf("Allocating %d bytes for %s...\n", size, description);
63 #endif
64         ret = malloc(size);
65         if (!ret) {
66                 sprintf(buf, "Can't allocate %s\n", description);
67                 fatal_error(ctx, buf);
68         }
69         memset(ret, 0, size);
70         return ret;
71 }
72
73 #ifndef HAVE_CONIO_H
74 int read_a_char(void)
75 {
76         char    c;
77         int     r;
78         int     fail = 0;
79
80         while(1) {
81                 if (e2fsck_global_ctx &&
82                     (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
83                         return 3;
84                 }
85                 r = read(0, &c, 1);
86                 if (r == 1)
87                         return c;
88                 if (fail++ > 100)
89                         break;
90         }
91         return EOF;
92 }
93 #endif
94
95 int ask_yn(const char * string, int def)
96 {
97         int             c;
98         const char      *defstr;
99         const char      *short_yes = _("yY");
100         const char      *short_no = _("nN");
101
102 #ifdef HAVE_TERMIOS_H
103         struct termios  termios, tmp;
104
105         tcgetattr (0, &termios);
106         tmp = termios;
107         tmp.c_lflag &= ~(ICANON | ECHO);
108         tmp.c_cc[VMIN] = 1;
109         tmp.c_cc[VTIME] = 0;
110         tcsetattr (0, TCSANOW, &tmp);
111 #endif
112
113         if (def == 1)
114                 defstr = _(_("<y>"));
115         else if (def == 0)
116                 defstr = _(_("<n>"));
117         else
118                 defstr = _(" (y/n)");
119         printf("%s%s? ", string, defstr);
120         while (1) {
121                 fflush (stdout);
122                 if ((c = read_a_char()) == EOF)
123                         break;
124                 if (c == 3) {
125 #ifdef HAVE_TERMIOS_H
126                         tcsetattr (0, TCSANOW, &termios);
127 #endif
128                         if (e2fsck_global_ctx &&
129                             e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
130                                 puts("\n");
131                                 longjmp(e2fsck_global_ctx->abort_loc, 1);
132                         }
133                         puts(_("cancelled!\n"));
134                         return 0;
135                 }
136                 if (strchr(short_yes, (char) c)) {
137                         def = 1;
138                         break;
139                 }
140                 else if (strchr(short_no, (char) c)) {
141                         def = 0;
142                         break;
143                 }
144                 else if ((c == ' ' || c == '\n') && (def != -1))
145                         break;
146         }
147         if (def)
148                 puts(_("yes\n"));
149         else
150                 puts (_("no\n"));
151 #ifdef HAVE_TERMIOS_H
152         tcsetattr (0, TCSANOW, &termios);
153 #endif
154         return def;
155 }
156
157 int ask (e2fsck_t ctx, const char * string, int def)
158 {
159         if (ctx->options & E2F_OPT_NO) {
160                 printf (_("%s? no\n\n"), string);
161                 return 0;
162         }
163         if (ctx->options & E2F_OPT_YES) {
164                 printf (_("%s? yes\n\n"), string);
165                 return 1;
166         }
167         if (ctx->options & E2F_OPT_PREEN) {
168                 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
169                 return def;
170         }
171         return ask_yn(string, def);
172 }
173
174 void e2fsck_read_bitmaps(e2fsck_t ctx)
175 {
176         ext2_filsys fs = ctx->fs;
177         errcode_t       retval;
178
179         if (ctx->invalid_bitmaps) {
180                 com_err(ctx->program_name, 0,
181                     _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
182                         ctx->device_name);
183                 fatal_error(ctx, 0);
184         }
185
186         ehandler_operation(_("reading inode and block bitmaps"));
187         retval = ext2fs_read_bitmaps(fs);
188         ehandler_operation(0);
189         if (retval) {
190                 com_err(ctx->program_name, retval,
191                         _("while retrying to read bitmaps for %s"),
192                         ctx->device_name);
193                 fatal_error(ctx, 0);
194         }
195 }
196
197 void e2fsck_write_bitmaps(e2fsck_t ctx)
198 {
199         ext2_filsys fs = ctx->fs;
200         errcode_t       retval;
201
202         if (ext2fs_test_bb_dirty(fs)) {
203                 ehandler_operation(_("writing block bitmaps"));
204                 retval = ext2fs_write_block_bitmap(fs);
205                 ehandler_operation(0);
206                 if (retval) {
207                         com_err(ctx->program_name, retval,
208                             _("while retrying to write block bitmaps for %s"),
209                                 ctx->device_name);
210                         fatal_error(ctx, 0);
211                 }
212         }
213
214         if (ext2fs_test_ib_dirty(fs)) {
215                 ehandler_operation(_("writing inode bitmaps"));
216                 retval = ext2fs_write_inode_bitmap(fs);
217                 ehandler_operation(0);
218                 if (retval) {
219                         com_err(ctx->program_name, retval,
220                             _("while retrying to write inode bitmaps for %s"),
221                                 ctx->device_name);
222                         fatal_error(ctx, 0);
223                 }
224         }
225 }
226
227 void preenhalt(e2fsck_t ctx)
228 {
229         ext2_filsys fs = ctx->fs;
230
231         if (!(ctx->options & E2F_OPT_PREEN))
232                 return;
233         fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
234                 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
235                ctx->device_name);
236         if (fs != NULL) {
237                 fs->super->s_state |= EXT2_ERROR_FS;
238                 ext2fs_mark_super_dirty(fs);
239                 ext2fs_close(fs);
240         }
241         exit(FSCK_UNCORRECTED);
242 }
243
244 #ifdef RESOURCE_TRACK
245 void init_resource_track(struct resource_track *track)
246 {
247 #ifdef HAVE_GETRUSAGE
248         struct rusage r;
249 #endif
250         
251         track->brk_start = sbrk(0);
252         gettimeofday(&track->time_start, 0);
253 #ifdef HAVE_GETRUSAGE
254 #ifdef sun
255         memset(&r, 0, sizeof(struct rusage));
256 #endif
257         getrusage(RUSAGE_SELF, &r);
258         track->user_start = r.ru_utime;
259         track->system_start = r.ru_stime;
260 #else
261         track->user_start.tv_sec = track->user_start.tv_usec = 0;
262         track->system_start.tv_sec = track->system_start.tv_usec = 0;
263 #endif
264 }
265
266 #ifdef __GNUC__
267 #define _INLINE_ __inline__
268 #else
269 #define _INLINE_
270 #endif
271
272 static _INLINE_ float timeval_subtract(struct timeval *tv1,
273                                        struct timeval *tv2)
274 {
275         return ((tv1->tv_sec - tv2->tv_sec) +
276                 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
277 }
278
279 void print_resource_track(const char *desc, struct resource_track *track)
280 {
281 #ifdef HAVE_GETRUSAGE
282         struct rusage r;
283 #endif
284 #ifdef HAVE_MALLINFO
285         struct mallinfo malloc_info;
286 #endif
287         struct timeval time_end;
288
289         gettimeofday(&time_end, 0);
290
291         if (desc)
292                 printf("%s: ", desc);
293
294 #ifdef HAVE_MALLINFO
295 #define kbytes(x)       (((x) + 1023) / 1024)
296         
297         malloc_info = mallinfo();
298         printf(_("Memory used: %dk/%dk (%dk/%dk), "),
299                kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
300                kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
301 #else
302         printf(_("Memory used: %d, "),
303                (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
304 #endif  
305 #ifdef HAVE_GETRUSAGE
306         getrusage(RUSAGE_SELF, &r);
307
308         printf(_("time: %5.2f/%5.2f/%5.2f\n"),
309                timeval_subtract(&time_end, &track->time_start),
310                timeval_subtract(&r.ru_utime, &track->user_start),
311                timeval_subtract(&r.ru_stime, &track->system_start));
312 #else
313         printf(_("elapsed time: %6.3f\n"),
314                timeval_subtract(&time_end, &track->time_start));
315 #endif
316 }
317 #endif /* RESOURCE_TRACK */
318
319 void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
320                               struct ext2_inode * inode, const char *proc)
321 {
322         int retval;
323
324         retval = ext2fs_read_inode(ctx->fs, ino, inode);
325         if (retval) {
326                 com_err("ext2fs_read_inode", retval,
327                         _("while reading inode %ld in %s"), ino, proc);
328                 fatal_error(ctx, 0);
329         }
330 }
331
332 extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
333                                struct ext2_inode * inode, const char *proc)
334 {
335         int retval;
336
337         retval = ext2fs_write_inode(ctx->fs, ino, inode);
338         if (retval) {
339                 com_err("ext2fs_write_inode", retval,
340                         _("while writing inode %ld in %s"), ino, proc);
341                 fatal_error(ctx, 0);
342         }
343 }
344
345 #ifdef MTRACE
346 void mtrace_print(char *mesg)
347 {
348         FILE    *malloc_get_mallstream();
349         FILE    *f = malloc_get_mallstream();
350
351         if (f)
352                 fprintf(f, "============= %s\n", mesg);
353 }
354 #endif
355
356 blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
357                    io_manager manager)
358 {
359         struct ext2_super_block *sb;
360         io_channel              io = NULL;
361         void                    *buf = NULL;
362         int                     blocksize;
363         blk_t                   superblock, ret_sb = 8193;
364         
365         if (fs && fs->super) {
366                 ret_sb = (fs->super->s_blocks_per_group +
367                           fs->super->s_first_data_block);
368                 if (ctx) {
369                         ctx->superblock = ret_sb;
370                         ctx->blocksize = fs->blocksize;
371                 }
372                 return ret_sb;
373         }
374                 
375         if (ctx) {
376                 if (ctx->blocksize) {
377                         ret_sb = ctx->blocksize * 8;
378                         if (ctx->blocksize == 1024)
379                                 ret_sb++;
380                         ctx->superblock = ret_sb;
381                         return ret_sb;
382                 }
383                 ctx->superblock = ret_sb;
384                 ctx->blocksize = 1024;
385         }
386
387         if (!name || !manager)
388                 goto cleanup;
389
390         if (manager->open(name, 0, &io) != 0)
391                 goto cleanup;
392
393         if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
394                 goto cleanup;
395         sb = (struct ext2_super_block *) buf;
396
397         for (blocksize = EXT2_MIN_BLOCK_SIZE;
398              blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
399                 superblock = blocksize*8;
400                 if (blocksize == 1024)
401                         superblock++;
402                 io_channel_set_blksize(io, blocksize);
403                 if (io_channel_read_blk(io, superblock,
404                                         -SUPERBLOCK_SIZE, buf))
405                         continue;
406 #ifdef EXT2FS_ENABLE_SWAPFS
407                 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
408                         ext2fs_swap_super(sb);
409 #endif
410                 if (sb->s_magic == EXT2_SUPER_MAGIC) {
411                         ret_sb = ctx->superblock = superblock;
412                         ctx->blocksize = blocksize;
413                         break;
414                 }
415         }
416
417 cleanup:
418         if (io)
419                 io_channel_close(io);
420         if (buf)
421                 ext2fs_free_mem(&buf);
422         return (ret_sb);
423 }
424
425 /*
426  * Given a mode, return the ext2 file type
427  */
428 int ext2_file_type(unsigned int mode)
429 {
430         if (LINUX_S_ISREG(mode))
431                 return EXT2_FT_REG_FILE;
432
433         if (LINUX_S_ISDIR(mode))
434                 return EXT2_FT_DIR;
435         
436         if (LINUX_S_ISCHR(mode))
437                 return EXT2_FT_CHRDEV;
438         
439         if (LINUX_S_ISBLK(mode))
440                 return EXT2_FT_BLKDEV;
441         
442         if (LINUX_S_ISLNK(mode))
443                 return EXT2_FT_SYMLINK;
444
445         if (LINUX_S_ISFIFO(mode))
446                 return EXT2_FT_FIFO;
447         
448         if (LINUX_S_ISSOCK(mode))
449                 return EXT2_FT_SOCK;
450         
451         return 0;
452 }