static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) { int flush = 0; int c, fd; #ifdef MTRACE extern void *mallwatch; #endif e2fsck_t ctx; errcode_t retval; #ifdef HAVE_SIGNAL_H struct sigaction sa; #endif char *extended_opts = 0; char *cp; int res; /* result of sscanf */ #ifdef CONFIG_JBD_DEBUG char *jbd_debug; #endif retval = e2fsck_allocate_context(&ctx); if (retval) return retval; *ret_ctx = ctx; setvbuf(stdout, NULL, _IONBF, BUFSIZ); setvbuf(stderr, NULL, _IONBF, BUFSIZ); if (isatty(0) && isatty(1)) { ctx->interactive = 1; } else { ctx->start_meta[0] = '\001'; ctx->stop_meta[0] = '\002'; } memset(bar, '=', sizeof(bar)-1); memset(spaces, ' ', sizeof(spaces)-1); add_error_table(&et_ext2_error_table); add_error_table(&et_prof_error_table); blkid_get_cache(&ctx->blkid, NULL); if (argc && *argv) ctx->program_name = *argv; else ctx->program_name = "e2fsck"; while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF) switch (c) { case 'C': ctx->progress = e2fsck_update_progress; res = sscanf(optarg, "%d", &ctx->progress_fd); if (res != 1) goto sscanf_err; if (ctx->progress_fd < 0) { ctx->progress = 0; ctx->progress_fd = ctx->progress_fd * -1; } if (!ctx->progress_fd) break; /* Validate the file descriptor to avoid disasters */ fd = dup(ctx->progress_fd); if (fd < 0) { fprintf(stderr, _("Error validating file descriptor %d: %s\n"), ctx->progress_fd, error_message(errno)); fatal_error(ctx, _("Invalid completion information file descriptor")); } else close(fd); break; case 'D': ctx->options |= E2F_OPT_COMPRESS_DIRS; break; case 'E': extended_opts = optarg; break; case 'p': case 'a': if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) { conflict_opt: fatal_error(ctx, _("Only one of the options -p/-a, -n or -y may be specified.")); } ctx->options |= E2F_OPT_PREEN; break; case 'n': if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN)) goto conflict_opt; ctx->options |= E2F_OPT_NO; break; case 'y': if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO)) goto conflict_opt; ctx->options |= E2F_OPT_YES; break; case 't': #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME) ctx->options |= E2F_OPT_TIME2; else ctx->options |= E2F_OPT_TIME; #else fprintf(stderr, _("The -t option is not " "supported on this version of e2fsck.\n")); #endif break; case 'c': if (cflag++) ctx->options |= E2F_OPT_WRITECHECK; ctx->options |= E2F_OPT_CHECKBLOCKS; break; case 'r': /* What we do by default, anyway! */ break; case 'b': res = sscanf(optarg, "%u", &ctx->use_superblock); if (res != 1) goto sscanf_err; ctx->flags |= E2F_FLAG_SB_SPECIFIED; break; case 'B': ctx->blocksize = atoi(optarg); break; case 'I': res = sscanf(optarg, "%d", &ctx->inode_buffer_blocks); if (res != 1) goto sscanf_err; break; case 'j': ctx->journal_name = blkid_get_devname(ctx->blkid, optarg, NULL); if (!ctx->journal_name) { com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), optarg); fatal_error(ctx, 0); } break; case 'P': res = sscanf(optarg, "%d", &ctx->process_inode_size); if (res != 1) goto sscanf_err; break; case 'L': replace_bad_blocks++; case 'l': bad_blocks_file = string_copy(ctx, optarg, 0); break; case 'd': ctx->options |= E2F_OPT_DEBUG; break; case 'f': ctx->options |= E2F_OPT_FORCE; break; case 'F': flush = 1; break; case 'v': verbose = 1; break; case 'V': show_version_only = 1; break; #ifdef MTRACE case 'M': mallwatch = (void *) strtol(optarg, NULL, 0); break; #endif case 'N': ctx->device_name = string_copy(ctx, optarg, 0); break; case 'k': keep_bad_blocks++; break; default: usage(ctx); } if (show_version_only) return 0; if (optind != argc - 1) usage(ctx); if ((ctx->options & E2F_OPT_NO) && (ctx->options & E2F_OPT_COMPRESS_DIRS)) { com_err(ctx->program_name, 0, _("The -n and -D options are incompatible.")); fatal_error(ctx, 0); } if ((ctx->options & E2F_OPT_NO) && cflag) { com_err(ctx->program_name, 0, _("The -n and -c options are incompatible.")); fatal_error(ctx, 0); } if ((ctx->options & E2F_OPT_NO) && bad_blocks_file) { com_err(ctx->program_name, 0, _("The -n and -l/-L options are incompatible.")); fatal_error(ctx, 0); } if (ctx->options & E2F_OPT_NO) ctx->options |= E2F_OPT_READONLY; ctx->io_options = strchr(argv[optind], '?'); if (ctx->io_options) *ctx->io_options++ = 0; ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0); if (!ctx->filesystem_name) { com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), argv[optind]); fatal_error(ctx, 0); } if (extended_opts) parse_extended_opts(ctx, extended_opts); if ((cp = getenv("E2FSCK_CONFIG")) != NULL) config_fn[0] = cp; profile_set_syntax_err_cb(syntax_err_report); profile_init(config_fn, &ctx->profile); if (flush) { fd = open(ctx->filesystem_name, O_RDONLY, 0); if (fd < 0) { com_err("open", errno, _("while opening %s for flushing"), ctx->filesystem_name); fatal_error(ctx, 0); } if ((retval = ext2fs_sync_device(fd, 1))) { com_err("ext2fs_sync_device", retval, _("while trying to flush %s"), ctx->filesystem_name); fatal_error(ctx, 0); } close(fd); } if (cflag && bad_blocks_file) { fprintf(stderr, _("The -c and the -l/-L options may " "not be both used at the same time.\n")); exit(FSCK_USAGE); } #ifdef HAVE_SIGNAL_H /* * Set up signal action */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = signal_cancel; sigaction(SIGINT, &sa, 0); sigaction(SIGTERM, &sa, 0); #ifdef SA_RESTART sa.sa_flags = SA_RESTART; #endif e2fsck_global_ctx = ctx; sa.sa_handler = signal_progress_on; sigaction(SIGUSR1, &sa, 0); sa.sa_handler = signal_progress_off; sigaction(SIGUSR2, &sa, 0); #endif /* Update our PATH to include /sbin if we need to run badblocks */ if (cflag) { char *oldpath = getenv("PATH"); char *newpath; int len = sizeof(PATH_SET) + 1; if (oldpath) len += strlen(oldpath); newpath = malloc(len); if (!newpath) fatal_error(ctx, "Couldn't malloc() newpath"); strcpy(newpath, PATH_SET); if (oldpath) { strcat(newpath, ":"); strcat(newpath, oldpath); } putenv(newpath); } #ifdef CONFIG_JBD_DEBUG jbd_debug = getenv("E2FSCK_JBD_DEBUG"); if (jbd_debug) { res = sscanf(jbd_debug, "%d", &journal_enable_debug); if (res != 1) { fprintf(stderr, _("E2FSCK_JBD_DEBUG \"%s\" not an integer\n\n"), jbd_debug); exit (1); } } #endif return 0; sscanf_err: fprintf(stderr, _("\nInvalid non-numeric argument to -%c (\"%s\")\n\n"), c, optarg); exit (1); }
static void PRS(int argc, char *argv[]) { int i, j; char *arg, *dev, *tmp = 0; char options[128]; int opt = 0; int opts_for_fsck = 0; struct sigaction sa; /* * Set up signal action */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = signal_cancel; sigaction(SIGINT, &sa, 0); sigaction(SIGTERM, &sa, 0); num_devices = 0; num_args = 0; instance_list = 0; for (i=1; i < argc; i++) { arg = argv[i]; if (!arg) continue; if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { if (num_devices >= MAX_DEVICES) { bb_error_msg_and_die("too many devices"); } dev = blkid_get_devname(cache, arg, NULL); if (!dev && strchr(arg, '=')) { /* * Check to see if we failed because * /proc/partitions isn't found. */ if (access("/proc/partitions", R_OK) < 0) { bb_perror_msg_and_die("cannot open /proc/partitions " "(is /proc mounted?)"); } /* * Check to see if this is because * we're not running as root */ if (geteuid()) bb_error_msg_and_die( "must be root to scan for matching filesystems: %s\n", arg); else bb_error_msg_and_die( "cannot find matching filesystem: %s", arg); } devices[num_devices++] = dev ? dev : string_copy(arg); continue; } if (arg[0] != '-' || opts_for_fsck) { if (num_args >= MAX_ARGS) { bb_error_msg_and_die("too many arguments"); } args[num_args++] = string_copy(arg); continue; } for (j=1; arg[j]; j++) { if (opts_for_fsck) { options[++opt] = arg[j]; continue; } switch (arg[j]) { case 'A': doall++; break; case 'C': progress++; if (arg[j+1]) { progress_fd = string_to_int(arg+j+1); if (progress_fd < 0) progress_fd = 0; else goto next_arg; } else if ((i+1) < argc && argv[i+1][0] != '-') { progress_fd = string_to_int(argv[i]); if (progress_fd < 0) progress_fd = 0; else { goto next_arg; i++; } } break; case 'V': verbose++; break; case 'N': noexecute++; break; case 'R': skip_root++; break; case 'T': notitle++; break; case 'M': like_mount++; break; case 'P': parallel_root++; break; case 's': serialize++; break; case 't': tmp = 0; if (fstype) bb_show_usage(); if (arg[j+1]) tmp = arg+j+1; else if ((i+1) < argc) tmp = argv[++i]; else bb_show_usage(); fstype = string_copy(tmp); compile_fs_type(fstype, &fs_type_compiled); goto next_arg; case '-': opts_for_fsck++; break; case '?': bb_show_usage(); break; default: options[++opt] = arg[j]; break; } } next_arg: if (opt) { options[0] = '-'; options[++opt] = '\0'; if (num_args >= MAX_ARGS) { bb_error_msg("too many arguments"); } args[num_args++] = string_copy(options); opt = 0; } } if (getenv("FSCK_FORCE_ALL_PARALLEL")) force_all_parallel++; if ((tmp = getenv("FSCK_MAX_INST"))) max_running = atoi(tmp); }
/* * Remove an external journal from the filesystem */ static void remove_journal_device(ext2_filsys fs) { char *journal_path; ext2_filsys jfs; char buf[1024]; journal_superblock_t *jsb; int i, nr_users; errcode_t retval; int commit_remove_journal = 0; io_manager io_ptr; if (f_flag) commit_remove_journal = 1; /* force removal even if error */ uuid_unparse(fs->super->s_journal_uuid, buf); journal_path = blkid_get_devname(NULL, "UUID", buf); if (!journal_path) { journal_path = ext2fs_find_block_device(fs->super->s_journal_dev); if (!journal_path) return; } #ifdef CONFIG_TESTIO_DEBUG io_ptr = test_io_manager; test_io_backing_manager = unix_io_manager; #else io_ptr = unix_io_manager; #endif retval = ext2fs_open(journal_path, EXT2_FLAG_RW| EXT2_FLAG_JOURNAL_DEV_OK, 0, fs->blocksize, io_ptr, &jfs); if (retval) { com_err(program_name, retval, _("while trying to open external journal")); goto no_valid_journal; } if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { fprintf(stderr, _("%s is not a journal device.\n"), journal_path); goto no_valid_journal; } /* Get the journal superblock */ if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { com_err(program_name, retval, _("while reading journal superblock")); goto no_valid_journal; } jsb = (journal_superblock_t *) buf; if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) { fputs(_("Journal superblock not found!\n"), stderr); goto no_valid_journal; } /* Find the filesystem UUID */ nr_users = ntohl(jsb->s_nr_users); for (i=0; i < nr_users; i++) { if (memcmp(fs->super->s_uuid, &jsb->s_users[i*16], 16) == 0) break; } if (i >= nr_users) { fputs(_("Filesystem's UUID not found on journal device.\n"), stderr); commit_remove_journal = 1; goto no_valid_journal; } nr_users--; for (i=0; i < nr_users; i++) memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); jsb->s_nr_users = htonl(nr_users); /* Write back the journal superblock */ if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { com_err(program_name, retval, "while writing journal superblock."); goto no_valid_journal; } commit_remove_journal = 1; no_valid_journal: if (commit_remove_journal == 0) { fputs(_("Journal NOT removed\n"), stderr); exit(1); } fs->super->s_journal_dev = 0; uuid_clear(fs->super->s_journal_uuid); ext2fs_mark_super_dirty(fs); fputs(_("Journal removed\n"), stdout); free(journal_path); }
void do_logdump(int argc, char **argv) { int c; int retval; char *out_fn; FILE *out_file; char *inode_spec = NULL; char *journal_fn = NULL; int journal_fd = 0; int use_sb = 0; ext2_ino_t journal_inum; struct ext2_inode journal_inode; ext2_file_t journal_file; char *tmp; struct journal_source journal_source; struct ext2_super_block *es = NULL; journal_source.where = 0; journal_source.fd = 0; journal_source.file = 0; dump_all = 0; dump_contents = 0; dump_descriptors = 1; block_to_dump = ANY_BLOCK; bitmap_to_dump = -1; inode_block_to_dump = ANY_BLOCK; inode_to_dump = -1; reset_getopt(); while ((c = getopt (argc, argv, "ab:ci:f:s")) != EOF) { switch (c) { case 'a': dump_all++; break; case 'b': block_to_dump = strtoul(optarg, &tmp, 0); if (*tmp) { com_err(argv[0], 0, "Bad block number - %s", optarg); return; } dump_descriptors = 0; break; case 'c': dump_contents++; break; case 'f': journal_fn = optarg; break; case 'i': inode_spec = optarg; dump_descriptors = 0; break; case 's': use_sb++; break; default: goto print_usage; } } if (optind != argc && optind != argc-1) { goto print_usage; } if (current_fs) es = current_fs->super; if (inode_spec) { int inode_group, group_offset, inodes_per_block; if (check_fs_open(argv[0])) return; inode_to_dump = string_to_inode(inode_spec); if (!inode_to_dump) return; inode_group = ((inode_to_dump - 1) / es->s_inodes_per_group); group_offset = ((inode_to_dump - 1) % es->s_inodes_per_group); inodes_per_block = (current_fs->blocksize / sizeof(struct ext2_inode)); inode_block_to_dump = current_fs->group_desc[inode_group].bg_inode_table + (group_offset / inodes_per_block); inode_offset_to_dump = ((group_offset % inodes_per_block) * sizeof(struct ext2_inode)); printf("Inode %u is at group %u, block %u, offset %u\n", inode_to_dump, inode_group, inode_block_to_dump, inode_offset_to_dump); } if (optind == argc) { out_file = stdout; } else { out_fn = argv[optind]; out_file = fopen(out_fn, "w"); if (!out_file < 0) { com_err(argv[0], errno, "while opening %s for logdump", out_fn); return; } } if (block_to_dump != ANY_BLOCK && current_fs != NULL) { group_to_dump = ((block_to_dump - es->s_first_data_block) / es->s_blocks_per_group); bitmap_to_dump = current_fs->group_desc[group_to_dump].bg_block_bitmap; } if (!journal_fn && check_fs_open(argv[0])) return; if (journal_fn) { /* Set up to read journal from a regular file somewhere */ journal_fd = open(journal_fn, O_RDONLY, 0); if (journal_fd < 0) { com_err(argv[0], errno, "while opening %s for logdump", journal_fn); return; } journal_source.where = JOURNAL_IS_EXTERNAL; journal_source.fd = journal_fd; } else if ((journal_inum = es->s_journal_inum)) { if (use_sb) { if (es->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS) { com_err(argv[0], 0, "no journal backup in super block\n"); return; } memset(&journal_inode, 0, sizeof(struct ext2_inode)); memcpy(&journal_inode.i_block[0], es->s_jnl_blocks, EXT2_N_BLOCKS*4); journal_inode.i_size = es->s_jnl_blocks[16]; journal_inode.i_links_count = 1; journal_inode.i_mode = LINUX_S_IFREG | 0600; } else { if (debugfs_read_inode(journal_inum, &journal_inode, argv[0])) return; } retval = ext2fs_file_open2(current_fs, journal_inum, &journal_inode, 0, &journal_file); if (retval) { com_err(argv[0], retval, "while opening ext2 file"); return; } journal_source.where = JOURNAL_IS_INTERNAL; journal_source.file = journal_file; } else { char uuid[37]; uuid_unparse(es->s_journal_uuid, uuid); journal_fn = blkid_get_devname(NULL, "UUID", uuid); if (!journal_fn) journal_fn = blkid_devno_to_devname(es->s_journal_dev); if (!journal_fn) { com_err(argv[0], 0, "filesystem has no journal"); return; } journal_fd = open(journal_fn, O_RDONLY, 0); if (journal_fd < 0) { com_err(argv[0], errno, "while opening %s for logdump", journal_fn); free(journal_fn); return; } fprintf(out_file, "Using external journal found at %s\n", journal_fn); free(journal_fn); journal_source.where = JOURNAL_IS_EXTERNAL; journal_source.fd = journal_fd; } dump_journal(argv[0], out_file, &journal_source); if (journal_source.where == JOURNAL_IS_INTERNAL) ext2fs_file_close(journal_file); else close(journal_fd); if (out_file != stdout) fclose(out_file); return; print_usage: fprintf(stderr, "%s: Usage: logdump [-ac] [-b<block>] [-i<inode>]\n\t" "[-f<journal_file>] [output_file]\n", argv[0]); }
static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) { struct process_block_struct pb; struct ext2_super_block *sb = ctx->fs->super; struct ext2_super_block jsuper; struct problem_context pctx; struct buffer_head *bh; struct inode *j_inode = NULL; struct kdev_s *dev_fs = NULL, *dev_journal; const char *journal_name = 0; journal_t *journal = NULL; errcode_t retval = 0; io_manager io_ptr = 0; unsigned long long start = 0; int ext_journal = 0; int tried_backup_jnl = 0; clear_problem_context(&pctx); journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal"); if (!journal) { return EXT2_ET_NO_MEMORY; } dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev"); if (!dev_fs) { retval = EXT2_ET_NO_MEMORY; goto errout; } dev_journal = dev_fs+1; dev_fs->k_ctx = dev_journal->k_ctx = ctx; dev_fs->k_dev = K_DEV_FS; dev_journal->k_dev = K_DEV_JOURNAL; journal->j_dev = dev_journal; journal->j_fs_dev = dev_fs; journal->j_inode = NULL; journal->j_blocksize = ctx->fs->blocksize; if (uuid_is_null(sb->s_journal_uuid)) { if (!sb->s_journal_inum) { retval = EXT2_ET_BAD_INODE_NUM; goto errout; } j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode), "journal inode"); if (!j_inode) { retval = EXT2_ET_NO_MEMORY; goto errout; } j_inode->i_ctx = ctx; j_inode->i_ino = sb->s_journal_inum; if ((retval = ext2fs_read_inode(ctx->fs, sb->s_journal_inum, &j_inode->i_ext2))) { try_backup_journal: if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || tried_backup_jnl) goto errout; memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, EXT2_N_BLOCKS*4); j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15]; j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; j_inode->i_ext2.i_links_count = 1; j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; e2fsck_use_inode_shortcuts(ctx, 1); ctx->stashed_ino = j_inode->i_ino; ctx->stashed_inode = &j_inode->i_ext2; tried_backup_jnl++; } if (!j_inode->i_ext2.i_links_count || !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { retval = EXT2_ET_NO_JOURNAL; goto try_backup_journal; } if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize < JFS_MIN_JOURNAL_BLOCKS) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } pb.last_block = -1; retval = ext2fs_block_iterate3(ctx->fs, j_inode->i_ino, BLOCK_FLAG_HOLE, 0, process_journal_block, &pb); if ((pb.last_block + 1) * ctx->fs->blocksize < EXT2_I_SIZE(&j_inode->i_ext2)) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } if (tried_backup_jnl && !(ctx->options & E2F_OPT_READONLY)) { retval = ext2fs_write_inode(ctx->fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) goto errout; } journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize; #ifdef USE_INODE_IO retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum, &j_inode->i_ext2, &journal_name); if (retval) goto errout; io_ptr = inode_io_manager; #else journal->j_inode = j_inode; ctx->journal_io = ctx->fs->io; if ((retval = journal_bmap(journal, 0, &start)) != 0) goto errout; #endif } else { ext_journal = 1; if (!ctx->journal_name) { char uuid[37]; uuid_unparse(sb->s_journal_uuid, uuid); ctx->journal_name = blkid_get_devname(ctx->blkid, "UUID", uuid); if (!ctx->journal_name) ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev); } journal_name = ctx->journal_name; if (!journal_name) { fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx); retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } jfs_debug(1, "Using journal file %s\n", journal_name); io_ptr = unix_io_manager; } #if 0 test_io_backing_manager = io_ptr; io_ptr = test_io_manager; #endif #ifndef USE_INODE_IO if (ext_journal) #endif retval = io_ptr->open(journal_name, IO_FLAG_RW | IO_FLAG_EXCLUSIVE, &ctx->journal_io); if (retval) goto errout; io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize); if (ext_journal) { if (ctx->fs->blocksize == 1024) start = 1; bh = getblk(dev_journal, start, ctx->fs->blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } ll_rw_block(READ, 1, &bh); if ((retval = bh->b_err) != 0) { brelse(bh); goto errout; } memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024, sizeof(jsuper)); brelse(bh); #ifdef WORDS_BIGENDIAN if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ext2fs_swap_super(&jsuper); #endif if (jsuper.s_magic != EXT2_SUPER_MAGIC || !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx); retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } /* Make sure the journal UUID is correct */ if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid, sizeof(jsuper.s_uuid))) { fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx); retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } journal->j_maxlen = ext2fs_blocks_count(&jsuper); start++; } if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) { retval = EXT2_ET_NO_MEMORY; goto errout; } journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; #ifdef USE_INODE_IO if (j_inode) ext2fs_free_mem(&j_inode); #endif *ret_journal = journal; e2fsck_use_inode_shortcuts(ctx, 0); return 0; errout: e2fsck_use_inode_shortcuts(ctx, 0); if (dev_fs) ext2fs_free_mem(&dev_fs); if (j_inode) ext2fs_free_mem(&j_inode); if (journal) ext2fs_free_mem(&journal); return retval; }
/* Also when no UUID= or LABEL= occur? No verbose? No warnings? */ const char * mount_get_devname_for_mounting(const char *spec) { return blkid_get_devname(blkid, spec, 0); }
void parse_journal_opts(const char *opts) { char *buf, *token, *next, *p, *arg; int len; int journal_usage = 0; len = strlen(opts); buf = malloc(len+1); if (!buf) { fputs(_("Couldn't allocate memory to parse journal " "options!\n"), stderr); exit(1); } strcpy(buf, opts); for (token = buf; token && *token; token = next) { p = strchr(token, ','); next = 0; if (p) { *p = 0; next = p+1; } arg = strchr(token, '='); if (arg) { *arg = 0; arg++; } #if 0 printf("Journal option=%s, argument=%s\n", token, arg ? arg : "NONE"); #endif if (strcmp(token, "device") == 0) { journal_device = blkid_get_devname(NULL, arg, NULL); if (!journal_device) { if (arg) fprintf(stderr, _("\nCould not find " "journal device matching %s\n"), arg); journal_usage++; continue; } } else if (strcmp(token, "size") == 0) { if (!arg) { journal_usage++; continue; } journal_size = strtoul(arg, &p, 0); if (*p) journal_usage++; } else if (strcmp(token, "v1_superblock") == 0) { journal_flags |= EXT2_MKJOURNAL_V1_SUPER; continue; } else journal_usage++; } if (journal_usage) { fputs(_("\nBad journal options specified.\n\n" "Journal options are separated by commas, " "and may take an argument which\n" "\tis set off by an equals ('=') sign.\n\n" "Valid journal options are:\n" "\tsize=<journal size in megabytes>\n" "\tdevice=<journal device>\n\n" "The journal size must be between " "1024 and 10240000 filesystem blocks.\n\n"), stderr); free(buf); exit(1); } free(buf); }
const char * mount_get_devname_by_label(const char *label) { return blkid_get_devname(blkid, "LABEL", label); }
const char * mount_get_devname_by_uuid(const char *uuid) { return blkid_get_devname(blkid, "UUID", uuid); }
/* * Remove an external journal from the filesystem */ static void remove_journal_device(ext2_filsys fs) { char *journal_path; ext2_filsys jfs; char buf[1024]; journal_superblock_t *jsb; int i, nr_users; errcode_t retval; int commit_remove_journal = 0; io_manager io_ptr; if (f_flag) commit_remove_journal = 1; /* force removal even if error */ uuid_unparse(fs->super->s_journal_uuid, buf); journal_path = blkid_get_devname(NULL, "UUID", buf); if (!journal_path) { journal_path = ext2fs_find_block_device(fs->super->s_journal_dev); if (!journal_path) return; } io_ptr = unix_io_manager; retval = ext2fs_open(journal_path, EXT2_FLAG_RW| EXT2_FLAG_JOURNAL_DEV_OK, 0, fs->blocksize, io_ptr, &jfs); if (retval) { bb_error_msg("Failed to open external journal"); goto no_valid_journal; } if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { bb_error_msg("%s is not a journal device", journal_path); goto no_valid_journal; } /* Get the journal superblock */ if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { bb_error_msg("Failed to read journal superblock"); goto no_valid_journal; } jsb = (journal_superblock_t *) buf; if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) { bb_error_msg("Journal superblock not found!"); goto no_valid_journal; } /* Find the filesystem UUID */ nr_users = ntohl(jsb->s_nr_users); for (i=0; i < nr_users; i++) { if (memcmp(fs->super->s_uuid, &jsb->s_users[i*16], 16) == 0) break; } if (i >= nr_users) { bb_error_msg("Filesystem's UUID not found on journal device"); commit_remove_journal = 1; goto no_valid_journal; } nr_users--; for (i=0; i < nr_users; i++) memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); jsb->s_nr_users = htonl(nr_users); /* Write back the journal superblock */ if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { bb_error_msg("Failed to write journal superblock"); goto no_valid_journal; } commit_remove_journal = 1; no_valid_journal: if (commit_remove_journal == 0) bb_error_msg_and_die("Journal NOT removed"); fs->super->s_journal_dev = 0; uuid_clear(fs->super->s_journal_uuid); ext2fs_mark_super_dirty(fs); puts("Journal removed"); free(journal_path); }
static errcode_t ext2fs_get_journal(ext2_filsys fs, journal_t **ret_journal) { struct process_block_struct pb; struct ext2_super_block *sb = fs->super; struct ext2_super_block jsuper; struct buffer_head *bh; struct inode *j_inode = NULL; struct kdev_s *dev_fs = NULL, *dev_journal; const char *journal_name = 0; journal_t *journal = NULL; errcode_t retval = 0; io_manager io_ptr = 0; unsigned long long start = 0; int ext_journal = 0; int tried_backup_jnl = 0; retval = ext2fs_get_memzero(sizeof(journal_t), &journal); if (retval) return retval; retval = ext2fs_get_memzero(2 * sizeof(struct kdev_s), &dev_fs); if (retval) goto errout; dev_journal = dev_fs+1; dev_fs->k_fs = dev_journal->k_fs = fs; dev_fs->k_dev = K_DEV_FS; dev_journal->k_dev = K_DEV_JOURNAL; journal->j_dev = dev_journal; journal->j_fs_dev = dev_fs; journal->j_inode = NULL; journal->j_blocksize = fs->blocksize; if (uuid_is_null(sb->s_journal_uuid)) { if (!sb->s_journal_inum) { retval = EXT2_ET_BAD_INODE_NUM; goto errout; } retval = ext2fs_get_memzero(sizeof(*j_inode), &j_inode); if (retval) goto errout; j_inode->i_fs = fs; j_inode->i_ino = sb->s_journal_inum; retval = ext2fs_read_inode(fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) { try_backup_journal: if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || tried_backup_jnl) goto errout; memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, EXT2_N_BLOCKS*4); j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15]; j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; j_inode->i_ext2.i_links_count = 1; j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; tried_backup_jnl++; } if (!j_inode->i_ext2.i_links_count || !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { retval = EXT2_ET_NO_JOURNAL; goto try_backup_journal; } if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize < JFS_MIN_JOURNAL_BLOCKS) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } pb.last_block = -1; retval = ext2fs_block_iterate3(fs, j_inode->i_ino, BLOCK_FLAG_HOLE, 0, process_journal_block, &pb); if ((pb.last_block + 1) * fs->blocksize < (int) EXT2_I_SIZE(&j_inode->i_ext2)) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } if (tried_backup_jnl && (fs->flags & EXT2_FLAG_RW)) { retval = ext2fs_write_inode(fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) goto errout; } journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize; #ifdef USE_INODE_IO retval = ext2fs_inode_io_intern2(fs, sb->s_journal_inum, &j_inode->i_ext2, &journal_name); if (retval) goto errout; io_ptr = inode_io_manager; #else journal->j_inode = j_inode; fs->journal_io = fs->io; retval = (errcode_t)journal_bmap(journal, 0, &start); if (retval) goto errout; #endif } else { ext_journal = 1; if (!fs->journal_name) { char uuid[37]; blkid_cache blkid; blkid_get_cache(&blkid, NULL); uuid_unparse(sb->s_journal_uuid, uuid); fs->journal_name = blkid_get_devname(blkid, "UUID", uuid); if (!fs->journal_name) fs->journal_name = blkid_devno_to_devname(sb->s_journal_dev); blkid_put_cache(blkid); } journal_name = fs->journal_name; if (!journal_name) { retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } jfs_debug(1, "Using journal file %s\n", journal_name); io_ptr = unix_io_manager; } #if 0 test_io_backing_manager = io_ptr; io_ptr = test_io_manager; #endif #ifndef USE_INODE_IO if (ext_journal) #endif { retval = io_ptr->open(journal_name, fs->flags & EXT2_FLAG_RW, &fs->journal_io); } if (retval) goto errout; io_channel_set_blksize(fs->journal_io, fs->blocksize); if (ext_journal) { blk64_t maxlen; start = ext2fs_journal_sb_start(fs->blocksize) - 1; bh = getblk(dev_journal, start, fs->blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } ll_rw_block(READ, 1, &bh); retval = bh->b_err; if (retval) { brelse(bh); goto errout; } memcpy(&jsuper, start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET, sizeof(jsuper)); #ifdef WORDS_BIGENDIAN if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ext2fs_swap_super(&jsuper); #endif if (jsuper.s_magic != EXT2_SUPER_MAGIC || !ext2fs_has_feature_journal_dev(&jsuper)) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } /* Make sure the journal UUID is correct */ if (memcmp(jsuper.s_uuid, fs->super->s_journal_uuid, sizeof(jsuper.s_uuid))) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } /* Check the superblock checksum */ if (ext2fs_has_feature_metadata_csum(&jsuper)) { struct struct_ext2_filsys fsx; struct ext2_super_block superx; void *p; p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET; memcpy(&fsx, fs, sizeof(fsx)); memcpy(&superx, fs->super, sizeof(superx)); fsx.super = &superx; ext2fs_set_feature_metadata_csum(fsx.super); if (!ext2fs_superblock_csum_verify(&fsx, p)) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } } brelse(bh); maxlen = ext2fs_blocks_count(&jsuper); journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : (1ULL << 32) - 1; start++; } bh = getblk(dev_journal, start, journal->j_blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; #ifdef USE_INODE_IO if (j_inode) ext2fs_free_mem(&j_inode); #endif *ret_journal = journal; return 0; errout: if (dev_fs) ext2fs_free_mem(&dev_fs); if (j_inode) ext2fs_free_mem(&j_inode); if (journal) ext2fs_free_mem(&journal); return retval; }
static void PRS(int argc, char *argv[]) { int i, j; char *arg, *dev, *tmp = 0; char options[128]; int opt = 0; int opts_for_fsck = 0; #ifdef HAVE_SIGNAL_H struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = signal_cancel; sigaction(SIGINT, &sa, 0); sigaction(SIGTERM, &sa, 0); #endif num_devices = 0; num_args = 0; instance_list = 0; progname = argv[0]; for (i=1; i < argc; i++) { arg = argv[i]; if (!arg) continue; if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { if (num_devices >= MAX_DEVICES) { fprintf(stderr, _("%s: too many devices\n"), progname); exit(EXIT_ERROR); } dev = blkid_get_devname(cache, arg, NULL); if (!dev && strchr(arg, '=')) { if (access("/proc/partitions", R_OK) < 0) { fprintf(stderr, "Couldn't open /proc/partitions: %s\n", strerror(errno)); fprintf(stderr, "Is /proc mounted?\n"); exit(EXIT_ERROR); } if (geteuid()) fprintf(stderr, "Must be root to scan for matching filesystems: %s\n", arg); else fprintf(stderr, "Couldn't find matching filesystem: %s\n", arg); exit(EXIT_ERROR); } devices[num_devices++] = dev ? dev : string_copy(arg); continue; } if (arg[0] != '-' || opts_for_fsck) { if (num_args >= MAX_ARGS) { fprintf(stderr, _("%s: too many arguments\n"), progname); exit(EXIT_ERROR); } args[num_args++] = string_copy(arg); continue; } for (j=1; arg[j]; j++) { if (opts_for_fsck) { options[++opt] = arg[j]; continue; } switch (arg[j]) { case 'A': doall++; break; case 'C': progress++; if (arg[j+1]) { progress_fd = string_to_int(arg+j+1); if (progress_fd < 0) progress_fd = 0; else goto next_arg; } else if ((i+1) < argc && !strncmp(argv[i+1], "-", 1) == 0) { progress_fd = string_to_int(argv[i]); if (progress_fd < 0) progress_fd = 0; else { goto next_arg; i++; } } break; case 'V': verbose++; break; case 'N': noexecute++; break; case 'R': skip_root++; break; case 'T': notitle++; break; case 'M': ignore_mounted++; break; case 'P': parallel_root++; break; case 's': serialize++; break; case 't': tmp = 0; if (fstype) usage(); if (arg[j+1]) tmp = arg+j+1; else if ((i+1) < argc) tmp = argv[++i]; else usage(); fstype = string_copy(tmp); compile_fs_type(fstype, &fs_type_compiled); goto next_arg; case '-': opts_for_fsck++; break; case '?': usage(); break; default: options[++opt] = arg[j]; break; } } next_arg: if (opt) { options[0] = '-'; options[++opt] = '\0'; if (num_args >= MAX_ARGS) { fprintf(stderr, _("%s: too many arguments\n"), progname); exit(EXIT_ERROR); } args[num_args++] = string_copy(options); opt = 0; } } if (getenv("FSCK_FORCE_ALL_PARALLEL")) force_all_parallel++; if ((tmp = getenv("FSCK_MAX_INST"))) max_running = atoi(tmp); }