xref: /qemu/qemu-io.c (revision c48101ae92c5ac6f2412ca345d9cc3557add8e47)
1 /*
2  * Command line utility to exercise the QEMU I/O path.
3  *
4  * Copyright (C) 2009 Red Hat, Inc.
5  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8  * See the COPYING file in the top-level directory.
9  */
10 #include <sys/types.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <getopt.h>
14 
15 #include "qemu-common.h"
16 #include "block_int.h"
17 #include "cmd.h"
18 
19 #define VERSION	"0.0.1"
20 
21 #define CMD_NOFILE_OK	0x01
22 
23 char *progname;
24 static BlockDriverState *bs;
25 
26 static int misalign;
27 
28 /*
29  * Memory allocation helpers.
30  *
31  * Make sure memory is aligned by default, or purposefully misaligned if
32  * that is specified on the command line.
33  */
34 
35 #define MISALIGN_OFFSET		16
36 static void *qemu_io_alloc(size_t len, int pattern)
37 {
38 	void *buf;
39 
40 	if (misalign)
41 		len += MISALIGN_OFFSET;
42 	buf = qemu_memalign(512, len);
43 	memset(buf, pattern, len);
44 	if (misalign)
45 		buf += MISALIGN_OFFSET;
46 	return buf;
47 }
48 
49 static void qemu_io_free(void *p)
50 {
51 	if (misalign)
52 		p -= MISALIGN_OFFSET;
53 	qemu_vfree(p);
54 }
55 
56 static void
57 dump_buffer(char *buffer, int64_t offset, int len)
58 {
59 	int i, j;
60 	char *p;
61 
62 	for (i = 0, p = buffer; i < len; i += 16) {
63 		char    *s = p;
64 
65 		printf("%08llx:  ", (unsigned long long)offset + i);
66 		for (j = 0; j < 16 && i + j < len; j++, p++)
67 			printf("%02x ", *p);
68 		printf(" ");
69 		for (j = 0; j < 16 && i + j < len; j++, s++) {
70 			if (isalnum((int)*s))
71 				printf("%c", *s);
72 			else
73 				printf(".");
74 		}
75 		printf("\n");
76 	}
77 }
78 
79 static void
80 print_report(const char *op, struct timeval *t, int64_t offset,
81 		int count, int total, int cnt, int Cflag)
82 {
83 	char s1[64], s2[64], ts[64];
84 
85 	timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
86 	if (!Cflag) {
87 		cvtstr((double)total, s1, sizeof(s1));
88 		cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
89 		printf("%s %d/%d bytes at offset %lld\n",
90 			op, total, count, (long long)offset);
91 		printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
92 			s1, cnt, ts, s2, tdiv((double)cnt, *t));
93 	} else {/* bytes,ops,time,bytes/sec,ops/sec */
94 		printf("%d,%d,%s,%.3f,%.3f\n",
95 			total, cnt, ts,
96 			tdiv((double)total, *t),
97 			tdiv((double)cnt, *t));
98 	}
99 }
100 
101 static int do_read(char *buf, int64_t offset, int count, int *total)
102 {
103 	int ret;
104 
105 	ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
106 	if (ret < 0)
107 		return ret;
108 	*total = count;
109 	return 1;
110 }
111 
112 static int do_write(char *buf, int64_t offset, int count, int *total)
113 {
114 	int ret;
115 
116 	ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
117 	if (ret < 0)
118 		return ret;
119 	*total = count;
120 	return 1;
121 }
122 
123 static int do_pread(char *buf, int64_t offset, int count, int *total)
124 {
125 	*total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
126 	if (*total < 0)
127 		return *total;
128 	return 1;
129 }
130 
131 static int do_pwrite(char *buf, int64_t offset, int count, int *total)
132 {
133 	*total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
134 	if (*total < 0)
135 		return *total;
136 	return 1;
137 }
138 
139 #define NOT_DONE 0x7fffffff
140 static void aio_rw_done(void *opaque, int ret)
141 {
142 	*(int *)opaque = ret;
143 }
144 
145 static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
146 {
147 	BlockDriverAIOCB *acb;
148 	int async_ret = NOT_DONE;
149 
150 	acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
151 			     aio_rw_done, &async_ret);
152 	if (!acb)
153 		return -EIO;
154 
155 	while (async_ret == NOT_DONE)
156 		qemu_aio_wait();
157 
158 	*total = qiov->size;
159 	return async_ret < 0 ? async_ret : 1;
160 }
161 
162 static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
163 {
164 	BlockDriverAIOCB *acb;
165 	int async_ret = NOT_DONE;
166 
167 	acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
168 			      aio_rw_done, &async_ret);
169 	if (!acb)
170 		return -EIO;
171 
172 	while (async_ret == NOT_DONE)
173 		qemu_aio_wait();
174 
175 	*total = qiov->size;
176 	return async_ret < 0 ? async_ret : 1;
177 }
178 
179 
180 static const cmdinfo_t read_cmd;
181 
182 static void
183 read_help(void)
184 {
185 	printf(
186 "\n"
187 " reads a range of bytes from the given offset\n"
188 "\n"
189 " Example:\n"
190 " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
191 "\n"
192 " Reads a segment of the currently open file, optionally dumping it to the\n"
193 " standard output stream (with -v option) for subsequent inspection.\n"
194 " -p, -- use bdrv_pread to read the file\n"
195 " -P, -- use a pattern to verify read data\n"
196 " -C, -- report statistics in a machine parsable format\n"
197 " -v, -- dump buffer to standard output\n"
198 " -q, -- quite mode, do not show I/O statistics\n"
199 "\n");
200 }
201 
202 static int
203 read_f(int argc, char **argv)
204 {
205 	struct timeval t1, t2;
206 	int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
207 	int c, cnt;
208 	char *buf;
209 	int64_t offset;
210 	int count, total;
211 	int pattern = 0;
212 	int Pflag = 0;
213 
214 	while ((c = getopt(argc, argv, "CpP:qv")) != EOF) {
215 		switch (c) {
216 		case 'C':
217 			Cflag = 1;
218 			break;
219 		case 'p':
220 			pflag = 1;
221 			break;
222 		case 'P':
223 			Pflag = 1;
224 			pattern = atoi(optarg);
225 			break;
226 		case 'q':
227 			qflag = 1;
228 			break;
229 		case 'v':
230 			vflag = 1;
231 			break;
232 		default:
233 			return command_usage(&read_cmd);
234 		}
235 	}
236 
237 	if (optind != argc - 2)
238 		return command_usage(&read_cmd);
239 
240 	offset = cvtnum(argv[optind]);
241 	if (offset < 0) {
242 		printf("non-numeric length argument -- %s\n", argv[optind]);
243 		return 0;
244 	}
245 
246 	optind++;
247 	count = cvtnum(argv[optind]);
248 	if (count < 0) {
249 		printf("non-numeric length argument -- %s\n", argv[optind]);
250 		return 0;
251 	}
252 
253 	if (!pflag)
254 		if (offset & 0x1ff) {
255 			printf("offset %lld is not sector aligned\n",
256 				(long long)offset);
257 			return 0;
258 
259 		if (count & 0x1ff) {
260 			printf("count %d is not sector aligned\n",
261 				count);
262 			return 0;
263 		}
264 	}
265 
266 	buf = qemu_io_alloc(count, 0xab);
267 
268 	gettimeofday(&t1, NULL);
269 	if (pflag)
270 		cnt = do_pread(buf, offset, count, &total);
271 	else
272 		cnt = do_read(buf, offset, count, &total);
273 	gettimeofday(&t2, NULL);
274 
275 	if (cnt < 0) {
276 		printf("read failed: %s\n", strerror(-cnt));
277 		return 0;
278 	}
279 
280 	if (Pflag) {
281 		void* cmp_buf = malloc(count);
282 		memset(cmp_buf, pattern, count);
283 		if (memcmp(buf, cmp_buf, count)) {
284 			printf("Pattern verification failed at offset %lld, "
285 				"%d bytes\n",
286 				(long long) offset, count);
287 		}
288 		free(cmp_buf);
289 	}
290 
291 	if (qflag)
292 		return 0;
293 
294         if (vflag)
295 		dump_buffer(buf, offset, count);
296 
297 	/* Finally, report back -- -C gives a parsable format */
298 	t2 = tsub(t2, t1);
299 	print_report("read", &t2, offset, count, total, cnt, Cflag);
300 
301 	qemu_io_free(buf);
302 
303 	return 0;
304 }
305 
306 static const cmdinfo_t read_cmd = {
307 	.name		= "read",
308 	.altname	= "r",
309 	.cfunc		= read_f,
310 	.argmin		= 2,
311 	.argmax		= -1,
312 	.args		= "[-aCpqv] [-P pattern ] off len",
313 	.oneline	= "reads a number of bytes at a specified offset",
314 	.help		= read_help,
315 };
316 
317 static const cmdinfo_t readv_cmd;
318 
319 static void
320 readv_help(void)
321 {
322 	printf(
323 "\n"
324 " reads a range of bytes from the given offset into multiple buffers\n"
325 "\n"
326 " Example:\n"
327 " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
328 "\n"
329 " Reads a segment of the currently open file, optionally dumping it to the\n"
330 " standard output stream (with -v option) for subsequent inspection.\n"
331 " Uses multiple iovec buffers if more than one byte range is specified.\n"
332 " -C, -- report statistics in a machine parsable format\n"
333 " -P, -- use a pattern to verify read data\n"
334 " -v, -- dump buffer to standard output\n"
335 " -q, -- quite mode, do not show I/O statistics\n"
336 "\n");
337 }
338 
339 static int
340 readv_f(int argc, char **argv)
341 {
342 	struct timeval t1, t2;
343 	int Cflag = 0, qflag = 0, vflag = 0;
344 	int c, cnt;
345 	char *buf, *p;
346 	int64_t offset;
347 	int count = 0, total;
348 	int nr_iov, i;
349 	QEMUIOVector qiov;
350 	int pattern = 0;
351 	int Pflag = 0;
352 
353 	while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
354 		switch (c) {
355 		case 'C':
356 			Cflag = 1;
357 			break;
358 		case 'P':
359 			Pflag = 1;
360 			pattern = atoi(optarg);
361 			break;
362 		case 'q':
363 			qflag = 1;
364 			break;
365 		case 'v':
366 			vflag = 1;
367 			break;
368 		default:
369 			return command_usage(&readv_cmd);
370 		}
371 	}
372 
373 	if (optind > argc - 2)
374 		return command_usage(&readv_cmd);
375 
376 
377 	offset = cvtnum(argv[optind]);
378 	if (offset < 0) {
379 		printf("non-numeric length argument -- %s\n", argv[optind]);
380 		return 0;
381 	}
382 	optind++;
383 
384 	if (offset & 0x1ff) {
385 		printf("offset %lld is not sector aligned\n",
386 			(long long)offset);
387 		return 0;
388 	}
389 
390 	if (count & 0x1ff) {
391 		printf("count %d is not sector aligned\n",
392 			count);
393 		return 0;
394 	}
395 
396 	for (i = optind; i < argc; i++) {
397 	        size_t len;
398 
399 		len = cvtnum(argv[i]);
400 		if (len < 0) {
401 			printf("non-numeric length argument -- %s\n", argv[i]);
402 			return 0;
403 		}
404 		count += len;
405 	}
406 
407 	nr_iov = argc - optind;
408 	qemu_iovec_init(&qiov, nr_iov);
409 	buf = p = qemu_io_alloc(count, 0xab);
410 	for (i = 0; i < nr_iov; i++) {
411 	        size_t len;
412 
413 		len = cvtnum(argv[optind]);
414 		if (len < 0) {
415 			printf("non-numeric length argument -- %s\n",
416 				argv[optind]);
417 			return 0;
418 		}
419 
420 		qemu_iovec_add(&qiov, p, len);
421 		p += len;
422 		optind++;
423 	}
424 
425 	gettimeofday(&t1, NULL);
426 	cnt = do_aio_readv(&qiov, offset, &total);
427 	gettimeofday(&t2, NULL);
428 
429 	if (cnt < 0) {
430 		printf("readv failed: %s\n", strerror(-cnt));
431 		return 0;
432 	}
433 
434 	if (Pflag) {
435 		void* cmp_buf = malloc(count);
436 		memset(cmp_buf, pattern, count);
437 		if (memcmp(buf, cmp_buf, count)) {
438 			printf("Pattern verification failed at offset %lld, "
439 				"%d bytes\n",
440 				(long long) offset, count);
441 		}
442 		free(cmp_buf);
443 	}
444 
445 	if (qflag)
446 		return 0;
447 
448         if (vflag)
449 		dump_buffer(buf, offset, qiov.size);
450 
451 	/* Finally, report back -- -C gives a parsable format */
452 	t2 = tsub(t2, t1);
453 	print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
454 
455 	qemu_io_free(buf);
456 
457 	return 0;
458 }
459 
460 static const cmdinfo_t readv_cmd = {
461 	.name		= "readv",
462 	.cfunc		= readv_f,
463 	.argmin		= 2,
464 	.argmax		= -1,
465 	.args		= "[-Cqv] [-P pattern ] off len [len..]",
466 	.oneline	= "reads a number of bytes at a specified offset",
467 	.help		= readv_help,
468 };
469 
470 static const cmdinfo_t write_cmd;
471 
472 static void
473 write_help(void)
474 {
475 	printf(
476 "\n"
477 " writes a range of bytes from the given offset\n"
478 "\n"
479 " Example:\n"
480 " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
481 "\n"
482 " Writes into a segment of the currently open file, using a buffer\n"
483 " filled with a set pattern (0xcdcdcdcd).\n"
484 " -p, -- use bdrv_pwrite to write the file\n"
485 " -P, -- use different pattern to fill file\n"
486 " -C, -- report statistics in a machine parsable format\n"
487 " -q, -- quite mode, do not show I/O statistics\n"
488 "\n");
489 }
490 
491 static int
492 write_f(int argc, char **argv)
493 {
494 	struct timeval t1, t2;
495 	int Cflag = 0, pflag = 0, qflag = 0;
496 	int c, cnt;
497 	char *buf;
498 	int64_t offset;
499 	int count, total;
500 	int pattern = 0xcd;
501 
502 	while ((c = getopt(argc, argv, "CpP:q")) != EOF) {
503 		switch (c) {
504 		case 'C':
505 			Cflag = 1;
506 			break;
507 		case 'p':
508 			pflag = 1;
509 			break;
510 		case 'P':
511 			pattern = atoi(optarg);
512 			break;
513 		case 'q':
514 			qflag = 1;
515 			break;
516 		default:
517 			return command_usage(&write_cmd);
518 		}
519 	}
520 
521 	if (optind != argc - 2)
522 		return command_usage(&write_cmd);
523 
524 	offset = cvtnum(argv[optind]);
525 	if (offset < 0) {
526 		printf("non-numeric length argument -- %s\n", argv[optind]);
527 		return 0;
528 	}
529 
530 	optind++;
531 	count = cvtnum(argv[optind]);
532 	if (count < 0) {
533 		printf("non-numeric length argument -- %s\n", argv[optind]);
534 		return 0;
535 	}
536 
537 	if (!pflag) {
538 		if (offset & 0x1ff) {
539 			printf("offset %lld is not sector aligned\n",
540 				(long long)offset);
541 			return 0;
542 		}
543 
544 		if (count & 0x1ff) {
545 			printf("count %d is not sector aligned\n",
546 				count);
547 			return 0;
548 		}
549 	}
550 
551 	buf = qemu_io_alloc(count, pattern);
552 
553 	gettimeofday(&t1, NULL);
554 	if (pflag)
555 		cnt = do_pwrite(buf, offset, count, &total);
556 	else
557 		cnt = do_write(buf, offset, count, &total);
558 	gettimeofday(&t2, NULL);
559 
560 	if (cnt < 0) {
561 		printf("write failed: %s\n", strerror(-cnt));
562 		return 0;
563 	}
564 
565 	if (qflag)
566 		return 0;
567 
568 	/* Finally, report back -- -C gives a parsable format */
569 	t2 = tsub(t2, t1);
570 	print_report("wrote", &t2, offset, count, total, cnt, Cflag);
571 
572 	qemu_io_free(buf);
573 
574 	return 0;
575 }
576 
577 static const cmdinfo_t write_cmd = {
578 	.name		= "write",
579 	.altname	= "w",
580 	.cfunc		= write_f,
581 	.argmin		= 2,
582 	.argmax		= -1,
583 	.args		= "[-aCpq] [-P pattern ] off len",
584 	.oneline	= "writes a number of bytes at a specified offset",
585 	.help		= write_help,
586 };
587 
588 static const cmdinfo_t writev_cmd;
589 
590 static void
591 writev_help(void)
592 {
593 	printf(
594 "\n"
595 " writes a range of bytes from the given offset source from multiple buffers\n"
596 "\n"
597 " Example:\n"
598 " 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
599 "\n"
600 " Writes into a segment of the currently open file, using a buffer\n"
601 " filled with a set pattern (0xcdcdcdcd).\n"
602 " -P, -- use different pattern to fill file\n"
603 " -C, -- report statistics in a machine parsable format\n"
604 " -q, -- quite mode, do not show I/O statistics\n"
605 "\n");
606 }
607 
608 static int
609 writev_f(int argc, char **argv)
610 {
611 	struct timeval t1, t2;
612 	int Cflag = 0, qflag = 0;
613 	int c, cnt;
614 	char *buf, *p;
615 	int64_t offset;
616 	int count = 0, total;
617 	int nr_iov, i;
618 	int pattern = 0xcd;
619 	QEMUIOVector qiov;
620 
621 	while ((c = getopt(argc, argv, "CqP:")) != EOF) {
622 		switch (c) {
623 		case 'C':
624 			Cflag = 1;
625 			break;
626 		case 'q':
627 			qflag = 1;
628 			break;
629 		case 'P':
630 			pattern = atoi(optarg);
631 			break;
632 		default:
633 			return command_usage(&writev_cmd);
634 		}
635 	}
636 
637 	if (optind > argc - 2)
638 		return command_usage(&writev_cmd);
639 
640 	offset = cvtnum(argv[optind]);
641 	if (offset < 0) {
642 		printf("non-numeric length argument -- %s\n", argv[optind]);
643 		return 0;
644 	}
645 	optind++;
646 
647 	if (offset & 0x1ff) {
648 		printf("offset %lld is not sector aligned\n",
649 			(long long)offset);
650 		return 0;
651 	}
652 
653 	if (count & 0x1ff) {
654 		printf("count %d is not sector aligned\n",
655 			count);
656 		return 0;
657 	}
658 
659 
660 	for (i = optind; i < argc; i++) {
661 	        size_t len;
662 
663 		len = cvtnum(argv[optind]);
664 		if (len < 0) {
665 			printf("non-numeric length argument -- %s\n", argv[i]);
666 			return 0;
667 		}
668 		count += len;
669 	}
670 
671 	nr_iov = argc - optind;
672 	qemu_iovec_init(&qiov, nr_iov);
673 	buf = p = qemu_io_alloc(count, pattern);
674 	for (i = 0; i < nr_iov; i++) {
675 	        size_t len;
676 
677 		len = cvtnum(argv[optind]);
678 		if (len < 0) {
679 			printf("non-numeric length argument -- %s\n",
680 				argv[optind]);
681 			return 0;
682 		}
683 
684 		qemu_iovec_add(&qiov, p, len);
685 		p += len;
686 		optind++;
687 	}
688 
689 	gettimeofday(&t1, NULL);
690 	cnt = do_aio_writev(&qiov, offset, &total);
691 	gettimeofday(&t2, NULL);
692 
693 	if (cnt < 0) {
694 		printf("writev failed: %s\n", strerror(-cnt));
695 		return 0;
696 	}
697 
698 	if (qflag)
699 		return 0;
700 
701 	/* Finally, report back -- -C gives a parsable format */
702 	t2 = tsub(t2, t1);
703 	print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
704 
705 	qemu_io_free(buf);
706 
707 	return 0;
708 }
709 
710 static const cmdinfo_t writev_cmd = {
711 	.name		= "writev",
712 	.cfunc		= writev_f,
713 	.argmin		= 2,
714 	.argmax		= -1,
715 	.args		= "[-Cq] [-P pattern ] off len [len..]",
716 	.oneline	= "writes a number of bytes at a specified offset",
717 	.help		= writev_help,
718 };
719 
720 static int
721 flush_f(int argc, char **argv)
722 {
723 	bdrv_flush(bs);
724 	return 0;
725 }
726 
727 static const cmdinfo_t flush_cmd = {
728 	.name		= "flush",
729 	.altname	= "f",
730 	.cfunc		= flush_f,
731 	.oneline	= "flush all in-core file state to disk",
732 };
733 
734 static int
735 truncate_f(int argc, char **argv)
736 {
737 	int64_t offset;
738 	int ret;
739 
740 	offset = cvtnum(argv[1]);
741 	if (offset < 0) {
742 		printf("non-numeric truncate argument -- %s\n", argv[1]);
743 		return 0;
744 	}
745 
746 	ret = bdrv_truncate(bs, offset);
747 	if (ret < 0) {
748 		printf("truncate: %s", strerror(ret));
749 		return 0;
750 	}
751 
752 	return 0;
753 }
754 
755 static const cmdinfo_t truncate_cmd = {
756 	.name		= "truncate",
757 	.altname	= "t",
758 	.cfunc		= truncate_f,
759 	.argmin		= 1,
760 	.argmax		= 1,
761 	.args		= "off",
762 	.oneline	= "truncates the current file at the given offset",
763 };
764 
765 static int
766 length_f(int argc, char **argv)
767 {
768         int64_t size;
769 	char s1[64];
770 
771 	size = bdrv_getlength(bs);
772 	if (size < 0) {
773 		printf("getlength: %s", strerror(size));
774 		return 0;
775 	}
776 
777 	cvtstr(size, s1, sizeof(s1));
778 	printf("%s\n", s1);
779 	return 0;
780 }
781 
782 
783 static const cmdinfo_t length_cmd = {
784 	.name		= "length",
785 	.altname	= "l",
786 	.cfunc		= length_f,
787 	.oneline	= "gets the length of the current file",
788 };
789 
790 
791 static int
792 info_f(int argc, char **argv)
793 {
794 	BlockDriverInfo bdi;
795 	char s1[64], s2[64];
796 	int ret;
797 
798 	if (bs->drv && bs->drv->format_name)
799 		printf("format name: %s\n", bs->drv->format_name);
800 	if (bs->drv && bs->drv->protocol_name)
801 		printf("format name: %s\n", bs->drv->protocol_name);
802 
803 	ret = bdrv_get_info(bs, &bdi);
804 	if (ret)
805 		return 0;
806 
807 	cvtstr(bdi.cluster_size, s1, sizeof(s1));
808 	cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
809 
810 	printf("cluster size: %s\n", s1);
811 	printf("vm state offset: %s\n", s2);
812 
813 	return 0;
814 }
815 
816 
817 
818 static const cmdinfo_t info_cmd = {
819 	.name		= "info",
820 	.altname	= "i",
821 	.cfunc		= info_f,
822 	.oneline	= "prints information about the current file",
823 };
824 
825 static int
826 alloc_f(int argc, char **argv)
827 {
828 	int64_t offset;
829 	int nb_sectors;
830 	char s1[64];
831 	int num;
832 	int ret;
833 	const char *retstr;
834 
835 	offset = cvtnum(argv[1]);
836 	if (offset & 0x1ff) {
837 		printf("offset %lld is not sector aligned\n",
838 			(long long)offset);
839 		return 0;
840 	}
841 
842 	if (argc == 3)
843 		nb_sectors = cvtnum(argv[2]);
844 	else
845 		nb_sectors = 1;
846 
847 	ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
848 
849 	cvtstr(offset, s1, sizeof(s1));
850 
851 	retstr = ret ? "allocated" : "not allocated";
852 	if (nb_sectors == 1)
853 		printf("sector %s at offset %s\n", retstr, s1);
854 	else
855 		printf("%d/%d sectors %s at offset %s\n",
856 			num, nb_sectors, retstr, s1);
857 	return 0;
858 }
859 
860 static const cmdinfo_t alloc_cmd = {
861 	.name		= "alloc",
862 	.altname	= "a",
863 	.argmin		= 1,
864 	.argmax		= 2,
865 	.cfunc		= alloc_f,
866 	.args		= "off [sectors]",
867 	.oneline	= "checks if a sector is present in the file",
868 };
869 
870 static int
871 close_f(int argc, char **argv)
872 {
873 	bdrv_close(bs);
874 	bs = NULL;
875 	return 0;
876 }
877 
878 static const cmdinfo_t close_cmd = {
879 	.name		= "close",
880 	.altname	= "c",
881 	.cfunc		= close_f,
882 	.oneline	= "close the current open file",
883 };
884 
885 static int openfile(char *name, int flags)
886 {
887 	if (bs) {
888 		fprintf(stderr, "file open already, try 'help close'\n");
889 		return 1;
890 	}
891 
892 	bs = bdrv_new("hda");
893 	if (!bs)
894 		return 1;
895 
896 	if (bdrv_open(bs, name, flags) == -1) {
897 		fprintf(stderr, "%s: can't open device %s\n", progname, name);
898 		bs = NULL;
899 		return 1;
900 	}
901 
902 	return 0;
903 }
904 
905 static void
906 open_help(void)
907 {
908 	printf(
909 "\n"
910 " opens a new file in the requested mode\n"
911 "\n"
912 " Example:\n"
913 " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
914 "\n"
915 " Opens a file for subsequent use by all of the other qemu-io commands.\n"
916 " -C, -- create new file if it doesn't exist\n"
917 " -r, -- open file read-only\n"
918 " -s, -- use snapshot file\n"
919 " -n, -- disable host cache\n"
920 "\n");
921 }
922 
923 static const cmdinfo_t open_cmd;
924 
925 static int
926 open_f(int argc, char **argv)
927 {
928 	int flags = 0;
929 	int readonly = 0;
930 	int c;
931 
932 	while ((c = getopt(argc, argv, "snCr")) != EOF) {
933 		switch (c) {
934 		case 's':
935 			flags |= BDRV_O_SNAPSHOT;
936 			break;
937 		case 'n':
938 			flags |= BDRV_O_NOCACHE;
939 			break;
940 		case 'C':
941 			flags |= BDRV_O_CREAT;
942 			break;
943 		case 'r':
944 			readonly = 1;
945 			break;
946 		default:
947 			return command_usage(&open_cmd);
948 		}
949 	}
950 
951 	if (readonly)
952 		flags |= BDRV_O_RDONLY;
953 	else
954 		flags |= BDRV_O_RDWR;
955 
956 	if (optind != argc - 1)
957 		return command_usage(&open_cmd);
958 
959 	return openfile(argv[optind], flags);
960 }
961 
962 static const cmdinfo_t open_cmd = {
963 	.name		= "open",
964 	.altname	= "o",
965 	.cfunc		= open_f,
966 	.argmin		= 1,
967 	.argmax		= -1,
968 	.flags		= CMD_NOFILE_OK,
969 	.args		= "[-Crsn] [path]",
970 	.oneline	= "open the file specified by path",
971 	.help		= open_help,
972 };
973 
974 static int
975 init_args_command(
976         int     index)
977 {
978 	/* only one device allowed so far */
979 	if (index >= 1)
980 		return 0;
981 	return ++index;
982 }
983 
984 static int
985 init_check_command(
986 	const cmdinfo_t *ct)
987 {
988 	if (ct->flags & CMD_FLAG_GLOBAL)
989 		return 1;
990 	if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
991 		fprintf(stderr, "no file open, try 'help open'\n");
992 		return 0;
993 	}
994 	return 1;
995 }
996 
997 static void usage(const char *name)
998 {
999 	printf(
1000 "Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n"
1001 "QEMU Disk excerciser\n"
1002 "\n"
1003 "  -C, --create         create new file if it doesn't exist\n"
1004 "  -c, --cmd            command to execute\n"
1005 "  -r, --read-only      export read-only\n"
1006 "  -s, --snapshot       use snapshot file\n"
1007 "  -n, --nocache        disable host cache\n"
1008 "  -m, --misalign       misalign allocations for O_DIRECT\n"
1009 "  -h, --help           display this help and exit\n"
1010 "  -V, --version        output version information and exit\n"
1011 "\n",
1012 	name);
1013 }
1014 
1015 
1016 int main(int argc, char **argv)
1017 {
1018 	int readonly = 0;
1019 	const char *sopt = "hVc:Crsnm";
1020 	struct option lopt[] = {
1021 		{ "help", 0, 0, 'h' },
1022 		{ "version", 0, 0, 'V' },
1023 		{ "offset", 1, 0, 'o' },
1024 		{ "cmd", 1, 0, 'c' },
1025 		{ "create", 0, 0, 'C' },
1026 		{ "read-only", 0, 0, 'r' },
1027 		{ "snapshot", 0, 0, 's' },
1028 		{ "nocache", 0, 0, 'n' },
1029 		{ "misalign", 0, 0, 'm' },
1030 		{ NULL, 0, 0, 0 }
1031 	};
1032 	int c;
1033 	int opt_index = 0;
1034 	int flags = 0;
1035 
1036 	progname = basename(argv[0]);
1037 
1038 	while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
1039 		switch (c) {
1040 		case 's':
1041 			flags |= BDRV_O_SNAPSHOT;
1042 			break;
1043 		case 'n':
1044 			flags |= BDRV_O_NOCACHE;
1045 			break;
1046 		case 'c':
1047 			add_user_command(optarg);
1048 			break;
1049 		case 'C':
1050 			flags |= BDRV_O_CREAT;
1051 			break;
1052 		case 'r':
1053 			readonly = 1;
1054 			break;
1055 		case 'm':
1056 			misalign = 1;
1057 			break;
1058 		case 'V':
1059 			printf("%s version %s\n", progname, VERSION);
1060 			exit(0);
1061 		case 'h':
1062 			usage(progname);
1063 			exit(0);
1064 		default:
1065 			usage(progname);
1066 			exit(1);
1067 		}
1068 	}
1069 
1070 	if ((argc - optind) > 1) {
1071 		usage(progname);
1072 		exit(1);
1073 	}
1074 
1075 	bdrv_init();
1076 
1077 	/* initialize commands */
1078 	quit_init();
1079 	help_init();
1080 	add_command(&open_cmd);
1081 	add_command(&close_cmd);
1082 	add_command(&read_cmd);
1083 	add_command(&readv_cmd);
1084 	add_command(&write_cmd);
1085 	add_command(&writev_cmd);
1086 	add_command(&flush_cmd);
1087 	add_command(&truncate_cmd);
1088 	add_command(&length_cmd);
1089 	add_command(&info_cmd);
1090 	add_command(&alloc_cmd);
1091 
1092 	add_args_command(init_args_command);
1093 	add_check_command(init_check_command);
1094 
1095 	/* open the device */
1096 	if (readonly)
1097 		flags |= BDRV_O_RDONLY;
1098 	else
1099 		flags |= BDRV_O_RDWR;
1100 
1101 	if ((argc - optind) == 1)
1102 		openfile(argv[optind], flags);
1103 	command_loop();
1104 
1105 	if (bs)
1106 		bdrv_close(bs);
1107 	return 0;
1108 }
1109