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 extern 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 char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)), 74 const char *str, int len) 75 { 76 char *ret; 77 78 if (!str) 79 return NULL; 80 if (!len) 81 len = strlen(str); 82 ret = malloc(len+1); 83 if (ret) { 84 strncpy(ret, str, len); 85 ret[len] = 0; 86 } 87 return ret; 88 } 89 90 #ifndef HAVE_STRNLEN 91 /* 92 * Incredibly, libc5 doesn't appear to have strnlen. So we have to 93 * provide our own. 94 */ 95 int e2fsck_strnlen(const char * s, int count) 96 { 97 const char *cp = s; 98 99 while (count-- && *cp) 100 cp++; 101 return cp - s; 102 } 103 #endif 104 105 #ifndef HAVE_CONIO_H 106 static int read_a_char(void) 107 { 108 char c; 109 int r; 110 int fail = 0; 111 112 while(1) { 113 if (e2fsck_global_ctx && 114 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) { 115 return 3; 116 } 117 r = read(0, &c, 1); 118 if (r == 1) 119 return c; 120 if (fail++ > 100) 121 break; 122 } 123 return EOF; 124 } 125 #endif 126 127 int ask_yn(const char * string, int def) 128 { 129 int c; 130 const char *defstr; 131 const char *short_yes = _("yY"); 132 const char *short_no = _("nN"); 133 134 #ifdef HAVE_TERMIOS_H 135 struct termios termios, tmp; 136 137 tcgetattr (0, &termios); 138 tmp = termios; 139 tmp.c_lflag &= ~(ICANON | ECHO); 140 tmp.c_cc[VMIN] = 1; 141 tmp.c_cc[VTIME] = 0; 142 tcsetattr (0, TCSANOW, &tmp); 143 #endif 144 145 if (def == 1) 146 defstr = _(_("<y>")); 147 else if (def == 0) 148 defstr = _(_("<n>")); 149 else 150 defstr = _(" (y/n)"); 151 printf("%s%s? ", string, defstr); 152 while (1) { 153 fflush (stdout); 154 if ((c = read_a_char()) == EOF) 155 break; 156 if (c == 3) { 157 #ifdef HAVE_TERMIOS_H 158 tcsetattr (0, TCSANOW, &termios); 159 #endif 160 if (e2fsck_global_ctx && 161 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) { 162 puts("\n"); 163 longjmp(e2fsck_global_ctx->abort_loc, 1); 164 } 165 puts(_("cancelled!\n")); 166 return 0; 167 } 168 if (strchr(short_yes, (char) c)) { 169 def = 1; 170 break; 171 } 172 else if (strchr(short_no, (char) c)) { 173 def = 0; 174 break; 175 } 176 else if ((c == ' ' || c == '\n') && (def != -1)) 177 break; 178 } 179 if (def) 180 puts(_("yes\n")); 181 else 182 puts (_("no\n")); 183 #ifdef HAVE_TERMIOS_H 184 tcsetattr (0, TCSANOW, &termios); 185 #endif 186 return def; 187 } 188 189 int ask (e2fsck_t ctx, const char * string, int def) 190 { 191 if (ctx->options & E2F_OPT_NO) { 192 printf (_("%s? no\n\n"), string); 193 return 0; 194 } 195 if (ctx->options & E2F_OPT_YES) { 196 printf (_("%s? yes\n\n"), string); 197 return 1; 198 } 199 if (ctx->options & E2F_OPT_PREEN) { 200 printf ("%s? %s\n\n", string, def ? _("yes") : _("no")); 201 return def; 202 } 203 return ask_yn(string, def); 204 } 205 206 void e2fsck_read_bitmaps(e2fsck_t ctx) 207 { 208 ext2_filsys fs = ctx->fs; 209 errcode_t retval; 210 const char *old_op; 211 212 if (ctx->invalid_bitmaps) { 213 com_err(ctx->program_name, 0, 214 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"), 215 ctx->device_name); 216 fatal_error(ctx, 0); 217 } 218 219 old_op = ehandler_operation(_("reading inode and block bitmaps")); 220 retval = ext2fs_read_bitmaps(fs); 221 ehandler_operation(old_op); 222 if (retval) { 223 com_err(ctx->program_name, retval, 224 _("while retrying to read bitmaps for %s"), 225 ctx->device_name); 226 fatal_error(ctx, 0); 227 } 228 } 229 230 void e2fsck_write_bitmaps(e2fsck_t ctx) 231 { 232 ext2_filsys fs = ctx->fs; 233 errcode_t retval; 234 const char *old_op; 235 236 if (ext2fs_test_bb_dirty(fs)) { 237 old_op = ehandler_operation(_("writing block bitmaps")); 238 retval = ext2fs_write_block_bitmap(fs); 239 ehandler_operation(old_op); 240 if (retval) { 241 com_err(ctx->program_name, retval, 242 _("while retrying to write block bitmaps for %s"), 243 ctx->device_name); 244 fatal_error(ctx, 0); 245 } 246 } 247 248 if (ext2fs_test_ib_dirty(fs)) { 249 old_op = ehandler_operation(_("writing inode bitmaps")); 250 retval = ext2fs_write_inode_bitmap(fs); 251 ehandler_operation(old_op); 252 if (retval) { 253 com_err(ctx->program_name, retval, 254 _("while retrying to write inode bitmaps for %s"), 255 ctx->device_name); 256 fatal_error(ctx, 0); 257 } 258 } 259 } 260 261 void preenhalt(e2fsck_t ctx) 262 { 263 ext2_filsys fs = ctx->fs; 264 265 if (!(ctx->options & E2F_OPT_PREEN)) 266 return; 267 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; " 268 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"), 269 ctx->device_name); 270 if (fs != NULL) { 271 fs->super->s_state |= EXT2_ERROR_FS; 272 ext2fs_mark_super_dirty(fs); 273 ext2fs_close(fs); 274 } 275 exit(FSCK_UNCORRECTED); 276 } 277 278 #ifdef RESOURCE_TRACK 279 void init_resource_track(struct resource_track *track) 280 { 281 #ifdef HAVE_GETRUSAGE 282 struct rusage r; 283 #endif 284 285 track->brk_start = sbrk(0); 286 gettimeofday(&track->time_start, 0); 287 #ifdef HAVE_GETRUSAGE 288 #ifdef sun 289 memset(&r, 0, sizeof(struct rusage)); 290 #endif 291 getrusage(RUSAGE_SELF, &r); 292 track->user_start = r.ru_utime; 293 track->system_start = r.ru_stime; 294 #else 295 track->user_start.tv_sec = track->user_start.tv_usec = 0; 296 track->system_start.tv_sec = track->system_start.tv_usec = 0; 297 #endif 298 } 299 300 #ifdef __GNUC__ 301 #define _INLINE_ __inline__ 302 #else 303 #define _INLINE_ 304 #endif 305 306 static _INLINE_ float timeval_subtract(struct timeval *tv1, 307 struct timeval *tv2) 308 { 309 return ((tv1->tv_sec - tv2->tv_sec) + 310 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); 311 } 312 313 void print_resource_track(const char *desc, struct resource_track *track) 314 { 315 #ifdef HAVE_GETRUSAGE 316 struct rusage r; 317 #endif 318 #ifdef HAVE_MALLINFO 319 struct mallinfo malloc_info; 320 #endif 321 struct timeval time_end; 322 323 gettimeofday(&time_end, 0); 324 325 if (desc) 326 printf("%s: ", desc); 327 328 #ifdef HAVE_MALLINFO 329 #define kbytes(x) (((x) + 1023) / 1024) 330 331 malloc_info = mallinfo(); 332 printf(_("Memory used: %dk/%dk (%dk/%dk), "), 333 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd), 334 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks)); 335 #else 336 printf(_("Memory used: %d, "), 337 (int) (((char *) sbrk(0)) - ((char *) track->brk_start))); 338 #endif 339 #ifdef HAVE_GETRUSAGE 340 getrusage(RUSAGE_SELF, &r); 341 342 printf(_("time: %5.2f/%5.2f/%5.2f\n"), 343 timeval_subtract(&time_end, &track->time_start), 344 timeval_subtract(&r.ru_utime, &track->user_start), 345 timeval_subtract(&r.ru_stime, &track->system_start)); 346 #else 347 printf(_("elapsed time: %6.3f\n"), 348 timeval_subtract(&time_end, &track->time_start)); 349 #endif 350 } 351 #endif /* RESOURCE_TRACK */ 352 353 void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino, 354 struct ext2_inode * inode, const char *proc) 355 { 356 int retval; 357 358 retval = ext2fs_read_inode(ctx->fs, ino, inode); 359 if (retval) { 360 com_err("ext2fs_read_inode", retval, 361 _("while reading inode %ld in %s"), ino, proc); 362 fatal_error(ctx, 0); 363 } 364 } 365 366 extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino, 367 struct ext2_inode * inode, int bufsize, 368 const char *proc) 369 { 370 int retval; 371 372 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize); 373 if (retval) { 374 com_err("ext2fs_write_inode", retval, 375 _("while writing inode %ld in %s"), ino, proc); 376 fatal_error(ctx, 0); 377 } 378 } 379 380 extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino, 381 struct ext2_inode * inode, const char *proc) 382 { 383 int retval; 384 385 retval = ext2fs_write_inode(ctx->fs, ino, inode); 386 if (retval) { 387 com_err("ext2fs_write_inode", retval, 388 _("while writing inode %ld in %s"), ino, proc); 389 fatal_error(ctx, 0); 390 } 391 } 392 393 #ifdef MTRACE 394 void mtrace_print(char *mesg) 395 { 396 FILE *malloc_get_mallstream(); 397 FILE *f = malloc_get_mallstream(); 398 399 if (f) 400 fprintf(f, "============= %s\n", mesg); 401 } 402 #endif 403 404 blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name, 405 io_manager manager) 406 { 407 struct ext2_super_block *sb; 408 io_channel io = NULL; 409 void *buf = NULL; 410 int blocksize; 411 blk_t superblock, ret_sb = 8193; 412 413 if (fs && fs->super) { 414 ret_sb = (fs->super->s_blocks_per_group + 415 fs->super->s_first_data_block); 416 if (ctx) { 417 ctx->superblock = ret_sb; 418 ctx->blocksize = fs->blocksize; 419 } 420 return ret_sb; 421 } 422 423 if (ctx) { 424 if (ctx->blocksize) { 425 ret_sb = ctx->blocksize * 8; 426 if (ctx->blocksize == 1024) 427 ret_sb++; 428 ctx->superblock = ret_sb; 429 return ret_sb; 430 } 431 ctx->superblock = ret_sb; 432 ctx->blocksize = 1024; 433 } 434 435 if (!name || !manager) 436 goto cleanup; 437 438 if (manager->open(name, 0, &io) != 0) 439 goto cleanup; 440 441 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf)) 442 goto cleanup; 443 sb = (struct ext2_super_block *) buf; 444 445 for (blocksize = EXT2_MIN_BLOCK_SIZE; 446 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) { 447 superblock = blocksize*8; 448 if (blocksize == 1024) 449 superblock++; 450 io_channel_set_blksize(io, blocksize); 451 if (io_channel_read_blk(io, superblock, 452 -SUPERBLOCK_SIZE, buf)) 453 continue; 454 #ifdef EXT2FS_ENABLE_SWAPFS 455 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) 456 ext2fs_swap_super(sb); 457 #endif 458 if ((sb->s_magic == EXT2_SUPER_MAGIC) && 459 (EXT2_BLOCK_SIZE(sb) == blocksize)) { 460 ret_sb = superblock; 461 if (ctx) { 462 ctx->superblock = superblock; 463 ctx->blocksize = blocksize; 464 } 465 break; 466 } 467 } 468 469 cleanup: 470 if (io) 471 io_channel_close(io); 472 if (buf) 473 ext2fs_free_mem(&buf); 474 return (ret_sb); 475 } 476 477 /* 478 * Given a mode, return the ext2 file type 479 */ 480 int ext2_file_type(unsigned int mode) 481 { 482 if (LINUX_S_ISREG(mode)) 483 return EXT2_FT_REG_FILE; 484 485 if (LINUX_S_ISDIR(mode)) 486 return EXT2_FT_DIR; 487 488 if (LINUX_S_ISCHR(mode)) 489 return EXT2_FT_CHRDEV; 490 491 if (LINUX_S_ISBLK(mode)) 492 return EXT2_FT_BLKDEV; 493 494 if (LINUX_S_ISLNK(mode)) 495 return EXT2_FT_SYMLINK; 496 497 if (LINUX_S_ISFIFO(mode)) 498 return EXT2_FT_FIFO; 499 500 if (LINUX_S_ISSOCK(mode)) 501 return EXT2_FT_SOCK; 502 503 return 0; 504 } 505