qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel][PATCH] qemu-fuse


From: Shahar Frank
Subject: [Qemu-devel][PATCH] qemu-fuse
Date: Wed, 27 Aug 2008 08:50:15 -0700

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 <address@hidden>

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: qemu-fuse-5089.patch
Description: qemu-fuse-5089.patch


reply via email to

[Prev in Thread] Current Thread [Next in Thread]