static int cmd_device_usage(int argc, char **argv) { unsigned unit_mode; int ret = 0; int i; unit_mode = get_unit_mode_from_arg(&argc, argv, 1); clean_args_no_options(argc, argv, cmd_device_usage_usage); if (check_argc_min(argc - optind, 1)) usage(cmd_device_usage_usage); for (i = optind; i < argc; i++) { int fd; DIR *dirstream = NULL; if (i > 1) printf("\n"); fd = btrfs_open_dir(argv[i], &dirstream, 1); if (fd < 0) { ret = 1; break; } ret = _cmd_device_usage(fd, argv[i], unit_mode); close_file_or_dir(fd, dirstream); if (ret) break; } return !!ret; }
int main(int argc, char **argv) { char *path; int fd; int ret; u64 flags = 0; char *dir = "html"; DIR *dirstream = NULL; while (1) { int c = getopt(argc, argv, "cmso:h"); if (c < 0) break; switch (c) { case 'c': use_color = 1; break; case 'd': flags |= BTRFS_BLOCK_GROUP_DATA; break; case 'm': flags |= BTRFS_BLOCK_GROUP_METADATA; break; case 's': flags |= BTRFS_BLOCK_GROUP_SYSTEM; break; case 'o': dir = optarg; break; case 'h': default: fragments_usage(); } } set_argv0(argv); if (check_argc_min(argc - optind, 1)) fragments_usage(); path = argv[optind++]; fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) exit(1); if (flags == 0) flags = BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA; ret = list_fragments(fd, flags, dir); close_file_or_dir(fd, dirstream); if (ret) exit(1); exit(0); }
int main(int argc, char **argv) { int c; unsigned long checksum = 0; char *str; char *buf; int length = 10; int seed = getpid() ^ getppid(); int loop = 0; int i; while ((c = getopt(argc, argv, "l:c:s:h")) != -1) { switch (c) { case 'l': length = atol(optarg); break; case 'c': sscanf(optarg, "%li", &checksum); loop = 1; break; case 's': seed = atol(optarg); break; case 'h': usage(); case '?': return 255; } } set_argv0(argv); str = argv[optind]; if (!loop) { if (check_argc_min(argc - optind, 1)) return 255; printf("%12u - %s\n", crc32c(~1, str, strlen(str)), str); return 0; } buf = malloc(length); if (!buf) return -ENOMEM; srand(seed); while (1) { for (i = 0; i < length; i++) buf[i] = rand() % 94 + 33; if (crc32c(~1, buf, length) == checksum) printf("%12lu - %.*s\n", checksum, length, buf); } return 0; }
int main(int argc, char **argv) { struct btrfs_root *root; int dev_fd; int opt; int ret; while ((opt = getopt(argc, argv, "l:o:g:")) != -1) { switch(opt) { case 'o': search_objectid = arg_strtou64(optarg); break; case 'g': search_generation = arg_strtou64(optarg); break; case 'l': search_level = arg_strtou64(optarg); break; default: usage(); exit(1); } } set_argv0(argv); argc = argc - optind; if (check_argc_min(argc, 1)) { usage(); exit(1); } dev_fd = open(argv[optind], O_RDONLY); if (dev_fd < 0) { fprintf(stderr, "Failed to open device %s\n", argv[optind]); exit(1); } root = open_ctree_broken(dev_fd, argv[optind]); close(dev_fd); if (!root) { fprintf(stderr, "Open ctree failed\n"); exit(1); } if (search_generation == 0) search_generation = btrfs_super_generation(root->fs_info->super_copy); csum_size = btrfs_super_csum_size(root->fs_info->super_copy); ret = find_root(root); close_ctree(root); 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_list(int argc, char **argv) { int ret; char *object = NULL; int types = 0; if (check_argc_min(argc, 2) || check_argc_max(argc, 3)) usage(cmd_list_usage); parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL); if (!object) { fprintf(stderr, "ERROR: invalid arguments.\n"); usage(cmd_set_usage); } ret = dump_props(types, object, 1); return ret; }
static int cmd_set(int argc, char **argv) { int ret; char *object; char *name; char *value; int types = 0; if (check_argc_min(argc, 4) || check_argc_max(argc, 5)) usage(cmd_set_usage); parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value); if (!object || !name || !value) { fprintf(stderr, "ERROR: invalid arguments.\n"); usage(cmd_set_usage); } ret = setget_prop(types, object, name, value); return ret; }
static int cmd_get(int argc, char **argv) { int ret; char *object; char *name = NULL; int types = 0; if (check_argc_min(argc, 2) || check_argc_max(argc, 4)) usage(cmd_get_usage); parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL); if (!object) { fprintf(stderr, "ERROR: invalid arguments.\n"); usage(cmd_set_usage); } if (name) ret = setget_prop(types, object, name, NULL); else ret = dump_props(types, object, 0); return ret; }
static int cmd_rm_dev(int argc, char **argv) { char *mntpnt; int i, fdmnt, ret=0, e; if (check_argc_min(argc, 3)) usage(cmd_rm_dev_usage); mntpnt = argv[argc - 1]; fdmnt = open_file_or_dir(mntpnt); if (fdmnt < 0) { fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt); return 12; } for(i=1 ; i < argc - 1; i++ ){ struct btrfs_ioctl_vol_args arg; int res; strncpy(arg.name, argv[i], BTRFS_PATH_NAME_MAX); arg.name[BTRFS_PATH_NAME_MAX-1] = 0; res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); e = errno; if(res<0){ fprintf(stderr, "ERROR: error removing the device '%s' - %s\n", argv[i], strerror(e)); ret++; } } close(fdmnt); if( ret) return ret+20; else return 0; }
static int cmd_add_dev(int argc, char **argv) { char *mntpnt; int i, fdmnt, ret=0, e; if (check_argc_min(argc, 3)) usage(cmd_add_dev_usage); mntpnt = argv[argc - 1]; fdmnt = open_file_or_dir(mntpnt); if (fdmnt < 0) { fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt); return 12; } for (i = 1; i < argc - 1; i++ ){ struct btrfs_ioctl_vol_args ioctl_args; int devfd, res; u64 dev_block_count = 0; struct stat st; int mixed = 0; res = check_mounted(argv[i]); if (res < 0) { fprintf(stderr, "error checking %s mount status\n", argv[i]); ret++; continue; } if (res == 1) { fprintf(stderr, "%s is mounted\n", argv[i]); ret++; continue; } devfd = open(argv[i], O_RDWR); if (!devfd) { fprintf(stderr, "ERROR: Unable to open device '%s'\n", argv[i]); close(devfd); ret++; continue; } res = fstat(devfd, &st); if (res) { fprintf(stderr, "ERROR: Unable to stat '%s'\n", argv[i]); close(devfd); ret++; continue; } if (!S_ISBLK(st.st_mode)) { fprintf(stderr, "ERROR: '%s' is not a block device\n", argv[i]); close(devfd); ret++; continue; } res = btrfs_prepare_device(devfd, argv[i], 1, &dev_block_count, 0, &mixed, 0); if (res) { fprintf(stderr, "ERROR: Unable to init '%s'\n", argv[i]); close(devfd); ret++; continue; } close(devfd); strncpy(ioctl_args.name, argv[i], BTRFS_PATH_NAME_MAX); ioctl_args.name[BTRFS_PATH_NAME_MAX-1] = 0; res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); e = errno; if(res<0){ fprintf(stderr, "ERROR: error adding the device '%s' - %s\n", argv[i], strerror(e)); ret++; } } close(fdmnt); if (ret) return ret+20; else return 0; }
int cmd_filesystem_usage(int argc, char **argv) { int ret = 0; unsigned unit_mode; int i; int more_than_one = 0; int tabular = 0; unit_mode = get_unit_mode_from_arg(&argc, argv, 1); optind = 1; while (1) { int c; c = getopt(argc, argv, "T"); if (c < 0) break; switch (c) { case 'T': tabular = 1; break; default: usage(cmd_filesystem_usage_usage); } } if (check_argc_min(argc - optind, 1)) usage(cmd_filesystem_usage_usage); for (i = optind; i < argc; i++) { int fd; DIR *dirstream = NULL; struct chunk_info *chunkinfo = NULL; struct device_info *devinfo = NULL; int chunkcount = 0; int devcount = 0; fd = open_file_or_dir(argv[i], &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", argv[i]); ret = 1; goto out; } if (more_than_one) printf("\n"); ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo, &devcount); if (ret) goto cleanup; ret = print_filesystem_usage_overall(fd, chunkinfo, chunkcount, devinfo, devcount, argv[i], unit_mode); if (ret) goto cleanup; printf("\n"); ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount, devinfo, devcount, argv[i], unit_mode, tabular); cleanup: close_file_or_dir(fd, dirstream); free(chunkinfo); free(devinfo); if (ret) goto out; more_than_one = 1; } out: return !!ret; }
static void parse_args(int argc, char **argv, const char * const *usage_str, int *types, char **object, char **name, char **value, int min_nonopt_args) { int ret; char *type_str = NULL; int max_nonopt_args = 1; optind = 1; while (1) { int c = getopt(argc, argv, "t:"); if (c < 0) break; switch (c) { case 't': type_str = optarg; break; default: usage(usage_str); } } if (name) max_nonopt_args++; if (value) max_nonopt_args++; if (check_argc_min(argc - optind, min_nonopt_args) || check_argc_max(argc - optind, max_nonopt_args)) usage(usage_str); *types = 0; if (type_str) { if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) { *types = prop_object_subvol; } else if (!strcmp(type_str, "f") || !strcmp(type_str, "filesystem")) { *types = prop_object_root; } else if (!strcmp(type_str, "i") || !strcmp(type_str, "inode")) { *types = prop_object_inode; } else if (!strcmp(type_str, "d") || !strcmp(type_str, "device")) { *types = prop_object_dev; } else { error("invalid object type: %s", type_str); usage(usage_str); } } *object = argv[optind++]; if (optind < argc) *name = argv[optind++]; if (optind < argc) *value = argv[optind++]; if (!*types) { ret = autodetect_object_types(*object, types); if (ret < 0) { error("failed to detect object type: %s", strerror(-ret)); usage(usage_str); } if (!*types) { error("object is not a btrfs object: %s", *object); usage(usage_str); } } }
static int cmd_subvol_sync(int argc, char **argv) { int fd = -1; int i; int ret = 1; DIR *dirstream = NULL; u64 *ids = NULL; int id_count; int sleep_interval = 1; optind = 1; while (1) { int c = getopt(argc, argv, "s:"); if (c < 0) break; switch (c) { case 's': sleep_interval = atoi(argv[optind]); if (sleep_interval < 1) { fprintf(stderr, "ERROR: invalid sleep interval %s\n", argv[optind]); ret = 1; goto out; } break; default: usage(cmd_subvol_sync_usage); } } if (check_argc_min(argc - optind, 1)) usage(cmd_subvol_sync_usage); fd = open_file_or_dir(argv[optind], &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]); ret = 1; goto out; } optind++; id_count = argc - optind; if (!id_count) { id_count = SUBVOL_ID_BATCH; ids = (u64*)malloc(id_count * sizeof(u64)); if (!ids) { fprintf(stderr, "ERROR: not enough memory\n"); ret = 1; goto out; } id_count = enumerate_dead_subvols(fd, id_count, &ids); if (id_count < 0) { fprintf(stderr, "ERROR: can't enumerate dead subvolumes: %s\n", strerror(-id_count)); ret = 1; goto out; } if (id_count == 0) { ret = 0; goto out; } } else { ids = (u64*)malloc(id_count * sizeof(u64)); if (!ids) { fprintf(stderr, "ERROR: not enough memory\n"); ret = 1; goto out; } for (i = 0; i < id_count; i++) { u64 id; const char *arg; arg = argv[optind + i]; errno = 0; id = strtoull(arg, NULL, 10); if (errno < 0) { fprintf(stderr, "ERROR: unrecognized subvolume id %s\n", arg); ret = 1; goto out; } if (id < BTRFS_FIRST_FREE_OBJECTID || id > BTRFS_LAST_FREE_OBJECTID) { fprintf(stderr, "ERROR: subvolume id %s out of range\n", arg); ret = 1; goto out; } ids[i] = id; } } ret = wait_for_subvolume_cleaning(fd, id_count, ids, sleep_interval); out: free(ids); close_file_or_dir(fd, dirstream); return !!ret; }
static int cmd_qgroup_limit(int argc, char **argv) { int ret = 0; int fd; int e; char *path = NULL; struct btrfs_ioctl_qgroup_limit_args args; unsigned long long size; int compressed = 0; int exclusive = 0; DIR *dirstream = NULL; optind = 1; while (1) { int c = getopt(argc, argv, "ce"); if (c < 0) break; switch (c) { case 'c': compressed = 1; break; case 'e': exclusive = 1; break; default: usage(cmd_qgroup_limit_usage); } } if (check_argc_min(argc - optind, 2)) usage(cmd_qgroup_limit_usage); if (!parse_limit(argv[optind], &size)) { error("invalid size argument: %s", argv[optind]); return 1; } memset(&args, 0, sizeof(args)); if (compressed) args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR | BTRFS_QGROUP_LIMIT_EXCL_CMPR; if (exclusive) { args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL; args.lim.max_exclusive = size; } else { args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER; args.lim.max_referenced = size; } if (argc - optind == 2) { args.qgroupid = 0; path = argv[optind + 1]; ret = test_issubvolume(path); if (ret < 0) { error("cannot access '%s': %s", path, strerror(-ret)); return 1; } if (!ret) { error("'%s' is not a subvolume", path); return 1; } /* * keep qgroupid at 0, this indicates that the subvolume the * fd refers to is to be limited */ } else if (argc - optind == 3) { args.qgroupid = parse_qgroupid(argv[optind + 1]); path = argv[optind + 2]; } else usage(cmd_qgroup_limit_usage); fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) return 1; ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) { error("unable to limit requested quota group: %s", strerror(e)); return 1; } return 0; }
static int cmd_add_dev(int argc, char **argv) { char *mntpnt; int i, fdmnt, ret=0, e; DIR *dirstream = NULL; int discard = 1; int force = 0; while (1) { int c; static const struct option long_options[] = { { "nodiscard", optional_argument, NULL, 'K'}, { "force", no_argument, NULL, 'f'}, { NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "Kf", long_options, NULL); if (c < 0) break; switch (c) { case 'K': discard = 0; break; case 'f': force = 1; break; default: usage(cmd_add_dev_usage); } } argc = argc - optind; if (check_argc_min(argc, 2)) usage(cmd_add_dev_usage); mntpnt = argv[optind + 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 = optind; i < optind + argc - 1; i++){ struct btrfs_ioctl_vol_args ioctl_args; int devfd, res; u64 dev_block_count = 0; int mixed = 0; char *path; res = test_dev_for_mkfs(argv[i], force); if (res) { ret++; continue; } devfd = open(argv[i], O_RDWR); if (devfd < 0) { fprintf(stderr, "ERROR: Unable to open device '%s'\n", argv[i]); ret++; continue; } res = btrfs_prepare_device(devfd, argv[i], 1, &dev_block_count, 0, &mixed, discard); close(devfd); if (res) { ret++; goto error_out; } path = canonicalize_path(argv[i]); if (!path) { fprintf(stderr, "ERROR: Could not canonicalize pathname '%s': %s\n", argv[i], strerror(errno)); ret++; goto error_out; } memset(&ioctl_args, 0, sizeof(ioctl_args)); strncpy_null(ioctl_args.name, path); res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); e = errno; if (res < 0) { fprintf(stderr, "ERROR: error adding the device '%s' - %s\n", path, strerror(e)); ret++; } free(path); } error_out: close_file_or_dir(fdmnt, dirstream); return !!ret; }
int cmd_send(int argc, char **argv) { char *subvol = NULL; int ret; char outname[PATH_MAX]; struct btrfs_send send; u32 i; char *mount_root = NULL; char *snapshot_parent = NULL; u64 root_id = 0; u64 parent_root_id = 0; int full_send = 1; int new_end_cmd_semantic = 0; u64 send_flags = 0; memset(&send, 0, sizeof(send)); send.dump_fd = fileno(stdout); outname[0] = 0; while (1) { enum { GETOPT_VAL_SEND_NO_DATA = 256 }; static const struct option long_options[] = { { "verbose", no_argument, NULL, 'v' }, { "quiet", no_argument, NULL, 'q' }, { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA } }; int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL); if (c < 0) break; switch (c) { case 'v': g_verbose++; break; case 'q': g_verbose = 0; break; case 'e': new_end_cmd_semantic = 1; break; case 'c': subvol = realpath(optarg, NULL); if (!subvol) { ret = -errno; error("realpath %s failed: %s\n", optarg, strerror(-ret)); goto out; } ret = set_root_info(&send, subvol, &root_id); if (ret < 0) goto out; ret = is_subvol_ro(&send, subvol); if (ret < 0) goto out; if (!ret) { ret = -EINVAL; error("cloned subvolume %s is not read-only", subvol); goto out; } ret = add_clone_source(&send, root_id); if (ret < 0) { error("cannot add clone source: %s", strerror(-ret)); goto out; } free(subvol); subvol = NULL; free_send_info(&send); full_send = 0; break; case 'f': if (arg_copy_path(outname, optarg, sizeof(outname))) { error("output file path too long (%zu)", strlen(optarg)); ret = 1; goto out; } break; case 'p': if (snapshot_parent) { error("you cannot have more than one parent (-p)"); ret = 1; goto out; } snapshot_parent = realpath(optarg, NULL); if (!snapshot_parent) { ret = -errno; error("realpath %s failed: %s", optarg, strerror(-ret)); goto out; } ret = is_subvol_ro(&send, snapshot_parent); if (ret < 0) goto out; if (!ret) { ret = -EINVAL; error("parent subvolume %s is not read-only", snapshot_parent); goto out; } full_send = 0; break; case 'i': error("option -i was removed, use -c instead"); ret = 1; goto out; case GETOPT_VAL_SEND_NO_DATA: send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA; break; case '?': default: error("send arguments invalid"); ret = 1; goto out; } } if (check_argc_min(argc - optind, 1)) usage(cmd_send_usage); if (outname[0]) { int tmpfd; /* * Try to use an existing file first. Even if send runs as * root, it might not have permissions to create file (eg. on a * NFS) but it should still be able to use a pre-created file. */ tmpfd = open(outname, O_WRONLY | O_TRUNC); if (tmpfd < 0) { if (errno == ENOENT) tmpfd = open(outname, O_CREAT | O_WRONLY | O_TRUNC, 0600); } send.dump_fd = tmpfd; if (send.dump_fd == -1) { ret = -errno; error("cannot create '%s': %s", outname, strerror(-ret)); goto out; } } if (isatty(send.dump_fd)) { error( "not dumping send stream into a terminal, redirect it into a file"); ret = 1; goto out; } /* use first send subvol to determine mount_root */ subvol = realpath(argv[optind], NULL); if (!subvol) { ret = -errno; error("unable to resolve %s", argv[optind]); goto out; } ret = init_root_path(&send, subvol); if (ret < 0) goto out; if (snapshot_parent != NULL) { ret = get_root_id(&send, subvol_strip_mountpoint(send.root_path, snapshot_parent), &parent_root_id); if (ret < 0) { error("could not resolve rootid for %s", snapshot_parent); goto out; } ret = add_clone_source(&send, parent_root_id); if (ret < 0) { error("cannot add clone source: %s", strerror(-ret)); goto out; } } for (i = optind; i < argc; i++) { free(subvol); subvol = realpath(argv[i], NULL); if (!subvol) { ret = -errno; error("unable to resolve %s", argv[i]); goto out; } ret = find_mount_root(subvol, &mount_root); if (ret < 0) { error("find_mount_root failed on %s: %s", subvol, strerror(-ret)); goto out; } if (ret > 0) { error("%s does not belong to btrfs mount point", subvol); ret = -EINVAL; goto out; } if (strcmp(send.root_path, mount_root) != 0) { ret = -EINVAL; error("all subvolumes must be from the same filesystem"); goto out; } free(mount_root); ret = is_subvol_ro(&send, subvol); if (ret < 0) goto out; if (!ret) { ret = -EINVAL; error("subvolume %s is not read-only", subvol); goto out; } } if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1) if (g_verbose > 1) fprintf(stderr, "Mode NO_FILE_DATA enabled\n"); for (i = optind; i < argc; i++) { int is_first_subvol; int is_last_subvol; free(subvol); subvol = argv[i]; if (g_verbose > 0) fprintf(stderr, "At subvol %s\n", subvol); subvol = realpath(subvol, NULL); if (!subvol) { ret = -errno; error("realpath %s failed: %s", argv[i], strerror(-ret)); goto out; } if (!full_send && !snapshot_parent) { ret = set_root_info(&send, subvol, &root_id); if (ret < 0) goto out; ret = find_good_parent(&send, root_id, &parent_root_id); if (ret < 0) { error("parent determination failed for %lld", root_id); goto out; } } if (new_end_cmd_semantic) { /* require new kernel */ is_first_subvol = (i == optind); is_last_subvol = (i == argc - 1); } else { /* be compatible to old and new kernel */ is_first_subvol = 1; is_last_subvol = 1; } ret = do_send(&send, parent_root_id, is_first_subvol, is_last_subvol, subvol, send_flags); if (ret < 0) goto out; if (!full_send && !snapshot_parent) { /* done with this subvol, so add it to the clone sources */ ret = add_clone_source(&send, root_id); if (ret < 0) { error("cannot add clone source: %s", strerror(-ret)); goto out; } free_send_info(&send); } } ret = 0; out: free(subvol); free(snapshot_parent); free(send.clone_sources); free_send_info(&send); return !!ret; }
int main(int ac, char **av) { struct cache_tree root_cache; struct btrfs_root *root; char *dev; char *output_file = NULL; u64 copy = 0; u64 logical = 0; u64 bytes = 0; u64 cur_logical = 0; u64 cur_len = 0; int out_fd = -1; int found = 0; int ret = 0; while(1) { int c; static const struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ { "logical", required_argument, NULL, 'l' }, { "copy", required_argument, NULL, 'c' }, { "output", required_argument, NULL, 'o' }, { "bytes", required_argument, NULL, 'b' }, { NULL, 0, NULL, 0} }; c = getopt_long(ac, av, "l:c:o:b:", long_options, NULL); if (c < 0) break; switch(c) { case 'l': logical = arg_strtou64(optarg); break; case 'c': copy = arg_strtou64(optarg); break; case 'b': bytes = arg_strtou64(optarg); break; case 'o': output_file = strdup(optarg); break; default: print_usage(); } } set_argv0(av); ac = ac - optind; if (check_argc_min(ac, 1)) print_usage(); if (logical == 0) print_usage(); dev = av[optind]; radix_tree_init(); cache_tree_init(&root_cache); root = open_ctree(dev, 0, 0); if (!root) { fprintf(stderr, "Open ctree failed\n"); exit(1); } info_file = stdout; if (output_file) { if (strcmp(output_file, "-") == 0) { out_fd = 1; info_file = stderr; } else { out_fd = open(output_file, O_RDWR | O_CREAT, 0600); if (out_fd < 0) goto close; ret = ftruncate(out_fd, 0); if (ret) { ret = 1; close(out_fd); goto close; } info_file = stdout; } } if (bytes == 0) bytes = root->nodesize; cur_logical = logical; cur_len = bytes; /* First find the nearest extent */ ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 0); if (ret < 0) { fprintf(stderr, "Failed to find extent at [%llu,%llu): %s\n", cur_logical, cur_logical + cur_len, strerror(-ret)); goto out_close_fd; } /* * Normally, search backward should be OK, but for special case like * given logical is quite small where no extents are before it, * we need to search forward. */ if (ret > 0) { ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 1); if (ret < 0) { fprintf(stderr, "Failed to find extent at [%llu,%llu): %s\n", cur_logical, cur_logical + cur_len, strerror(-ret)); goto out_close_fd; } if (ret > 0) { fprintf(stderr, "Failed to find any extent at [%llu,%llu)\n", cur_logical, cur_logical + cur_len); goto out_close_fd; } } while (cur_logical + cur_len >= logical && cur_logical < logical + bytes) { u64 real_logical; u64 real_len; found = 1; ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 1); if (ret < 0) goto out_close_fd; if (ret > 0) break; real_logical = max(logical, cur_logical); real_len = min(logical + bytes, cur_logical + cur_len) - real_logical; ret = print_mapping_info(root->fs_info, real_logical, real_len); if (ret < 0) goto out_close_fd; if (output_file && out_fd != -1) { ret = write_extent_content(root->fs_info, out_fd, real_logical, real_len, copy); if (ret < 0) goto out_close_fd; } cur_logical += cur_len; } if (!found) { fprintf(stderr, "No extent found at range [%llu,%llu)\n", logical, logical + bytes); } out_close_fd: if (output_file && out_fd != 1) close(out_fd); close: close_ctree(root); if (ret < 0) ret = 1; return ret; }
int cmd_inspect_dump_super(int argc, char **argv) { int all = 0; int full = 0; int force = 0; char *filename; int fd = -1; int i; int ret = 0; u64 arg; u64 sb_bytenr = btrfs_sb_offset(0); while (1) { int c; enum { GETOPT_VAL_BYTENR = 257 }; static const struct option long_options[] = { {"all", no_argument, NULL, 'a'}, {"bytenr", required_argument, NULL, GETOPT_VAL_BYTENR }, {"full", no_argument, NULL, 'f'}, {"force", no_argument, NULL, 'F'}, {"super", required_argument, NULL, 's' }, {NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "fFai:s:", long_options, NULL); if (c < 0) break; switch (c) { case 'i': warning( "option -i is deprecated, please use -s or --super"); arg = arg_strtou64(optarg); if (arg >= BTRFS_SUPER_MIRROR_MAX) { error("super mirror too big: %llu >= %d", arg, BTRFS_SUPER_MIRROR_MAX); return 1; } sb_bytenr = btrfs_sb_offset(arg); break; case 'a': all = 1; break; case 'f': full = 1; break; case 'F': force = 1; break; case 's': arg = arg_strtou64(optarg); if (BTRFS_SUPER_MIRROR_MAX <= arg) { warning( "deprecated use of -s <bytenr> with %llu, assuming --bytenr", (unsigned long long)arg); sb_bytenr = arg; } else { sb_bytenr = btrfs_sb_offset(arg); } all = 0; break; case GETOPT_VAL_BYTENR: arg = arg_strtou64(optarg); sb_bytenr = arg; all = 0; break; default: usage_unknown_option(cmd_inspect_dump_super_usage, argv); } } if (check_argc_min(argc - optind, 1)) return 1; for (i = optind; i < argc; i++) { filename = argv[i]; fd = open(filename, O_RDONLY); if (fd < 0) { error("cannot open %s: %m", filename); ret = 1; goto out; } if (all) { int idx; for (idx = 0; idx < BTRFS_SUPER_MIRROR_MAX; idx++) { sb_bytenr = btrfs_sb_offset(idx); if (load_and_dump_sb(filename, fd, sb_bytenr, full, force)) { close(fd); ret = 1; goto out; } putchar('\n'); } } else { load_and_dump_sb(filename, fd, sb_bytenr, full, force); putchar('\n'); } close(fd); } out: return ret; }
int cmd_device_usage(int argc, char **argv) { unsigned unit_mode = UNITS_DEFAULT; int ret = 0; int i, more_than_one = 0; optind = 1; while (1) { int c; static const struct option long_options[] = { { "raw", no_argument, NULL, 'b'}, { "kbytes", no_argument, NULL, 'k'}, { "mbytes", no_argument, NULL, 'm'}, { "gbytes", no_argument, NULL, 'g'}, { "tbytes", no_argument, NULL, 't'}, { "si", no_argument, NULL, GETOPT_VAL_SI}, { "iec", no_argument, NULL, GETOPT_VAL_IEC}, { "human-readable", no_argument, NULL, GETOPT_VAL_HUMAN_READABLE}, { NULL, 0, NULL, 0 } }; c = getopt_long(argc, argv, "bhHkmgt", long_options, NULL); if (c < 0) break; switch (c) { case 'b': unit_mode = UNITS_RAW; break; case 'k': units_set_base(&unit_mode, UNITS_KBYTES); break; case 'm': units_set_base(&unit_mode, UNITS_MBYTES); break; case 'g': units_set_base(&unit_mode, UNITS_GBYTES); break; case 't': units_set_base(&unit_mode, UNITS_TBYTES); break; case GETOPT_VAL_HUMAN_READABLE: case 'h': unit_mode = UNITS_HUMAN_BINARY; break; case 'H': unit_mode = UNITS_HUMAN_DECIMAL; break; case GETOPT_VAL_SI: units_set_mode(&unit_mode, UNITS_DECIMAL); break; case GETOPT_VAL_IEC: units_set_mode(&unit_mode, UNITS_BINARY); break; default: usage(cmd_device_usage_usage); } } if (check_argc_min(argc - optind, 1)) usage(cmd_device_usage_usage); for (i = optind; i < argc ; i++) { int fd; DIR *dirstream = NULL; if (more_than_one) printf("\n"); fd = open_file_or_dir(argv[i], &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", argv[1]); ret = 1; goto out; } ret = _cmd_device_usage(fd, argv[i], unit_mode); close_file_or_dir(fd, dirstream); if (ret) goto out; more_than_one = 1; } out: return !!ret; }
static int cmd_subvol_sync(int argc, char **argv) { int fd = -1; int i; int ret = 1; DIR *dirstream = NULL; u64 *ids = NULL; int id_count; int remaining; int sleep_interval = 1; optind = 1; while (1) { int c = getopt(argc, argv, "s:"); if (c < 0) break; switch (c) { case 's': sleep_interval = atoi(argv[optind]); if (sleep_interval < 1) { fprintf(stderr, "ERROR: invalid sleep interval %s\n", argv[optind]); ret = 1; goto out; } break; default: usage(cmd_subvol_sync_usage); } } if (check_argc_min(argc - optind, 1)) usage(cmd_subvol_sync_usage); fd = open_file_or_dir(argv[optind], &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]); ret = 1; goto out; } optind++; id_count = argc - optind; /* * Wait for all */ if (!id_count) { while (1) { ret = fs_has_dead_subvolumes(fd); if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(-ret)); ret = 1; goto out; } if (!ret) goto out; sleep(sleep_interval); } } /* * Wait only for the requested ones */ ids = (u64*)malloc(sizeof(u64) * id_count); if (!ids) { fprintf(stderr, "ERROR: not enough memory\n"); ret = 1; goto out; } for (i = 0; i < id_count; i++) { u64 id; const char *arg; arg = argv[optind + i]; errno = 0; id = strtoull(arg, NULL, 10); if (errno < 0) { fprintf(stderr, "ERROR: unrecognized subvolume id %s\n", arg); ret = 1; goto out; } if (id < BTRFS_FIRST_FREE_OBJECTID || id > BTRFS_LAST_FREE_OBJECTID) { fprintf(stderr, "ERROR: subvolume id %s out of range\n", arg); ret = 1; goto out; } ids[i] = id; } remaining = id_count; while (1) { for (i = 0; i < id_count; i++) { if (!ids[i]) continue; ret = is_subvolume_cleaned(fd, ids[i]); if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(-ret)); goto out; } if (ret) { printf("Subvolume id %llu is gone\n", ids[i]); ids[i] = 0; remaining--; } } if (!remaining) break; sleep(sleep_interval); } out: free(ids); close_file_or_dir(fd, dirstream); 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 cmd_subvol_delete(int argc, char **argv) { int res, e, ret = 0; int cnt; int fd = -1; struct btrfs_ioctl_vol_args args; char *dname, *vname, *cpath; char *dupdname = NULL; char *dupvname = NULL; char *path; DIR *dirstream = NULL; int verbose = 0; int commit_mode = 0; optind = 1; while (1) { int c; static const struct option long_options[] = { {"commit-after", no_argument, NULL, 'c'}, /* commit mode 1 */ {"commit-each", no_argument, NULL, 'C'}, /* commit mode 2 */ {NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "cC", long_options, NULL); if (c < 0) break; switch(c) { case 'c': commit_mode = 1; break; case 'C': commit_mode = 2; break; case 'v': verbose++; break; default: usage(cmd_subvol_delete_usage); } } if (check_argc_min(argc - optind, 1)) usage(cmd_subvol_delete_usage); if (verbose > 0) { printf("Transaction commit: %s\n", !commit_mode ? "none (default)" : commit_mode == 1 ? "at the end" : "after each"); } cnt = optind; again: path = argv[cnt]; res = test_issubvolume(path); if (res < 0) { fprintf(stderr, "ERROR: error accessing '%s'\n", path); ret = 1; goto out; } if (!res) { fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path); ret = 1; goto out; } cpath = realpath(path, NULL); if (!cpath) { ret = errno; fprintf(stderr, "ERROR: finding real path for '%s': %s\n", path, strerror(errno)); goto out; } dupdname = strdup(cpath); dname = dirname(dupdname); dupvname = strdup(cpath); vname = basename(dupvname); free(cpath); fd = open_file_or_dir(dname, &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", dname); ret = 1; goto out; } printf("Delete subvolume (%s): '%s/%s'\n", commit_mode == 2 || (commit_mode == 1 && cnt + 1 == argc) ? "commit" : "no-commit", dname, vname); memset(&args, 0, sizeof(args)); strncpy_null(args.name, vname); res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args); e = errno; if(res < 0 ){ fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n", dname, vname, strerror(e)); ret = 1; goto out; } if (commit_mode == 1) { res = wait_for_commit(fd); if (res < 0) { fprintf(stderr, "ERROR: unable to wait for commit after '%s': %s\n", path, strerror(errno)); ret = 1; } } out: free(dupdname); free(dupvname); dupdname = NULL; dupvname = NULL; cnt++; if (cnt < argc) { close_file_or_dir(fd, dirstream); /* avoid double free */ fd = -1; dirstream = NULL; goto again; } if (commit_mode == 2 && fd != -1) { res = wait_for_commit(fd); if (res < 0) { fprintf(stderr, "ERROR: unable to do final sync: %s\n", strerror(errno)); ret = 1; } } close_file_or_dir(fd, dirstream); return ret; }
static int cmd_device_add(int argc, char **argv) { char *mntpnt; int i, fdmnt, ret = 0; DIR *dirstream = NULL; int discard = 1; int force = 0; int last_dev; optind = 0; while (1) { int c; static const struct option long_options[] = { { "nodiscard", optional_argument, NULL, 'K'}, { "force", no_argument, NULL, 'f'}, { NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "Kf", long_options, NULL); if (c < 0) break; switch (c) { case 'K': discard = 0; break; case 'f': force = 1; break; default: usage(cmd_device_add_usage); } } if (check_argc_min(argc - optind, 2)) usage(cmd_device_add_usage); last_dev = argc - 1; mntpnt = argv[last_dev]; fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1); if (fdmnt < 0) return 1; for (i = optind; i < last_dev; i++){ struct btrfs_ioctl_vol_args ioctl_args; int devfd, res; u64 dev_block_count = 0; char *path; res = test_dev_for_mkfs(argv[i], force); if (res) { ret++; continue; } devfd = open(argv[i], O_RDWR); if (devfd < 0) { error("unable to open device '%s'", argv[i]); ret++; continue; } res = btrfs_prepare_device(devfd, argv[i], &dev_block_count, 0, PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE | (discard ? PREP_DEVICE_DISCARD : 0)); close(devfd); if (res) { ret++; goto error_out; } path = canonicalize_path(argv[i]); if (!path) { error("could not canonicalize pathname '%s': %m", argv[i]); ret++; goto error_out; } memset(&ioctl_args, 0, sizeof(ioctl_args)); strncpy_null(ioctl_args.name, path); res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); if (res < 0) { error("error adding device '%s': %m", path); ret++; } free(path); } error_out: close_file_or_dir(fdmnt, dirstream); return !!ret; }
int main(int argc, char **argv) { int opt; int all = 0; int full = 0; int force = 0; char *filename; int fd = -1; int i; u64 arg; u64 sb_bytenr = btrfs_sb_offset(0); while ((opt = getopt(argc, argv, "fFai:s:")) != -1) { switch (opt) { case 'i': arg = arg_strtou64(optarg); if (arg >= BTRFS_SUPER_MIRROR_MAX) { fprintf(stderr, "Illegal super_mirror %llu\n", arg); print_usage(); exit(1); } sb_bytenr = btrfs_sb_offset(arg); break; case 'a': all = 1; break; case 'f': full = 1; break; case 'F': force = 1; break; case 's': sb_bytenr = arg_strtou64(optarg); all = 0; break; default: print_usage(); exit(1); } } set_argv0(argv); if (check_argc_min(argc - optind, 1)) { print_usage(); exit(1); } for (i = optind; i < argc; i++) { filename = argv[i]; fd = open(filename, O_RDONLY, 0666); if (fd < 0) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } if (all) { int idx; for (idx = 0; idx < BTRFS_SUPER_MIRROR_MAX; idx++) { sb_bytenr = btrfs_sb_offset(idx); if (load_and_dump_sb(filename, fd, sb_bytenr, full, force)) { close(fd); exit(1); } putchar('\n'); } } else { load_and_dump_sb(filename, fd, sb_bytenr, full, force); putchar('\n'); } close(fd); } exit(0); }
int main(int argc, char **argv) { struct btrfs_fs_info *fs_info; struct btrfs_find_root_filter filter = {0}; struct cache_tree result; struct cache_extent *found; int ret; /* Default to search root tree */ filter.objectid = BTRFS_ROOT_TREE_OBJECTID; filter.match_gen = (u64)-1; filter.match_level = (u8)-1; while (1) { static const struct option long_options[] = { { "help", no_argument, NULL, GETOPT_VAL_HELP}, { NULL, 0, NULL, 0 } }; int c = getopt_long(argc, argv, "al:o:g:", long_options, NULL); if (c < 0) break; switch (c) { case 'a': filter.search_all = 1; break; case 'o': filter.objectid = arg_strtou64(optarg); break; case 'g': filter.generation = arg_strtou64(optarg); break; case 'l': filter.level = arg_strtou64(optarg); break; case GETOPT_VAL_HELP: default: find_root_usage(); exit(c != GETOPT_VAL_HELP); } } set_argv0(argv); if (check_argc_min(argc - optind, 1)) { find_root_usage(); exit(1); } fs_info = open_ctree_fs_info(argv[optind], 0, 0, 0, OPEN_CTREE_CHUNK_ROOT_ONLY | OPEN_CTREE_IGNORE_CHUNK_TREE_ERROR); if (!fs_info) { error("open ctree failed"); exit(1); } cache_tree_init(&result); get_root_gen_and_level(filter.objectid, fs_info, &filter.match_gen, &filter.match_level); ret = btrfs_find_root_search(fs_info, &filter, &result, &found); if (ret < 0) { fprintf(stderr, "Fail to search the tree root: %s\n", strerror(-ret)); goto out; } if (ret > 0) { printf("Found tree root at %llu gen %llu level %u\n", found->start, filter.match_gen, filter.match_level); ret = 0; } print_find_root_result(&result, &filter); out: btrfs_find_root_free(&result); close_ctree_fs_info(fs_info); btrfs_close_all_devices(); return ret; }