/* * This function loads the device_info structure and put them in an array */ static int load_device_info(int fd, struct device_info **device_info_ptr, int *device_info_count) { int ret, i, ndevs; struct btrfs_ioctl_fs_info_args fi_args; struct btrfs_ioctl_dev_info_args dev_info; struct device_info *info; *device_info_count = 0; *device_info_ptr = NULL; ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); if (ret < 0) { if (errno == EPERM) return -errno; error("cannot get filesystem info: %s", strerror(errno)); return 1; } info = calloc(fi_args.num_devices, sizeof(struct device_info)); if (!info) { error("not enough memory"); return 1; } for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) { BUG_ON(ndevs >= fi_args.num_devices); memset(&dev_info, 0, sizeof(dev_info)); ret = get_device_info(fd, i, &dev_info); if (ret == -ENODEV) continue; if (ret) { error("cannot get info about device devid=%d", i); free(info); return ret; } info[ndevs].devid = dev_info.devid; if (!dev_info.path[0]) { strcpy(info[ndevs].path, "missing"); } else { strcpy(info[ndevs].path, (char *)dev_info.path); info[ndevs].device_size = get_partition_size((char *)dev_info.path); } info[ndevs].size = dev_info.total_bytes; ++ndevs; } BUG_ON(ndevs != fi_args.num_devices); qsort(info, fi_args.num_devices, sizeof(struct device_info), cmp_device_info); *device_info_count = fi_args.num_devices; *device_info_ptr = info; return 0; }
/// check partition size int check_size(int* ret, unsigned long long size) { unsigned long long dest_size; int debug = 1; dest_size = get_partition_size(ret); if (dest_size < size){ log_mesg(0, 1, 1, debug, "Target partition size(%llu MB) is smaller than source(%llu MB). Use option -C to disable size checking(Dangerous).\n", print_size(dest_size, MBYTE), print_size(size, MBYTE)); return 1; } return 0; }
/// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { int src; if ((src = open_source(device, &opt)) == -1) { log_mesg(0, 1, 1, opt.debug, "Error exit\n"); } strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, raw_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = PART_SECTOR_SIZE; image_hdr->device_size = get_partition_size(&src); image_hdr->totalblock = image_hdr->device_size / PART_SECTOR_SIZE; image_hdr->usedblocks = image_hdr->device_size / PART_SECTOR_SIZE; close(src); }
/* * This function print the results of the command "btrfs fi usage" * in tabular format */ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, struct btrfs_ioctl_space_args *sargs, struct chunk_info *chunks_info_ptr, int chunks_info_count, struct device_info *device_info_ptr, int device_info_count) { int i; u64 total_unused = 0; struct string_table *matrix = 0; int ncols, nrows; ncols = sargs->total_spaces + 2; nrows = 2 + 1 + device_info_count + 1 + 2; matrix = table_create(ncols, nrows); if (!matrix) { fprintf(stderr, "ERROR: not enough memory\n"); return; } /* header */ for (i = 0; i < sargs->total_spaces; i++) { const char *description; u64 flags = sargs->spaces[i].flags; if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; description = btrfs_group_type_str(flags); table_printf(matrix, 1+i, 0, "<%s", description); } for (i = 0; i < sargs->total_spaces; i++) { const char *r_mode; u64 flags = sargs->spaces[i].flags; r_mode = btrfs_group_profile_str(flags); table_printf(matrix, 1+i, 1, "<%s", r_mode); } table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated"); /* body */ for (i = 0; i < device_info_count; i++) { int k, col; char *p; u64 total_allocated = 0, unused; p = strrchr(device_info_ptr[i].path, '/'); if (!p) p = device_info_ptr[i].path; else p++; table_printf(matrix, 0, i + 3, "<%s", device_info_ptr[i].path); for (col = 1, k = 0 ; k < sargs->total_spaces ; k++) { u64 flags = sargs->spaces[k].flags; u64 devid = device_info_ptr[i].devid; int j; u64 size = 0; for (j = 0 ; j < chunks_info_count ; j++) { if (chunks_info_ptr[j].type != flags ) continue; if (chunks_info_ptr[j].devid != devid) continue; size += calc_chunk_size(chunks_info_ptr+j); } if (size) table_printf(matrix, col, i+3, ">%s", pretty_size_mode(size, unit_mode)); else table_printf(matrix, col, i+3, ">-"); total_allocated += size; col++; } unused = get_partition_size(device_info_ptr[i].path) - total_allocated; table_printf(matrix, sargs->total_spaces + 1, i + 3, ">%s", pretty_size_mode(unused, unit_mode)); total_unused += unused; } for (i = 0; i <= sargs->total_spaces; i++) table_printf(matrix, i + 1, device_info_count + 3, "="); /* footer */ table_printf(matrix, 0, device_info_count + 4, "<Total"); for (i = 0; i < sargs->total_spaces; i++) table_printf(matrix, 1 + i, device_info_count + 4, ">%s", pretty_size_mode(sargs->spaces[i].total_bytes, unit_mode)); table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4, ">%s", pretty_size_mode(total_unused, unit_mode)); table_printf(matrix, 0, device_info_count + 5, "<Used"); for (i = 0; i < sargs->total_spaces; i++) table_printf(matrix, 1 + i, device_info_count+5, ">%s", pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode)); table_dump(matrix); table_free(matrix); }
partition_info_t *create_partition(const char *device_name, partition_info_t **new_part_info) { partition_info_t *follow_part_info; u32 partition_order; u64 size_in_kilobytes = 0, total_kilobytes = 0, used_kilobytes = 0; char buf1[PATH_MAX], buf2[64], buf3[PATH_MAX]; // options of mount info needs more buffer size. int len; if(new_part_info == NULL) return NULL; *new_part_info = NULL; // initial value. if(device_name == NULL || get_device_type_by_device(device_name) != DEVICE_TYPE_DISK) return NULL; if(!is_disk_name(device_name) && !is_partition_name(device_name, &partition_order)) return NULL; if(initial_part_data(&follow_part_info) == NULL) return NULL; len = strlen(device_name); follow_part_info->device = (char *)malloc(len+1); if(!follow_part_info->device){ free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->device, device_name, len); follow_part_info->device[len] = 0; follow_part_info->partition_order = partition_order; if(read_mount_data(device_name, buf1, buf2, buf3)){ len = strlen(buf1); follow_part_info->mount_point = (char *)malloc(len+1); if(!follow_part_info->mount_point){ free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->mount_point, buf1, len); follow_part_info->mount_point[len] = 0; len = strlen(buf2); follow_part_info->file_system = (char *)malloc(len+1); if(!follow_part_info->file_system){ free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->file_system, buf2, len); follow_part_info->file_system[len] = 0; len = strlen(buf3); follow_part_info->permission = (char *)malloc(len+1); if(!follow_part_info->permission){ free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->permission, buf3, len); follow_part_info->permission[len] = 0; if(get_mount_size(follow_part_info->mount_point, &total_kilobytes, &used_kilobytes)){ follow_part_info->size_in_kilobytes = total_kilobytes; follow_part_info->used_kilobytes = used_kilobytes; } } else{ if(is_disk_name(device_name)){ // Disk free_partition_data(&follow_part_info); return NULL; } else{ len = strlen(PARTITION_TYPE_UNKNOWN); follow_part_info->file_system = (char *)malloc(len+1); if(!follow_part_info->file_system){ free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->file_system, PARTITION_TYPE_UNKNOWN, len); follow_part_info->file_system[len] = 0; get_partition_size(device_name, &size_in_kilobytes); follow_part_info->size_in_kilobytes = size_in_kilobytes; } } *new_part_info = follow_part_info; return *new_part_info; }
partition_info_t *create_partition(const char *device_name, partition_info_t **new_part_info){ partition_info_t *follow_part_info; char label[128]; u32 partition_order = 0; u64 size_in_kilobytes = 0, total_kilobytes = 0, used_kilobytes = 0; char buf1[PATH_MAX], buf2[64], buf3[PATH_MAX]; // options of mount info needs more buffer size. int len; if(new_part_info == NULL){ usb_dbg("Bad input!!\n"); return NULL; } *new_part_info = NULL; // initial value. if(device_name == NULL || get_device_type_by_device(device_name) != DEVICE_TYPE_DISK) return NULL; if(!is_disk_name(device_name) && !is_partition_name(device_name, &partition_order)) return NULL; if(initial_part_data(&follow_part_info) == NULL){ usb_dbg("No memory!!(follow_part_info)\n"); return NULL; } len = strlen(device_name); follow_part_info->device = (char *)malloc(len+1); if(follow_part_info->device == NULL){ usb_dbg("No memory!!(follow_part_info->device)\n"); free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->device, device_name, len); follow_part_info->device[len] = 0; if(find_partition_label(device_name, label)){ strntrim(label); len = strlen(label); follow_part_info->label = (char *)malloc(len+1); if(follow_part_info->label == NULL){ usb_dbg("No memory!!(follow_part_info->label)\n"); free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->label, label, len); follow_part_info->label[len] = 0; } follow_part_info->partition_order = partition_order; if(read_mount_data(device_name, buf1, PATH_MAX, buf2, 64, buf3, PATH_MAX)){ len = strlen(buf1); follow_part_info->mount_point = (char *)malloc(len+1); if(follow_part_info->mount_point == NULL){ usb_dbg("No memory!!(follow_part_info->mount_point)\n"); free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->mount_point, buf1, len); follow_part_info->mount_point[len] = 0; len = strlen(buf2); follow_part_info->file_system = (char *)malloc(len+1); if(follow_part_info->file_system == NULL){ usb_dbg("No memory!!(follow_part_info->file_system)\n"); free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->file_system, buf2, len); follow_part_info->file_system[len] = 0; len = strlen(buf3); follow_part_info->permission = (char *)malloc(len+1); if(follow_part_info->permission == NULL){ usb_dbg("No memory!!(follow_part_info->permission)\n"); free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->permission, buf3, len); follow_part_info->permission[len] = 0; if(get_mount_size(follow_part_info->mount_point, &total_kilobytes, &used_kilobytes)){ follow_part_info->size_in_kilobytes = total_kilobytes; follow_part_info->used_kilobytes = used_kilobytes; } } else{ /*if(is_disk_name(device_name)){ // Disk free_partition_data(&follow_part_info); return NULL; } else{//*/ len = strlen(PARTITION_TYPE_UNKNOWN); follow_part_info->file_system = (char *)malloc(len+1); if(follow_part_info->file_system == NULL){ usb_dbg("No memory!!(follow_part_info->file_system)\n"); free_partition_data(&follow_part_info); return NULL; } strncpy(follow_part_info->file_system, PARTITION_TYPE_UNKNOWN, len); follow_part_info->file_system[len] = 0; get_partition_size(device_name, &size_in_kilobytes); follow_part_info->size_in_kilobytes = size_in_kilobytes; //} } *new_part_info = follow_part_info; return *new_part_info; }
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; }
/* * This function print the results of the command "btrfs fi usage" * in tabular format */ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, struct btrfs_ioctl_space_args *sargs, struct chunk_info *chunks_info_ptr, int chunks_info_count, struct device_info *device_info_ptr, int device_info_count) { int i; u64 total_unused = 0; struct string_table *matrix = NULL; int ncols, nrows; int col; int unallocated_col; int spaceinfos_col; const int vhdr_skip = 3; /* amount of vertical header space */ /* id, path, unallocated */ ncols = 3; spaceinfos_col = 2; /* Properly count the real space infos */ for (i = 0; i < sargs->total_spaces; i++) { if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; ncols++; } /* 2 for header, empty line, devices, ===, total, used */ nrows = vhdr_skip + device_info_count + 1 + 2; matrix = table_create(ncols, nrows); if (!matrix) { error("not enough memory"); return; } /* * We have to skip the global block reserve everywhere as it's an * artificial blockgroup */ /* header */ for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) { u64 flags = sargs->spaces[i].flags; if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; table_printf(matrix, col, 0, "<%s", btrfs_group_type_str(flags)); table_printf(matrix, col, 1, "<%s", btrfs_group_profile_str(flags)); col++; } unallocated_col = col; table_printf(matrix, 0, 1, "<Id"); table_printf(matrix, 1, 1, "<Path"); table_printf(matrix, unallocated_col, 1, "<Unallocated"); /* body */ for (i = 0; i < device_info_count; i++) { int k; char *p; u64 total_allocated = 0, unused; p = strrchr(device_info_ptr[i].path, '/'); if (!p) p = device_info_ptr[i].path; else p++; table_printf(matrix, 0, vhdr_skip + i, ">%llu", device_info_ptr[i].devid); table_printf(matrix, 1, vhdr_skip + i, "<%s", device_info_ptr[i].path); for (col = spaceinfos_col, k = 0; k < sargs->total_spaces; k++) { u64 flags = sargs->spaces[k].flags; u64 devid = device_info_ptr[i].devid; int j; u64 size = 0; if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; for (j = 0 ; j < chunks_info_count ; j++) { if (chunks_info_ptr[j].type != flags ) continue; if (chunks_info_ptr[j].devid != devid) continue; size += calc_chunk_size(chunks_info_ptr+j); } if (size) table_printf(matrix, col, vhdr_skip+ i, ">%s", pretty_size_mode(size, unit_mode)); else table_printf(matrix, col, vhdr_skip + i, ">-"); total_allocated += size; col++; } unused = get_partition_size(device_info_ptr[i].path) - total_allocated; table_printf(matrix, unallocated_col, vhdr_skip + i, ">%s", pretty_size_mode(unused, unit_mode)); total_unused += unused; } for (i = 0; i < spaceinfos_col; i++) { table_printf(matrix, i, vhdr_skip - 1, "*-"); table_printf(matrix, i, vhdr_skip + device_info_count, "*-"); } for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) { if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; table_printf(matrix, col, vhdr_skip - 1, "*-"); table_printf(matrix, col, vhdr_skip + device_info_count, "*-"); col++; } /* One for Unallocated */ table_printf(matrix, col, vhdr_skip - 1, "*-"); table_printf(matrix, col, vhdr_skip + device_info_count, "*-"); /* footer */ table_printf(matrix, 1, vhdr_skip + device_info_count + 1, "<Total"); for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) { if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; table_printf(matrix, col++, vhdr_skip + device_info_count + 1, ">%s", pretty_size_mode(sargs->spaces[i].total_bytes, unit_mode)); } table_printf(matrix, unallocated_col, vhdr_skip + device_info_count + 1, ">%s", pretty_size_mode(total_unused, unit_mode)); table_printf(matrix, 1, vhdr_skip + device_info_count + 2, "<Used"); for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) { if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; table_printf(matrix, col++, vhdr_skip + device_info_count + 2, ">%s", pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode)); } table_dump(matrix); table_free(matrix); }
int build_platform_ioctl(int fd, unsigned long op, ...) { status_t error = FS_BAD_VALUE; va_list list; // count arguments va_start(list, op); switch (op) { case 7: // B_GET_GEOMETRY { #ifdef ANTARES_HOST_PLATFORM_LINUX { device_geometry *geometry = va_arg(list, device_geometry*); struct hd_geometry hdGeometry; // BLKGETSIZE and BLKGETSIZE64 don't seem to work for // partitions. So we get the device geometry (there only seems // to be HDIO_GETGEO, which is kind of obsolete, BTW), and // get the partition size via binary search. if (ioctl(fd, HDIO_GETGEO, &hdGeometry) == 0) { off_t bytesPerCylinder = (off_t)hdGeometry.heads * hdGeometry.sectors * 512; off_t deviceSize = bytesPerCylinder * hdGeometry.cylinders; off_t partitionSize = get_partition_size(fd, deviceSize); geometry->head_count = hdGeometry.heads; geometry->cylinder_count = partitionSize / bytesPerCylinder; geometry->sectors_per_track = hdGeometry.sectors; // TODO: Get the real values... geometry->bytes_per_sector = 512; geometry->device_type = B_DISK; geometry->removable = false; geometry->read_only = false; geometry->write_once = false; error = FS_OK; } else error = from_platform_error(errno); } #endif // ANTARES_HOST_PLATFORM_LINUX break; } case 20: // B_FLUSH_DRIVE_CACHE error = FS_OK; break; case 10000: // IOCTL_FILE_UNCACHED_IO error = FS_OK; break; } va_end(list); if (error != FS_OK) { errno = error; return -1; } return 0; }