|
|
1.1 root 1: /*
2: * Block driver for RAW files (posix)
3: *
4: * Copyright (c) 2006 Fabrice Bellard
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24: #include "qemu-common.h"
25: #include "qemu-timer.h"
26: #include "qemu-char.h"
27: #include "qemu-log.h"
28: #include "block_int.h"
29: #include "module.h"
1.1.1.2 root 30: #include "block/raw-posix-aio.h"
1.1 root 31:
32: #ifdef CONFIG_COCOA
33: #include <paths.h>
34: #include <sys/param.h>
35: #include <IOKit/IOKitLib.h>
36: #include <IOKit/IOBSD.h>
37: #include <IOKit/storage/IOMediaBSDClient.h>
38: #include <IOKit/storage/IOMedia.h>
39: #include <IOKit/storage/IOCDMedia.h>
40: //#include <IOKit/storage/IOCDTypes.h>
41: #include <CoreFoundation/CoreFoundation.h>
42: #endif
43:
44: #ifdef __sun__
45: #define _POSIX_PTHREAD_SEMANTICS 1
46: #include <sys/dkio.h>
47: #endif
48: #ifdef __linux__
1.1.1.6 root 49: #include <sys/types.h>
50: #include <sys/stat.h>
1.1 root 51: #include <sys/ioctl.h>
1.1.1.5 root 52: #include <sys/param.h>
1.1 root 53: #include <linux/cdrom.h>
54: #include <linux/fd.h>
55: #endif
1.1.1.2 root 56: #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 57: #include <sys/disk.h>
58: #include <sys/cdio.h>
59: #endif
60:
61: #ifdef __OpenBSD__
62: #include <sys/ioctl.h>
63: #include <sys/disklabel.h>
64: #include <sys/dkio.h>
65: #endif
66:
1.1.1.6 root 67: #ifdef __NetBSD__
68: #include <sys/ioctl.h>
69: #include <sys/disklabel.h>
70: #include <sys/dkio.h>
71: #include <sys/disk.h>
72: #endif
73:
1.1 root 74: #ifdef __DragonFly__
75: #include <sys/ioctl.h>
76: #include <sys/diskslice.h>
77: #endif
78:
1.1.1.5 root 79: #ifdef CONFIG_XFS
80: #include <xfs/xfs.h>
81: #endif
82:
1.1 root 83: //#define DEBUG_FLOPPY
84:
85: //#define DEBUG_BLOCK
86: #if defined(DEBUG_BLOCK)
87: #define DEBUG_BLOCK_PRINT(formatCstr, ...) do { if (qemu_log_enabled()) \
88: { qemu_log(formatCstr, ## __VA_ARGS__); qemu_log_flush(); } } while (0)
89: #else
90: #define DEBUG_BLOCK_PRINT(formatCstr, ...)
91: #endif
92:
93: /* OS X does not have O_DSYNC */
94: #ifndef O_DSYNC
95: #ifdef O_SYNC
96: #define O_DSYNC O_SYNC
97: #elif defined(O_FSYNC)
98: #define O_DSYNC O_FSYNC
99: #endif
100: #endif
101:
102: /* Approximate O_DIRECT with O_DSYNC if O_DIRECT isn't available */
103: #ifndef O_DIRECT
104: #define O_DIRECT O_DSYNC
105: #endif
106:
107: #define FTYPE_FILE 0
108: #define FTYPE_CD 1
109: #define FTYPE_FD 2
110:
1.1.1.5 root 111: /* if the FD is not accessed during that time (in ns), we try to
1.1 root 112: reopen it to see if the disk has been changed */
1.1.1.5 root 113: #define FD_OPEN_TIMEOUT (1000000000)
114:
115: #define MAX_BLOCKSIZE 4096
1.1 root 116:
117: typedef struct BDRVRawState {
118: int fd;
119: int type;
120: int open_flags;
121: #if defined(__linux__)
122: /* linux floppy specific */
123: int64_t fd_open_time;
124: int64_t fd_error_time;
125: int fd_got_error;
126: int fd_media_changed;
127: #endif
1.1.1.2 root 128: #ifdef CONFIG_LINUX_AIO
129: int use_aio;
130: void *aio_ctx;
131: #endif
1.1.1.5 root 132: uint8_t *aligned_buf;
133: unsigned aligned_buf_size;
134: #ifdef CONFIG_XFS
135: bool is_xfs : 1;
136: #endif
1.1 root 137: } BDRVRawState;
138:
139: static int fd_open(BlockDriverState *bs);
140: static int64_t raw_getlength(BlockDriverState *bs);
141:
1.1.1.2 root 142: #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 143: static int cdrom_reopen(BlockDriverState *bs);
144: #endif
145:
1.1.1.6 root 146: #if defined(__NetBSD__)
147: static int raw_normalize_devicepath(const char **filename)
148: {
149: static char namebuf[PATH_MAX];
150: const char *dp, *fname;
151: struct stat sb;
152:
153: fname = *filename;
154: dp = strrchr(fname, '/');
155: if (lstat(fname, &sb) < 0) {
156: fprintf(stderr, "%s: stat failed: %s\n",
157: fname, strerror(errno));
158: return -errno;
159: }
160:
161: if (!S_ISBLK(sb.st_mode)) {
162: return 0;
163: }
164:
165: if (dp == NULL) {
166: snprintf(namebuf, PATH_MAX, "r%s", fname);
167: } else {
168: snprintf(namebuf, PATH_MAX, "%.*s/r%s",
169: (int)(dp - fname), fname, dp + 1);
170: }
171: fprintf(stderr, "%s is a block device", fname);
172: *filename = namebuf;
173: fprintf(stderr, ", using %s\n", *filename);
174:
175: return 0;
176: }
177: #else
178: static int raw_normalize_devicepath(const char **filename)
179: {
180: return 0;
181: }
182: #endif
183:
1.1 root 184: static int raw_open_common(BlockDriverState *bs, const char *filename,
185: int bdrv_flags, int open_flags)
186: {
187: BDRVRawState *s = bs->opaque;
188: int fd, ret;
189:
1.1.1.6 root 190: ret = raw_normalize_devicepath(&filename);
191: if (ret != 0) {
192: return ret;
193: }
194:
1.1 root 195: s->open_flags = open_flags | O_BINARY;
196: s->open_flags &= ~O_ACCMODE;
1.1.1.4 root 197: if (bdrv_flags & BDRV_O_RDWR) {
1.1 root 198: s->open_flags |= O_RDWR;
199: } else {
200: s->open_flags |= O_RDONLY;
201: }
202:
203: /* Use O_DSYNC for write-through caching, no flags for write-back caching,
204: * and O_DIRECT for no caching. */
205: if ((bdrv_flags & BDRV_O_NOCACHE))
206: s->open_flags |= O_DIRECT;
1.1.1.6 root 207: if (!(bdrv_flags & BDRV_O_CACHE_WB))
1.1 root 208: s->open_flags |= O_DSYNC;
209:
210: s->fd = -1;
1.1.1.2 root 211: fd = qemu_open(filename, s->open_flags, 0644);
1.1 root 212: if (fd < 0) {
213: ret = -errno;
214: if (ret == -EROFS)
215: ret = -EACCES;
216: return ret;
217: }
218: s->fd = fd;
219: s->aligned_buf = NULL;
1.1.1.2 root 220:
1.1 root 221: if ((bdrv_flags & BDRV_O_NOCACHE)) {
1.1.1.5 root 222: /*
223: * Allocate a buffer for read/modify/write cycles. Chose the size
224: * pessimistically as we don't know the block size yet.
225: */
226: s->aligned_buf_size = 32 * MAX_BLOCKSIZE;
227: s->aligned_buf = qemu_memalign(MAX_BLOCKSIZE, s->aligned_buf_size);
1.1 root 228: if (s->aligned_buf == NULL) {
1.1.1.2 root 229: goto out_close;
1.1 root 230: }
231: }
1.1.1.2 root 232:
1.1.1.7 ! root 233: /* We're falling back to POSIX AIO in some cases so init always */
! 234: if (paio_init() < 0) {
! 235: goto out_free_buf;
! 236: }
! 237:
1.1.1.2 root 238: #ifdef CONFIG_LINUX_AIO
1.1.1.7 ! root 239: /*
! 240: * Currently Linux do AIO only for files opened with O_DIRECT
! 241: * specified so check NOCACHE flag too
! 242: */
1.1.1.2 root 243: if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
244: (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
245:
246: s->aio_ctx = laio_init();
247: if (!s->aio_ctx) {
248: goto out_free_buf;
249: }
250: s->use_aio = 1;
251: } else
252: #endif
253: {
254: #ifdef CONFIG_LINUX_AIO
255: s->use_aio = 0;
256: #endif
257: }
258:
1.1.1.5 root 259: #ifdef CONFIG_XFS
260: if (platform_test_xfs_fd(s->fd)) {
261: s->is_xfs = 1;
262: }
263: #endif
264:
1.1 root 265: return 0;
1.1.1.2 root 266:
267: out_free_buf:
268: qemu_vfree(s->aligned_buf);
269: out_close:
270: close(fd);
271: return -errno;
1.1 root 272: }
273:
274: static int raw_open(BlockDriverState *bs, const char *filename, int flags)
275: {
276: BDRVRawState *s = bs->opaque;
277:
278: s->type = FTYPE_FILE;
1.1.1.4 root 279: return raw_open_common(bs, filename, flags, 0);
1.1 root 280: }
281:
282: /* XXX: use host sector size if necessary with:
283: #ifdef DIOCGSECTORSIZE
284: {
285: unsigned int sectorsize = 512;
286: if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) &&
287: sectorsize > bufsize)
288: bufsize = sectorsize;
289: }
290: #endif
291: #ifdef CONFIG_COCOA
1.1.1.4 root 292: uint32_t blockSize = 512;
1.1 root 293: if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
294: bufsize = blockSize;
295: }
296: #endif
297: */
298:
299: /*
1.1.1.2 root 300: * Check if all memory in this vector is sector aligned.
301: */
1.1.1.5 root 302: static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
1.1 root 303: {
1.1.1.2 root 304: int i;
1.1 root 305:
1.1.1.2 root 306: for (i = 0; i < qiov->niov; i++) {
1.1.1.5 root 307: if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) {
1.1.1.2 root 308: return 0;
1.1 root 309: }
310: }
311:
1.1.1.2 root 312: return 1;
1.1 root 313: }
314:
1.1.1.2 root 315: static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
316: int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
317: BlockDriverCompletionFunc *cb, void *opaque, int type)
1.1 root 318: {
319: BDRVRawState *s = bs->opaque;
320:
321: if (fd_open(bs) < 0)
322: return NULL;
323:
324: /*
325: * If O_DIRECT is used the buffer needs to be aligned on a sector
1.1.1.7 ! root 326: * boundary. Check if this is the case or tell the low-level
1.1.1.2 root 327: * driver that it needs to copy the buffer.
1.1 root 328: */
1.1.1.2 root 329: if (s->aligned_buf) {
1.1.1.5 root 330: if (!qiov_is_aligned(bs, qiov)) {
1.1.1.2 root 331: type |= QEMU_AIO_MISALIGNED;
332: #ifdef CONFIG_LINUX_AIO
333: } else if (s->use_aio) {
334: return laio_submit(bs, s->aio_ctx, s->fd, sector_num, qiov,
335: nb_sectors, cb, opaque, type);
336: #endif
337: }
338: }
1.1 root 339:
1.1.1.2 root 340: return paio_submit(bs, s->fd, sector_num, qiov, nb_sectors,
341: cb, opaque, type);
1.1 root 342: }
343:
344: static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
345: int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
346: BlockDriverCompletionFunc *cb, void *opaque)
347: {
1.1.1.2 root 348: return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
349: cb, opaque, QEMU_AIO_READ);
1.1 root 350: }
351:
352: static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
353: int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
354: BlockDriverCompletionFunc *cb, void *opaque)
355: {
1.1.1.2 root 356: return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
357: cb, opaque, QEMU_AIO_WRITE);
1.1 root 358: }
1.1.1.2 root 359:
360: static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
361: BlockDriverCompletionFunc *cb, void *opaque)
1.1 root 362: {
1.1.1.2 root 363: BDRVRawState *s = bs->opaque;
364:
365: if (fd_open(bs) < 0)
366: return NULL;
1.1 root 367:
1.1.1.2 root 368: return paio_submit(bs, s->fd, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
369: }
1.1 root 370:
371: static void raw_close(BlockDriverState *bs)
372: {
373: BDRVRawState *s = bs->opaque;
374: if (s->fd >= 0) {
375: close(s->fd);
376: s->fd = -1;
377: if (s->aligned_buf != NULL)
1.1.1.3 root 378: qemu_vfree(s->aligned_buf);
1.1 root 379: }
380: }
381:
382: static int raw_truncate(BlockDriverState *bs, int64_t offset)
383: {
384: BDRVRawState *s = bs->opaque;
1.1.1.7 ! root 385: struct stat st;
! 386:
! 387: if (fstat(s->fd, &st)) {
1.1 root 388: return -errno;
1.1.1.7 ! root 389: }
! 390:
! 391: if (S_ISREG(st.st_mode)) {
! 392: if (ftruncate(s->fd, offset) < 0) {
! 393: return -errno;
! 394: }
! 395: } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
! 396: if (offset > raw_getlength(bs)) {
! 397: return -EINVAL;
! 398: }
! 399: } else {
! 400: return -ENOTSUP;
! 401: }
! 402:
1.1 root 403: return 0;
404: }
405:
406: #ifdef __OpenBSD__
407: static int64_t raw_getlength(BlockDriverState *bs)
408: {
409: BDRVRawState *s = bs->opaque;
410: int fd = s->fd;
411: struct stat st;
412:
413: if (fstat(fd, &st))
414: return -1;
415: if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
416: struct disklabel dl;
417:
418: if (ioctl(fd, DIOCGDINFO, &dl))
419: return -1;
420: return (uint64_t)dl.d_secsize *
421: dl.d_partitions[DISKPART(st.st_rdev)].p_size;
422: } else
423: return st.st_size;
424: }
1.1.1.6 root 425: #elif defined(__NetBSD__)
426: static int64_t raw_getlength(BlockDriverState *bs)
427: {
428: BDRVRawState *s = bs->opaque;
429: int fd = s->fd;
430: struct stat st;
431:
432: if (fstat(fd, &st))
433: return -1;
434: if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
435: struct dkwedge_info dkw;
436:
437: if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) {
438: return dkw.dkw_size * 512;
439: } else {
440: struct disklabel dl;
441:
442: if (ioctl(fd, DIOCGDINFO, &dl))
443: return -1;
444: return (uint64_t)dl.d_secsize *
445: dl.d_partitions[DISKPART(st.st_rdev)].p_size;
446: }
447: } else
448: return st.st_size;
449: }
1.1.1.4 root 450: #elif defined(__sun__)
451: static int64_t raw_getlength(BlockDriverState *bs)
452: {
453: BDRVRawState *s = bs->opaque;
454: struct dk_minfo minfo;
455: int ret;
456:
457: ret = fd_open(bs);
458: if (ret < 0) {
459: return ret;
460: }
461:
462: /*
463: * Use the DKIOCGMEDIAINFO ioctl to read the size.
464: */
465: ret = ioctl(s->fd, DKIOCGMEDIAINFO, &minfo);
466: if (ret != -1) {
467: return minfo.dki_lbsize * minfo.dki_capacity;
468: }
469:
470: /*
471: * There are reports that lseek on some devices fails, but
472: * irc discussion said that contingency on contingency was overkill.
473: */
474: return lseek(s->fd, 0, SEEK_END);
475: }
476: #elif defined(CONFIG_BSD)
477: static int64_t raw_getlength(BlockDriverState *bs)
1.1 root 478: {
479: BDRVRawState *s = bs->opaque;
480: int fd = s->fd;
481: int64_t size;
482: struct stat sb;
1.1.1.2 root 483: #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 484: int reopened = 0;
485: #endif
486: int ret;
487:
488: ret = fd_open(bs);
489: if (ret < 0)
490: return ret;
491:
1.1.1.2 root 492: #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 493: again:
494: #endif
495: if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
496: #ifdef DIOCGMEDIASIZE
497: if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
498: #elif defined(DIOCGPART)
499: {
500: struct partinfo pi;
501: if (ioctl(fd, DIOCGPART, &pi) == 0)
502: size = pi.media_size;
503: else
504: size = 0;
505: }
506: if (size == 0)
507: #endif
508: #ifdef CONFIG_COCOA
509: size = LONG_LONG_MAX;
510: #else
511: size = lseek(fd, 0LL, SEEK_END);
512: #endif
1.1.1.2 root 513: #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 514: switch(s->type) {
515: case FTYPE_CD:
516: /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
517: if (size == 2048LL * (unsigned)-1)
518: size = 0;
519: /* XXX no disc? maybe we need to reopen... */
520: if (size <= 0 && !reopened && cdrom_reopen(bs) >= 0) {
521: reopened = 1;
522: goto again;
523: }
524: }
525: #endif
1.1.1.4 root 526: } else {
1.1 root 527: size = lseek(fd, 0, SEEK_END);
528: }
529: return size;
530: }
1.1.1.4 root 531: #else
532: static int64_t raw_getlength(BlockDriverState *bs)
533: {
534: BDRVRawState *s = bs->opaque;
535: int ret;
536:
537: ret = fd_open(bs);
538: if (ret < 0) {
539: return ret;
540: }
541:
542: return lseek(s->fd, 0, SEEK_END);
543: }
1.1 root 544: #endif
545:
1.1.1.6 root 546: static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
547: {
548: struct stat st;
549: BDRVRawState *s = bs->opaque;
550:
551: if (fstat(s->fd, &st) < 0) {
552: return -errno;
553: }
554: return (int64_t)st.st_blocks * 512;
555: }
556:
1.1 root 557: static int raw_create(const char *filename, QEMUOptionParameter *options)
558: {
559: int fd;
560: int result = 0;
561: int64_t total_size = 0;
562:
563: /* Read out options */
564: while (options && options->name) {
565: if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
1.1.1.4 root 566: total_size = options->value.n / BDRV_SECTOR_SIZE;
1.1 root 567: }
568: options++;
569: }
570:
571: fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
572: 0644);
573: if (fd < 0) {
574: result = -errno;
575: } else {
1.1.1.4 root 576: if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
1.1 root 577: result = -errno;
578: }
579: if (close(fd) != 0) {
580: result = -errno;
581: }
582: }
583: return result;
584: }
585:
1.1.1.5 root 586: #ifdef CONFIG_XFS
587: static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
588: {
589: struct xfs_flock64 fl;
590:
591: memset(&fl, 0, sizeof(fl));
592: fl.l_whence = SEEK_SET;
593: fl.l_start = sector_num << 9;
594: fl.l_len = (int64_t)nb_sectors << 9;
595:
596: if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
597: DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
598: return -errno;
599: }
600:
601: return 0;
602: }
603: #endif
604:
1.1.1.7 ! root 605: static coroutine_fn int raw_co_discard(BlockDriverState *bs,
! 606: int64_t sector_num, int nb_sectors)
1.1.1.5 root 607: {
608: #ifdef CONFIG_XFS
609: BDRVRawState *s = bs->opaque;
610:
611: if (s->is_xfs) {
612: return xfs_discard(s, sector_num, nb_sectors);
613: }
614: #endif
615:
616: return 0;
617: }
1.1 root 618:
619: static QEMUOptionParameter raw_create_options[] = {
620: {
621: .name = BLOCK_OPT_SIZE,
622: .type = OPT_SIZE,
623: .help = "Virtual disk size"
624: },
625: { NULL }
626: };
627:
1.1.1.4 root 628: static BlockDriver bdrv_file = {
629: .format_name = "file",
630: .protocol_name = "file",
1.1 root 631: .instance_size = sizeof(BDRVRawState),
632: .bdrv_probe = NULL, /* no probe for protocols */
1.1.1.4 root 633: .bdrv_file_open = raw_open,
1.1 root 634: .bdrv_close = raw_close,
635: .bdrv_create = raw_create,
1.1.1.7 ! root 636: .bdrv_co_discard = raw_co_discard,
1.1 root 637:
638: .bdrv_aio_readv = raw_aio_readv,
639: .bdrv_aio_writev = raw_aio_writev,
1.1.1.2 root 640: .bdrv_aio_flush = raw_aio_flush,
1.1 root 641:
642: .bdrv_truncate = raw_truncate,
643: .bdrv_getlength = raw_getlength,
1.1.1.6 root 644: .bdrv_get_allocated_file_size
645: = raw_get_allocated_file_size,
1.1 root 646:
647: .create_options = raw_create_options,
648: };
649:
650: /***********************************************/
651: /* host device */
652:
653: #ifdef CONFIG_COCOA
654: static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
655: static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
656:
657: kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
658: {
659: kern_return_t kernResult;
660: mach_port_t masterPort;
661: CFMutableDictionaryRef classesToMatch;
662:
663: kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
664: if ( KERN_SUCCESS != kernResult ) {
665: printf( "IOMasterPort returned %d\n", kernResult );
666: }
667:
668: classesToMatch = IOServiceMatching( kIOCDMediaClass );
669: if ( classesToMatch == NULL ) {
670: printf( "IOServiceMatching returned a NULL dictionary.\n" );
671: } else {
672: CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
673: }
674: kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
675: if ( KERN_SUCCESS != kernResult )
676: {
677: printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
678: }
679:
680: return kernResult;
681: }
682:
683: kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
684: {
685: io_object_t nextMedia;
686: kern_return_t kernResult = KERN_FAILURE;
687: *bsdPath = '\0';
688: nextMedia = IOIteratorNext( mediaIterator );
689: if ( nextMedia )
690: {
691: CFTypeRef bsdPathAsCFString;
692: bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
693: if ( bsdPathAsCFString ) {
694: size_t devPathLength;
695: strcpy( bsdPath, _PATH_DEV );
696: strcat( bsdPath, "r" );
697: devPathLength = strlen( bsdPath );
698: if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
699: kernResult = KERN_SUCCESS;
700: }
701: CFRelease( bsdPathAsCFString );
702: }
703: IOObjectRelease( nextMedia );
704: }
705:
706: return kernResult;
707: }
708:
709: #endif
710:
711: static int hdev_probe_device(const char *filename)
712: {
713: struct stat st;
714:
715: /* allow a dedicated CD-ROM driver to match with a higher priority */
716: if (strstart(filename, "/dev/cdrom", NULL))
717: return 50;
718:
719: if (stat(filename, &st) >= 0 &&
720: (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
721: return 100;
722: }
723:
724: return 0;
725: }
726:
727: static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
728: {
729: BDRVRawState *s = bs->opaque;
730:
731: #ifdef CONFIG_COCOA
732: if (strstart(filename, "/dev/cdrom", NULL)) {
733: kern_return_t kernResult;
734: io_iterator_t mediaIterator;
735: char bsdPath[ MAXPATHLEN ];
736: int fd;
737:
738: kernResult = FindEjectableCDMedia( &mediaIterator );
739: kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
740:
741: if ( bsdPath[ 0 ] != '\0' ) {
742: strcat(bsdPath,"s0");
743: /* some CDs don't have a partition 0 */
744: fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
745: if (fd < 0) {
746: bsdPath[strlen(bsdPath)-1] = '1';
747: } else {
748: close(fd);
749: }
750: filename = bsdPath;
751: }
752:
753: if ( mediaIterator )
754: IOObjectRelease( mediaIterator );
755: }
756: #endif
757:
758: s->type = FTYPE_FILE;
1.1.1.2 root 759: #if defined(__linux__)
1.1.1.5 root 760: {
761: char resolved_path[ MAXPATHLEN ], *temp;
762:
763: temp = realpath(filename, resolved_path);
764: if (temp && strstart(temp, "/dev/sg", NULL)) {
765: bs->sg = 1;
766: }
1.1 root 767: }
768: #endif
769:
770: return raw_open_common(bs, filename, flags, 0);
771: }
772:
773: #if defined(__linux__)
774: /* Note: we do not have a reliable method to detect if the floppy is
775: present. The current method is to try to open the floppy at every
776: I/O and to keep it opened during a few hundreds of ms. */
777: static int fd_open(BlockDriverState *bs)
778: {
779: BDRVRawState *s = bs->opaque;
780: int last_media_present;
781:
782: if (s->type != FTYPE_FD)
783: return 0;
784: last_media_present = (s->fd >= 0);
785: if (s->fd >= 0 &&
1.1.1.5 root 786: (get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
1.1 root 787: close(s->fd);
788: s->fd = -1;
789: #ifdef DEBUG_FLOPPY
790: printf("Floppy closed\n");
791: #endif
792: }
793: if (s->fd < 0) {
794: if (s->fd_got_error &&
1.1.1.5 root 795: (get_clock() - s->fd_error_time) < FD_OPEN_TIMEOUT) {
1.1 root 796: #ifdef DEBUG_FLOPPY
797: printf("No floppy (open delayed)\n");
798: #endif
799: return -EIO;
800: }
801: s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK);
802: if (s->fd < 0) {
1.1.1.5 root 803: s->fd_error_time = get_clock();
1.1 root 804: s->fd_got_error = 1;
805: if (last_media_present)
806: s->fd_media_changed = 1;
807: #ifdef DEBUG_FLOPPY
808: printf("No floppy\n");
809: #endif
810: return -EIO;
811: }
812: #ifdef DEBUG_FLOPPY
813: printf("Floppy opened\n");
814: #endif
815: }
816: if (!last_media_present)
817: s->fd_media_changed = 1;
1.1.1.5 root 818: s->fd_open_time = get_clock();
1.1 root 819: s->fd_got_error = 0;
820: return 0;
821: }
822:
823: static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
824: {
825: BDRVRawState *s = bs->opaque;
826:
827: return ioctl(s->fd, req, buf);
828: }
829:
830: static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
831: unsigned long int req, void *buf,
832: BlockDriverCompletionFunc *cb, void *opaque)
833: {
834: BDRVRawState *s = bs->opaque;
835:
836: if (fd_open(bs) < 0)
837: return NULL;
1.1.1.2 root 838: return paio_ioctl(bs, s->fd, req, buf, cb, opaque);
1.1 root 839: }
840:
1.1.1.2 root 841: #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 842: static int fd_open(BlockDriverState *bs)
843: {
844: BDRVRawState *s = bs->opaque;
845:
846: /* this is just to ensure s->fd is sane (its called by io ops) */
847: if (s->fd >= 0)
848: return 0;
849: return -EIO;
850: }
851: #else /* !linux && !FreeBSD */
852:
853: static int fd_open(BlockDriverState *bs)
854: {
855: return 0;
856: }
857:
858: #endif /* !linux && !FreeBSD */
859:
860: static int hdev_create(const char *filename, QEMUOptionParameter *options)
861: {
862: int fd;
863: int ret = 0;
864: struct stat stat_buf;
865: int64_t total_size = 0;
866:
867: /* Read out options */
868: while (options && options->name) {
869: if (!strcmp(options->name, "size")) {
1.1.1.4 root 870: total_size = options->value.n / BDRV_SECTOR_SIZE;
1.1 root 871: }
872: options++;
873: }
874:
875: fd = open(filename, O_WRONLY | O_BINARY);
876: if (fd < 0)
1.1.1.4 root 877: return -errno;
1.1 root 878:
879: if (fstat(fd, &stat_buf) < 0)
1.1.1.4 root 880: ret = -errno;
1.1 root 881: else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
1.1.1.4 root 882: ret = -ENODEV;
883: else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
1.1 root 884: ret = -ENOSPC;
885:
886: close(fd);
887: return ret;
888: }
889:
1.1.1.4 root 890: static int hdev_has_zero_init(BlockDriverState *bs)
891: {
892: return 0;
893: }
894:
1.1 root 895: static BlockDriver bdrv_host_device = {
1.1.1.2 root 896: .format_name = "host_device",
1.1.1.4 root 897: .protocol_name = "host_device",
1.1.1.2 root 898: .instance_size = sizeof(BDRVRawState),
899: .bdrv_probe_device = hdev_probe_device,
1.1.1.4 root 900: .bdrv_file_open = hdev_open,
1.1.1.2 root 901: .bdrv_close = raw_close,
1.1 root 902: .bdrv_create = hdev_create,
1.1.1.2 root 903: .create_options = raw_create_options,
1.1.1.4 root 904: .bdrv_has_zero_init = hdev_has_zero_init,
1.1 root 905:
906: .bdrv_aio_readv = raw_aio_readv,
907: .bdrv_aio_writev = raw_aio_writev,
1.1.1.2 root 908: .bdrv_aio_flush = raw_aio_flush,
1.1 root 909:
1.1.1.7 ! root 910: .bdrv_truncate = raw_truncate,
1.1 root 911: .bdrv_getlength = raw_getlength,
1.1.1.6 root 912: .bdrv_get_allocated_file_size
913: = raw_get_allocated_file_size,
1.1 root 914:
915: /* generic scsi device */
916: #ifdef __linux__
917: .bdrv_ioctl = hdev_ioctl,
918: .bdrv_aio_ioctl = hdev_aio_ioctl,
919: #endif
920: };
921:
922: #ifdef __linux__
923: static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
924: {
925: BDRVRawState *s = bs->opaque;
926: int ret;
927:
928: s->type = FTYPE_FD;
929:
930: /* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
931: ret = raw_open_common(bs, filename, flags, O_NONBLOCK);
932: if (ret)
933: return ret;
934:
935: /* close fd so that we can reopen it as needed */
936: close(s->fd);
937: s->fd = -1;
938: s->fd_media_changed = 1;
939:
940: return 0;
941: }
942:
943: static int floppy_probe_device(const char *filename)
944: {
1.1.1.4 root 945: int fd, ret;
946: int prio = 0;
947: struct floppy_struct fdparam;
1.1.1.6 root 948: struct stat st;
1.1.1.4 root 949:
1.1 root 950: if (strstart(filename, "/dev/fd", NULL))
1.1.1.4 root 951: prio = 50;
952:
953: fd = open(filename, O_RDONLY | O_NONBLOCK);
954: if (fd < 0) {
955: goto out;
956: }
1.1.1.6 root 957: ret = fstat(fd, &st);
958: if (ret == -1 || !S_ISBLK(st.st_mode)) {
959: goto outc;
960: }
1.1.1.4 root 961:
962: /* Attempt to detect via a floppy specific ioctl */
963: ret = ioctl(fd, FDGETPRM, &fdparam);
964: if (ret >= 0)
965: prio = 100;
966:
1.1.1.6 root 967: outc:
1.1.1.4 root 968: close(fd);
969: out:
970: return prio;
1.1 root 971: }
972:
973:
974: static int floppy_is_inserted(BlockDriverState *bs)
975: {
976: return fd_open(bs) >= 0;
977: }
978:
979: static int floppy_media_changed(BlockDriverState *bs)
980: {
981: BDRVRawState *s = bs->opaque;
982: int ret;
983:
984: /*
985: * XXX: we do not have a true media changed indication.
986: * It does not work if the floppy is changed without trying to read it.
987: */
988: fd_open(bs);
989: ret = s->fd_media_changed;
990: s->fd_media_changed = 0;
991: #ifdef DEBUG_FLOPPY
992: printf("Floppy changed=%d\n", ret);
993: #endif
994: return ret;
995: }
996:
1.1.1.7 ! root 997: static void floppy_eject(BlockDriverState *bs, int eject_flag)
1.1 root 998: {
999: BDRVRawState *s = bs->opaque;
1000: int fd;
1001:
1002: if (s->fd >= 0) {
1003: close(s->fd);
1004: s->fd = -1;
1005: }
1006: fd = open(bs->filename, s->open_flags | O_NONBLOCK);
1007: if (fd >= 0) {
1008: if (ioctl(fd, FDEJECT, 0) < 0)
1009: perror("FDEJECT");
1010: close(fd);
1011: }
1012: }
1013:
1014: static BlockDriver bdrv_host_floppy = {
1015: .format_name = "host_floppy",
1.1.1.4 root 1016: .protocol_name = "host_floppy",
1.1 root 1017: .instance_size = sizeof(BDRVRawState),
1018: .bdrv_probe_device = floppy_probe_device,
1.1.1.4 root 1019: .bdrv_file_open = floppy_open,
1.1 root 1020: .bdrv_close = raw_close,
1021: .bdrv_create = hdev_create,
1.1.1.2 root 1022: .create_options = raw_create_options,
1.1.1.4 root 1023: .bdrv_has_zero_init = hdev_has_zero_init,
1.1 root 1024:
1025: .bdrv_aio_readv = raw_aio_readv,
1026: .bdrv_aio_writev = raw_aio_writev,
1.1.1.2 root 1027: .bdrv_aio_flush = raw_aio_flush,
1.1 root 1028:
1.1.1.7 ! root 1029: .bdrv_truncate = raw_truncate,
1.1 root 1030: .bdrv_getlength = raw_getlength,
1.1.1.6 root 1031: .bdrv_get_allocated_file_size
1032: = raw_get_allocated_file_size,
1.1 root 1033:
1034: /* removable device support */
1035: .bdrv_is_inserted = floppy_is_inserted,
1036: .bdrv_media_changed = floppy_media_changed,
1037: .bdrv_eject = floppy_eject,
1038: };
1039:
1040: static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
1041: {
1042: BDRVRawState *s = bs->opaque;
1043:
1044: s->type = FTYPE_CD;
1045:
1046: /* open will not fail even if no CD is inserted, so add O_NONBLOCK */
1047: return raw_open_common(bs, filename, flags, O_NONBLOCK);
1048: }
1049:
1050: static int cdrom_probe_device(const char *filename)
1051: {
1.1.1.4 root 1052: int fd, ret;
1053: int prio = 0;
1.1.1.6 root 1054: struct stat st;
1.1.1.4 root 1055:
1056: fd = open(filename, O_RDONLY | O_NONBLOCK);
1057: if (fd < 0) {
1058: goto out;
1059: }
1.1.1.6 root 1060: ret = fstat(fd, &st);
1061: if (ret == -1 || !S_ISBLK(st.st_mode)) {
1062: goto outc;
1063: }
1.1.1.4 root 1064:
1065: /* Attempt to detect via a CDROM specific ioctl */
1066: ret = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
1067: if (ret >= 0)
1068: prio = 100;
1069:
1.1.1.6 root 1070: outc:
1.1.1.4 root 1071: close(fd);
1072: out:
1073: return prio;
1.1 root 1074: }
1075:
1076: static int cdrom_is_inserted(BlockDriverState *bs)
1077: {
1078: BDRVRawState *s = bs->opaque;
1079: int ret;
1080:
1081: ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
1082: if (ret == CDS_DISC_OK)
1083: return 1;
1084: return 0;
1085: }
1086:
1.1.1.7 ! root 1087: static void cdrom_eject(BlockDriverState *bs, int eject_flag)
1.1 root 1088: {
1089: BDRVRawState *s = bs->opaque;
1090:
1091: if (eject_flag) {
1092: if (ioctl(s->fd, CDROMEJECT, NULL) < 0)
1093: perror("CDROMEJECT");
1094: } else {
1095: if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0)
1096: perror("CDROMEJECT");
1097: }
1098: }
1099:
1.1.1.7 ! root 1100: static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
1.1 root 1101: {
1102: BDRVRawState *s = bs->opaque;
1103:
1104: if (ioctl(s->fd, CDROM_LOCKDOOR, locked) < 0) {
1105: /*
1106: * Note: an error can happen if the distribution automatically
1107: * mounts the CD-ROM
1108: */
1109: /* perror("CDROM_LOCKDOOR"); */
1110: }
1111: }
1112:
1113: static BlockDriver bdrv_host_cdrom = {
1114: .format_name = "host_cdrom",
1.1.1.4 root 1115: .protocol_name = "host_cdrom",
1.1 root 1116: .instance_size = sizeof(BDRVRawState),
1117: .bdrv_probe_device = cdrom_probe_device,
1.1.1.4 root 1118: .bdrv_file_open = cdrom_open,
1.1 root 1119: .bdrv_close = raw_close,
1120: .bdrv_create = hdev_create,
1.1.1.2 root 1121: .create_options = raw_create_options,
1.1.1.4 root 1122: .bdrv_has_zero_init = hdev_has_zero_init,
1.1 root 1123:
1124: .bdrv_aio_readv = raw_aio_readv,
1125: .bdrv_aio_writev = raw_aio_writev,
1.1.1.2 root 1126: .bdrv_aio_flush = raw_aio_flush,
1.1 root 1127:
1.1.1.7 ! root 1128: .bdrv_truncate = raw_truncate,
1.1 root 1129: .bdrv_getlength = raw_getlength,
1.1.1.6 root 1130: .bdrv_get_allocated_file_size
1131: = raw_get_allocated_file_size,
1.1 root 1132:
1133: /* removable device support */
1134: .bdrv_is_inserted = cdrom_is_inserted,
1135: .bdrv_eject = cdrom_eject,
1.1.1.7 ! root 1136: .bdrv_lock_medium = cdrom_lock_medium,
1.1 root 1137:
1138: /* generic scsi device */
1139: .bdrv_ioctl = hdev_ioctl,
1140: .bdrv_aio_ioctl = hdev_aio_ioctl,
1141: };
1142: #endif /* __linux__ */
1143:
1.1.1.2 root 1144: #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 1145: static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
1146: {
1147: BDRVRawState *s = bs->opaque;
1148: int ret;
1149:
1150: s->type = FTYPE_CD;
1151:
1152: ret = raw_open_common(bs, filename, flags, 0);
1153: if (ret)
1154: return ret;
1155:
1156: /* make sure the door isnt locked at this time */
1157: ioctl(s->fd, CDIOCALLOW);
1158: return 0;
1159: }
1160:
1161: static int cdrom_probe_device(const char *filename)
1162: {
1163: if (strstart(filename, "/dev/cd", NULL) ||
1164: strstart(filename, "/dev/acd", NULL))
1165: return 100;
1166: return 0;
1167: }
1168:
1169: static int cdrom_reopen(BlockDriverState *bs)
1170: {
1171: BDRVRawState *s = bs->opaque;
1172: int fd;
1173:
1174: /*
1175: * Force reread of possibly changed/newly loaded disc,
1176: * FreeBSD seems to not notice sometimes...
1177: */
1178: if (s->fd >= 0)
1179: close(s->fd);
1180: fd = open(bs->filename, s->open_flags, 0644);
1181: if (fd < 0) {
1182: s->fd = -1;
1183: return -EIO;
1184: }
1185: s->fd = fd;
1186:
1187: /* make sure the door isnt locked at this time */
1188: ioctl(s->fd, CDIOCALLOW);
1189: return 0;
1190: }
1191:
1192: static int cdrom_is_inserted(BlockDriverState *bs)
1193: {
1194: return raw_getlength(bs) > 0;
1195: }
1196:
1.1.1.7 ! root 1197: static void cdrom_eject(BlockDriverState *bs, int eject_flag)
1.1 root 1198: {
1199: BDRVRawState *s = bs->opaque;
1200:
1201: if (s->fd < 0)
1.1.1.7 ! root 1202: return;
1.1 root 1203:
1204: (void) ioctl(s->fd, CDIOCALLOW);
1205:
1206: if (eject_flag) {
1207: if (ioctl(s->fd, CDIOCEJECT) < 0)
1208: perror("CDIOCEJECT");
1209: } else {
1210: if (ioctl(s->fd, CDIOCCLOSE) < 0)
1211: perror("CDIOCCLOSE");
1212: }
1213:
1.1.1.7 ! root 1214: cdrom_reopen(bs);
1.1 root 1215: }
1216:
1.1.1.7 ! root 1217: static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
1.1 root 1218: {
1219: BDRVRawState *s = bs->opaque;
1220:
1221: if (s->fd < 0)
1.1.1.7 ! root 1222: return;
1.1 root 1223: if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
1224: /*
1225: * Note: an error can happen if the distribution automatically
1226: * mounts the CD-ROM
1227: */
1228: /* perror("CDROM_LOCKDOOR"); */
1229: }
1230: }
1231:
1232: static BlockDriver bdrv_host_cdrom = {
1233: .format_name = "host_cdrom",
1.1.1.4 root 1234: .protocol_name = "host_cdrom",
1.1 root 1235: .instance_size = sizeof(BDRVRawState),
1236: .bdrv_probe_device = cdrom_probe_device,
1.1.1.4 root 1237: .bdrv_file_open = cdrom_open,
1.1 root 1238: .bdrv_close = raw_close,
1239: .bdrv_create = hdev_create,
1.1.1.2 root 1240: .create_options = raw_create_options,
1.1.1.4 root 1241: .bdrv_has_zero_init = hdev_has_zero_init,
1.1 root 1242:
1243: .bdrv_aio_readv = raw_aio_readv,
1244: .bdrv_aio_writev = raw_aio_writev,
1.1.1.2 root 1245: .bdrv_aio_flush = raw_aio_flush,
1.1 root 1246:
1.1.1.7 ! root 1247: .bdrv_truncate = raw_truncate,
1.1 root 1248: .bdrv_getlength = raw_getlength,
1.1.1.6 root 1249: .bdrv_get_allocated_file_size
1250: = raw_get_allocated_file_size,
1.1 root 1251:
1252: /* removable device support */
1253: .bdrv_is_inserted = cdrom_is_inserted,
1254: .bdrv_eject = cdrom_eject,
1.1.1.7 ! root 1255: .bdrv_lock_medium = cdrom_lock_medium,
1.1 root 1256: };
1257: #endif /* __FreeBSD__ */
1258:
1.1.1.4 root 1259: static void bdrv_file_init(void)
1.1 root 1260: {
1261: /*
1262: * Register all the drivers. Note that order is important, the driver
1263: * registered last will get probed first.
1264: */
1.1.1.4 root 1265: bdrv_register(&bdrv_file);
1.1 root 1266: bdrv_register(&bdrv_host_device);
1267: #ifdef __linux__
1268: bdrv_register(&bdrv_host_floppy);
1269: bdrv_register(&bdrv_host_cdrom);
1270: #endif
1.1.1.2 root 1271: #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1.1 root 1272: bdrv_register(&bdrv_host_cdrom);
1273: #endif
1274: }
1275:
1.1.1.4 root 1276: block_init(bdrv_file_init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.