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