qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel][PATCH] qemu-fuse
@ 2008-08-27 15:50 Shahar Frank
  2008-08-27 16:28 ` Anthony Liguori
  2008-08-28 21:05 ` [Qemu-devel] Re: [PATCH] qemu-fuse Szabolcs Szakacsits
  0 siblings, 2 replies; 13+ messages in thread
From: Shahar Frank @ 2008-08-27 15:50 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 21042 bytes --]

Hi All,

	The attached is a small utility to mount qemu images as pseudo
partition files. It can be very useful to access (rw) images from the
host.
I would not use it for production, but it seems to be stable.

Limitations:

1. Only primary partitions on disks are recognized.
2. The qemu-fuse is forced to be single threaded.
3. The write behind option is enabled for the images (better to be
turned off).
4. No snapshot access support.
5. Other?

Signed-off-by: Shahar Frank <shaharf@qumranet.com>

Index: qemu-fuse.c
===================================================================
--- qemu-fuse.c	(revision 0)
+++ qemu-fuse.c	(revision 0)
@@ -0,0 +1,643 @@
+/*
+ * QEMU disk image fuse server
+ *
+ * Copyright (c) 2008 Shahar Frank
+ *
+ * Permission is hereby granted, free of charge, to any person
obtaining a copy
+ * of this software and associated documentation files (the
"Software"), to deal
+ * in the Software without restriction, including without limitation
the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
+ * copies of the Software, and to permit persons to whom the Software
is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "block_int.h"
+#include <assert.h>
+
+#define FUSE_USE_VERSION 26
+
+#include <fuse/fuse_lowlevel.h>
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#define QDISK_MAX_PART          5
+typedef struct QDiskPart {
+	uint32_t start;
+	uint64_t count;
+	unsigned char type;
+	int boot;
+	char const *path;
+} QDiskPart;
+
+QDiskPart qparttbl[QDISK_MAX_PART];
+
+static const char *qemu_parttbl_path = "/parttbl";
+static char qemu_parttbl_str[8192];
+static int qemu_parttbl_str_len;
+
+static BlockDriverState *qemu_bs;
+static BlockDriver *qemu_bdrv;
+static char *qemu_img_path;
+static char *prog;
+static long qemu_dsize;
+static int open_flags = 0;
+
+
+void *qemu_memalign(size_t alignment, size_t size)
+{
+#if defined(_POSIX_C_SOURCE)
+	int ret;
+	void *ptr;
+	ret = posix_memalign(&ptr, alignment, size);
+	if (ret != 0)
+		return NULL;
+	return ptr;
+#elif defined(_BSD)
+	return valloc(size);
+#else
+	return memalign(alignment, size);
+#endif
+}
+
+static void __attribute__ ((noreturn)) error(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "qemu-fuse: ");
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	exit(1);
+	va_end(ap);
+}
+
+static void format_print(void *opaque, const char *name)
+{
+	printf(" %s", name);
+}
+
+void usage(void)
+{
+	printf("%s version " QEMU_VERSION
+	       ", Copyright (c) 2007 Qumranet, Shahar Frank\n"
+	       "usage: qemu-fuse [options] <image_path> <mount_point>
[fuse options]\n"
+	       "QEMU disk image file system utility\n" "\n" "Options:\n"
+	       "  -d            # debug mode (force also forground)\n"
+	       "  -f fmt        # force image format\n"
+	       "  -F            # keep program in forground\n"
+	       "  -h            # help (this text)\n" "\n" "Examples:\n"
+	       "\tmkdir -p /tmp/qemu /tmp/ext3 /tmp/ntfs\n"
+	       "\t%s /images/disk.vmdk /tmp/qemu\n"
+	       "\tmount -o loop /tmp/qemu/img2 /tmp/ext3\n"
+	       "\tmount -o loop -t ntfs-3g -o force /tmp/qemu/img1
/tmp/ntfs\n",
+	       prog, prog);
+	printf("\nSupported formats:");
+	bdrv_iterate_format(format_print, NULL);
+	printf("\n");
+	exit(1);
+}
+
+void help(void)
+{
+	usage();
+}
+
+#include <termios.h>
+
+static struct termios oldtty;
+
+static void term_exit(void)
+{
+	tcsetattr(0, TCSANOW, &oldtty);
+}
+
+static void term_init(void)
+{
+	struct termios tty;
+
+	tcgetattr(0, &tty);
+	oldtty = tty;
+
+	tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+			 | INLCR | IGNCR | ICRNL | IXON);
+	tty.c_oflag |= OPOST;
+	tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
+	tty.c_cflag &= ~(CSIZE | PARENB);
+	tty.c_cflag |= CS8;
+	tty.c_cc[VMIN] = 1;
+	tty.c_cc[VTIME] = 0;
+
+	tcsetattr(0, TCSANOW, &tty);
+
+	atexit(term_exit);
+}
+
+static int read_password(char *buf, int buf_size)
+{
+	uint8_t ch;
+	int i, ret;
+
+	printf("password: ");
+	fflush(stdout);
+	term_init();
+	i = 0;
+	for (;;) {
+		ret = read(0, &ch, 1);
+		if (ret == -1) {
+			if (errno == EAGAIN || errno == EINTR) {
+				continue;
+			} else {
+				ret = -1;
+				break;
+			}
+		} else if (ret == 0) {
+			ret = -1;
+			break;
+		} else {
+			if (ch == '\r') {
+				ret = 0;
+				break;
+			}
+			if (i < (buf_size - 1))
+				buf[i++] = ch;
+		}
+	}
+	term_exit();
+	buf[i] = '\0';
+	printf("\n");
+	return ret;
+}
+
+static BlockDriverState *bdrv_new_open(const char *filename,
+				       const char *fmt)
+{
+	BlockDriverState *bs;
+	BlockDriver *drv;
+	char password[256];
+
+	bs = bdrv_new("");
+	if (!bs)
+		error("Not enough memory");
+	if (fmt) {
+		drv = bdrv_find_format(fmt);
+		if (!drv)
+			error("Unknown file format '%s'", fmt);
+	} else {
+		drv = NULL;
+	}
+	if (bdrv_open2(bs, filename, open_flags, drv) < 0) {
+		error("Could not open '%s'", filename);
+	}
+	if (bdrv_is_encrypted(bs)) {
+		printf("Disk image '%s' is encrypted.\n", filename);
+		if (read_password(password, sizeof(password)) < 0)
+			error("No password given");
+		if (bdrv_set_key(bs, password) < 0)
+			error("invalid password");
+	}
+	qemu_bs = bs;
+	qemu_bdrv = drv;
+	return bs;
+}
+
+static int64_t get_allocated_file_size(const char *filename)
+{
+	struct stat st;
+	if (stat(filename, &st) < 0)
+		return -1;
+	return (int64_t) st.st_blocks * 512;
+}
+
+static void dump_snapshots(BlockDriverState * bs)
+{
+	QEMUSnapshotInfo *sn_tab, *sn;
+	int nb_sns, i;
+	char buf[256];
+
+	nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+	if (nb_sns <= 0)
+		return;
+	printf("Snapshot list:\n");
+	printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+	for (i = 0; i < nb_sns; i++) {
+		sn = &sn_tab[i];
+		printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf),
sn));
+	}
+	qemu_free(sn_tab);
+}
+
+static int open_img(const char *filename, const char *fmt)
+{
+	BlockDriverState *bs;
+	char fmt_name[128], size_buf[128], dsize_buf[128];
+	uint64_t total_sectors;
+	int64_t allocated_size;
+	char backing_filename[1024];
+	char backing_filename2[1024];
+	BlockDriverInfo bdi;
+
+	if (!(bs = bdrv_new_open(filename, fmt))) {
+		error("Could not open '%s'", filename);
+	}
+	bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
+	bdrv_get_geometry(bs, &total_sectors);
+	get_human_readable_size(size_buf, sizeof(size_buf),
+				total_sectors * 512);
+	allocated_size = get_allocated_file_size(filename);
+	if (allocated_size < 0)
+		sprintf(dsize_buf, "unavailable");
+	else
+		get_human_readable_size(dsize_buf, sizeof(dsize_buf),
+					allocated_size);
+	printf("image: %s\n"
+	       "file format: %s\n"
+	       "virtual size: %s (%" PRId64 " bytes)\n"
+	       "disk size: %s\n",
+	       filename, fmt_name, size_buf,
+	       (total_sectors * 512), dsize_buf);
+	if (bdrv_is_encrypted(bs))
+		printf("encrypted: yes\n");
+	if (bdrv_get_info(bs, &bdi) >= 0) {
+		if (bdi.cluster_size != 0)
+			printf("cluster_size: %d\n", bdi.cluster_size);
+	}
+	bdrv_get_backing_filename(bs, backing_filename,
+				  sizeof(backing_filename));
+	if (backing_filename[0] != '\0') {
+		path_combine(backing_filename2,
sizeof(backing_filename2),
+			     filename, backing_filename);
+		printf("backing file: %s (actual path: %s)\n",
+		       backing_filename, backing_filename2);
+	}
+	dump_snapshots(bs);
+	qemu_img_path = strdup(filename);
+	qemu_dsize = total_sectors * 512;
+	return 0;
+}
+
+
+#define DOS_PARTTBL_OFFS        0x1be
+#define DOS_PARTTBL_SZ          66
+#define DOS_PARTTBL_ENT_SZ      16
+#define DOS_PARTTBL_MAGIC_LO    0x55
+#define DOS_PARTTBL_MAGIC_HI    0xaa
+#define DOS_PARTTBL_MAX_PART    4
+
+typedef struct PTableEntry {
+	unsigned char bootdisk;
+	unsigned char start_cylinder;
+	unsigned char start_head;
+	unsigned char start_sector;
+	unsigned char part_type;
+	unsigned char end_cylinder;
+	unsigned char end_head;
+	unsigned char end_sector;
+	unsigned char start_lba[4];
+	unsigned char sectors_count[4];
+} PTableEntry;			/*  use char only so
__attribute__((packed)) not required */
+
+static unsigned lt32_to_u32(char *lt32)
+{
+	uint32_t u = 0;
+	int i;
+	for (i = 0; i < 4; i++)
+		u |= ((uint32_t) lt32[i] & 0xff) << (i * 8);
+	return u;
+}
+
+static int fill_pent(QDiskPart * qtbl, char *buf, int n)
+{
+	return snprintf(buf, n,
+			"%s:\tstart %10u \tsectors %10llu \ttype %x
%s\n",
+			qtbl->path, qtbl->start,
+			(long long unsigned) qtbl->count, (int)
qtbl->type,
+			qtbl->boot ? "*" : "");
+}
+
+/* FIXME: parses only primary partition table */
+static char *build_partition_table(unsigned char *tbl, QDiskPart *
qtbl)
+{
+	PTableEntry *pent;
+	char buf[64] = "";
+	int i = 0, n = 0;
+
+	/* Init first entry as the whole disk */
+	qtbl[0].start = 0;
+	qtbl[0].count = qemu_dsize / 512;
+	qtbl[0].type = 0;
+	qtbl[0].boot = 0;
+	qtbl[0].path = "/img";
+	n += fill_pent(qtbl, qemu_parttbl_str + n,
+		       sizeof(qemu_parttbl_str) - n - 1);
+	if (n >= sizeof(qemu_parttbl_str) - 1)
+		return "parttbl string too large";
+	qemu_parttbl_str_len = n;
+
+	/*
+	 * disk part tbl should be the last 66 bytes of the first
sector,
+	 * last two bytes are magic.
+	 */
+	if (tbl[DOS_PARTTBL_SZ - 2] != DOS_PARTTBL_MAGIC_LO ||
+	    tbl[DOS_PARTTBL_SZ - 1] != DOS_PARTTBL_MAGIC_HI)
+		return NULL;	/* no valid partition table, only /img
file will be created */
+
+	for (i = 1; i < DOS_PARTTBL_MAX_PART;
+	     i++, tbl += DOS_PARTTBL_ENT_SZ) {
+		if (i >= QDISK_MAX_PART)
+			return "Internal: too much partitions";
+		pent = (void *) tbl;
+		qtbl[i].start = lt32_to_u32(pent->start_lba);
+		if (qtbl[i].start == 0)
+			continue;
+		qtbl[i].count = lt32_to_u32(pent->sectors_count);
+		qtbl[i].type = pent->part_type;
+		qtbl[i].boot = pent->bootdisk & 0x80;
+		snprintf(buf, sizeof(buf) - 1, "/img%d", i);
+		qtbl[i].path = strdup(buf);
+		n += fill_pent(qtbl + i, qemu_parttbl_str + n,
+			       sizeof(qemu_parttbl_str) - n - 1);
+		if (n >= sizeof(qemu_parttbl_str) - 1)
+			return "parttbl string too large";
+	}
+	qemu_parttbl_str_len = n;
+	return NULL;
+}
+
+static int has_path(const char *path)
+{
+	int i;
+
+	if (!strcmp(path, qemu_parttbl_path))
+		return 1;
+	for (i = 0; i < QDISK_MAX_PART; i++)
+		if (!strcmp(path, qparttbl[i].path))
+			return 1;
+	return 0;
+}
+
+static QDiskPart *find_part(const char *path)
+{
+	int i;
+
+	for (i = 0; i < QDISK_MAX_PART; i++)
+		if (!strcmp(path, qparttbl[i].path))
+			return qparttbl + i;
+	return NULL;
+}
+
+static int qemu_parttbl_read(char *buf, int sz, long offset)
+{
+	if (offset >= qemu_parttbl_str_len)
+		return 0;
+
+	if (sz > qemu_parttbl_str_len - offset)
+		sz = qemu_parttbl_str_len - offset;
+
+	memcpy(buf, qemu_parttbl_str + offset, sz);
+
+	return sz;
+}
+
+static int qemu_getattr(const char *path, struct stat *stbuf)
+{
+	int i;
+
+	memset(stbuf, 0, sizeof(struct stat));
+	if (strcmp(path, "/") == 0) {
+		stbuf->st_mode = S_IFDIR | 0755;
+		stbuf->st_nlink = 2;
+		return 0;
+	}
+
+	if (strcmp(path, qemu_parttbl_path) == 0) {
+		stbuf->st_mode = S_IFREG | 0444;
+		stbuf->st_nlink = 1;
+		stbuf->st_size = qemu_parttbl_str_len;
+		return 0;
+	}
+
+	for (i = 0; i < QDISK_MAX_PART; i++) {
+		if (!qparttbl[i].path
+		    || (strcmp(path, qparttbl[i].path) != 0))
+			continue;
+		stbuf->st_mode = S_IFREG | 0666;
+		stbuf->st_nlink = 1;
+		stbuf->st_size = (uint64_t) qparttbl[i].count * 512;
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static int qemu_readdir(const char *path, void *buf,
+			fuse_fill_dir_t filler, off_t offset,
+			struct fuse_file_info *fi)
+{
+	int i;
+
+	(void) offset;
+	(void) fi;
+
+	if (strcmp(path, "/") != 0)
+		return -ENOENT;
+
+	filler(buf, ".", NULL, 0);
+	filler(buf, "..", NULL, 0);
+	filler(buf, qemu_parttbl_path + 1, NULL, 0);
+	for (i = 0; i < QDISK_MAX_PART; i++)
+		if (qparttbl[i].path)
+			filler(buf, qparttbl[i].path + 1, NULL, 0);
+	return 0;
+}
+
+static int qemu_open(const char *path, struct fuse_file_info *fi)
+{
+	if (!has_path(path))
+		return -ENOENT;
+
+	return 0;
+}
+
+static int qemu_read(const char *path, char *buf, size_t size,
+		     off_t offset, struct fuse_file_info *fi)
+{
+	QDiskPart *qpart;
+
+	if (strcmp(path, qemu_parttbl_path) == 0)
+		return qemu_parttbl_read(buf, size, offset);
+	if (!(qpart = find_part(path)))
+		return -ENOENT;
+	return bdrv_pread(qemu_bs, offset + qpart->start * 512, buf,
size);
+}
+
+static int qemu_write(const char *path, const char *buf, size_t size,
+		      off_t offset, struct fuse_file_info *fi)
+{
+	QDiskPart *qpart;
+
+	fprintf(stderr, "W: path %s\n", path);
+	if (strcmp(path, qemu_parttbl_path) == 0)
+		return -EPERM;
+	if (!(qpart = find_part(path)))
+		return -ENOENT;
+	return bdrv_pwrite(qemu_bs, offset + qpart->start * 512, buf,
+			   size);
+}
+
+static int qemu_flush(const char *path, struct fuse_file_info *fi)
+{
+	bdrv_flush(qemu_bs);
+	return 0;
+}
+
+/** Rename a file */
+//static int qemu_rename (const char *, const char *);
+
+/** Create a hard link to a file */
+//int qemu_link (const char *, const char *){}
+
+
+/** Change the permission bits of a file */
+static int qemu_chmod(const char *s, mode_t m)
+{
+	return 0;
+}
+
+/** Change the owner and group of a file */
+static int qemu_chown(const char *s, uid_t u, gid_t g)
+{
+	return 0;
+}
+
+    /** Change the size of a file */
+static int qemu_truncate(const char *s, off_t t)
+{
+	return 0;
+}
+
+/** Change the access and/or modification times of a file
+ *
+ * Deprecated, use utimens() instead.
+ */
+static int qemu_utime(const char *s, struct utimbuf *u)
+{
+	return 0;
+}
+
+static struct fuse_operations qemu_oper = {
+	.getattr = qemu_getattr,
+	.readdir = qemu_readdir,
+	.open = qemu_open,
+	.read = qemu_read,
+	.write = qemu_write,
+	.flush = qemu_flush,
+	//    .rename = qemu_rename,
+	.chmod = qemu_chmod,
+	.chown = qemu_chown,
+	.truncate = qemu_truncate,
+	.utime = qemu_utime,
+};
+
+char *init_fs(void)
+{
+	unsigned char buf[DOS_PARTTBL_SZ];
+
+	if (bdrv_pread(qemu_bs, DOS_PARTTBL_OFFS, buf, DOS_PARTTBL_SZ)
!=
+	    DOS_PARTTBL_SZ)
+		error("can't read partion table, bad read size");
+
+	return build_partition_table(buf, qparttbl);
+}
+
+int main(int argc, char *argv[])
+{
+	char *err, *filename, *fmt = NULL, **newargs;
+	int forground = 0, debug = 0;
+	int c, r;
+
+	prog = strrchr(argv[0], '/');
+	if (!prog)
+		prog = argv[0];
+
+	for (;;) {
+		/*
+		   The + in the start of opsting is to force POSIX
parsing -
+		   i.e. stop parsing at first non option. This is
required to
+		   handle fuse options correctly. Without the +, the
getopt will
+		   permute the options to force them at start...
+		 */
+		c = getopt(argc, argv, "+f:hFd");
+		if (c == -1)
+			break;
+		switch (c) {
+		case 'h':
+			help();
+			break;
+		case 'f':
+			fmt = optarg;
+			break;
+		case 'F':
+			forground = 1;
+			break;
+		case 'd':
+			debug = 1;
+			forground = 1;
+			break;
+		}
+	}
+	if (optind >= argc)
+		help();
+	filename = argv[optind++];
+
+	
+	if (!forground) {
+		if ((r = fork()) < 0)
+			error("can't fork");
+		if (r > 0)
+			exit(0);
+		/* chield */
+		if (daemon(0, 0) < 0) {
+			error("qemu-fuse: failed to daemonize
program\n");
+			return -1;
+		}
+	}
+	
+	bdrv_init();
+
+	open_img(filename, fmt);
+
+	if ((err = init_fs()))
+		error("init: %s", err);
+
+	// remove first arg and pass the rest to fuse_main
+	if (argc < optind)
+		error("Missing mount point");
+
+	argc -= optind - 1;
+
+	if (!(newargs = calloc(argc + 3, sizeof(char *))))
+		error("out of mem");
+	memcpy(newargs, argv + optind - 1, argc * sizeof(char *));
+	newargs[0] = argv[0];
+	newargs[argc] = "-s";	/* force single thread mode - qemu code
is not thread safe */
+	if (debug)
+		newargs[argc + 1] = "-d";	/* force debug and
forground mode */
+	else
+		newargs[argc + 1] = "-f";	/* force forground mode,
overcome signal masking problems */
+	newargs[argc + 2] = 0;
+
+	return fuse_main(argc + 2, newargs, &qemu_oper, NULL);
+}
Index: Makefile
===================================================================
--- Makefile	(revision 5089)
+++ Makefile	(working copy)
@@ -188,6 +188,14 @@
 qemu-img-%.o: %.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_IMG -c -o $@ $<
 
+ifdef CONFIG_FUSE
+qemu-fuse$(EXESUF): qemu-fuse.o qemu-img-block.o $(QEMU_IMG_BLOCK_OBJS)
+	$(CC) $(LDFLAGS)  -o $@ $^ $(FUSELIBS) -lz $(LIBS)
+
+qemu-fuse.o: qemu-fuse.c
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS)  -DQEMU_IMG
$(FUSEFLAGS) -g -c -o $@ $<
+endif
+
 %.o: %.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
@@ -342,6 +350,7 @@
         $(bindir)/qemu-cris \
         $(bindir)/qemu-img \
         $(bindir)/qemu-nbd \
+        $(bindir)/qemu-fuse \
 	$(datadir)/bios.bin \
 	$(datadir)/vgabios.bin \
 	$(datadir)/vgabios-cirrus.bin \
Index: configure
===================================================================
--- configure	(revision 5089)
+++ configure	(working copy)
@@ -110,6 +110,7 @@
 aio="yes"
 nptl="yes"
 mixemu="no"
+fuse="no"
 
 # OS specific
 targetos=`uname -s`
@@ -340,6 +341,8 @@
   ;;
   --disable-aio) aio="no"
   ;;
+  --enable-fuse) fuse="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -436,6 +439,7 @@
 echo "  --sparc_cpu=V            Build qemu for Sparc architecture v7,
v8, v8plus, v8plusa, v9"
 echo "  --disable-vde            disable support for vde network"
 echo "  --disable-aio            disable AIO support"
+echo "  --enable-fuse            enable fuse support"
 echo ""
 echo "NOTE: The object files are built at the place where configure is
launched"
 exit 1
@@ -479,7 +483,11 @@
 
 if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then
     AIOLIBS=
+    FUSELIBS=
+    FUSEFLAGS=
 else
+    FUSELIBS="-lfuse"
+    FUSEFLAGS=-D_FILE_OFFSET_BITS=64
     # Some Linux architectures (e.g. s390) don't imply -lpthread
automatically.
     AIOLIBS="-lrt -lpthread"
 fi
@@ -889,6 +897,22 @@
   fi
 fi
 
+##########################################
+# Fuse probe
+if test "$fuse" = "yes" ; then
+  fuse=no
+  cat > $TMPC << EOF
+#define FUSE_USE_VERSION 26
+#include <fuse/fuse_lowlevel.h>
+#include <fuse.h>
+static struct fuse_operations qemu_oper = {};
+int main(int argc, char **argv) { return fuse_main(argc, argv,
&qemu_oper, NULL);}
+EOF
+  if $cc $ARCH_CFLAGS $FUSEFLAGS -o $TMPE $FUSELIBS $TMPC 2> /dev/null
; then
+    fuse=yes
+  fi
+fi
+
 # Check if tools are available to build documentation.
 if [ -x "`which texi2html 2>/dev/null`" ] && \
    [ -x "`which pod2man 2>/dev/null`" ]; then
@@ -961,6 +985,7 @@
 echo "NPTL support      $nptl"
 echo "vde support       $vde"
 echo "AIO support       $aio"
+echo "FUSE support      $fuse"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL
support"
@@ -1007,6 +1032,9 @@
 echo "LDFLAGS=$LDFLAGS" >> $config_mak
 echo "EXESUF=$EXESUF" >> $config_mak
 echo "AIOLIBS=$AIOLIBS" >> $config_mak
+echo "FUSELIBS=$FUSELIBS" >> $config_mak
+echo "FUSEFLAGS=$FUSEFLAGS" >> $config_mak
+
 case "$cpu" in
   i386)
     echo "ARCH=i386" >> $config_mak
@@ -1216,6 +1244,10 @@
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
 fi
+if test "$fuse" = "yes" ; then
+  echo "#define CONFIG_FUSE 1" >> $config_h
+  echo "CONFIG_FUSE=yes" >> $config_mak
+fi
 
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
@@ -1232,6 +1264,9 @@
   if [ "$linux" = "yes" ] ; then
       tools="qemu-nbd\$(EXESUF) $tools"
   fi
+  if [ "$fuse" = "yes" ];then
+      tools="$tools qemu-fuse\$(EXESUF)"
+  fi
 fi
 echo "TOOLS=$tools" >> $config_mak
  

[-- Attachment #2: qemu-fuse-5089.patch --]
[-- Type: application/octet-stream, Size: 19757 bytes --]

Signed-off-by: Shahar Frank <shaharf@qumranet.com>

Index: qemu-fuse.c
===================================================================
--- qemu-fuse.c	(revision 0)
+++ qemu-fuse.c	(revision 0)
@@ -0,0 +1,643 @@
+/*
+ * QEMU disk image fuse server
+ *
+ * Copyright (c) 2008 Shahar Frank
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "block_int.h"
+#include <assert.h>
+
+#define FUSE_USE_VERSION 26
+
+#include <fuse/fuse_lowlevel.h>
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#define QDISK_MAX_PART          5
+typedef struct QDiskPart {
+	uint32_t start;
+	uint64_t count;
+	unsigned char type;
+	int boot;
+	char const *path;
+} QDiskPart;
+
+QDiskPart qparttbl[QDISK_MAX_PART];
+
+static const char *qemu_parttbl_path = "/parttbl";
+static char qemu_parttbl_str[8192];
+static int qemu_parttbl_str_len;
+
+static BlockDriverState *qemu_bs;
+static BlockDriver *qemu_bdrv;
+static char *qemu_img_path;
+static char *prog;
+static long qemu_dsize;
+static int open_flags = 0;
+
+
+void *qemu_memalign(size_t alignment, size_t size)
+{
+#if defined(_POSIX_C_SOURCE)
+	int ret;
+	void *ptr;
+	ret = posix_memalign(&ptr, alignment, size);
+	if (ret != 0)
+		return NULL;
+	return ptr;
+#elif defined(_BSD)
+	return valloc(size);
+#else
+	return memalign(alignment, size);
+#endif
+}
+
+static void __attribute__ ((noreturn)) error(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "qemu-fuse: ");
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	exit(1);
+	va_end(ap);
+}
+
+static void format_print(void *opaque, const char *name)
+{
+	printf(" %s", name);
+}
+
+void usage(void)
+{
+	printf("%s version " QEMU_VERSION
+	       ", Copyright (c) 2007 Qumranet, Shahar Frank\n"
+	       "usage: qemu-fuse [options] <image_path> <mount_point> [fuse options]\n"
+	       "QEMU disk image file system utility\n" "\n" "Options:\n"
+	       "  -d            # debug mode (force also forground)\n"
+	       "  -f fmt        # force image format\n"
+	       "  -F            # keep program in forground\n"
+	       "  -h            # help (this text)\n" "\n" "Examples:\n"
+	       "\tmkdir -p /tmp/qemu /tmp/ext3 /tmp/ntfs\n"
+	       "\t%s /images/disk.vmdk /tmp/qemu\n"
+	       "\tmount -o loop /tmp/qemu/img2 /tmp/ext3\n"
+	       "\tmount -o loop -t ntfs-3g -o force /tmp/qemu/img1 /tmp/ntfs\n",
+	       prog, prog);
+	printf("\nSupported formats:");
+	bdrv_iterate_format(format_print, NULL);
+	printf("\n");
+	exit(1);
+}
+
+void help(void)
+{
+	usage();
+}
+
+#include <termios.h>
+
+static struct termios oldtty;
+
+static void term_exit(void)
+{
+	tcsetattr(0, TCSANOW, &oldtty);
+}
+
+static void term_init(void)
+{
+	struct termios tty;
+
+	tcgetattr(0, &tty);
+	oldtty = tty;
+
+	tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+			 | INLCR | IGNCR | ICRNL | IXON);
+	tty.c_oflag |= OPOST;
+	tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
+	tty.c_cflag &= ~(CSIZE | PARENB);
+	tty.c_cflag |= CS8;
+	tty.c_cc[VMIN] = 1;
+	tty.c_cc[VTIME] = 0;
+
+	tcsetattr(0, TCSANOW, &tty);
+
+	atexit(term_exit);
+}
+
+static int read_password(char *buf, int buf_size)
+{
+	uint8_t ch;
+	int i, ret;
+
+	printf("password: ");
+	fflush(stdout);
+	term_init();
+	i = 0;
+	for (;;) {
+		ret = read(0, &ch, 1);
+		if (ret == -1) {
+			if (errno == EAGAIN || errno == EINTR) {
+				continue;
+			} else {
+				ret = -1;
+				break;
+			}
+		} else if (ret == 0) {
+			ret = -1;
+			break;
+		} else {
+			if (ch == '\r') {
+				ret = 0;
+				break;
+			}
+			if (i < (buf_size - 1))
+				buf[i++] = ch;
+		}
+	}
+	term_exit();
+	buf[i] = '\0';
+	printf("\n");
+	return ret;
+}
+
+static BlockDriverState *bdrv_new_open(const char *filename,
+				       const char *fmt)
+{
+	BlockDriverState *bs;
+	BlockDriver *drv;
+	char password[256];
+
+	bs = bdrv_new("");
+	if (!bs)
+		error("Not enough memory");
+	if (fmt) {
+		drv = bdrv_find_format(fmt);
+		if (!drv)
+			error("Unknown file format '%s'", fmt);
+	} else {
+		drv = NULL;
+	}
+	if (bdrv_open2(bs, filename, open_flags, drv) < 0) {
+		error("Could not open '%s'", filename);
+	}
+	if (bdrv_is_encrypted(bs)) {
+		printf("Disk image '%s' is encrypted.\n", filename);
+		if (read_password(password, sizeof(password)) < 0)
+			error("No password given");
+		if (bdrv_set_key(bs, password) < 0)
+			error("invalid password");
+	}
+	qemu_bs = bs;
+	qemu_bdrv = drv;
+	return bs;
+}
+
+static int64_t get_allocated_file_size(const char *filename)
+{
+	struct stat st;
+	if (stat(filename, &st) < 0)
+		return -1;
+	return (int64_t) st.st_blocks * 512;
+}
+
+static void dump_snapshots(BlockDriverState * bs)
+{
+	QEMUSnapshotInfo *sn_tab, *sn;
+	int nb_sns, i;
+	char buf[256];
+
+	nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+	if (nb_sns <= 0)
+		return;
+	printf("Snapshot list:\n");
+	printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+	for (i = 0; i < nb_sns; i++) {
+		sn = &sn_tab[i];
+		printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+	}
+	qemu_free(sn_tab);
+}
+
+static int open_img(const char *filename, const char *fmt)
+{
+	BlockDriverState *bs;
+	char fmt_name[128], size_buf[128], dsize_buf[128];
+	uint64_t total_sectors;
+	int64_t allocated_size;
+	char backing_filename[1024];
+	char backing_filename2[1024];
+	BlockDriverInfo bdi;
+
+	if (!(bs = bdrv_new_open(filename, fmt))) {
+		error("Could not open '%s'", filename);
+	}
+	bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
+	bdrv_get_geometry(bs, &total_sectors);
+	get_human_readable_size(size_buf, sizeof(size_buf),
+				total_sectors * 512);
+	allocated_size = get_allocated_file_size(filename);
+	if (allocated_size < 0)
+		sprintf(dsize_buf, "unavailable");
+	else
+		get_human_readable_size(dsize_buf, sizeof(dsize_buf),
+					allocated_size);
+	printf("image: %s\n"
+	       "file format: %s\n"
+	       "virtual size: %s (%" PRId64 " bytes)\n"
+	       "disk size: %s\n",
+	       filename, fmt_name, size_buf,
+	       (total_sectors * 512), dsize_buf);
+	if (bdrv_is_encrypted(bs))
+		printf("encrypted: yes\n");
+	if (bdrv_get_info(bs, &bdi) >= 0) {
+		if (bdi.cluster_size != 0)
+			printf("cluster_size: %d\n", bdi.cluster_size);
+	}
+	bdrv_get_backing_filename(bs, backing_filename,
+				  sizeof(backing_filename));
+	if (backing_filename[0] != '\0') {
+		path_combine(backing_filename2, sizeof(backing_filename2),
+			     filename, backing_filename);
+		printf("backing file: %s (actual path: %s)\n",
+		       backing_filename, backing_filename2);
+	}
+	dump_snapshots(bs);
+	qemu_img_path = strdup(filename);
+	qemu_dsize = total_sectors * 512;
+	return 0;
+}
+
+
+#define DOS_PARTTBL_OFFS        0x1be
+#define DOS_PARTTBL_SZ          66
+#define DOS_PARTTBL_ENT_SZ      16
+#define DOS_PARTTBL_MAGIC_LO    0x55
+#define DOS_PARTTBL_MAGIC_HI    0xaa
+#define DOS_PARTTBL_MAX_PART    4
+
+typedef struct PTableEntry {
+	unsigned char bootdisk;
+	unsigned char start_cylinder;
+	unsigned char start_head;
+	unsigned char start_sector;
+	unsigned char part_type;
+	unsigned char end_cylinder;
+	unsigned char end_head;
+	unsigned char end_sector;
+	unsigned char start_lba[4];
+	unsigned char sectors_count[4];
+} PTableEntry;			/*  use char only so __attribute__((packed)) not required */
+
+static unsigned lt32_to_u32(char *lt32)
+{
+	uint32_t u = 0;
+	int i;
+	for (i = 0; i < 4; i++)
+		u |= ((uint32_t) lt32[i] & 0xff) << (i * 8);
+	return u;
+}
+
+static int fill_pent(QDiskPart * qtbl, char *buf, int n)
+{
+	return snprintf(buf, n,
+			"%s:\tstart %10u \tsectors %10llu \ttype %x %s\n",
+			qtbl->path, qtbl->start,
+			(long long unsigned) qtbl->count, (int) qtbl->type,
+			qtbl->boot ? "*" : "");
+}
+
+/* FIXME: parses only primary partition table */
+static char *build_partition_table(unsigned char *tbl, QDiskPart * qtbl)
+{
+	PTableEntry *pent;
+	char buf[64] = "";
+	int i = 0, n = 0;
+
+	/* Init first entry as the whole disk */
+	qtbl[0].start = 0;
+	qtbl[0].count = qemu_dsize / 512;
+	qtbl[0].type = 0;
+	qtbl[0].boot = 0;
+	qtbl[0].path = "/img";
+	n += fill_pent(qtbl, qemu_parttbl_str + n,
+		       sizeof(qemu_parttbl_str) - n - 1);
+	if (n >= sizeof(qemu_parttbl_str) - 1)
+		return "parttbl string too large";
+	qemu_parttbl_str_len = n;
+
+	/*
+	 * disk part tbl should be the last 66 bytes of the first sector,
+	 * last two bytes are magic.
+	 */
+	if (tbl[DOS_PARTTBL_SZ - 2] != DOS_PARTTBL_MAGIC_LO ||
+	    tbl[DOS_PARTTBL_SZ - 1] != DOS_PARTTBL_MAGIC_HI)
+		return NULL;	/* no valid partition table, only /img file will be created */
+
+	for (i = 1; i < DOS_PARTTBL_MAX_PART;
+	     i++, tbl += DOS_PARTTBL_ENT_SZ) {
+		if (i >= QDISK_MAX_PART)
+			return "Internal: too much partitions";
+		pent = (void *) tbl;
+		qtbl[i].start = lt32_to_u32(pent->start_lba);
+		if (qtbl[i].start == 0)
+			continue;
+		qtbl[i].count = lt32_to_u32(pent->sectors_count);
+		qtbl[i].type = pent->part_type;
+		qtbl[i].boot = pent->bootdisk & 0x80;
+		snprintf(buf, sizeof(buf) - 1, "/img%d", i);
+		qtbl[i].path = strdup(buf);
+		n += fill_pent(qtbl + i, qemu_parttbl_str + n,
+			       sizeof(qemu_parttbl_str) - n - 1);
+		if (n >= sizeof(qemu_parttbl_str) - 1)
+			return "parttbl string too large";
+	}
+	qemu_parttbl_str_len = n;
+	return NULL;
+}
+
+static int has_path(const char *path)
+{
+	int i;
+
+	if (!strcmp(path, qemu_parttbl_path))
+		return 1;
+	for (i = 0; i < QDISK_MAX_PART; i++)
+		if (!strcmp(path, qparttbl[i].path))
+			return 1;
+	return 0;
+}
+
+static QDiskPart *find_part(const char *path)
+{
+	int i;
+
+	for (i = 0; i < QDISK_MAX_PART; i++)
+		if (!strcmp(path, qparttbl[i].path))
+			return qparttbl + i;
+	return NULL;
+}
+
+static int qemu_parttbl_read(char *buf, int sz, long offset)
+{
+	if (offset >= qemu_parttbl_str_len)
+		return 0;
+
+	if (sz > qemu_parttbl_str_len - offset)
+		sz = qemu_parttbl_str_len - offset;
+
+	memcpy(buf, qemu_parttbl_str + offset, sz);
+
+	return sz;
+}
+
+static int qemu_getattr(const char *path, struct stat *stbuf)
+{
+	int i;
+
+	memset(stbuf, 0, sizeof(struct stat));
+	if (strcmp(path, "/") == 0) {
+		stbuf->st_mode = S_IFDIR | 0755;
+		stbuf->st_nlink = 2;
+		return 0;
+	}
+
+	if (strcmp(path, qemu_parttbl_path) == 0) {
+		stbuf->st_mode = S_IFREG | 0444;
+		stbuf->st_nlink = 1;
+		stbuf->st_size = qemu_parttbl_str_len;
+		return 0;
+	}
+
+	for (i = 0; i < QDISK_MAX_PART; i++) {
+		if (!qparttbl[i].path
+		    || (strcmp(path, qparttbl[i].path) != 0))
+			continue;
+		stbuf->st_mode = S_IFREG | 0666;
+		stbuf->st_nlink = 1;
+		stbuf->st_size = (uint64_t) qparttbl[i].count * 512;
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static int qemu_readdir(const char *path, void *buf,
+			fuse_fill_dir_t filler, off_t offset,
+			struct fuse_file_info *fi)
+{
+	int i;
+
+	(void) offset;
+	(void) fi;
+
+	if (strcmp(path, "/") != 0)
+		return -ENOENT;
+
+	filler(buf, ".", NULL, 0);
+	filler(buf, "..", NULL, 0);
+	filler(buf, qemu_parttbl_path + 1, NULL, 0);
+	for (i = 0; i < QDISK_MAX_PART; i++)
+		if (qparttbl[i].path)
+			filler(buf, qparttbl[i].path + 1, NULL, 0);
+	return 0;
+}
+
+static int qemu_open(const char *path, struct fuse_file_info *fi)
+{
+	if (!has_path(path))
+		return -ENOENT;
+
+	return 0;
+}
+
+static int qemu_read(const char *path, char *buf, size_t size,
+		     off_t offset, struct fuse_file_info *fi)
+{
+	QDiskPart *qpart;
+
+	if (strcmp(path, qemu_parttbl_path) == 0)
+		return qemu_parttbl_read(buf, size, offset);
+	if (!(qpart = find_part(path)))
+		return -ENOENT;
+	return bdrv_pread(qemu_bs, offset + qpart->start * 512, buf, size);
+}
+
+static int qemu_write(const char *path, const char *buf, size_t size,
+		      off_t offset, struct fuse_file_info *fi)
+{
+	QDiskPart *qpart;
+
+	fprintf(stderr, "W: path %s\n", path);
+	if (strcmp(path, qemu_parttbl_path) == 0)
+		return -EPERM;
+	if (!(qpart = find_part(path)))
+		return -ENOENT;
+	return bdrv_pwrite(qemu_bs, offset + qpart->start * 512, buf,
+			   size);
+}
+
+static int qemu_flush(const char *path, struct fuse_file_info *fi)
+{
+	bdrv_flush(qemu_bs);
+	return 0;
+}
+
+/** Rename a file */
+//static int qemu_rename (const char *, const char *);
+
+/** Create a hard link to a file */
+//int qemu_link (const char *, const char *){}
+
+
+/** Change the permission bits of a file */
+static int qemu_chmod(const char *s, mode_t m)
+{
+	return 0;
+}
+
+/** Change the owner and group of a file */
+static int qemu_chown(const char *s, uid_t u, gid_t g)
+{
+	return 0;
+}
+
+    /** Change the size of a file */
+static int qemu_truncate(const char *s, off_t t)
+{
+	return 0;
+}
+
+/** Change the access and/or modification times of a file
+ *
+ * Deprecated, use utimens() instead.
+ */
+static int qemu_utime(const char *s, struct utimbuf *u)
+{
+	return 0;
+}
+
+static struct fuse_operations qemu_oper = {
+	.getattr = qemu_getattr,
+	.readdir = qemu_readdir,
+	.open = qemu_open,
+	.read = qemu_read,
+	.write = qemu_write,
+	.flush = qemu_flush,
+	//    .rename = qemu_rename,
+	.chmod = qemu_chmod,
+	.chown = qemu_chown,
+	.truncate = qemu_truncate,
+	.utime = qemu_utime,
+};
+
+char *init_fs(void)
+{
+	unsigned char buf[DOS_PARTTBL_SZ];
+
+	if (bdrv_pread(qemu_bs, DOS_PARTTBL_OFFS, buf, DOS_PARTTBL_SZ) !=
+	    DOS_PARTTBL_SZ)
+		error("can't read partion table, bad read size");
+
+	return build_partition_table(buf, qparttbl);
+}
+
+int main(int argc, char *argv[])
+{
+	char *err, *filename, *fmt = NULL, **newargs;
+	int forground = 0, debug = 0;
+	int c, r;
+
+	prog = strrchr(argv[0], '/');
+	if (!prog)
+		prog = argv[0];
+
+	for (;;) {
+		/*
+		   The + in the start of opsting is to force POSIX parsing -
+		   i.e. stop parsing at first non option. This is required to
+		   handle fuse options correctly. Without the +, the getopt will
+		   permute the options to force them at start...
+		 */
+		c = getopt(argc, argv, "+f:hFd");
+		if (c == -1)
+			break;
+		switch (c) {
+		case 'h':
+			help();
+			break;
+		case 'f':
+			fmt = optarg;
+			break;
+		case 'F':
+			forground = 1;
+			break;
+		case 'd':
+			debug = 1;
+			forground = 1;
+			break;
+		}
+	}
+	if (optind >= argc)
+		help();
+	filename = argv[optind++];
+
+	
+	if (!forground) {
+		if ((r = fork()) < 0)
+			error("can't fork");
+		if (r > 0)
+			exit(0);
+		/* chield */
+		if (daemon(0, 0) < 0) {
+			error("qemu-fuse: failed to daemonize program\n");
+			return -1;
+		}
+	}
+	
+	bdrv_init();
+
+	open_img(filename, fmt);
+
+	if ((err = init_fs()))
+		error("init: %s", err);
+
+	// remove first arg and pass the rest to fuse_main
+	if (argc < optind)
+		error("Missing mount point");
+
+	argc -= optind - 1;
+
+	if (!(newargs = calloc(argc + 3, sizeof(char *))))
+		error("out of mem");
+	memcpy(newargs, argv + optind - 1, argc * sizeof(char *));
+	newargs[0] = argv[0];
+	newargs[argc] = "-s";	/* force single thread mode - qemu code is not thread safe */
+	if (debug)
+		newargs[argc + 1] = "-d";	/* force debug and forground mode */
+	else
+		newargs[argc + 1] = "-f";	/* force forground mode, overcome signal masking problems */
+	newargs[argc + 2] = 0;
+
+	return fuse_main(argc + 2, newargs, &qemu_oper, NULL);
+}
Index: Makefile
===================================================================
--- Makefile	(revision 5089)
+++ Makefile	(working copy)
@@ -188,6 +188,14 @@
 qemu-img-%.o: %.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_IMG -c -o $@ $<
 
+ifdef CONFIG_FUSE
+qemu-fuse$(EXESUF): qemu-fuse.o qemu-img-block.o $(QEMU_IMG_BLOCK_OBJS)
+	$(CC) $(LDFLAGS)  -o $@ $^ $(FUSELIBS) -lz $(LIBS)
+
+qemu-fuse.o: qemu-fuse.c
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS)  -DQEMU_IMG $(FUSEFLAGS) -g -c -o $@ $<
+endif
+
 %.o: %.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
@@ -342,6 +350,7 @@
         $(bindir)/qemu-cris \
         $(bindir)/qemu-img \
         $(bindir)/qemu-nbd \
+        $(bindir)/qemu-fuse \
 	$(datadir)/bios.bin \
 	$(datadir)/vgabios.bin \
 	$(datadir)/vgabios-cirrus.bin \
Index: configure
===================================================================
--- configure	(revision 5089)
+++ configure	(working copy)
@@ -110,6 +110,7 @@
 aio="yes"
 nptl="yes"
 mixemu="no"
+fuse="no"
 
 # OS specific
 targetos=`uname -s`
@@ -340,6 +341,8 @@
   ;;
   --disable-aio) aio="no"
   ;;
+  --enable-fuse) fuse="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -436,6 +439,7 @@
 echo "  --sparc_cpu=V            Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
 echo "  --disable-vde            disable support for vde network"
 echo "  --disable-aio            disable AIO support"
+echo "  --enable-fuse            enable fuse support"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -479,7 +483,11 @@
 
 if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then
     AIOLIBS=
+    FUSELIBS=
+    FUSEFLAGS=
 else
+    FUSELIBS="-lfuse"
+    FUSEFLAGS=-D_FILE_OFFSET_BITS=64
     # Some Linux architectures (e.g. s390) don't imply -lpthread automatically.
     AIOLIBS="-lrt -lpthread"
 fi
@@ -889,6 +897,22 @@
   fi
 fi
 
+##########################################
+# Fuse probe
+if test "$fuse" = "yes" ; then
+  fuse=no
+  cat > $TMPC << EOF
+#define FUSE_USE_VERSION 26
+#include <fuse/fuse_lowlevel.h>
+#include <fuse.h>
+static struct fuse_operations qemu_oper = {};
+int main(int argc, char **argv) { return fuse_main(argc, argv, &qemu_oper, NULL);}
+EOF
+  if $cc $ARCH_CFLAGS $FUSEFLAGS -o $TMPE $FUSELIBS $TMPC 2> /dev/null ; then
+    fuse=yes
+  fi
+fi
+
 # Check if tools are available to build documentation.
 if [ -x "`which texi2html 2>/dev/null`" ] && \
    [ -x "`which pod2man 2>/dev/null`" ]; then
@@ -961,6 +985,7 @@
 echo "NPTL support      $nptl"
 echo "vde support       $vde"
 echo "AIO support       $aio"
+echo "FUSE support      $fuse"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1007,6 +1032,9 @@
 echo "LDFLAGS=$LDFLAGS" >> $config_mak
 echo "EXESUF=$EXESUF" >> $config_mak
 echo "AIOLIBS=$AIOLIBS" >> $config_mak
+echo "FUSELIBS=$FUSELIBS" >> $config_mak
+echo "FUSEFLAGS=$FUSEFLAGS" >> $config_mak
+
 case "$cpu" in
   i386)
     echo "ARCH=i386" >> $config_mak
@@ -1216,6 +1244,10 @@
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
 fi
+if test "$fuse" = "yes" ; then
+  echo "#define CONFIG_FUSE 1" >> $config_h
+  echo "CONFIG_FUSE=yes" >> $config_mak
+fi
 
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
@@ -1232,6 +1264,9 @@
   if [ "$linux" = "yes" ] ; then
       tools="qemu-nbd\$(EXESUF) $tools"
   fi
+  if [ "$fuse" = "yes" ];then
+      tools="$tools qemu-fuse\$(EXESUF)"
+  fi
 fi
 echo "TOOLS=$tools" >> $config_mak
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2008-08-28 21:10 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-27 15:50 [Qemu-devel][PATCH] qemu-fuse Shahar Frank
2008-08-27 16:28 ` Anthony Liguori
2008-08-27 17:02   ` Luca Bigliardi
2008-08-27 18:00     ` Anthony Liguori
2008-08-27 18:10       ` Daniel P. Berrange
2008-08-27 18:59         ` Jamie Lokier
2008-08-28  8:03           ` Shahar Frank
2008-08-28  9:27             ` [Qemu-devel][PATCH] block level testing/execersing utility Shahar Frank
2008-08-28  9:47               ` Samuel Thibault
2008-08-28 12:22                 ` Shahar Frank
2008-08-28 20:11               ` Anthony Liguori
2008-08-27 18:00   ` [Qemu-devel][PATCH] qemu-fuse Jamie Lokier
2008-08-28 21:05 ` [Qemu-devel] Re: [PATCH] qemu-fuse Szabolcs Szakacsits

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).