/*
 *  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;
}
Beispiel #2
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;

}
Beispiel #3
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);
}
Beispiel #4
0
/*
 *  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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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);
}
Beispiel #9
0
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;
}