aboutsummaryrefslogtreecommitdiff
path: root/block-raw-posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'block-raw-posix.c')
-rw-r--r--block-raw-posix.c155
1 files changed, 153 insertions, 2 deletions
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 1a1a1781bc..be6dd8333f 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -55,6 +55,7 @@
#ifdef __FreeBSD__
#include <signal.h>
#include <sys/disk.h>
+#include <sys/cdio.h>
#endif
#ifdef __OpenBSD__
@@ -110,6 +111,9 @@ typedef struct BDRVRawState {
int fd_got_error;
int fd_media_changed;
#endif
+#if defined(__FreeBSD__)
+ int cd_open_flags;
+#endif
uint8_t* aligned_buf;
} BDRVRawState;
@@ -117,6 +121,12 @@ static int posix_aio_init(void);
static int fd_open(BlockDriverState *bs);
+#if defined(__FreeBSD__)
+static int cd_open(BlockDriverState *bs);
+#endif
+
+static int raw_is_inserted(BlockDriverState *bs);
+
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
@@ -773,6 +783,9 @@ static int64_t raw_getlength(BlockDriverState *bs)
int64_t size;
#ifdef HOST_BSD
struct stat sb;
+#ifdef __FreeBSD__
+ int reopened = 0;
+#endif
#endif
#ifdef __sun__
struct dk_minfo minfo;
@@ -785,6 +798,9 @@ static int64_t raw_getlength(BlockDriverState *bs)
return ret;
#ifdef HOST_BSD
+#ifdef __FreeBSD__
+again:
+#endif
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
#ifdef DIOCGMEDIASIZE
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
@@ -803,6 +819,19 @@ static int64_t raw_getlength(BlockDriverState *bs)
#else
size = lseek(fd, 0LL, SEEK_END);
#endif
+#ifdef __FreeBSD__
+ switch(s->type) {
+ case FTYPE_CD:
+ /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
+ if (size == 2048LL * (unsigned)-1)
+ size = 0;
+ /* XXX no disc? maybe we need to reopen... */
+ if (size <= 0 && !reopened && cd_open(bs) >= 0) {
+ reopened = 1;
+ goto again;
+ }
+ }
+#endif
} else
#endif
#ifdef __sun__
@@ -993,6 +1022,14 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
bs->sg = 1;
}
#endif
+#if defined(__FreeBSD__)
+ if (strstart(filename, "/dev/cd", NULL) ||
+ strstart(filename, "/dev/acd", NULL)) {
+ s->type = FTYPE_CD;
+ s->cd_open_flags = open_flags;
+ }
+#endif
+ s->fd = -1;
fd = open(filename, open_flags, 0644);
if (fd < 0) {
ret = -errno;
@@ -1001,6 +1038,11 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
return ret;
}
s->fd = fd;
+#if defined(__FreeBSD__)
+ /* make sure the door isnt locked at this time */
+ if (s->type == FTYPE_CD)
+ ioctl (s->fd, CDIOCALLOW);
+#endif
#if defined(__linux__)
/* close fd so that we can reopen it as needed */
if (s->type == FTYPE_FD) {
@@ -1167,7 +1209,116 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return ioctl(s->fd, req, buf);
}
-#else
+#elif defined(__FreeBSD__)
+
+static int fd_open(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+
+ /* this is just to ensure s->fd is sane (its called by io ops) */
+ if (s->fd >= 0)
+ return 0;
+ return -EIO;
+}
+
+static int cd_open(BlockDriverState *bs)
+{
+#if defined(__FreeBSD__)
+ BDRVRawState *s = bs->opaque;
+ int fd;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ /* XXX force reread of possibly changed/newly loaded disc,
+ * FreeBSD seems to not notice sometimes... */
+ if (s->fd >= 0)
+ close (s->fd);
+ fd = open(bs->filename, s->cd_open_flags, 0644);
+ if (fd < 0) {
+ s->fd = -1;
+ return -EIO;
+ }
+ s->fd = fd;
+ /* make sure the door isnt locked at this time */
+ ioctl (s->fd, CDIOCALLOW);
+ }
+#endif
+ return 0;
+}
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ return (raw_getlength(bs) > 0);
+ case FTYPE_FD:
+ /* XXX handle this */
+ /* FALLTHRU */
+ default:
+ return 1;
+ }
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+ return -ENOTSUP;
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (s->fd < 0)
+ return -ENOTSUP;
+ (void) ioctl (s->fd, CDIOCALLOW);
+ if (eject_flag) {
+ if (ioctl (s->fd, CDIOCEJECT) < 0)
+ perror("CDIOCEJECT");
+ } else {
+ if (ioctl (s->fd, CDIOCCLOSE) < 0)
+ perror("CDIOCCLOSE");
+ }
+ if (cd_open(bs) < 0)
+ return -ENOTSUP;
+ break;
+ case FTYPE_FD:
+ /* XXX handle this */
+ /* FALLTHRU */
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (s->fd < 0)
+ return -ENOTSUP;
+ if (ioctl (s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
+ /* Note: an error can happen if the distribution automatically
+ mounts the CD-ROM */
+ // perror("CDROM_LOCKDOOR");
+ }
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+{
+ return -ENOTSUP;
+}
+#else /* !linux && !FreeBSD */
static int fd_open(BlockDriverState *bs)
{
@@ -1198,7 +1349,7 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
return -ENOTSUP;
}
-#endif /* !linux */
+#endif /* !linux && !FreeBSD */
static int raw_sg_send_command(BlockDriverState *bs, void *buf, int count)
{