fuse: Add more tracing for calls into guestmount functions.
[libguestfs.git] / fuse / guestmount.c
index 55b71d7..3d3da39 100644 (file)
@@ -65,6 +65,13 @@ int keys_from_stdin = 0;
 int echo_keys = 0;
 const char *libvirt_uri;
 int dir_cache_timeout = 60;
+static int trace_calls = 0;
+
+#define TRACE_CALL(fs,...)                                              \
+  if (trace_calls) {                                                    \
+    fprintf (stderr, "%s: %s (" fs ")\n",                               \
+             program_name, __func__, __VA_ARGS__);                      \
+  }
 
 static int
 error (void)
@@ -106,6 +113,8 @@ static int
 fg_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
             off_t offset, struct fuse_file_info *fi)
 {
+  TRACE_CALL ("%s, %p, %ld", path, buf, (long) offset);
+
   time_t now;
   time (&now);
 
@@ -227,6 +236,8 @@ fg_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
 static int
 fg_getattr (const char *path, struct stat *statbuf)
 {
+  TRACE_CALL ("%s, %p", path, statbuf);
+
   const struct stat *buf;
 
   buf = lsc_lookup (path);
@@ -267,6 +278,8 @@ fg_getattr (const char *path, struct stat *statbuf)
 static int
 fg_access (const char *path, int mask)
 {
+  TRACE_CALL ("%s, %d", path, mask);
+
   struct stat statbuf;
   int r;
 
@@ -302,6 +315,8 @@ fg_access (const char *path, int mask)
 static int
 fg_readlink (const char *path, char *buf, size_t size)
 {
+  TRACE_CALL ("%s, %p, %zu", path, buf, size);
+
   const char *r;
   int free_it = 0;
 
@@ -334,6 +349,8 @@ fg_readlink (const char *path, char *buf, size_t size)
 static int
 fg_mknod (const char *path, mode_t mode, dev_t rdev)
 {
+  TRACE_CALL ("%s, 0%o, 0x%lx", path, mode, (long) rdev);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -350,6 +367,8 @@ fg_mknod (const char *path, mode_t mode, dev_t rdev)
 static int
 fg_mkdir (const char *path, mode_t mode)
 {
+  TRACE_CALL ("%s, 0%o", path, mode);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -366,6 +385,8 @@ fg_mkdir (const char *path, mode_t mode)
 static int
 fg_unlink (const char *path)
 {
+  TRACE_CALL ("%s", path);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -382,6 +403,8 @@ fg_unlink (const char *path)
 static int
 fg_rmdir (const char *path)
 {
+  TRACE_CALL ("%s", path);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -398,6 +421,8 @@ fg_rmdir (const char *path)
 static int
 fg_symlink (const char *from, const char *to)
 {
+  TRACE_CALL ("%s, %s", from, to);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -414,6 +439,8 @@ fg_symlink (const char *from, const char *to)
 static int
 fg_rename (const char *from, const char *to)
 {
+  TRACE_CALL ("%s, %s", from, to);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -435,6 +462,8 @@ fg_rename (const char *from, const char *to)
 static int
 fg_link (const char *from, const char *to)
 {
+  TRACE_CALL ("%s, %s", from, to);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -452,6 +481,8 @@ fg_link (const char *from, const char *to)
 static int
 fg_chmod (const char *path, mode_t mode)
 {
+  TRACE_CALL ("%s, 0%o", path, mode);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -468,6 +499,8 @@ fg_chmod (const char *path, mode_t mode)
 static int
 fg_chown (const char *path, uid_t uid, gid_t gid)
 {
+  TRACE_CALL ("%s, %ld, %ld", path, (long) uid, (long) gid);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -484,6 +517,8 @@ fg_chown (const char *path, uid_t uid, gid_t gid)
 static int
 fg_truncate (const char *path, off_t size)
 {
+  TRACE_CALL ("%s, %ld", path, (long) size);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -500,6 +535,9 @@ fg_truncate (const char *path, off_t size)
 static int
 fg_utimens (const char *path, const struct timespec ts[2])
 {
+  TRACE_CALL ("%s, [{ %ld, %ld }, { %ld, %ld }]",
+              path, ts[0].tv_sec, ts[0].tv_nsec, ts[1].tv_sec, ts[1].tv_nsec);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -535,53 +573,18 @@ fg_utimens (const char *path, const struct timespec ts[2])
   return 0;
 }
 
-/* This call is quite hard to emulate through the guestfs(3) API.  In
- * one sense it's a little like access (see above) because it tests
- * whether opening a file would succeed given the flags.  But it also
- * has side effects such as truncating the file if O_TRUNC is given.
- * Therefore we need to emulate it ... painfully.
+/* All this function needs to do is to check that the requested open
+ * flags are valid.  See the notes in <fuse/fuse.h>.
  */
 static int
 fg_open (const char *path, struct fuse_file_info *fi)
 {
-  int r, exists;
-
-  if (fi->flags & O_WRONLY) {
-    if (read_only)
-      return -EROFS;
-  }
-
-  exists = guestfs_exists (g, path);
-  if (exists == -1)
-    return error ();
-
-  if (fi->flags & O_CREAT) {
-    if (read_only)
-      return -EROFS;
-
-    dir_cache_invalidate (path);
-
-    /* Exclusive?  File must not exist already. */
-    if (fi->flags & O_EXCL) {
-      if (exists)
-        return -EEXIST;
-    }
+  TRACE_CALL ("%s, 0%o", path, fi->flags);
+             
+  int flags = fi->flags & 3;
 
-    /* Create?  Touch it and optionally truncate it. */
-    r = guestfs_touch (g, path);
-    if (r == -1)
-      return error ();
-
-    if (fi->flags & O_TRUNC) {
-      r = guestfs_truncate (g, path);
-      if (r == -1)
-        return error ();
-    }
-  } else {
-    /* Not create, just check it exists. */
-    if (!exists)
-      return -ENOENT;
-  }
+  if (read_only && flags != O_RDONLY)
+    return -EROFS;
 
   return 0;
 }
@@ -590,6 +593,8 @@ static int
 fg_read (const char *path, char *buf, size_t size, off_t offset,
          struct fuse_file_info *fi)
 {
+  TRACE_CALL ("%s, %p, %zu, %ld", path, buf, size, offset);
+             
   char *r;
   size_t rsize;
 
@@ -625,6 +630,8 @@ static int
 fg_write (const char *path, const char *buf, size_t size,
           off_t offset, struct fuse_file_info *fi)
 {
+  TRACE_CALL ("%s, %p, %zu, %ld", path, buf, size, offset);
+
   if (read_only) return -EROFS;
 
   dir_cache_invalidate (path);
@@ -645,6 +652,8 @@ fg_write (const char *path, const char *buf, size_t size,
 static int
 fg_statfs (const char *path, struct statvfs *stbuf)
 {
+  TRACE_CALL ("%s, %p", path, stbuf);
+
   struct guestfs_statvfs *r;
 
   r = guestfs_statvfs (g, path);
@@ -671,6 +680,8 @@ fg_statfs (const char *path, struct statvfs *stbuf)
 static int
 fg_release (const char *path, struct fuse_file_info *fi)
 {
+  TRACE_CALL ("%s", path);
+
   /* Just a stub. This method is optional and can safely be left
    * unimplemented.
    */
@@ -681,6 +692,8 @@ fg_release (const char *path, struct fuse_file_info *fi)
 static int fg_fsync(const char *path, int isdatasync,
                      struct fuse_file_info *fi)
 {
+  TRACE_CALL ("%s, %d", path, isdatasync);
+
   int r;
 
   r = guestfs_sync (g);
@@ -694,6 +707,8 @@ static int
 fg_setxattr (const char *path, const char *name, const char *value,
              size_t size, int flags)
 {
+  TRACE_CALL ("%s, %s, %p, %zu", path, name, value, size);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -716,6 +731,8 @@ static int
 fg_getxattr (const char *path, const char *name, char *value,
              size_t size)
 {
+  TRACE_CALL ("%s, %s, %p, %zu", path, name, value, size);
+
   const struct guestfs_xattr_list *xattrs;
   int free_attrs = 0;
 
@@ -750,6 +767,8 @@ fg_getxattr (const char *path, const char *name, char *value,
 static int
 fg_listxattr (const char *path, char *list, size_t size)
 {
+  TRACE_CALL ("%s, %p, %zu", path, list, size);
+
   const struct guestfs_xattr_list *xattrs;
   int free_attrs = 0;
 
@@ -785,6 +804,8 @@ fg_listxattr (const char *path, char *list, size_t size)
 static int
 fg_removexattr(const char *path, const char *name)
 {
+  TRACE_CALL ("%s, %s", path, name);
+
   int r;
 
   if (read_only) return -EROFS;
@@ -884,7 +905,7 @@ main (int argc, char *argv[])
   /* The command line arguments are broadly compatible with (a subset
    * of) guestfish.  Thus we have to deal mainly with -a, -m and --ro.
    */
-  static const char *options = "a:c:d:im:no:rv?Vx";
+  static const char *options = "a:c:d:im:no:rv?Vwx";
   static const struct option long_options[] = {
     { "add", 1, 0, 'a' },
     { "connect", 1, 0, 'c' },
@@ -900,6 +921,7 @@ main (int argc, char *argv[])
     { "no-sync", 0, 0, 'n' },
     { "option", 1, 0, 'o' },
     { "ro", 0, 0, 'r' },
+    { "rw", 0, 0, 'w' },
     { "selinux", 0, 0, 0 },
     { "trace", 0, 0, 'x' },
     { "verbose", 0, 0, 'v' },
@@ -1043,10 +1065,15 @@ main (int argc, char *argv[])
       OPTION_V;
       break;
 
+    case 'w':
+      OPTION_w;
+      break;
+
     case 'x':
       OPTION_x;
       ADD_FUSE_ARG ("-f");
       guestfs_set_recovery_proc (g, 1);
+      trace_calls = 1;
       break;
 
     case HELP_OPTION: