Statistics
| Branch: | Revision:

root / block / raw-posix.c @ 2dedf83e

History | View | Annotate | Download (35.9 kB)

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