/* * Find the mount point for a mounted device. * On success, returns 0 with mountpoint in *mp. * On failure, returns -errno (not mounted yields -EINVAL) * Is noisy on failures, expects to be given a mounted device. */ int get_btrfs_mount(const char *dev, char *mp, size_t mp_size) { int ret; int fd = -1; ret = is_block_device(dev); if (ret <= 0) { if (!ret) { fprintf(stderr, "%s is not a block device\n", dev); ret = -EINVAL; } else { fprintf(stderr, "Could not check %s: %s\n", dev, strerror(-ret)); } goto out; } fd = open(dev, O_RDONLY); if (fd < 0) { ret = -errno; fprintf(stderr, "Could not open %s: %s\n", dev, strerror(errno)); goto out; } ret = check_mounted_where(fd, dev, mp, mp_size, NULL); if (!ret) { ret = -EINVAL; } else { /* mounted, all good */ ret = 0; } out: if (fd != -1) close(fd); return ret; }
static int cmd_rm_dev(int argc, char **argv) { char *mntpnt; int i, fdmnt, ret=0, e; DIR *dirstream = NULL; if (check_argc_min(argc, 3)) usage(cmd_rm_dev_usage); mntpnt = argv[argc - 1]; fdmnt = open_file_or_dir(mntpnt, &dirstream); if (fdmnt < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", mntpnt); return 1; } for(i=1 ; i < argc - 1; i++ ){ struct btrfs_ioctl_vol_args arg; int res; if (!is_block_device(argv[i])) { fprintf(stderr, "ERROR: %s is not a block device\n", argv[i]); ret++; continue; } memset(&arg, 0, sizeof(arg)); strncpy_null(arg.name, argv[i]); res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); e = errno; if (res) { const char *msg; if (res > 0) msg = btrfs_err_str(res); else msg = strerror(e); fprintf(stderr, "ERROR: error removing the device '%s' - %s\n", argv[i], msg); ret++; } } close_file_or_dir(fdmnt, dirstream); return !!ret; }
static int cmd_ready_dev(int argc, char **argv) { struct btrfs_ioctl_vol_args args; int fd; int ret; char *path; if (check_argc_min(argc, 2)) usage(cmd_ready_dev_usage); fd = open("/dev/btrfs-control", O_RDWR); if (fd < 0) { perror("failed to open /dev/btrfs-control"); return 1; } path = canonicalize_path(argv[argc - 1]); if (!path) { fprintf(stderr, "ERROR: Could not canonicalize pathname '%s': %s\n", argv[argc - 1], strerror(errno)); ret = 1; goto out; } if (!is_block_device(path)) { fprintf(stderr, "ERROR: %s is not a block device\n", path); ret = 1; goto out; } memset(&args, 0, sizeof(args)); strncpy_null(args.name, path); ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); if (ret < 0) { fprintf(stderr, "ERROR: unable to determine if the device '%s'" " is ready for mounting - %s\n", path, strerror(errno)); ret = 1; } out: free(path); close(fd); return ret; }
static int cmd_device_ready(int argc, char **argv) { struct btrfs_ioctl_vol_args args; int fd; int ret; char *path; clean_args_no_options(argc, argv, cmd_device_ready_usage); if (check_argc_exact(argc - optind, 1)) usage(cmd_device_ready_usage); fd = open("/dev/btrfs-control", O_RDWR); if (fd < 0) { perror("failed to open /dev/btrfs-control"); return 1; } path = canonicalize_path(argv[optind]); if (!path) { error("could not canonicalize pathname '%s': %m", argv[optind]); ret = 1; goto out; } if (is_block_device(path) != 1) { error("not a block device: %s", path); ret = 1; goto out; } memset(&args, 0, sizeof(args)); strncpy_null(args.name, path); ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); if (ret < 0) { error("unable to determine if device '%s' is ready for mount: %m", path); ret = 1; } out: free(path); close(fd); return ret; }
/* * Given a pathname, return a filehandle to: * the original pathname or, * if the pathname is a mounted btrfs device, to its mountpoint. * * On error, return -1, errno should be set. */ int open_path_or_dev_mnt(const char *path, DIR **dirstream) { char mp[BTRFS_PATH_NAME_MAX + 1]; int fdmnt; if (is_block_device(path)) { int ret; ret = get_btrfs_mount(path, mp, sizeof(mp)); if (ret < 0) { /* not a mounted btrfs dev */ errno = EINVAL; return -1; } fdmnt = open_file_or_dir(mp, dirstream); } else { fdmnt = open_file_or_dir(path, dirstream); } return fdmnt; }
int main(int ac, char **av) { char *file; struct btrfs_root *root; struct btrfs_trans_handle *trans; char *label = NULL; char *first_file; u64 block_count = 0; u64 dev_block_count = 0; u64 blocks[7]; u64 alloc_start = 0; u64 metadata_profile = 0; u64 data_profile = 0; u32 leafsize = sysconf(_SC_PAGESIZE); u32 sectorsize = 4096; u32 nodesize = leafsize; u32 stripesize = 4096; int zero_end = 1; int option_index = 0; int fd; int ret; int i; int mixed = 0; int data_profile_opt = 0; int metadata_profile_opt = 0; int discard = 1; int ssd = 0; int force_overwrite = 0; char *source_dir = NULL; int source_dir_set = 0; u64 num_of_meta_chunks = 0; u64 size_of_data = 0; u64 source_dir_size = 0; int dev_cnt = 0; int saved_optind; char estr[100]; u64 features = 0; while(1) { int c; c = getopt_long(ac, av, "A:b:fl:n:s:m:d:L:O:r:VMK", long_options, &option_index); if (c < 0) break; switch(c) { case 'A': alloc_start = parse_size(optarg); break; case 'f': force_overwrite = 1; break; case 'd': data_profile = parse_profile(optarg); data_profile_opt = 1; break; case 'l': case 'n': nodesize = parse_size(optarg); leafsize = parse_size(optarg); break; case 'L': label = parse_label(optarg); break; case 'm': metadata_profile = parse_profile(optarg); metadata_profile_opt = 1; break; case 'M': mixed = 1; break; case 'O': { char *orig = strdup(optarg); char *tmp = orig; tmp = parse_fs_features(tmp, &features); if (tmp) { fprintf(stderr, "Unrecognized filesystem feature '%s'\n", tmp); free(orig); exit(1); } free(orig); if (features & BTRFS_FEATURE_LIST_ALL) { list_all_fs_features(); exit(0); } break; } case 's': sectorsize = parse_size(optarg); break; case 'b': block_count = parse_size(optarg); if (block_count <= 1024*1024*1024) { printf("SMALL VOLUME: forcing mixed " "metadata/data groups\n"); mixed = 1; } zero_end = 0; break; case 'V': print_version(); break; case 'r': source_dir = optarg; source_dir_set = 1; break; case 'K': discard = 0; break; default: print_usage(); } } sectorsize = max(sectorsize, (u32)sysconf(_SC_PAGESIZE)); if (check_leaf_or_node_size(leafsize, sectorsize)) exit(1); if (check_leaf_or_node_size(nodesize, sectorsize)) exit(1); saved_optind = optind; dev_cnt = ac - optind; if (dev_cnt == 0) print_usage(); if (source_dir_set && dev_cnt > 1) { fprintf(stderr, "The -r option is limited to a single device\n"); exit(1); } while (dev_cnt-- > 0) { file = av[optind++]; if (is_block_device(file)) if (test_dev_for_mkfs(file, force_overwrite, estr)) { fprintf(stderr, "Error: %s", estr); exit(1); } } optind = saved_optind; dev_cnt = ac - optind; file = av[optind++]; ssd = is_ssd(file); if (is_vol_small(file)) { printf("SMALL VOLUME: forcing mixed metadata/data groups\n"); mixed = 1; if (metadata_profile != data_profile) { if (metadata_profile_opt || data_profile_opt) { fprintf(stderr, "With mixed block groups data and metadata profiles must be the same\n"); exit(1); } } } /* * Set default profiles according to number of added devices. * For mixed groups defaults are single/single. */ if (!mixed) { if (!metadata_profile_opt) { if (dev_cnt == 1 && ssd) printf("Detected a SSD, turning off metadata " "duplication. Mkfs with -m dup if you want to " "force metadata duplication.\n"); metadata_profile = (dev_cnt > 1) ? BTRFS_BLOCK_GROUP_RAID1 : (ssd) ? 0: BTRFS_BLOCK_GROUP_DUP; } if (!data_profile_opt) { data_profile = (dev_cnt > 1) ? BTRFS_BLOCK_GROUP_RAID0 : 0; /* raid0 or single */ } } else { metadata_profile = 0; data_profile = 0; } ret = test_num_disk_vs_raid(metadata_profile, data_profile, dev_cnt, mixed, estr); if (ret) { fprintf(stderr, "Error: %s\n", estr); exit(1); } /* if we are here that means all devs are good to btrfsify */ printf("\nWARNING! - %s IS EXPERIMENTAL\n", BTRFS_BUILD_VERSION); printf("WARNING! - see http://btrfs.wiki.kernel.org before using\n\n"); dev_cnt--; if (!source_dir_set) { /* * open without O_EXCL so that the problem should not * occur by the following processing. * (btrfs_register_one_device() fails if O_EXCL is on) */ fd = open(file, O_RDWR); if (fd < 0) { fprintf(stderr, "unable to open %s: %s\n", file, strerror(errno)); exit(1); } first_file = file; ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, block_count, &mixed, discard); if (block_count && block_count > dev_block_count) { fprintf(stderr, "%s is smaller than requested size\n", file); exit(1); } } else { fd = open_target(file); if (fd < 0) { fprintf(stderr, "unable to open the %s\n", file); exit(1); } first_file = file; source_dir_size = size_sourcedir(source_dir, sectorsize, &num_of_meta_chunks, &size_of_data); if(block_count < source_dir_size) block_count = source_dir_size; ret = zero_output_file(fd, block_count, sectorsize); if (ret) { fprintf(stderr, "unable to zero the output file\n"); exit(1); } /* our "device" is the new image file */ dev_block_count = block_count; } /* To create the first block group and chunk 0 in make_btrfs */ if (dev_block_count < BTRFS_MKFS_SYSTEM_GROUP_SIZE) { fprintf(stderr, "device is too small to make filesystem\n"); exit(1); } blocks[0] = BTRFS_SUPER_INFO_OFFSET; for (i = 1; i < 7; i++) { blocks[i] = BTRFS_SUPER_INFO_OFFSET + 1024 * 1024 + leafsize * i; } /* * FS features that can be set by other means than -O * just set the bit here */ if (mixed) features |= BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS; if ((data_profile | metadata_profile) & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6)) { features |= BTRFS_FEATURE_INCOMPAT_RAID56; } process_fs_features(features); ret = make_btrfs(fd, file, label, blocks, dev_block_count, nodesize, leafsize, sectorsize, stripesize, features); if (ret) { fprintf(stderr, "error during mkfs: %s\n", strerror(-ret)); exit(1); } root = open_ctree(file, 0, OPEN_CTREE_WRITES); if (!root) { fprintf(stderr, "Open ctree failed\n"); close(fd); exit(1); } root->fs_info->alloc_start = alloc_start; ret = make_root_dir(root, mixed); if (ret) { fprintf(stderr, "failed to setup the root directory\n"); exit(1); } trans = btrfs_start_transaction(root, 1); if (dev_cnt == 0) goto raid_groups; btrfs_register_one_device(file); zero_end = 1; while (dev_cnt-- > 0) { int old_mixed = mixed; file = av[optind++]; /* * open without O_EXCL so that the problem should not * occur by the following processing. * (btrfs_register_one_device() fails if O_EXCL is on) */ fd = open(file, O_RDWR); if (fd < 0) { fprintf(stderr, "unable to open %s: %s\n", file, strerror(errno)); exit(1); } ret = btrfs_device_already_in_root(root, fd, BTRFS_SUPER_INFO_OFFSET); if (ret) { fprintf(stderr, "skipping duplicate device %s in FS\n", file); close(fd); continue; } ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, block_count, &mixed, discard); mixed = old_mixed; BUG_ON(ret); ret = btrfs_add_to_fsid(trans, root, fd, file, dev_block_count, sectorsize, sectorsize, sectorsize); BUG_ON(ret); btrfs_register_one_device(file); } raid_groups: if (!source_dir_set) { ret = create_raid_groups(trans, root, data_profile, data_profile_opt, metadata_profile, metadata_profile_opt, mixed, ssd); BUG_ON(ret); } ret = create_data_reloc_tree(trans, root); BUG_ON(ret); printf("fs created label %s on %s\n\tnodesize %u leafsize %u " "sectorsize %u size %s\n", label, first_file, nodesize, leafsize, sectorsize, pretty_size(btrfs_super_total_bytes(root->fs_info->super_copy))); printf("%s\n", BTRFS_BUILD_VERSION); btrfs_commit_transaction(trans, root); if (source_dir_set) { trans = btrfs_start_transaction(root, 1); ret = create_chunks(trans, root, num_of_meta_chunks, size_of_data); BUG_ON(ret); btrfs_commit_transaction(trans, root); ret = make_image(source_dir, root, fd); BUG_ON(ret); } ret = close_ctree(root); BUG_ON(ret); free(label); return 0; }
static int cmd_device_scan(int argc, char **argv) { int i; int devstart; int all = 0; int ret = 0; optind = 0; while (1) { int c; static const struct option long_options[] = { { "all-devices", no_argument, NULL, 'd'}, { NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "d", long_options, NULL); if (c < 0) break; switch (c) { case 'd': all = 1; break; default: usage(cmd_device_scan_usage); } } devstart = optind; if (all && check_argc_max(argc - optind, 1)) usage(cmd_device_scan_usage); if (all || argc - optind == 0) { printf("Scanning for Btrfs filesystems\n"); ret = btrfs_scan_devices(); error_on(ret, "error %d while scanning", ret); ret = btrfs_register_all_devices(); error_on(ret, "there are %d errors while registering devices", ret); goto out; } for( i = devstart ; i < argc ; i++ ){ char *path; if (is_block_device(argv[i]) != 1) { error("not a block device: %s", argv[i]); ret = 1; goto out; } path = canonicalize_path(argv[i]); if (!path) { error("could not canonicalize path '%s': %m", argv[i]); ret = 1; goto out; } printf("Scanning for Btrfs filesystems in '%s'\n", path); if (btrfs_register_one_device(path) != 0) { ret = 1; free(path); goto out; } free(path); } out: return !!ret; }
static int _cmd_device_remove(int argc, char **argv, const char * const *usagestr) { char *mntpnt; int i, fdmnt, ret = 0; DIR *dirstream = NULL; clean_args_no_options(argc, argv, usagestr); if (check_argc_min(argc - optind, 2)) usage(usagestr); mntpnt = argv[argc - 1]; fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1); if (fdmnt < 0) return 1; for(i = optind; i < argc - 1; i++) { struct btrfs_ioctl_vol_args arg; struct btrfs_ioctl_vol_args_v2 argv2 = {0}; int is_devid = 0; int res; if (string_is_numerical(argv[i])) { argv2.devid = arg_strtou64(argv[i]); argv2.flags = BTRFS_DEVICE_SPEC_BY_ID; is_devid = 1; } else if (is_block_device(argv[i]) == 1 || strcmp(argv[i], "missing") == 0) { strncpy_null(argv2.name, argv[i]); } else { error("not a block device: %s", argv[i]); ret++; continue; } /* * Positive values are from BTRFS_ERROR_DEV_*, * otherwise it's a generic error, one of errnos */ res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2); /* * If BTRFS_IOC_RM_DEV_V2 is not supported we get ENOTTY and if * argv2.flags includes a flag which kernel doesn't understand then * we shall get EOPNOTSUPP */ if (res < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) { if (is_devid) { error("device delete by id failed: %m"); ret++; continue; } memset(&arg, 0, sizeof(arg)); strncpy_null(arg.name, argv[i]); res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); } if (res) { const char *msg; if (res > 0) msg = btrfs_err_str(res); else msg = strerror(errno); if (is_devid) { error("error removing devid %llu: %s", (unsigned long long)argv2.devid, msg); } else { error("error removing device '%s': %s", argv[i], msg); } ret++; } } close_file_or_dir(fdmnt, dirstream); return !!ret; }
static int dev_replace_handle_sigint(int fd) { struct sigaction sa = { .sa_handler = fd == -1 ? SIG_DFL : dev_replace_sigint_handler }; dev_replace_cancel_fd = fd; return sigaction(SIGINT, &sa, NULL); } static const char *const cmd_replace_start_usage[] = { "btrfs replace start [-Bfr] <srcdev>|<devid> <targetdev> <mount_point>", "Replace device of a btrfs filesystem.", "On a live filesystem, duplicate the data to the target device which", "is currently stored on the source device. If the source device is not", "available anymore, or if the -r option is set, the data is built", "only using the RAID redundancy mechanisms. After completion of the", "operation, the source device is removed from the filesystem.", "If the <srcdev> is a numerical value, it is assumed to be the device id", "of the filesystem which is mounted at <mount_point>, otherwise it is", "the path to the source device. If the source device is disconnected,", "from the system, you have to use the <devid> parameter format.", "The <targetdev> needs to be same size or larger than the <srcdev>.", "", "-r only read from <srcdev> if no other zero-defect mirror exists", " (enable this if your drive has lots of read errors, the access", " would be very slow)", "-f force using and overwriting <targetdev> even if it looks like", " containing a valid btrfs filesystem. A valid filesystem is", " assumed if a btrfs superblock is found which contains a", " correct checksum. Devices which are currently mounted are", " never allowed to be used as the <targetdev>", "-B do not background", NULL }; static int cmd_replace_start(int argc, char **argv) { struct btrfs_ioctl_dev_replace_args start_args = {0}; struct btrfs_ioctl_dev_replace_args status_args = {0}; int ret; int i; int c; int fdmnt = -1; int fddstdev = -1; char *path; char *srcdev; char *dstdev = NULL; int avoid_reading_from_srcdev = 0; int force_using_targetdev = 0; u64 dstdev_block_count; int do_not_background = 0; DIR *dirstream = NULL; u64 srcdev_size; u64 dstdev_size; while ((c = getopt(argc, argv, "Brf")) != -1) { switch (c) { case 'B': do_not_background = 1; break; case 'r': avoid_reading_from_srcdev = 1; break; case 'f': force_using_targetdev = 1; break; case '?': default: usage(cmd_replace_start_usage); } } start_args.start.cont_reading_from_srcdev_mode = avoid_reading_from_srcdev ? BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID : BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS; if (check_argc_exact(argc - optind, 3)) usage(cmd_replace_start_usage); path = argv[optind + 2]; fdmnt = open_path_or_dev_mnt(path, &dirstream, 1); if (fdmnt < 0) goto leave_with_error; /* check for possible errors before backgrounding */ status_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS; status_args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT; ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &status_args); if (ret < 0) { fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s", path, strerror(errno)); if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT) fprintf(stderr, ", %s\n", replace_dev_result2string(status_args.result)); else fprintf(stderr, "\n"); goto leave_with_error; } if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) { error("ioctl(DEV_REPLACE_STATUS) on '%s' returns error: %s", path, replace_dev_result2string(status_args.result)); goto leave_with_error; } if (status_args.status.replace_state == BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) { error("device replace on '%s' already started", path); goto leave_with_error; } srcdev = argv[optind]; dstdev = canonicalize_path(argv[optind + 1]); if (!dstdev) { error("cannot canonicalize path '%s': %s", argv[optind + 1], strerror(errno)); goto leave_with_error; } if (string_is_numerical(srcdev)) { struct btrfs_ioctl_fs_info_args fi_args; struct btrfs_ioctl_dev_info_args *di_args = NULL; start_args.start.srcdevid = arg_strtou64(srcdev); ret = get_fs_info(path, &fi_args, &di_args); if (ret) { error("failed to get device info: %s", strerror(-ret)); free(di_args); goto leave_with_error; } if (!fi_args.num_devices) { error("no devices found"); free(di_args); goto leave_with_error; } for (i = 0; i < fi_args.num_devices; i++) if (start_args.start.srcdevid == di_args[i].devid) break; srcdev_size = di_args[i].total_bytes; free(di_args); if (i == fi_args.num_devices) { error("'%s' is not a valid devid for filesystem '%s'", srcdev, path); goto leave_with_error; } } else if (is_block_device(srcdev) > 0) { strncpy((char *)start_args.start.srcdev_name, srcdev, BTRFS_DEVICE_PATH_NAME_MAX); start_args.start.srcdevid = 0; srcdev_size = get_partition_size(srcdev); } else { error("source device must be a block device or a devid"); goto leave_with_error; } ret = test_dev_for_mkfs(dstdev, force_using_targetdev); if (ret) goto leave_with_error; dstdev_size = get_partition_size(dstdev); if (srcdev_size > dstdev_size) { error("target device smaller than source device (required %llu bytes)", srcdev_size); goto leave_with_error; } fddstdev = open(dstdev, O_RDWR); if (fddstdev < 0) { error("unable to open %s: %s", dstdev, strerror(errno)); goto leave_with_error; } strncpy((char *)start_args.start.tgtdev_name, dstdev, BTRFS_DEVICE_PATH_NAME_MAX); ret = btrfs_prepare_device(fddstdev, dstdev, &dstdev_block_count, 0, PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE); if (ret) goto leave_with_error; close(fddstdev); fddstdev = -1; free(dstdev); dstdev = NULL; dev_replace_handle_sigint(fdmnt); if (!do_not_background) { if (daemon(0, 0) < 0) { error("backgrounding failed: %s", strerror(errno)); goto leave_with_error; } } start_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_START; start_args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT; ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &start_args); if (do_not_background) { if (ret < 0) { fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_START) failed on \"%s\": %s", path, strerror(errno)); if (start_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT) fprintf(stderr, ", %s\n", replace_dev_result2string(start_args.result)); else fprintf(stderr, "\n"); if (errno == EOPNOTSUPP) warning("device replace of RAID5/6 not supported with this kernel"); goto leave_with_error; } if (start_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) { error("ioctl(DEV_REPLACE_START) on '%s' returns error: %s", path, replace_dev_result2string(start_args.result)); goto leave_with_error; } } close_file_or_dir(fdmnt, dirstream); return 0; leave_with_error: if (dstdev) free(dstdev); if (fdmnt != -1) close(fdmnt); if (fddstdev != -1) close(fddstdev); return 1; } static const char *const cmd_replace_status_usage[] = { "btrfs replace status [-1] <mount_point>", "Print status and progress information of a running device replace", "operation", "", "-1 print once instead of print continuously until the replace", " operation finishes (or is canceled)", NULL }; static int cmd_replace_status(int argc, char **argv) { int fd; int c; char *path; int once = 0; int ret; DIR *dirstream = NULL; while ((c = getopt(argc, argv, "1")) != -1) { switch (c) { case '1': once = 1; break; case '?': default: usage(cmd_replace_status_usage); } } if (check_argc_exact(argc - optind, 1)) usage(cmd_replace_status_usage); path = argv[optind]; fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) return 1; ret = print_replace_status(fd, path, once); close_file_or_dir(fd, dirstream); return !!ret; }
static int cmd_scan_dev(int argc, char **argv) { int i; int devstart = 1; int all = 0; int ret = 0; optind = 1; while (1) { int c; static const struct option long_options[] = { { "all-devices", no_argument, NULL, 'd'}, { NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "d", long_options, NULL); if (c < 0) break; switch (c) { case 'd': all = 1; break; default: usage(cmd_scan_dev_usage); } } if (all && check_argc_max(argc, 2)) usage(cmd_scan_dev_usage); if (all || argc == 1) { printf("Scanning for Btrfs filesystems\n"); ret = btrfs_scan_lblkid(); if (ret) fprintf(stderr, "ERROR: error %d while scanning\n", ret); ret = btrfs_register_all_devices(); if (ret) fprintf(stderr, "ERROR: error %d while registering\n", ret); goto out; } for( i = devstart ; i < argc ; i++ ){ char *path; if (!is_block_device(argv[i])) { fprintf(stderr, "ERROR: %s is not a block device\n", argv[i]); ret = 1; goto out; } path = canonicalize_path(argv[i]); if (!path) { fprintf(stderr, "ERROR: Could not canonicalize path '%s': %s\n", argv[i], strerror(errno)); ret = 1; goto out; } printf("Scanning for Btrfs filesystems in '%s'\n", path); if (btrfs_register_one_device(path) != 0) { ret = 1; free(path); goto out; } free(path); } out: return !!ret; }