Whamcloud - gitweb
LU-6210 utils: Use C99 struct initializers in lr_reader.c
[fs/lustre-release.git] / lustre / utils / lr_reader.c
index ecbc11d..1b39180 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * GPL HEADER END
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright (c) 2013, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -44,6 +42,9 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <getopt.h>
 
-#include <lustre_disk.h>
+#include <asm/byteorder.h>
+#include <linux/lustre_disk.h>
 #include <lustre_ver.h>
 
-int run_command(char *cmd)
+char *progname;
+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 },
+       { .name = NULL } };
+
+/* Executes the command \a cmd and returns command status.
+ */
+int run_command(char *cmd, size_t cmdsz)
 {
-        char log[] = "/tmp/mkfs_logXXXXXX";
-        int fd, rc;
-        
-        
-        if ((fd = mkstemp(log)) >= 0) {
-                close(fd);
-                strcat(cmd, " >");
-                strcat(cmd, log);
-        }
-        strcat(cmd, " 2>&1");
-
-        /* 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);
-                }
-        }
-        if (fd >= 0) 
-                remove(log);
-        return rc;
-}                                                       
+       char log[] = "/tmp/run_command_logXXXXXX";
+       int fd, rc;
+
+       if (strlen(cmd) + strlen(log) + 8 > cmdsz) {
+               fprintf(stderr, "Command buffer overflow: %.*s...\n",
+                       (int)cmdsz, cmd);
+               return -ENOMEM;
+       }
 
+       fd = mkstemp(log);
+       if (fd >= 0) {
+               close(fd);
+               strncat(cmd, " >", 2);
+               strncat(cmd, log, strlen(log));
+       }
+       strncat(cmd, " 2>&1", 5);
+
+       /* 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);
+               }
+       }
+       if (fd >= 0)
+               remove(log);
+       return rc;
+}
+
+
+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("\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");
+}
 
 
 int main(int argc, char *const argv[])
 {
-        char tmpdir[] = "/tmp/dirXXXXXX";
-        char cmd[128];
-        char filepnm[128];
-        char *progname, *dev;
-        struct lr_server_data lsd;
-        FILE *filep;
-        int ret;
-
-        if ((argc < 2) || (argv[argc - 1][0] == '-')) {
-                printf("Usage: %s devicename\n", argv[0]);
-                printf("Read and print the last_rcvd file from a device\n");
-                printf("(safe for mounted devices)\n");
-                return EINVAL;
-        }
-
-        progname = argv[0];
-        dev = argv[argc - 1];
-
-        /* Make a temporary directory to hold Lustre data files. */
-        if (!mkdtemp(tmpdir)) {
-                fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
-                        progname, tmpdir, strerror(errno));
-                return errno;
-        }
-
-        memset(cmd, 0, sizeof(cmd));
-        sprintf(cmd,
-                "%s -c -R 'dump /%s %s/%s' %s",
-                DEBUGFS, LAST_RCVD, tmpdir, LAST_RCVD, dev);
-
-        ret = run_command(cmd);
-        if (ret) {
-                fprintf(stderr, "%s: Unable to dump %s file\n",
-                        progname, LAST_RCVD);
-                goto out_rmdir;
-        }
-
-        sprintf(filepnm, "%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;
-        }
-
-        printf("Reading %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;
-        }
-
-        #if 0
-        __u8  lsd_uuid[40];        /* server UUID */
-        __u64 lsd_last_transno;    /* last completed transaction ID */
-        __u64 lsd_compat14;        /* reserved - compat with old last_rcvd */
-        __u64 lsd_mount_count;     /* incarnation number */
-        __u32 lsd_feature_compat;  /* compatible feature flags */
-        __u32 lsd_feature_rocompat;/* read-only compatible feature flags */
-        __u32 lsd_feature_incompat;/* incompatible feature flags */
-        __u32 lsd_server_size;     /* size of server data area */
-        __u32 lsd_client_start;    /* start of per-client data area */
-        __u16 lsd_client_size;     /* size of per-client data area */
-        __u16 lsd_subdir_count;    /* number of subdirectories for objects */
-        __u64 lsd_catalog_oid;     /* recovery catalog object id */
-        __u32 lsd_catalog_ogen;    /* recovery catalog inode generation */
-        __u8  lsd_peeruuid[40];    /* UUID of MDS associated with this OST */
-        __u32 lsd_ost_index;       /* index number of OST in LOV */
-        __u32 lsd_mdt_index;       /* index number of MDT in LMV */
-        __u8  lsd_padding[LR_SERVER_SIZE - 148];
-        #endif
-
-        printf("UUID %s\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", (long long)lsd.lsd_last_transno);
-        printf("ost index %u\n", lsd.lsd_ost_index);
-        printf("mdt index %u\n", lsd.lsd_mdt_index);
-
-        if ((lsd.lsd_feature_compat & OBD_COMPAT_OST) ||
-            (lsd.lsd_feature_incompat & OBD_INCOMPAT_OST)) {
-                printf("OST, index %d\n", lsd.lsd_ost_index);
-        } else if ((lsd.lsd_feature_compat & OBD_COMPAT_MDT) ||
-                   (lsd.lsd_feature_incompat & OBD_INCOMPAT_MDT)) {
-                /* We must co-locate so mgs can see old logs.
-                   If user doesn't want this, they can copy the old
-                   logs manually and re-tunefs. */
-                printf("MDS, index %d\n", lsd.lsd_mdt_index);
-        } else  {
-                /* If neither is set, we're pre-1.4.6, make a guess. */
-                /* Construct debugfs command line. */
-                memset(cmd, 0, sizeof(cmd));
-                sprintf(cmd,
-                        "%s -c -R 'rdump /%s %s' %s",
-                        DEBUGFS, MDT_LOGS_DIR, tmpdir, dev);
-
-                run_command(cmd);
-
-                sprintf(filepnm, "%s/%s", tmpdir, MDT_LOGS_DIR);
-                if (lsd.lsd_ost_index > 0) {
-                        printf("non-flagged OST, index %d\n", 
-                               lsd.lsd_ost_index);
-                } else {
-                        /* If there's a LOGS dir, it's an MDT */
-                        if ((ret = access(filepnm, F_OK)) == 0) {
-                                /* Old MDT's are always index 0 
-                                   (pre CMD) */
-                                printf("non-flagged MDS, index 0\n");
-                        } else {
-                                printf("non-flagged OST, index unknown\n");
-                        }
-                }
-        }
-        
-out_close:        
-        fclose(filep);
+       char tmpdir[] = "/tmp/dirXXXXXX";
+       char cmd[128];
+       char filepnm[128] = "";
+       char *dev;
+       struct lr_server_data lsd;
+       FILE *filep = NULL;
+       int ret;
+       int c;
+       int opt_client = 0;
+       int opt_reply = 0;
+
+       progname = argv[0];
+       while ((c = getopt_long(argc, argv, "chr", long_opts, NULL)) != -1) {
+               switch (c) {
+               case 'c':
+                       opt_client = 1;
+                       break;
+               case 'r':
+                       opt_reply = 1;
+                       break;
+               case 'h':
+               default:
+                       display_usage();
+                       return -1;
+               }
+       }
+       dev = argv[optind];
+       if (!dev) {
+               display_usage();
+               return -1;
+       }
+
+       /* Make a temporary directory to hold Lustre data files. */
+       if (!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", lsd.lsd_last_transno);
+       printf("  target_index: %u\n", lsd.lsd_osd_index);
+       printf("  mount_count: %llu\n", lsd.lsd_mount_count);
+
+       /* 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));
+                       ret = errno;
+                       goto out_close;
+               }
+
+               /* 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",
+                              lcd.lcd_last_transno);
+                       printf("    last_xid: %llu\n", 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",
+                                      lcd.lcd_last_close_transno);
+                               printf("    last_close_xid: %llu\n",
+                                      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);
+                       }
+               }
+       }
+       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);
+
+               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;
+                       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: %llu\n", lrd.lrd_transno);
+                       printf("    last_xid: %llu\n", lrd.lrd_xid);
+                       printf("    last_result: %u\n", lrd.lrd_result);
+                       printf("    last_data: %llu\n\n", lrd.lrd_data);
+               }
+       }
+
+out_close:
+       if (filep != NULL)
+               fclose(filep);
 
 out_rmdir:
-        memset(cmd, 0, sizeof(cmd));
-        sprintf(cmd, "rm -rf %s", tmpdir);
-        run_command(cmd);
-        return ret;
+       rmdir(tmpdir);
+       return ret;
 }