]> granicus.if.org Git - strace/blobdiff - file_ioctl.c
Update NEWS
[strace] / file_ioctl.c
index 3a735dc49a6e5478250ec88e184f88921d4f3b59..de8101937b3058745a8dcfb35d80fb9eaf06e9c2 100644 (file)
  */
 
 #include "defs.h"
-#include <sys/ioctl.h>
+#include <linux/ioctl.h>
 #include <linux/fs.h>
+
+#ifdef HAVE_LINUX_FIEMAP_H
+# include <linux/fiemap.h>
+# include "xlat/fiemap_flags.h"
+# include "xlat/fiemap_extent_flags.h"
+#endif
+
 #ifndef FICLONE
-#define FICLONE         _IOW(0x94, 9, int)
+# define FICLONE         _IOW(0x94, 9, int)
 #endif
 
 #ifndef FICLONERANGE
-#define FICLONERANGE    _IOW(0x94, 13, struct file_clone_range)
+# define FICLONERANGE    _IOW(0x94, 13, struct file_clone_range)
 struct file_clone_range {
        int64_t src_fd;
        uint64_t src_offset;
@@ -43,7 +50,7 @@ struct file_clone_range {
 #endif
 
 #ifndef FIDEDUPERANGE
-#define FIDEDUPERANGE   _IOWR(0x94, 54, struct file_dedupe_range)
+# define FIDEDUPERANGE   _IOWR(0x94, 54, struct file_dedupe_range)
 struct file_dedupe_range_info {
        int64_t dest_fd;        /* in - destination file */
        uint64_t dest_offset;   /* in - start of extent in destination */
@@ -68,36 +75,85 @@ struct file_dedupe_range {
 };
 #endif
 
+static bool
+print_file_dedupe_range_info(struct tcb *tcp, void *elem_buf,
+                            size_t elem_size, void *data)
+{
+       const struct file_dedupe_range_info *info = elem_buf;
+       unsigned int *count = data;
+
+       if (count) {
+               if (*count == 0) {
+                       tprints("...");
+                       return false;
+               }
+               --*count;
+       }
+
+       if (entering(tcp)) {
+               tprints("{dest_fd=");
+               printfd(tcp, info->dest_fd);
+               tprintf(", dest_offset=%" PRIu64 "}",
+                       (uint64_t) info->dest_offset);
+       } else {
+               tprintf("{bytes_deduped=%" PRIu64 ", status=%d}",
+                       (uint64_t) info->bytes_deduped, info->status);
+       }
+
+       return true;
+}
+
+#ifdef HAVE_LINUX_FIEMAP_H
+static bool
+print_fiemap_extent(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
+{
+       const struct fiemap_extent *fe = elem_buf;
+
+       tprintf("{fe_logical=%" PRI__u64
+               ", fe_physical=%" PRI__u64
+               ", fe_length=%" PRI__u64 ", ",
+               fe->fe_logical, fe->fe_physical, fe->fe_length);
+
+       printflags64(fiemap_extent_flags, fe->fe_flags,
+                    "FIEMAP_EXTENT_???");
+       tprints("}");
+
+       return true;
+}
+#endif /* HAVE_LINUX_FIEMAP_H */
+
 int
 file_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
 {
        switch (code) {
-       /* take a signed int */
        case FICLONE:   /* W */
-               tprintf(", %d", (int)arg);
+               tprintf(", %d", (int) arg);
                break;
 
        case FICLONERANGE: { /* W */
                struct file_clone_range args;
 
                tprints(", ");
-
                if (umove_or_printaddr(tcp, arg, &args))
                        break;
 
-               tprintf("{src_fd=%" PRIi64 ", "
-                       "src_offset=%" PRIu64 ", "
-                       "src_length=%" PRIu64 ", "
-                       "dest_offset=%" PRIu64 "}",
-                       (int64_t)args.src_fd, (uint64_t)args.src_offset,
-                       (uint64_t)args.src_length, (uint64_t)args.dest_offset);
+               tprints("{src_fd=");
+               printfd(tcp, args.src_fd);
+               tprintf(", src_offset=%" PRIu64
+                       ", src_length=%" PRIu64
+                       ", dest_offset=%" PRIu64 "}",
+                       (uint64_t) args.src_offset,
+                       (uint64_t) args.src_length,
+                       (uint64_t) args.dest_offset);
                break;
        }
 
        case FIDEDUPERANGE: { /* RW */
                struct file_dedupe_range args;
-               uint64_t info_addr;
-               uint16_t i;
+               struct file_dedupe_range_info info;
+               unsigned int *limit = NULL;
+               unsigned int count = 2;
+               bool rc;
 
                if (entering(tcp))
                        tprints(", ");
@@ -109,50 +165,80 @@ file_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
                if (umove_or_printaddr(tcp, arg, &args))
                        break;
 
+               tprints("{");
                if (entering(tcp)) {
-                       tprintf("{src_offset=%" PRIu64 ", "
-                               "src_length=%" PRIu64 ", "
-                               "dest_count=%hu, info=",
-                               (uint64_t)args.src_offset,
-                               (uint64_t)args.src_length,
-                               (uint16_t)args.dest_count);
-               } else
-                       tprints("{info=");
+                       tprintf("src_offset=%" PRIu64
+                               ", src_length=%" PRIu64
+                               ", dest_count=%hu, ",
+                               (uint64_t) args.src_offset,
+                               (uint64_t) args.src_length,
+                               (uint16_t) args.dest_count);
+               }
+
+               tprints("info=");
+
+               /* Limit how many elements we print in abbrev mode. */
+               if (abbrev(tcp) && args.dest_count > count)
+                       limit = &count;
+
+               rc = print_array(tcp, arg + offsetof(typeof(args), info),
+                                args.dest_count, &info, sizeof(info),
+                                umoven_or_printaddr,
+                                print_file_dedupe_range_info, limit);
 
+               tprints("}");
+               if (!rc || exiting(tcp))
+                       break;
+
+               return 0;
+       }
+
+#ifdef HAVE_LINUX_FIEMAP_H
+       case FS_IOC_FIEMAP: {
+               struct fiemap args;
+
+               if (entering(tcp))
+                       tprints(", ");
+               else if (syserror(tcp))
+                       break;
+               else
+                       tprints(" => ");
+
+               if (umove_or_printaddr(tcp, arg, &args))
+                       break;
+
+               if (entering(tcp)) {
+                       tprintf("{fm_start=%" PRI__u64 ", "
+                               "fm_length=%" PRI__u64 ", "
+                               "fm_flags=",
+                               args.fm_start, args.fm_length);
+                       printflags64(fiemap_flags, args.fm_flags,
+                                    "FIEMAP_FLAG_???");
+                       tprintf(", fm_extent_count=%u}", args.fm_extent_count);
+                       return 0;
+               }
+
+               tprints("{fm_flags=");
+               printflags64(fiemap_flags, args.fm_flags,
+                            "FIEMAP_FLAG_???");
+               tprintf(", fm_mapped_extents=%u",
+                       args.fm_mapped_extents);
+               tprints(", fm_extents=");
                if (abbrev(tcp)) {
-                       tprints("...}");
+                       tprints("...");
                } else {
-                       tprints("[");
-                       info_addr = arg + offsetof(typeof(args), info);
-                       for (i = 0; i < args.dest_count; i++) {
-                               struct file_dedupe_range_info info;
-                               uint64_t addr = info_addr + sizeof(info) * i;
-                               if (i)
-                                       tprints(", ");
-
-                               if (umoven(tcp, addr, sizeof(info), &info)) {
-                                       tprints("...");
-                                       break;
-                               }
-
-                               if (entering(tcp))
-                                       tprintf("{dest_fd=%" PRIi64 ", "
-                                               "dest_offset=%" PRIu64 "}",
-                                               (int64_t)info.dest_fd,
-                                               (uint64_t)info.dest_offset);
-                               else {
-                                       tprintf("{bytes_deduped=%" PRIu64 ", "
-                                               "status=%d}",
-                                               (uint64_t)info.bytes_deduped,
-                                               info.status);
-                               }
-                       }
-                       tprints("]}");
+                       struct fiemap_extent fe;
+                       print_array(tcp,
+                                   arg + offsetof(typeof(args), fm_extents),
+                                   args.fm_mapped_extents, &fe, sizeof(fe),
+                                   umoven_or_printaddr,
+                                   print_fiemap_extent, 0);
                }
-               if (entering(tcp))
-                       return 0;
+               tprints("}");
+
                break;
        }
+#endif /* HAVE_LINUX_FIEMAP_H */
 
        default:
                return RVAL_DECODED;