qemu/block/raw-posix.c
<<
>>
Prefs
   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"
  30#include "block/raw-posix-aio.h"
  31
  32#if defined(__APPLE__) && (__MACH__)
  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__
  49#include <sys/types.h>
  50#include <sys/stat.h>
  51#include <sys/ioctl.h>
  52#include <sys/param.h>
  53#include <linux/cdrom.h>
  54#include <linux/fd.h>
  55#endif
  56#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
  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
  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
  74#ifdef __DragonFly__
  75#include <sys/ioctl.h>
  76#include <sys/diskslice.h>
  77#endif
  78
  79#ifdef CONFIG_XFS
  80#include <xfs/xfs.h>
  81#endif
  82
  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
 111/* if the FD is not accessed during that time (in ns), we try to
 112   reopen it to see if the disk has been changed */
 113#define FD_OPEN_TIMEOUT (1000000000)
 114
 115#define MAX_BLOCKSIZE   4096
 116
 117typedef 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
 128#ifdef CONFIG_LINUX_AIO
 129    int use_aio;
 130    void *aio_ctx;
 131#endif
 132    uint8_t *aligned_buf;
 133    unsigned aligned_buf_size;
 134#ifdef CONFIG_XFS
 135    bool is_xfs : 1;
 136#endif
 137} BDRVRawState;
 138
 139static int fd_open(BlockDriverState *bs);
 140static int64_t raw_getlength(BlockDriverState *bs);
 141
 142#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 143static int cdrom_reopen(BlockDriverState *bs);
 144#endif
 145
 146#if defined(__NetBSD__)
 147static 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
 178static int raw_normalize_devicepath(const char **filename)
 179{
 180    return 0;
 181}
 182#endif
 183
 184static 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
 190    ret = raw_normalize_devicepath(&filename);
 191    if (ret != 0) {
 192        return ret;
 193    }
 194
 195    s->open_flags = open_flags | O_BINARY;
 196    s->open_flags &= ~O_ACCMODE;
 197    if (bdrv_flags & BDRV_O_RDWR) {
 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;
 207    if (!(bdrv_flags & BDRV_O_CACHE_WB))
 208        s->open_flags |= O_DSYNC;
 209
 210    s->fd = -1;
 211    fd = qemu_open(filename, s->open_flags, 0644);
 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;
 220
 221    if ((bdrv_flags & BDRV_O_NOCACHE)) {
 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);
 228        if (s->aligned_buf == NULL) {
 229            goto out_close;
 230        }
 231    }
 232
 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
 238#ifdef CONFIG_LINUX_AIO
 239    /*
 240     * Currently Linux do AIO only for files opened with O_DIRECT
 241     * specified so check NOCACHE flag too
 242     */
 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
 259#ifdef CONFIG_XFS
 260    if (platform_test_xfs_fd(s->fd)) {
 261        s->is_xfs = 1;
 262    }
 263#endif
 264
 265    return 0;
 266
 267out_free_buf:
 268    qemu_vfree(s->aligned_buf);
 269out_close:
 270    close(fd);
 271    return -errno;
 272}
 273
 274static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 275{
 276    BDRVRawState *s = bs->opaque;
 277
 278    s->type = FTYPE_FILE;
 279    return raw_open_common(bs, filename, flags, 0);
 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, &sectorsize) &&
 287                sectorsize > bufsize)
 288                bufsize = sectorsize;
 289        }
 290#endif
 291#ifdef CONFIG_COCOA
 292        uint32_t blockSize = 512;
 293        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
 294            bufsize = blockSize;
 295        }
 296#endif
 297*/
 298
 299/*
 300 * Check if all memory in this vector is sector aligned.
 301 */
 302static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
 303{
 304    int i;
 305
 306    for (i = 0; i < qiov->niov; i++) {
 307        if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) {
 308            return 0;
 309        }
 310    }
 311
 312    return 1;
 313}
 314
 315static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
 316        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 317        BlockDriverCompletionFunc *cb, void *opaque, int type)
 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
 326     * boundary.  Check if this is the case or tell the low-level
 327     * driver that it needs to copy the buffer.
 328     */
 329    if (s->aligned_buf) {
 330        if (!qiov_is_aligned(bs, qiov)) {
 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    }
 339
 340    return paio_submit(bs, s->fd, sector_num, qiov, nb_sectors,
 341                       cb, opaque, type);
 342}
 343
 344static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
 345        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 346        BlockDriverCompletionFunc *cb, void *opaque)
 347{
 348    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
 349                          cb, opaque, QEMU_AIO_READ);
 350}
 351
 352static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
 353        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 354        BlockDriverCompletionFunc *cb, void *opaque)
 355{
 356    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
 357                          cb, opaque, QEMU_AIO_WRITE);
 358}
 359
 360static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
 361        BlockDriverCompletionFunc *cb, void *opaque)
 362{
 363    BDRVRawState *s = bs->opaque;
 364
 365    if (fd_open(bs) < 0)
 366        return NULL;
 367
 368    return paio_submit(bs, s->fd, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
 369}
 370
 371static 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)
 378            qemu_vfree(s->aligned_buf);
 379    }
 380}
 381
 382static int raw_truncate(BlockDriverState *bs, int64_t offset)
 383{
 384    BDRVRawState *s = bs->opaque;
 385    struct stat st;
 386
 387    if (fstat(s->fd, &st)) {
 388        return -errno;
 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
 403    return 0;
 404}
 405
 406#ifdef __OpenBSD__
 407static 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}
 425#elif defined(__NetBSD__)
 426static 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}
 450#elif defined(__sun__)
 451static 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)
 477static int64_t raw_getlength(BlockDriverState *bs)
 478{
 479    BDRVRawState *s = bs->opaque;
 480    int fd = s->fd;
 481    int64_t size;
 482    struct stat sb;
 483#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 484    int reopened = 0;
 485#endif
 486    int ret;
 487
 488    ret = fd_open(bs);
 489    if (ret < 0)
 490        return ret;
 491
 492#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 493again:
 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#if defined(__APPLE__) && defined(__MACH__)
 509        size = LONG_LONG_MAX;
 510#else
 511        size = lseek(fd, 0LL, SEEK_END);
 512#endif
 513#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 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
 526    } else {
 527        size = lseek(fd, 0, SEEK_END);
 528    }
 529    return size;
 530}
 531#else
 532static 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}
 544#endif
 545
 546static 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
 557static 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)) {
 566            total_size = options->value.n / BDRV_SECTOR_SIZE;
 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 {
 576        if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
 577            result = -errno;
 578        }
 579        if (close(fd) != 0) {
 580            result = -errno;
 581        }
 582    }
 583    return result;
 584}
 585
 586#ifdef CONFIG_XFS
 587static 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
 605static coroutine_fn int raw_co_discard(BlockDriverState *bs,
 606    int64_t sector_num, int nb_sectors)
 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}
 618
 619static QEMUOptionParameter raw_create_options[] = {
 620    {
 621        .name = BLOCK_OPT_SIZE,
 622        .type = OPT_SIZE,
 623        .help = "Virtual disk size"
 624    },
 625    { NULL }
 626};
 627
 628static BlockDriver bdrv_file = {
 629    .format_name = "file",
 630    .protocol_name = "file",
 631    .instance_size = sizeof(BDRVRawState),
 632    .bdrv_probe = NULL, /* no probe for protocols */
 633    .bdrv_file_open = raw_open,
 634    .bdrv_close = raw_close,
 635    .bdrv_create = raw_create,
 636    .bdrv_co_discard = raw_co_discard,
 637
 638    .bdrv_aio_readv = raw_aio_readv,
 639    .bdrv_aio_writev = raw_aio_writev,
 640    .bdrv_aio_flush = raw_aio_flush,
 641
 642    .bdrv_truncate = raw_truncate,
 643    .bdrv_getlength = raw_getlength,
 644    .bdrv_get_allocated_file_size
 645                        = raw_get_allocated_file_size,
 646
 647    .create_options = raw_create_options,
 648};
 649
 650/***********************************************/
 651/* host device */
 652
 653#if defined(__APPLE__) && defined(__MACH__)
 654static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
 655static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
 656
 657kern_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
 683kern_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
 711static 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
 727static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 728{
 729    BDRVRawState *s = bs->opaque;
 730
 731#if defined(__APPLE__) && defined(__MACH__)
 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;
 759#if defined(__linux__)
 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        }
 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. */
 777static 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 &&
 786        (get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
 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 &&
 795            (get_clock() - s->fd_error_time) < FD_OPEN_TIMEOUT) {
 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) {
 803            s->fd_error_time = get_clock();
 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;
 818    s->fd_open_time = get_clock();
 819    s->fd_got_error = 0;
 820    return 0;
 821}
 822
 823static 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
 830static 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;
 838    return paio_ioctl(bs, s->fd, req, buf, cb, opaque);
 839}
 840
 841#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 842static 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
 853static int fd_open(BlockDriverState *bs)
 854{
 855    return 0;
 856}
 857
 858#endif /* !linux && !FreeBSD */
 859
 860static 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")) {
 870            total_size = options->value.n / BDRV_SECTOR_SIZE;
 871        }
 872        options++;
 873    }
 874
 875    fd = open(filename, O_WRONLY | O_BINARY);
 876    if (fd < 0)
 877        return -errno;
 878
 879    if (fstat(fd, &stat_buf) < 0)
 880        ret = -errno;
 881    else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
 882        ret = -ENODEV;
 883    else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
 884        ret = -ENOSPC;
 885
 886    close(fd);
 887    return ret;
 888}
 889
 890static int hdev_has_zero_init(BlockDriverState *bs)
 891{
 892    return 0;
 893}
 894
 895static BlockDriver bdrv_host_device = {
 896    .format_name        = "host_device",
 897    .protocol_name        = "host_device",
 898    .instance_size      = sizeof(BDRVRawState),
 899    .bdrv_probe_device  = hdev_probe_device,
 900    .bdrv_file_open     = hdev_open,
 901    .bdrv_close         = raw_close,
 902    .bdrv_create        = hdev_create,
 903    .create_options     = raw_create_options,
 904    .bdrv_has_zero_init = hdev_has_zero_init,
 905
 906    .bdrv_aio_readv     = raw_aio_readv,
 907    .bdrv_aio_writev    = raw_aio_writev,
 908    .bdrv_aio_flush     = raw_aio_flush,
 909
 910    .bdrv_truncate      = raw_truncate,
 911    .bdrv_getlength     = raw_getlength,
 912    .bdrv_get_allocated_file_size
 913                        = raw_get_allocated_file_size,
 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__
 923static 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
 943static int floppy_probe_device(const char *filename)
 944{
 945    int fd, ret;
 946    int prio = 0;
 947    struct floppy_struct fdparam;
 948    struct stat st;
 949
 950    if (strstart(filename, "/dev/fd", NULL))
 951        prio = 50;
 952
 953    fd = open(filename, O_RDONLY | O_NONBLOCK);
 954    if (fd < 0) {
 955        goto out;
 956    }
 957    ret = fstat(fd, &st);
 958    if (ret == -1 || !S_ISBLK(st.st_mode)) {
 959        goto outc;
 960    }
 961
 962    /* Attempt to detect via a floppy specific ioctl */
 963    ret = ioctl(fd, FDGETPRM, &fdparam);
 964    if (ret >= 0)
 965        prio = 100;
 966
 967outc:
 968    close(fd);
 969out:
 970    return prio;
 971}
 972
 973
 974static int floppy_is_inserted(BlockDriverState *bs)
 975{
 976    return fd_open(bs) >= 0;
 977}
 978
 979static 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
 997static void floppy_eject(BlockDriverState *bs, bool eject_flag)
 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
1014static BlockDriver bdrv_host_floppy = {
1015    .format_name        = "host_floppy",
1016    .protocol_name      = "host_floppy",
1017    .instance_size      = sizeof(BDRVRawState),
1018    .bdrv_probe_device  = floppy_probe_device,
1019    .bdrv_file_open     = floppy_open,
1020    .bdrv_close         = raw_close,
1021    .bdrv_create        = hdev_create,
1022    .create_options     = raw_create_options,
1023    .bdrv_has_zero_init = hdev_has_zero_init,
1024
1025    .bdrv_aio_readv     = raw_aio_readv,
1026    .bdrv_aio_writev    = raw_aio_writev,
1027    .bdrv_aio_flush     = raw_aio_flush,
1028
1029    .bdrv_truncate      = raw_truncate,
1030    .bdrv_getlength     = raw_getlength,
1031    .bdrv_get_allocated_file_size
1032                        = raw_get_allocated_file_size,
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
1040static 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
1050static int cdrom_probe_device(const char *filename)
1051{
1052    int fd, ret;
1053    int prio = 0;
1054    struct stat st;
1055
1056    fd = open(filename, O_RDONLY | O_NONBLOCK);
1057    if (fd < 0) {
1058        goto out;
1059    }
1060    ret = fstat(fd, &st);
1061    if (ret == -1 || !S_ISBLK(st.st_mode)) {
1062        goto outc;
1063    }
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
1070outc:
1071    close(fd);
1072out:
1073    return prio;
1074}
1075
1076static 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
1087static void cdrom_eject(BlockDriverState *bs, bool eject_flag)
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
1100static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
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
1113static BlockDriver bdrv_host_cdrom = {
1114    .format_name        = "host_cdrom",
1115    .protocol_name      = "host_cdrom",
1116    .instance_size      = sizeof(BDRVRawState),
1117    .bdrv_probe_device  = cdrom_probe_device,
1118    .bdrv_file_open     = cdrom_open,
1119    .bdrv_close         = raw_close,
1120    .bdrv_create        = hdev_create,
1121    .create_options     = raw_create_options,
1122    .bdrv_has_zero_init = hdev_has_zero_init,
1123
1124    .bdrv_aio_readv     = raw_aio_readv,
1125    .bdrv_aio_writev    = raw_aio_writev,
1126    .bdrv_aio_flush     = raw_aio_flush,
1127
1128    .bdrv_truncate      = raw_truncate,
1129    .bdrv_getlength     = raw_getlength,
1130    .bdrv_get_allocated_file_size
1131                        = raw_get_allocated_file_size,
1132
1133    /* removable device support */
1134    .bdrv_is_inserted   = cdrom_is_inserted,
1135    .bdrv_eject         = cdrom_eject,
1136    .bdrv_lock_medium   = cdrom_lock_medium,
1137
1138    /* generic scsi device */
1139    .bdrv_ioctl         = hdev_ioctl,
1140    .bdrv_aio_ioctl     = hdev_aio_ioctl,
1141};
1142#endif /* __linux__ */
1143
1144#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1145static 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 isn't locked at this time */
1157    ioctl(s->fd, CDIOCALLOW);
1158    return 0;
1159}
1160
1161static 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
1169static 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 isn't locked at this time */
1188    ioctl(s->fd, CDIOCALLOW);
1189    return 0;
1190}
1191
1192static int cdrom_is_inserted(BlockDriverState *bs)
1193{
1194    return raw_getlength(bs) > 0;
1195}
1196
1197static void cdrom_eject(BlockDriverState *bs, bool eject_flag)
1198{
1199    BDRVRawState *s = bs->opaque;
1200
1201    if (s->fd < 0)
1202        return;
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
1214    cdrom_reopen(bs);
1215}
1216
1217static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
1218{
1219    BDRVRawState *s = bs->opaque;
1220
1221    if (s->fd < 0)
1222        return;
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
1232static BlockDriver bdrv_host_cdrom = {
1233    .format_name        = "host_cdrom",
1234    .protocol_name      = "host_cdrom",
1235    .instance_size      = sizeof(BDRVRawState),
1236    .bdrv_probe_device  = cdrom_probe_device,
1237    .bdrv_file_open     = cdrom_open,
1238    .bdrv_close         = raw_close,
1239    .bdrv_create        = hdev_create,
1240    .create_options     = raw_create_options,
1241    .bdrv_has_zero_init = hdev_has_zero_init,
1242
1243    .bdrv_aio_readv     = raw_aio_readv,
1244    .bdrv_aio_writev    = raw_aio_writev,
1245    .bdrv_aio_flush     = raw_aio_flush,
1246
1247    .bdrv_truncate      = raw_truncate,
1248    .bdrv_getlength     = raw_getlength,
1249    .bdrv_get_allocated_file_size
1250                        = raw_get_allocated_file_size,
1251
1252    /* removable device support */
1253    .bdrv_is_inserted   = cdrom_is_inserted,
1254    .bdrv_eject         = cdrom_eject,
1255    .bdrv_lock_medium   = cdrom_lock_medium,
1256};
1257#endif /* __FreeBSD__ */
1258
1259static void bdrv_file_init(void)
1260{
1261    /*
1262     * Register all the drivers.  Note that order is important, the driver
1263     * registered last will get probed first.
1264     */
1265    bdrv_register(&bdrv_file);
1266    bdrv_register(&bdrv_host_device);
1267#ifdef __linux__
1268    bdrv_register(&bdrv_host_floppy);
1269    bdrv_register(&bdrv_host_cdrom);
1270#endif
1271#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1272    bdrv_register(&bdrv_host_cdrom);
1273#endif
1274}
1275
1276block_init(bdrv_file_init);
1277