Whamcloud - gitweb
LU-16029 utils: add options to lr_reader to parse raw files
[fs/lustre-release.git] / lustre / utils / lr_reader.c
index f347845..2a14f8f 100644 (file)
@@ -67,75 +67,306 @@ static struct option const long_opts[] = {
        { .val = 'c',   .name = "client",       .has_arg = no_argument },
        { .val = 'h',   .name = "help",         .has_arg = no_argument },
        { .val = 'r',   .name = "reply",        .has_arg = no_argument },
+       { .val = 'R',   .name = "reply_data",   .has_arg = required_argument },
+       { .val = 'C',   .name = "last_rcvd",    .has_arg = required_argument },
        { .name = NULL } };
 
-/* Executes the command \a cmd and returns command status.
- */
-int run_command(char *cmd, size_t cmdsz)
+void dump_log(int fd)
+{
+       char buf[128];
+       int n;
+
+       do {
+               n = read(fd, buf, sizeof(buf));
+               n = write(2, buf, n);
+       } while (n == sizeof(buf));
+
+       fprintf(stderr, "\n");
+}
+
+FILE *open_debugfs_file(char *filename, char *tmpdir, char *dev)
 {
        char log[] = "/tmp/run_command_logXXXXXX";
-       int fd, rc;
+       char filepnm[128];
+       char *cmd = NULL;
+       FILE *fp = NULL;
+       int flog = 0;
+       int cmdsize;
+       int n = 128;
+       int rc = 0;
+
+       flog = mkstemp(log);
+       if (flog < 0)
+               return NULL;
+
+       do {
+               cmdsize = n;
+               cmd = realloc(cmd, cmdsize);
+               if (!cmd) {
+                       fprintf(stderr, "%s: Unable to allocate cmd buffer\n",
+                               progname);
+                       goto out;
+               }
+
+               n = snprintf(cmd, cmdsize,
+                        "%s -c -R 'dump /%s %s/%s' %s > %s 2>&1",
+                        DEBUGFS, filename, tmpdir, filename, dev, log);
+               n++;
 
-       if (strlen(cmd) + strlen(log) + 8 > cmdsz) {
-               fprintf(stderr, "Command buffer overflow: %.*s...\n",
-                       (int)cmdsz, cmd);
-               return -ENOMEM;
+       } while (n > cmdsize);
+
+       rc = system(cmd);
+       free(cmd);
+       if (rc) {
+               fprintf(stderr, "%s: Unable to dump %s file\n",
+                       progname, filename);
+               goto out;
        }
 
-       fd = mkstemp(log);
-       if (fd >= 0) {
-               close(fd);
-               strncat(cmd, " >", cmdsz);
-               strncat(cmd, log, cmdsz);
+       snprintf(filepnm, sizeof(filepnm), "%s/%s", tmpdir, filename);
+       fp = fopen(filepnm, "r");
+       if (!fp)
+               rc = errno;
+
+       unlink(filepnm);
+
+out:
+       if (rc)
+               dump_log(flog);
+
+       close(flog);
+       unlink(log);
+
+       errno = rc;
+       return fp;
+}
+
+int print_last_rcvd(FILE *fp, int opt_client)
+{
+       struct lr_server_data lsd = {};
+       int rc = 0;
+       int n;
+
+       /* read lr_server_data structure */
+       printf("%s:\n", LAST_RCVD);
+       n = fread(&lsd, 1, sizeof(lsd), fp);
+       if (n < sizeof(lsd)) {
+               fprintf(stderr, "%s: Short read (%d of %d)\n",
+                       progname, n, (int)sizeof(lsd));
+               rc = ferror(fp) ? EIO : EINVAL;
        }
-       strncat(cmd, " 2>&1", cmdsz - strlen(cmd));
 
-       /* Can't use popen because we need the rv of the command */
-       rc = system(cmd);
-       if (rc && fd >= 0) {
-               char buf[128];
-               FILE *fp;
-               fp = fopen(log, "r");
-               if (fp) {
-                       while (fgets(buf, sizeof(buf), fp) != NULL) {
-                               if (rc)
-                                       printf("   %s", buf);
-                       }
-                       fclose(fp);
+       /* swab structure fields of interest */
+       lsd.lsd_feature_compat = __le32_to_cpu(lsd.lsd_feature_compat);
+       lsd.lsd_feature_incompat = __le32_to_cpu(lsd.lsd_feature_incompat);
+       lsd.lsd_feature_rocompat = __le32_to_cpu(lsd.lsd_feature_rocompat);
+       lsd.lsd_last_transno = __le64_to_cpu(lsd.lsd_last_transno);
+       lsd.lsd_osd_index = __le32_to_cpu(lsd.lsd_osd_index);
+       lsd.lsd_mount_count = __le64_to_cpu(lsd.lsd_mount_count);
+
+       /* display */
+       printf("  uuid: %.40s\n", lsd.lsd_uuid);
+       printf("  feature_compat: %#x\n", lsd.lsd_feature_compat);
+       printf("  feature_incompat: %#x\n", lsd.lsd_feature_incompat);
+       printf("  feature_rocompat: %#x\n", lsd.lsd_feature_rocompat);
+       printf("  last_transaction: %llu\n",
+              (unsigned long long)lsd.lsd_last_transno);
+       printf("  target_index: %u\n", lsd.lsd_osd_index);
+       printf("  mount_count: %llu\n",
+              (unsigned long long)lsd.lsd_mount_count);
+
+       if (!opt_client || rc)
+               return rc;
+
+       /* read client information */
+       lsd.lsd_client_start = __le32_to_cpu(lsd.lsd_client_start);
+       lsd.lsd_client_size = __le16_to_cpu(lsd.lsd_client_size);
+       printf("  client_area_start: %u\n", lsd.lsd_client_start);
+       printf("  client_area_size: %hu\n", lsd.lsd_client_size);
+
+       /* seek to per-client data area */
+       rc = fseek(fp, lsd.lsd_client_start, SEEK_SET);
+       if (rc) {
+               fprintf(stderr, "%s: seek failed. %s\n",
+                       progname, strerror(errno));
+               return errno;
+       }
+
+       /* walk throuh the per-client data area */
+       while (true) {
+               struct lsd_client_data lcd;
+
+               /* read a per-client data area */
+               n = fread(&lcd, 1, sizeof(lcd), fp);
+               if (n < sizeof(lcd)) {
+                       if (feof(fp))
+                               break;
+                       fprintf(stderr, "%s: Short read (%d of %d)\n",
+                               progname, n, (int)sizeof(lcd));
+                       return ferror(fp) ? EIO : EINVAL;
+               }
+
+               if (lcd.lcd_uuid[0] == '\0')
+                       continue;
+
+               /* swab structure fields */
+               lcd.lcd_last_transno =
+                       __le64_to_cpu(lcd.lcd_last_transno);
+               lcd.lcd_last_xid = __le64_to_cpu(lcd.lcd_last_xid);
+               lcd.lcd_last_result = __le32_to_cpu(lcd.lcd_last_result);
+               lcd.lcd_last_data = __le32_to_cpu(lcd.lcd_last_data);
+               lcd.lcd_generation = __le32_to_cpu(lcd.lcd_generation);
+
+               /* display per-client data area */
+               printf("\n  %.40s:\n", lcd.lcd_uuid);
+               printf("    generation: %u\n", lcd.lcd_generation);
+               printf("    last_transaction: %llu\n",
+                      (unsigned long long)lcd.lcd_last_transno);
+               printf("    last_xid: %llu\n",
+                      (unsigned long long)lcd.lcd_last_xid);
+               printf("    last_result: %u\n", lcd.lcd_last_result);
+               printf("    last_data: %u\n", lcd.lcd_last_data);
+
+               if (lcd.lcd_last_close_transno != 0 &&
+                   lcd.lcd_last_close_xid != 0) {
+                       lcd.lcd_last_close_transno =
+                               __le64_to_cpu(lcd.lcd_last_close_transno);
+                       lcd.lcd_last_close_xid =
+                               __le64_to_cpu(lcd.lcd_last_close_xid);
+                       lcd.lcd_last_close_result =
+                               __le32_to_cpu(lcd.lcd_last_close_result);
+                       lcd.lcd_last_close_data =
+                               __le32_to_cpu(lcd.lcd_last_close_data);
+                       printf("    last_close_transation: %llu\n",
+                              (unsigned long long)lcd.lcd_last_close_transno);
+                       printf("    last_close_xid: %llu\n",
+                              (unsigned long long)lcd.lcd_last_close_xid);
+                       printf("    last_close_result: %u\n",
+                              lcd.lcd_last_close_result);
+                       printf("    last_close_data: %u\n",
+                              lcd.lcd_last_close_data);
                }
        }
-       if (fd >= 0)
-               remove(log);
-       return rc;
+
+       return 0;
 }
 
+int print_reply_data(FILE *fp)
+{
+       struct lsd_reply_header lrh = {};
+       unsigned long long slot;
+       int rc = 0;
+       int n;
+
+       /* read reply_data header */
+       printf("\n%s:\n", REPLY_DATA);
+       n = fread(&lrh, 1, sizeof(lrh), fp);
+       if (n < sizeof(lrh)) {
+               fprintf(stderr, "%s: Short read (%d of %d)\n",
+                       progname, n, (int)sizeof(lrh));
+               rc = ferror(fp) ? EIO : EINVAL;
+       }
+
+       /* check header */
+       lrh.lrh_magic = __le32_to_cpu(lrh.lrh_magic);
+       lrh.lrh_header_size = __le32_to_cpu(lrh.lrh_header_size);
+       lrh.lrh_reply_size = __le32_to_cpu(lrh.lrh_reply_size);
+       if (lrh.lrh_magic != LRH_MAGIC) {
+               fprintf(stderr,
+                       "%s: invalid %s header: lrh_magic=0x%08x expected 0x%08x\n",
+                       progname, REPLY_DATA, lrh.lrh_magic, LRH_MAGIC);
+               rc = EINVAL;
+       }
+       if (lrh.lrh_header_size != sizeof(struct lsd_reply_header)) {
+               fprintf(stderr,
+                       "%s: invalid %s header: lrh_header_size=0x%08x expected 0x%08x\n",
+                       progname, REPLY_DATA, lrh.lrh_header_size,
+                       (unsigned int)sizeof(struct lsd_reply_header));
+               rc = EINVAL;
+       }
+       if (lrh.lrh_reply_size != sizeof(struct lsd_reply_data)) {
+               fprintf(stderr,
+                       "%s: invalid %s header: lrh_reply_size=0x%08x expected 0x%08x\n",
+                       progname, REPLY_DATA, lrh.lrh_reply_size,
+                       (unsigned int)sizeof(struct lsd_reply_data));
+               rc = EINVAL;
+       }
+
+       if (rc) {
+               /* dump header */
+               fprintf(stderr, "lsd_reply_header:\n");
+               fprintf(stderr, "\tlrh_magic: 0x%08x\n", lrh.lrh_magic);
+               fprintf(stderr, "\tlrh_header_size: %u\n", lrh.lrh_header_size);
+               fprintf(stderr, "\tlrh_reply_size: %u\n", lrh.lrh_reply_size);
+               return rc;
+       }
+
+       /* walk throuh the reply data */
+       for (slot = 0; ; slot++) {
+               struct lsd_reply_data lrd;
+
+               /* read a reply data */
+               n = fread(&lrd, 1, sizeof(lrd), fp);
+               if (n < sizeof(lrd)) {
+                       if (feof(fp))
+                               break;
+                       fprintf(stderr, "%s: Short read (%d of %d)\n",
+                               progname, n, (int)sizeof(lrd));
+                       return ferror(fp) ? EIO : EINVAL;
+               }
+
+               /* display reply data */
+               lrd.lrd_transno = __le64_to_cpu(lrd.lrd_transno);
+               lrd.lrd_xid = __le64_to_cpu(lrd.lrd_xid);
+               lrd.lrd_data = __le64_to_cpu(lrd.lrd_data);
+               lrd.lrd_result = __le32_to_cpu(lrd.lrd_result);
+               lrd.lrd_client_gen = __le32_to_cpu(lrd.lrd_client_gen);
+
+               printf("  %lld:\n", slot);
+               printf("    client_generation: %u\n",
+                      lrd.lrd_client_gen);
+               printf("    last_transaction: %lluu\n",
+                      (unsigned long long)lrd.lrd_transno);
+               printf("    last_xid: %llu\n",
+                      (unsigned long long)lrd.lrd_xid);
+               printf("    last_result: %u\n", lrd.lrd_result);
+               printf("    last_data: %llu\n\n",
+                      (unsigned long long)lrd.lrd_data);
+       }
+
+       return 0;
+}
 
 void display_usage(void)
 {
        printf("Usage: %s [OPTIONS] devicename\n", progname);
-       printf("Read and print the last_rcvd file from a device\n");
-       printf("(safe for mounted devices)\n");
+       printf("Usage: %s [OPTIONS] -C <last_rcvd_file> -R <reply_data_file>\n",
+              progname);
+       printf("Read and print the last_rcvd/reply_data file from a device\n");
+       printf("(safe for mounted devices) or from a file\n");
        printf("\t-c, --client, display client information\n");
        printf("\t-h, --help,   display this help and exit\n");
        printf("\t-r, --reply,  display reply data information\n");
+       printf("\t-C FILE, --last_rcvd=FILE, specify FILE as input for client information\n");
+       printf("\t-R FILE, --reply_data=FILE, specify FILE as input for reply information\n");
 }
 
 
 int main(int argc, char *const argv[])
 {
        char tmpdir[] = "/tmp/dirXXXXXX";
-       char cmd[128];
-       char filepnm[128] = "";
        char *dev;
-       struct lr_server_data lsd;
        FILE *filep = NULL;
-       int ret;
+       int ret = 0;
        int c;
        int opt_client = 0;
        int opt_reply = 0;
+       char *file_client = NULL;
+       char *file_reply = NULL;
+       int need_dev = 1;
 
-       progname = argv[0];
-       while ((c = getopt_long(argc, argv, "chr", long_opts, NULL)) != -1) {
+       progname = basename(argv[0]);
+       while ((c = getopt_long(argc, argv, "hcrC:R:", long_opts, NULL)) != -1) {
                switch (c) {
                case 'c':
                        opt_client = 1;
@@ -143,255 +374,76 @@ int main(int argc, char *const argv[])
                case 'r':
                        opt_reply = 1;
                        break;
+               case 'C':
+                       file_client = optarg;
+                       break;
+               case 'R':
+                       file_reply = optarg;
+                       break;
                case 'h':
                default:
                        display_usage();
                        return -1;
                }
        }
+
+       if ((file_reply && file_client) ||
+           (!opt_reply && file_client) ||
+           (!opt_client && opt_reply && file_reply))
+               need_dev = 0;
+
        dev = argv[optind];
-       if (!dev) {
+       if (need_dev && !dev) {
                display_usage();
                return -1;
        }
 
        /* Make a temporary directory to hold Lustre data files. */
-       if (!mkdtemp(tmpdir)) {
+       if (need_dev && !mkdtemp(tmpdir)) {
                fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
                        progname, tmpdir, strerror(errno));
                return errno;
        }
 
-       memset(cmd, 0, sizeof(cmd));
-       snprintf(cmd, sizeof(cmd),
-               "%s -c -R 'dump /%s %s/%s' %s",
-               DEBUGFS, LAST_RCVD, tmpdir, LAST_RCVD, dev);
-
-       ret = run_command(cmd, sizeof(cmd));
-       if (ret) {
-               fprintf(stderr, "%s: Unable to dump %s file\n",
-                       progname, LAST_RCVD);
-               goto out_rmdir;
-       }
-
-       snprintf(filepnm, 128, "%s/%s", tmpdir, LAST_RCVD);
-       filep = fopen(filepnm, "r");
-       if (!filep) {
-               fprintf(stderr, "%s: Unable to read old data\n",
-                       progname);
-               ret = -errno;
-               goto out_rmdir;
-       }
-       unlink(filepnm);
-
-       /* read lr_server_data structure */
-       printf("%s:\n", LAST_RCVD);
-       ret = fread(&lsd, 1, sizeof(lsd), filep);
-       if (ret < sizeof(lsd)) {
-               fprintf(stderr, "%s: Short read (%d of %d)\n",
-                       progname, ret, (int)sizeof(lsd));
-               ret = -ferror(filep);
-               if (ret)
-                       goto out_close;
-       }
-
-       /* swab structure fields of interest */
-       lsd.lsd_feature_compat = __le32_to_cpu(lsd.lsd_feature_compat);
-       lsd.lsd_feature_incompat = __le32_to_cpu(lsd.lsd_feature_incompat);
-       lsd.lsd_feature_rocompat = __le32_to_cpu(lsd.lsd_feature_rocompat);
-       lsd.lsd_last_transno = __le64_to_cpu(lsd.lsd_last_transno);
-       lsd.lsd_osd_index = __le32_to_cpu(lsd.lsd_osd_index);
-       lsd.lsd_mount_count = __le64_to_cpu(lsd.lsd_mount_count);
-
-       /* display */
-       printf("  uuid: %.40s\n", lsd.lsd_uuid);
-       printf("  feature_compat: %#x\n", lsd.lsd_feature_compat);
-       printf("  feature_incompat: %#x\n", lsd.lsd_feature_incompat);
-       printf("  feature_rocompat: %#x\n", lsd.lsd_feature_rocompat);
-       printf("  last_transaction: %llu\n",
-              (unsigned long long)lsd.lsd_last_transno);
-       printf("  target_index: %u\n", lsd.lsd_osd_index);
-       printf("  mount_count: %llu\n",
-              (unsigned long long)lsd.lsd_mount_count);
+       if (file_client || dev) {
+               if (file_client)
+                       filep = fopen(file_client, "r");
+               else
+                       filep = open_debugfs_file(LAST_RCVD, tmpdir, dev);
 
-       /* read client information */
-       if (opt_client) {
-               lsd.lsd_client_start = __le32_to_cpu(lsd.lsd_client_start);
-               lsd.lsd_client_size = __le16_to_cpu(lsd.lsd_client_size);
-               printf("  client_area_start: %u\n", lsd.lsd_client_start);
-               printf("  client_area_size: %hu\n", lsd.lsd_client_size);
-
-               /* seek to per-client data area */
-               ret = fseek(filep, lsd.lsd_client_start, SEEK_SET);
-               if (ret) {
-                       fprintf(stderr, "%s: seek failed. %s\n",
-                               progname, strerror(errno));
+               if (!filep) {
                        ret = errno;
-                       goto out_close;
+                       fprintf(stderr, "%s: Can't open %s: %s\n",
+                               progname, LAST_RCVD, strerror(errno));
+                       goto out_rmdir;
                }
 
-               /* walk throuh the per-client data area */
-               while (true) {
-                       struct lsd_client_data lcd;
-
-                       /* read a per-client data area */
-                       ret = fread(&lcd, 1, sizeof(lcd), filep);
-                       if (ret < sizeof(lcd)) {
-                               if (feof(filep))
-                                       break;
-                               fprintf(stderr, "%s: Short read (%d of %d)\n",
-                                       progname, ret, (int)sizeof(lcd));
-                               ret = -ferror(filep);
-                               goto out_close;
-                       }
-
-                       if (lcd.lcd_uuid[0] == '\0')
-                               continue;
-
-                       /* swab structure fields */
-                       lcd.lcd_last_transno =
-                                       __le64_to_cpu(lcd.lcd_last_transno);
-                       lcd.lcd_last_xid = __le64_to_cpu(lcd.lcd_last_xid);
-                       lcd.lcd_last_result = __le32_to_cpu(lcd.lcd_last_result);
-                       lcd.lcd_last_data = __le32_to_cpu(lcd.lcd_last_data);
-                       lcd.lcd_generation = __le32_to_cpu(lcd.lcd_generation);
-
-                       /* display per-client data area */
-                       printf("\n  %.40s:\n", lcd.lcd_uuid);
-                       printf("    generation: %u\n", lcd.lcd_generation);
-                       printf("    last_transaction: %llu\n",
-                              (unsigned long long)lcd.lcd_last_transno);
-                       printf("    last_xid: %llu\n",
-                              (unsigned long long)lcd.lcd_last_xid);
-                       printf("    last_result: %u\n", lcd.lcd_last_result);
-                       printf("    last_data: %u\n", lcd.lcd_last_data);
-
-                       if (lcd.lcd_last_close_transno != 0 &&
-                           lcd.lcd_last_close_xid != 0) {
-                               lcd.lcd_last_close_transno =
-                                       __le64_to_cpu(lcd.lcd_last_close_transno);
-                               lcd.lcd_last_close_xid =
-                                       __le64_to_cpu(lcd.lcd_last_close_xid);
-                               lcd.lcd_last_close_result =
-                                       __le32_to_cpu(lcd.lcd_last_close_result);
-                               lcd.lcd_last_close_data =
-                                       __le32_to_cpu(lcd.lcd_last_close_data);
-                               printf("    last_close_transation: %llu\n",
-                                      (unsigned long long)lcd.lcd_last_close_transno);
-                               printf("    last_close_xid: %llu\n",
-                                      (unsigned long long)lcd.lcd_last_close_xid);
-                               printf("    last_close_result: %u\n",
-                                      lcd.lcd_last_close_result);
-                               printf("    last_close_data: %u\n",
-                                      lcd.lcd_last_close_data);
-                       }
-               }
+               ret = print_last_rcvd(filep, opt_client);
+               fclose(filep);
+               filep = NULL;
+               if (ret)
+                       goto out_rmdir;
        }
-       fclose(filep);
-       filep = NULL;
 
-       /* read reply data information */
        if (opt_reply) {
-               struct lsd_reply_header lrh;
-               struct lsd_reply_data lrd;
-               unsigned long long slot;
-
-               snprintf(cmd, sizeof(cmd),
-                        "%s -c -R 'dump /%s %s/%s' %s",
-                        DEBUGFS, REPLY_DATA, tmpdir, REPLY_DATA, dev);
+               if (file_reply)
+                       filep = fopen(file_reply, "r");
+               else
+                       filep = open_debugfs_file(REPLY_DATA, tmpdir, dev);
 
-               ret = run_command(cmd, sizeof(cmd));
-               if (ret) {
-                       fprintf(stderr, "%s: Unable to dump %s file\n",
-                               progname, REPLY_DATA);
-                       goto out_rmdir;
-               }
-
-               snprintf(filepnm, sizeof(filepnm),
-                        "%s/%s", tmpdir, REPLY_DATA);
-               filep = fopen(filepnm, "r");
                if (!filep) {
-                       fprintf(stderr, "%s: Unable to read reply data\n",
-                               progname);
-                       ret = -errno;
+                       ret = errno;
+                       fprintf(stderr, "%s: Can't open %s: %s\n",
+                               progname, LAST_RCVD, strerror(errno));
                        goto out_rmdir;
                }
-               unlink(filepnm);
-
-               /* read reply_data header */
-               printf("\n%s:\n", REPLY_DATA);
-               ret = fread(&lrh, 1, sizeof(lrh), filep);
-               if (ret < sizeof(lrh)) {
-                       fprintf(stderr, "%s: Short read (%d of %d)\n",
-                               progname, ret, (int)sizeof(lrh));
-                       ret = -ferror(filep);
-                       if (ret)
-                               goto out_close;
-               }
 
-               /* check header */
-               lrh.lrh_magic = __le32_to_cpu(lrh.lrh_magic);
-               lrh.lrh_header_size = __le32_to_cpu(lrh.lrh_header_size);
-               lrh.lrh_reply_size = __le32_to_cpu(lrh.lrh_reply_size);
-               if (lrh.lrh_magic != LRH_MAGIC) {
-                       fprintf(stderr, "%s: invalid %s header: "
-                               "lrh_magic=%08x expected %08x\n",
-                               progname, REPLY_DATA, lrh.lrh_magic, LRH_MAGIC);
-                       goto out_close;
-               }
-               if (lrh.lrh_header_size != sizeof(struct lsd_reply_header)) {
-                       fprintf(stderr, "%s: invalid %s header: "
-                               "lrh_header_size=%08x expected %08x\n",
-                               progname, REPLY_DATA, lrh.lrh_header_size,
-                               (unsigned int)sizeof(struct lsd_reply_header));
-                       goto out_close;
-               }
-               if (lrh.lrh_reply_size != sizeof(struct lsd_reply_data)) {
-                       fprintf(stderr, "%s: invalid %s header: "
-                               "lrh_reply_size=%08x expected %08x\n",
-                               progname, REPLY_DATA, lrh.lrh_reply_size,
-                               (unsigned int)sizeof(struct lsd_reply_data));
-                       goto out_close;
-               }
-
-               /* walk throuh the reply data */
-               for (slot = 0; ; slot++) {
-                       /* read a reply data */
-                       ret = fread(&lrd, 1, sizeof(lrd), filep);
-                       if (ret < sizeof(lrd)) {
-                               if (feof(filep))
-                                       break;
-                               fprintf(stderr, "%s: Short read (%d of %d)\n",
-                                       progname, ret, (int)sizeof(lrd));
-                               ret = -ferror(filep);
-                               goto out_close;
-                       }
-
-                       /* display reply data */
-                       lrd.lrd_transno = __le64_to_cpu(lrd.lrd_transno);
-                       lrd.lrd_xid = __le64_to_cpu(lrd.lrd_xid);
-                       lrd.lrd_data = __le64_to_cpu(lrd.lrd_data);
-                       lrd.lrd_result = __le32_to_cpu(lrd.lrd_result);
-                       lrd.lrd_client_gen = __le32_to_cpu(lrd.lrd_client_gen);
-
-                       printf("  %lld:\n", slot);
-                       printf("    client_generation: %u\n",
-                              lrd.lrd_client_gen);
-                       printf("    last_transaction: %lluu\n",
-                              (unsigned long long)lrd.lrd_transno);
-                       printf("    last_xid: %llu\n",
-                              (unsigned long long)lrd.lrd_xid);
-                       printf("    last_result: %u\n", lrd.lrd_result);
-                       printf("    last_data: %llu\n\n",
-                              (unsigned long long)lrd.lrd_data);
-               }
-       }
-
-out_close:
-       if (filep != NULL)
+               ret = print_reply_data(filep);
                fclose(filep);
+       }
 
 out_rmdir:
-       rmdir(tmpdir);
+       if (need_dev)
+               rmdir(tmpdir);
        return ret;
 }