Annotation of qemu/block-raw-posix.c, revision 1.1

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: #ifndef QEMU_IMG
        !            26: #include "qemu-timer.h"
        !            27: #include "exec-all.h"
        !            28: #endif
        !            29: #include "block_int.h"
        !            30: #include <assert.h>
        !            31: #include <aio.h>
        !            32: 
        !            33: #ifdef CONFIG_COCOA
        !            34: #include <paths.h>
        !            35: #include <sys/param.h>
        !            36: #include <IOKit/IOKitLib.h>
        !            37: #include <IOKit/IOBSD.h>
        !            38: #include <IOKit/storage/IOMediaBSDClient.h>
        !            39: #include <IOKit/storage/IOMedia.h>
        !            40: #include <IOKit/storage/IOCDMedia.h>
        !            41: //#include <IOKit/storage/IOCDTypes.h>
        !            42: #include <CoreFoundation/CoreFoundation.h>
        !            43: #endif
        !            44: 
        !            45: #ifdef __sun__
        !            46: #define _POSIX_PTHREAD_SEMANTICS 1
        !            47: #include <signal.h>
        !            48: #include <sys/dkio.h>
        !            49: #endif
        !            50: #ifdef __linux__
        !            51: #include <sys/ioctl.h>
        !            52: #include <linux/cdrom.h>
        !            53: #include <linux/fd.h>
        !            54: #endif
        !            55: #ifdef __FreeBSD__
        !            56: #include <sys/disk.h>
        !            57: #endif
        !            58: 
        !            59: //#define DEBUG_FLOPPY
        !            60: 
        !            61: //#define DEBUG_BLOCK
        !            62: #if defined(DEBUG_BLOCK) && !defined(QEMU_IMG)
        !            63: #define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
        !            64:     { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
        !            65: #else
        !            66: #define DEBUG_BLOCK_PRINT(formatCstr, args...)
        !            67: #endif
        !            68: 
        !            69: #define FTYPE_FILE   0
        !            70: #define FTYPE_CD     1
        !            71: #define FTYPE_FD     2
        !            72: 
        !            73: /* if the FD is not accessed during that time (in ms), we try to
        !            74:    reopen it to see if the disk has been changed */
        !            75: #define FD_OPEN_TIMEOUT 1000
        !            76: 
        !            77: typedef struct BDRVRawState {
        !            78:     int fd;
        !            79:     int type;
        !            80:     unsigned int lseek_err_cnt;
        !            81: #if defined(__linux__)
        !            82:     /* linux floppy specific */
        !            83:     int fd_open_flags;
        !            84:     int64_t fd_open_time;
        !            85:     int64_t fd_error_time;
        !            86:     int fd_got_error;
        !            87:     int fd_media_changed;
        !            88: #endif
        !            89: } BDRVRawState;
        !            90: 
        !            91: static int fd_open(BlockDriverState *bs);
        !            92: 
        !            93: static int raw_open(BlockDriverState *bs, const char *filename, int flags)
        !            94: {
        !            95:     BDRVRawState *s = bs->opaque;
        !            96:     int fd, open_flags, ret;
        !            97: 
        !            98:     s->lseek_err_cnt = 0;
        !            99: 
        !           100:     open_flags = O_BINARY;
        !           101:     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
        !           102:         open_flags |= O_RDWR;
        !           103:     } else {
        !           104:         open_flags |= O_RDONLY;
        !           105:         bs->read_only = 1;
        !           106:     }
        !           107:     if (flags & BDRV_O_CREAT)
        !           108:         open_flags |= O_CREAT | O_TRUNC;
        !           109: #ifdef O_DIRECT
        !           110:     if (flags & BDRV_O_DIRECT)
        !           111:         open_flags |= O_DIRECT;
        !           112: #endif
        !           113: 
        !           114:     s->type = FTYPE_FILE;
        !           115: 
        !           116:     fd = open(filename, open_flags, 0644);
        !           117:     if (fd < 0) {
        !           118:         ret = -errno;
        !           119:         if (ret == -EROFS)
        !           120:             ret = -EACCES;
        !           121:         return ret;
        !           122:     }
        !           123:     s->fd = fd;
        !           124:     return 0;
        !           125: }
        !           126: 
        !           127: /* XXX: use host sector size if necessary with:
        !           128: #ifdef DIOCGSECTORSIZE
        !           129:         {
        !           130:             unsigned int sectorsize = 512;
        !           131:             if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
        !           132:                 sectorsize > bufsize)
        !           133:                 bufsize = sectorsize;
        !           134:         }
        !           135: #endif
        !           136: #ifdef CONFIG_COCOA
        !           137:         u_int32_t   blockSize = 512;
        !           138:         if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
        !           139:             bufsize = blockSize;
        !           140:         }
        !           141: #endif
        !           142: */
        !           143: 
        !           144: static int raw_pread(BlockDriverState *bs, int64_t offset,
        !           145:                      uint8_t *buf, int count)
        !           146: {
        !           147:     BDRVRawState *s = bs->opaque;
        !           148:     int ret;
        !           149: 
        !           150:     ret = fd_open(bs);
        !           151:     if (ret < 0)
        !           152:         return ret;
        !           153: 
        !           154:     if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
        !           155:         ++(s->lseek_err_cnt);
        !           156:         if(s->lseek_err_cnt <= 10) {
        !           157:             DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
        !           158:                               "] lseek failed : %d = %s\n",
        !           159:                               s->fd, bs->filename, offset, buf, count,
        !           160:                               bs->total_sectors, errno, strerror(errno));
        !           161:         }
        !           162:         return -1;
        !           163:     }
        !           164:     s->lseek_err_cnt=0;
        !           165: 
        !           166:     ret = read(s->fd, buf, count);
        !           167:     if (ret == count)
        !           168:         goto label__raw_read__success;
        !           169: 
        !           170:     DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
        !           171:                       "] read failed %d : %d = %s\n",
        !           172:                       s->fd, bs->filename, offset, buf, count,
        !           173:                       bs->total_sectors, ret, errno, strerror(errno));
        !           174: 
        !           175:     /* Try harder for CDrom. */
        !           176:     if (bs->type == BDRV_TYPE_CDROM) {
        !           177:         lseek(s->fd, offset, SEEK_SET);
        !           178:         ret = read(s->fd, buf, count);
        !           179:         if (ret == count)
        !           180:             goto label__raw_read__success;
        !           181:         lseek(s->fd, offset, SEEK_SET);
        !           182:         ret = read(s->fd, buf, count);
        !           183:         if (ret == count)
        !           184:             goto label__raw_read__success;
        !           185: 
        !           186:         DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
        !           187:                           "] retry read failed %d : %d = %s\n",
        !           188:                           s->fd, bs->filename, offset, buf, count,
        !           189:                           bs->total_sectors, ret, errno, strerror(errno));
        !           190:     }
        !           191: 
        !           192: label__raw_read__success:
        !           193: 
        !           194:     return ret;
        !           195: }
        !           196: 
        !           197: static int raw_pwrite(BlockDriverState *bs, int64_t offset,
        !           198:                       const uint8_t *buf, int count)
        !           199: {
        !           200:     BDRVRawState *s = bs->opaque;
        !           201:     int ret;
        !           202: 
        !           203:     ret = fd_open(bs);
        !           204:     if (ret < 0)
        !           205:         return ret;
        !           206: 
        !           207:     if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
        !           208:         ++(s->lseek_err_cnt);
        !           209:         if(s->lseek_err_cnt) {
        !           210:             DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
        !           211:                               PRId64 "] lseek failed : %d = %s\n",
        !           212:                               s->fd, bs->filename, offset, buf, count,
        !           213:                               bs->total_sectors, errno, strerror(errno));
        !           214:         }
        !           215:         return -1;
        !           216:     }
        !           217:     s->lseek_err_cnt = 0;
        !           218: 
        !           219:     ret = write(s->fd, buf, count);
        !           220:     if (ret == count)
        !           221:         goto label__raw_write__success;
        !           222: 
        !           223:     DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
        !           224:                       "] write failed %d : %d = %s\n",
        !           225:                       s->fd, bs->filename, offset, buf, count,
        !           226:                       bs->total_sectors, ret, errno, strerror(errno));
        !           227: 
        !           228: label__raw_write__success:
        !           229: 
        !           230:     return ret;
        !           231: }
        !           232: 
        !           233: /***********************************************************/
        !           234: /* Unix AIO using POSIX AIO */
        !           235: 
        !           236: typedef struct RawAIOCB {
        !           237:     BlockDriverAIOCB common;
        !           238:     struct aiocb aiocb;
        !           239:     struct RawAIOCB *next;
        !           240: } RawAIOCB;
        !           241: 
        !           242: static int aio_sig_num = SIGUSR2;
        !           243: static RawAIOCB *first_aio; /* AIO issued */
        !           244: static int aio_initialized = 0;
        !           245: 
        !           246: static void aio_signal_handler(int signum)
        !           247: {
        !           248: #ifndef QEMU_IMG
        !           249:     CPUState *env = cpu_single_env;
        !           250:     if (env) {
        !           251:         /* stop the currently executing cpu because a timer occured */
        !           252:         cpu_interrupt(env, CPU_INTERRUPT_EXIT);
        !           253: #ifdef USE_KQEMU
        !           254:         if (env->kqemu_enabled) {
        !           255:             kqemu_cpu_interrupt(env);
        !           256:         }
        !           257: #endif
        !           258:     }
        !           259: #endif
        !           260: }
        !           261: 
        !           262: void qemu_aio_init(void)
        !           263: {
        !           264:     struct sigaction act;
        !           265: 
        !           266:     aio_initialized = 1;
        !           267: 
        !           268:     sigfillset(&act.sa_mask);
        !           269:     act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
        !           270:     act.sa_handler = aio_signal_handler;
        !           271:     sigaction(aio_sig_num, &act, NULL);
        !           272: 
        !           273: #if defined(__GLIBC__) && defined(__linux__)
        !           274:     {
        !           275:         /* XXX: aio thread exit seems to hang on RedHat 9 and this init
        !           276:            seems to fix the problem. */
        !           277:         struct aioinit ai;
        !           278:         memset(&ai, 0, sizeof(ai));
        !           279:         ai.aio_threads = 1;
        !           280:         ai.aio_num = 1;
        !           281:         ai.aio_idle_time = 365 * 100000;
        !           282:         aio_init(&ai);
        !           283:     }
        !           284: #endif
        !           285: }
        !           286: 
        !           287: void qemu_aio_poll(void)
        !           288: {
        !           289:     RawAIOCB *acb, **pacb;
        !           290:     int ret;
        !           291: 
        !           292:     for(;;) {
        !           293:         pacb = &first_aio;
        !           294:         for(;;) {
        !           295:             acb = *pacb;
        !           296:             if (!acb)
        !           297:                 goto the_end;
        !           298:             ret = aio_error(&acb->aiocb);
        !           299:             if (ret == ECANCELED) {
        !           300:                 /* remove the request */
        !           301:                 *pacb = acb->next;
        !           302:                 qemu_aio_release(acb);
        !           303:             } else if (ret != EINPROGRESS) {
        !           304:                 /* end of aio */
        !           305:                 if (ret == 0) {
        !           306:                     ret = aio_return(&acb->aiocb);
        !           307:                     if (ret == acb->aiocb.aio_nbytes)
        !           308:                         ret = 0;
        !           309:                     else
        !           310:                         ret = -EINVAL;
        !           311:                 } else {
        !           312:                     ret = -ret;
        !           313:                 }
        !           314:                 /* remove the request */
        !           315:                 *pacb = acb->next;
        !           316:                 /* call the callback */
        !           317:                 acb->common.cb(acb->common.opaque, ret);
        !           318:                 qemu_aio_release(acb);
        !           319:                 break;
        !           320:             } else {
        !           321:                 pacb = &acb->next;
        !           322:             }
        !           323:         }
        !           324:     }
        !           325:  the_end: ;
        !           326: }
        !           327: 
        !           328: /* Wait for all IO requests to complete.  */
        !           329: void qemu_aio_flush(void)
        !           330: {
        !           331:     qemu_aio_wait_start();
        !           332:     qemu_aio_poll();
        !           333:     while (first_aio) {
        !           334:         qemu_aio_wait();
        !           335:     }
        !           336:     qemu_aio_wait_end();
        !           337: }
        !           338: 
        !           339: /* wait until at least one AIO was handled */
        !           340: static sigset_t wait_oset;
        !           341: 
        !           342: void qemu_aio_wait_start(void)
        !           343: {
        !           344:     sigset_t set;
        !           345: 
        !           346:     if (!aio_initialized)
        !           347:         qemu_aio_init();
        !           348:     sigemptyset(&set);
        !           349:     sigaddset(&set, aio_sig_num);
        !           350:     sigprocmask(SIG_BLOCK, &set, &wait_oset);
        !           351: }
        !           352: 
        !           353: void qemu_aio_wait(void)
        !           354: {
        !           355:     sigset_t set;
        !           356:     int nb_sigs;
        !           357: 
        !           358: #ifndef QEMU_IMG
        !           359:     if (qemu_bh_poll())
        !           360:         return;
        !           361: #endif
        !           362:     sigemptyset(&set);
        !           363:     sigaddset(&set, aio_sig_num);
        !           364:     sigwait(&set, &nb_sigs);
        !           365:     qemu_aio_poll();
        !           366: }
        !           367: 
        !           368: void qemu_aio_wait_end(void)
        !           369: {
        !           370:     sigprocmask(SIG_SETMASK, &wait_oset, NULL);
        !           371: }
        !           372: 
        !           373: static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
        !           374:         int64_t sector_num, uint8_t *buf, int nb_sectors,
        !           375:         BlockDriverCompletionFunc *cb, void *opaque)
        !           376: {
        !           377:     BDRVRawState *s = bs->opaque;
        !           378:     RawAIOCB *acb;
        !           379: 
        !           380:     if (fd_open(bs) < 0)
        !           381:         return NULL;
        !           382: 
        !           383:     acb = qemu_aio_get(bs, cb, opaque);
        !           384:     if (!acb)
        !           385:         return NULL;
        !           386:     acb->aiocb.aio_fildes = s->fd;
        !           387:     acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
        !           388:     acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
        !           389:     acb->aiocb.aio_buf = buf;
        !           390:     if (nb_sectors < 0)
        !           391:         acb->aiocb.aio_nbytes = -nb_sectors;
        !           392:     else
        !           393:         acb->aiocb.aio_nbytes = nb_sectors * 512;
        !           394:     acb->aiocb.aio_offset = sector_num * 512;
        !           395:     acb->next = first_aio;
        !           396:     first_aio = acb;
        !           397:     return acb;
        !           398: }
        !           399: 
        !           400: static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
        !           401:         int64_t sector_num, uint8_t *buf, int nb_sectors,
        !           402:         BlockDriverCompletionFunc *cb, void *opaque)
        !           403: {
        !           404:     RawAIOCB *acb;
        !           405: 
        !           406:     acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
        !           407:     if (!acb)
        !           408:         return NULL;
        !           409:     if (aio_read(&acb->aiocb) < 0) {
        !           410:         qemu_aio_release(acb);
        !           411:         return NULL;
        !           412:     }
        !           413:     return &acb->common;
        !           414: }
        !           415: 
        !           416: static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
        !           417:         int64_t sector_num, const uint8_t *buf, int nb_sectors,
        !           418:         BlockDriverCompletionFunc *cb, void *opaque)
        !           419: {
        !           420:     RawAIOCB *acb;
        !           421: 
        !           422:     acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
        !           423:     if (!acb)
        !           424:         return NULL;
        !           425:     if (aio_write(&acb->aiocb) < 0) {
        !           426:         qemu_aio_release(acb);
        !           427:         return NULL;
        !           428:     }
        !           429:     return &acb->common;
        !           430: }
        !           431: 
        !           432: static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
        !           433: {
        !           434:     int ret;
        !           435:     RawAIOCB *acb = (RawAIOCB *)blockacb;
        !           436:     RawAIOCB **pacb;
        !           437: 
        !           438:     ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
        !           439:     if (ret == AIO_NOTCANCELED) {
        !           440:         /* fail safe: if the aio could not be canceled, we wait for
        !           441:            it */
        !           442:         while (aio_error(&acb->aiocb) == EINPROGRESS);
        !           443:     }
        !           444: 
        !           445:     /* remove the callback from the queue */
        !           446:     pacb = &first_aio;
        !           447:     for(;;) {
        !           448:         if (*pacb == NULL) {
        !           449:             break;
        !           450:         } else if (*pacb == acb) {
        !           451:             *pacb = acb->next;
        !           452:             qemu_aio_release(acb);
        !           453:             break;
        !           454:         }
        !           455:         pacb = &acb->next;
        !           456:     }
        !           457: }
        !           458: 
        !           459: static void raw_close(BlockDriverState *bs)
        !           460: {
        !           461:     BDRVRawState *s = bs->opaque;
        !           462:     if (s->fd >= 0) {
        !           463:         close(s->fd);
        !           464:         s->fd = -1;
        !           465:     }
        !           466: }
        !           467: 
        !           468: static int raw_truncate(BlockDriverState *bs, int64_t offset)
        !           469: {
        !           470:     BDRVRawState *s = bs->opaque;
        !           471:     if (s->type != FTYPE_FILE)
        !           472:         return -ENOTSUP;
        !           473:     if (ftruncate(s->fd, offset) < 0)
        !           474:         return -errno;
        !           475:     return 0;
        !           476: }
        !           477: 
        !           478: static int64_t  raw_getlength(BlockDriverState *bs)
        !           479: {
        !           480:     BDRVRawState *s = bs->opaque;
        !           481:     int fd = s->fd;
        !           482:     int64_t size;
        !           483: #ifdef _BSD
        !           484:     struct stat sb;
        !           485: #endif
        !           486: #ifdef __sun__
        !           487:     struct dk_minfo minfo;
        !           488:     int rv;
        !           489: #endif
        !           490:     int ret;
        !           491: 
        !           492:     ret = fd_open(bs);
        !           493:     if (ret < 0)
        !           494:         return ret;
        !           495: 
        !           496: #ifdef _BSD
        !           497:     if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
        !           498: #ifdef DIOCGMEDIASIZE
        !           499:        if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
        !           500: #endif
        !           501: #ifdef CONFIG_COCOA
        !           502:         size = LONG_LONG_MAX;
        !           503: #else
        !           504:         size = lseek(fd, 0LL, SEEK_END);
        !           505: #endif
        !           506:     } else
        !           507: #endif
        !           508: #ifdef __sun__
        !           509:     /*
        !           510:      * use the DKIOCGMEDIAINFO ioctl to read the size.
        !           511:      */
        !           512:     rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
        !           513:     if ( rv != -1 ) {
        !           514:         size = minfo.dki_lbsize * minfo.dki_capacity;
        !           515:     } else /* there are reports that lseek on some devices
        !           516:               fails, but irc discussion said that contingency
        !           517:               on contingency was overkill */
        !           518: #endif
        !           519:     {
        !           520:         size = lseek(fd, 0, SEEK_END);
        !           521:     }
        !           522:     return size;
        !           523: }
        !           524: 
        !           525: static int raw_create(const char *filename, int64_t total_size,
        !           526:                       const char *backing_file, int flags)
        !           527: {
        !           528:     int fd;
        !           529: 
        !           530:     if (flags || backing_file)
        !           531:         return -ENOTSUP;
        !           532: 
        !           533:     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
        !           534:               0644);
        !           535:     if (fd < 0)
        !           536:         return -EIO;
        !           537:     ftruncate(fd, total_size * 512);
        !           538:     close(fd);
        !           539:     return 0;
        !           540: }
        !           541: 
        !           542: static void raw_flush(BlockDriverState *bs)
        !           543: {
        !           544:     BDRVRawState *s = bs->opaque;
        !           545:     fsync(s->fd);
        !           546: }
        !           547: 
        !           548: BlockDriver bdrv_raw = {
        !           549:     "raw",
        !           550:     sizeof(BDRVRawState),
        !           551:     NULL, /* no probe for protocols */
        !           552:     raw_open,
        !           553:     NULL,
        !           554:     NULL,
        !           555:     raw_close,
        !           556:     raw_create,
        !           557:     raw_flush,
        !           558: 
        !           559:     .bdrv_aio_read = raw_aio_read,
        !           560:     .bdrv_aio_write = raw_aio_write,
        !           561:     .bdrv_aio_cancel = raw_aio_cancel,
        !           562:     .aiocb_size = sizeof(RawAIOCB),
        !           563:     .protocol_name = "file",
        !           564:     .bdrv_pread = raw_pread,
        !           565:     .bdrv_pwrite = raw_pwrite,
        !           566:     .bdrv_truncate = raw_truncate,
        !           567:     .bdrv_getlength = raw_getlength,
        !           568: };
        !           569: 
        !           570: /***********************************************/
        !           571: /* host device */
        !           572: 
        !           573: #ifdef CONFIG_COCOA
        !           574: static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
        !           575: static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
        !           576: 
        !           577: kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
        !           578: {
        !           579:     kern_return_t       kernResult;
        !           580:     mach_port_t     masterPort;
        !           581:     CFMutableDictionaryRef  classesToMatch;
        !           582: 
        !           583:     kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
        !           584:     if ( KERN_SUCCESS != kernResult ) {
        !           585:         printf( "IOMasterPort returned %d\n", kernResult );
        !           586:     }
        !           587: 
        !           588:     classesToMatch = IOServiceMatching( kIOCDMediaClass );
        !           589:     if ( classesToMatch == NULL ) {
        !           590:         printf( "IOServiceMatching returned a NULL dictionary.\n" );
        !           591:     } else {
        !           592:     CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
        !           593:     }
        !           594:     kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
        !           595:     if ( KERN_SUCCESS != kernResult )
        !           596:     {
        !           597:         printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
        !           598:     }
        !           599: 
        !           600:     return kernResult;
        !           601: }
        !           602: 
        !           603: kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
        !           604: {
        !           605:     io_object_t     nextMedia;
        !           606:     kern_return_t   kernResult = KERN_FAILURE;
        !           607:     *bsdPath = '\0';
        !           608:     nextMedia = IOIteratorNext( mediaIterator );
        !           609:     if ( nextMedia )
        !           610:     {
        !           611:         CFTypeRef   bsdPathAsCFString;
        !           612:     bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
        !           613:         if ( bsdPathAsCFString ) {
        !           614:             size_t devPathLength;
        !           615:             strcpy( bsdPath, _PATH_DEV );
        !           616:             strcat( bsdPath, "r" );
        !           617:             devPathLength = strlen( bsdPath );
        !           618:             if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
        !           619:                 kernResult = KERN_SUCCESS;
        !           620:             }
        !           621:             CFRelease( bsdPathAsCFString );
        !           622:         }
        !           623:         IOObjectRelease( nextMedia );
        !           624:     }
        !           625: 
        !           626:     return kernResult;
        !           627: }
        !           628: 
        !           629: #endif
        !           630: 
        !           631: static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
        !           632: {
        !           633:     BDRVRawState *s = bs->opaque;
        !           634:     int fd, open_flags, ret;
        !           635: 
        !           636: #ifdef CONFIG_COCOA
        !           637:     if (strstart(filename, "/dev/cdrom", NULL)) {
        !           638:         kern_return_t kernResult;
        !           639:         io_iterator_t mediaIterator;
        !           640:         char bsdPath[ MAXPATHLEN ];
        !           641:         int fd;
        !           642: 
        !           643:         kernResult = FindEjectableCDMedia( &mediaIterator );
        !           644:         kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
        !           645: 
        !           646:         if ( bsdPath[ 0 ] != '\0' ) {
        !           647:             strcat(bsdPath,"s0");
        !           648:             /* some CDs don't have a partition 0 */
        !           649:             fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
        !           650:             if (fd < 0) {
        !           651:                 bsdPath[strlen(bsdPath)-1] = '1';
        !           652:             } else {
        !           653:                 close(fd);
        !           654:             }
        !           655:             filename = bsdPath;
        !           656:         }
        !           657: 
        !           658:         if ( mediaIterator )
        !           659:             IOObjectRelease( mediaIterator );
        !           660:     }
        !           661: #endif
        !           662:     open_flags = O_BINARY;
        !           663:     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
        !           664:         open_flags |= O_RDWR;
        !           665:     } else {
        !           666:         open_flags |= O_RDONLY;
        !           667:         bs->read_only = 1;
        !           668:     }
        !           669: #ifdef O_DIRECT
        !           670:     if (flags & BDRV_O_DIRECT)
        !           671:         open_flags |= O_DIRECT;
        !           672: #endif
        !           673: 
        !           674:     s->type = FTYPE_FILE;
        !           675: #if defined(__linux__)
        !           676:     if (strstart(filename, "/dev/cd", NULL)) {
        !           677:         /* open will not fail even if no CD is inserted */
        !           678:         open_flags |= O_NONBLOCK;
        !           679:         s->type = FTYPE_CD;
        !           680:     } else if (strstart(filename, "/dev/fd", NULL)) {
        !           681:         s->type = FTYPE_FD;
        !           682:         s->fd_open_flags = open_flags;
        !           683:         /* open will not fail even if no floppy is inserted */
        !           684:         open_flags |= O_NONBLOCK;
        !           685:     } else if (strstart(filename, "/dev/sg", NULL)) {
        !           686:         bs->sg = 1;
        !           687:     }
        !           688: #endif
        !           689:     fd = open(filename, open_flags, 0644);
        !           690:     if (fd < 0) {
        !           691:         ret = -errno;
        !           692:         if (ret == -EROFS)
        !           693:             ret = -EACCES;
        !           694:         return ret;
        !           695:     }
        !           696:     s->fd = fd;
        !           697: #if defined(__linux__)
        !           698:     /* close fd so that we can reopen it as needed */
        !           699:     if (s->type == FTYPE_FD) {
        !           700:         close(s->fd);
        !           701:         s->fd = -1;
        !           702:         s->fd_media_changed = 1;
        !           703:     }
        !           704: #endif
        !           705:     return 0;
        !           706: }
        !           707: 
        !           708: #if defined(__linux__) && !defined(QEMU_IMG)
        !           709: 
        !           710: /* Note: we do not have a reliable method to detect if the floppy is
        !           711:    present. The current method is to try to open the floppy at every
        !           712:    I/O and to keep it opened during a few hundreds of ms. */
        !           713: static int fd_open(BlockDriverState *bs)
        !           714: {
        !           715:     BDRVRawState *s = bs->opaque;
        !           716:     int last_media_present;
        !           717: 
        !           718:     if (s->type != FTYPE_FD)
        !           719:         return 0;
        !           720:     last_media_present = (s->fd >= 0);
        !           721:     if (s->fd >= 0 &&
        !           722:         (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
        !           723:         close(s->fd);
        !           724:         s->fd = -1;
        !           725: #ifdef DEBUG_FLOPPY
        !           726:         printf("Floppy closed\n");
        !           727: #endif
        !           728:     }
        !           729:     if (s->fd < 0) {
        !           730:         if (s->fd_got_error &&
        !           731:             (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
        !           732: #ifdef DEBUG_FLOPPY
        !           733:             printf("No floppy (open delayed)\n");
        !           734: #endif
        !           735:             return -EIO;
        !           736:         }
        !           737:         s->fd = open(bs->filename, s->fd_open_flags);
        !           738:         if (s->fd < 0) {
        !           739:             s->fd_error_time = qemu_get_clock(rt_clock);
        !           740:             s->fd_got_error = 1;
        !           741:             if (last_media_present)
        !           742:                 s->fd_media_changed = 1;
        !           743: #ifdef DEBUG_FLOPPY
        !           744:             printf("No floppy\n");
        !           745: #endif
        !           746:             return -EIO;
        !           747:         }
        !           748: #ifdef DEBUG_FLOPPY
        !           749:         printf("Floppy opened\n");
        !           750: #endif
        !           751:     }
        !           752:     if (!last_media_present)
        !           753:         s->fd_media_changed = 1;
        !           754:     s->fd_open_time = qemu_get_clock(rt_clock);
        !           755:     s->fd_got_error = 0;
        !           756:     return 0;
        !           757: }
        !           758: #else
        !           759: static int fd_open(BlockDriverState *bs)
        !           760: {
        !           761:     return 0;
        !           762: }
        !           763: #endif
        !           764: 
        !           765: #if defined(__linux__)
        !           766: 
        !           767: static int raw_is_inserted(BlockDriverState *bs)
        !           768: {
        !           769:     BDRVRawState *s = bs->opaque;
        !           770:     int ret;
        !           771: 
        !           772:     switch(s->type) {
        !           773:     case FTYPE_CD:
        !           774:         ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
        !           775:         if (ret == CDS_DISC_OK)
        !           776:             return 1;
        !           777:         else
        !           778:             return 0;
        !           779:         break;
        !           780:     case FTYPE_FD:
        !           781:         ret = fd_open(bs);
        !           782:         return (ret >= 0);
        !           783:     default:
        !           784:         return 1;
        !           785:     }
        !           786: }
        !           787: 
        !           788: /* currently only used by fdc.c, but a CD version would be good too */
        !           789: static int raw_media_changed(BlockDriverState *bs)
        !           790: {
        !           791:     BDRVRawState *s = bs->opaque;
        !           792: 
        !           793:     switch(s->type) {
        !           794:     case FTYPE_FD:
        !           795:         {
        !           796:             int ret;
        !           797:             /* XXX: we do not have a true media changed indication. It
        !           798:                does not work if the floppy is changed without trying
        !           799:                to read it */
        !           800:             fd_open(bs);
        !           801:             ret = s->fd_media_changed;
        !           802:             s->fd_media_changed = 0;
        !           803: #ifdef DEBUG_FLOPPY
        !           804:             printf("Floppy changed=%d\n", ret);
        !           805: #endif
        !           806:             return ret;
        !           807:         }
        !           808:     default:
        !           809:         return -ENOTSUP;
        !           810:     }
        !           811: }
        !           812: 
        !           813: static int raw_eject(BlockDriverState *bs, int eject_flag)
        !           814: {
        !           815:     BDRVRawState *s = bs->opaque;
        !           816: 
        !           817:     switch(s->type) {
        !           818:     case FTYPE_CD:
        !           819:         if (eject_flag) {
        !           820:             if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
        !           821:                 perror("CDROMEJECT");
        !           822:         } else {
        !           823:             if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
        !           824:                 perror("CDROMEJECT");
        !           825:         }
        !           826:         break;
        !           827:     case FTYPE_FD:
        !           828:         {
        !           829:             int fd;
        !           830:             if (s->fd >= 0) {
        !           831:                 close(s->fd);
        !           832:                 s->fd = -1;
        !           833:             }
        !           834:             fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
        !           835:             if (fd >= 0) {
        !           836:                 if (ioctl(fd, FDEJECT, 0) < 0)
        !           837:                     perror("FDEJECT");
        !           838:                 close(fd);
        !           839:             }
        !           840:         }
        !           841:         break;
        !           842:     default:
        !           843:         return -ENOTSUP;
        !           844:     }
        !           845:     return 0;
        !           846: }
        !           847: 
        !           848: static int raw_set_locked(BlockDriverState *bs, int locked)
        !           849: {
        !           850:     BDRVRawState *s = bs->opaque;
        !           851: 
        !           852:     switch(s->type) {
        !           853:     case FTYPE_CD:
        !           854:         if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
        !           855:             /* Note: an error can happen if the distribution automatically
        !           856:                mounts the CD-ROM */
        !           857:             //        perror("CDROM_LOCKDOOR");
        !           858:         }
        !           859:         break;
        !           860:     default:
        !           861:         return -ENOTSUP;
        !           862:     }
        !           863:     return 0;
        !           864: }
        !           865: 
        !           866: static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
        !           867: {
        !           868:     BDRVRawState *s = bs->opaque;
        !           869: 
        !           870:     return ioctl(s->fd, req, buf);
        !           871: }
        !           872: #else
        !           873: 
        !           874: static int raw_is_inserted(BlockDriverState *bs)
        !           875: {
        !           876:     return 1;
        !           877: }
        !           878: 
        !           879: static int raw_media_changed(BlockDriverState *bs)
        !           880: {
        !           881:     return -ENOTSUP;
        !           882: }
        !           883: 
        !           884: static int raw_eject(BlockDriverState *bs, int eject_flag)
        !           885: {
        !           886:     return -ENOTSUP;
        !           887: }
        !           888: 
        !           889: static int raw_set_locked(BlockDriverState *bs, int locked)
        !           890: {
        !           891:     return -ENOTSUP;
        !           892: }
        !           893: 
        !           894: static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
        !           895: {
        !           896:     return -ENOTSUP;
        !           897: }
        !           898: #endif /* !linux */
        !           899: 
        !           900: BlockDriver bdrv_host_device = {
        !           901:     "host_device",
        !           902:     sizeof(BDRVRawState),
        !           903:     NULL, /* no probe for protocols */
        !           904:     hdev_open,
        !           905:     NULL,
        !           906:     NULL,
        !           907:     raw_close,
        !           908:     NULL,
        !           909:     raw_flush,
        !           910: 
        !           911:     .bdrv_aio_read = raw_aio_read,
        !           912:     .bdrv_aio_write = raw_aio_write,
        !           913:     .bdrv_aio_cancel = raw_aio_cancel,
        !           914:     .aiocb_size = sizeof(RawAIOCB),
        !           915:     .bdrv_pread = raw_pread,
        !           916:     .bdrv_pwrite = raw_pwrite,
        !           917:     .bdrv_getlength = raw_getlength,
        !           918: 
        !           919:     /* removable device support */
        !           920:     .bdrv_is_inserted = raw_is_inserted,
        !           921:     .bdrv_media_changed = raw_media_changed,
        !           922:     .bdrv_eject = raw_eject,
        !           923:     .bdrv_set_locked = raw_set_locked,
        !           924:     /* generic scsi device */
        !           925:     .bdrv_ioctl = raw_ioctl,
        !           926: };

unix.superglobalmegacorp.com