hammer2 - Add media dump command, improve help output
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 15 May 2012 05:40:10 +0000 (22:40 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 15 May 2012 05:41:17 +0000 (22:41 -0700)
* Add 'hammer2 show <device>'.  This will dump the contents of the
  hammer2 filesystem structure on-media.

* Improve usage() output.

* Rename 'hammer2 debug <host>' to 'hammer2 shell <host>'.

sbin/hammer2/cmd_debug.c
sbin/hammer2/cmd_service.c
sbin/hammer2/hammer2.h
sbin/hammer2/main.c
sbin/hammer2/subs.c

index 87add09..f648ab1 100644 (file)
 
 #include "hammer2.h"
 
-static void debug_recv(hammer2_iocom_t *iocom);
-static void debug_send(hammer2_iocom_t *iocom);
-static void debug_tty(hammer2_iocom_t *iocom);
-static void hammer2_debug_parse(hammer2_msg_t *msg, char *cmdbuf);
+#define SHOW_TAB       2
+
+static void shell_recv(hammer2_iocom_t *iocom);
+static void shell_send(hammer2_iocom_t *iocom);
+static void shell_tty(hammer2_iocom_t *iocom);
+static void hammer2_shell_parse(hammer2_msg_t *msg, char *cmdbuf);
+
+/************************************************************************
+ *                                 SHELL                               *
+ ************************************************************************/
 
 int
-cmd_debug(const char *hostname)
+cmd_shell(const char *hostname)
 {
        struct sockaddr_in lsin;
        struct hammer2_iocom iocom;
@@ -94,7 +100,7 @@ cmd_debug(const char *hostname)
        msg = hammer2_allocmsg(&iocom, HAMMER2_DBG_SHELL, 0);
        hammer2_ioq_write(msg);
 
-       hammer2_iocom_core(&iocom, debug_recv, debug_send, debug_tty);
+       hammer2_iocom_core(&iocom, shell_recv, shell_send, shell_tty);
        fprintf(stderr, "debug: disconnected\n");
        close(fd);
        return 0;
@@ -106,7 +112,7 @@ cmd_debug(const char *hostname)
  */
 static
 void
-debug_recv(hammer2_iocom_t *iocom)
+shell_recv(hammer2_iocom_t *iocom)
 {
        hammer2_msg_t *msg;
 
@@ -157,14 +163,14 @@ debug_recv(hammer2_iocom_t *iocom)
  */
 static
 void
-debug_send(hammer2_iocom_t *iocom)
+shell_send(hammer2_iocom_t *iocom)
 {
        hammer2_iocom_flush(iocom);
 }
 
 static
 void
-debug_tty(hammer2_iocom_t *iocom)
+shell_tty(hammer2_iocom_t *iocom)
 {
        hammer2_msg_t *msg;
        char buf[256];
@@ -193,7 +199,7 @@ debug_tty(hammer2_iocom_t *iocom)
  * then finish up by outputting another prompt.
  */
 void
-hammer2_debug_remote(hammer2_msg_t *msg)
+hammer2_shell_remote(hammer2_msg_t *msg)
 {
        /* hammer2_iocom_t *iocom = msg->iocom; */
 
@@ -212,13 +218,13 @@ hammer2_debug_remote(hammer2_msg_t *msg)
                 * Otherwise this is a command which we must process.
                 * When we are finished we generate a final reply.
                 */
-               hammer2_debug_parse(msg, msg->aux_data);
+               hammer2_shell_parse(msg, msg->aux_data);
                hammer2_replymsg(msg, 0);
        }
 }
 
 static void
-hammer2_debug_parse(hammer2_msg_t *msg, char *cmdbuf)
+hammer2_shell_parse(hammer2_msg_t *msg, char *cmdbuf)
 {
        /* hammer2_iocom_t *iocom = msg->iocom; */
        char *cmd = strsep(&cmdbuf, " \t");
@@ -255,3 +261,229 @@ msg_printf(hammer2_msg_t *msg, const char *ctl, ...)
 
        hammer2_ioq_write(rmsg);
 }
+
+/************************************************************************
+ *                                 SHOW                                *
+ ************************************************************************/
+
+static void show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref);
+static void tabprintf(int tab, const char *ctl, ...);
+
+int
+cmd_show(const char *devpath)
+{
+       hammer2_blockref_t broot;
+       int fd;
+
+       fd = open(devpath, O_RDONLY);
+       if (fd < 0) {
+               perror("open");
+               return 1;
+       }
+       bzero(&broot, sizeof(broot));
+       broot.type = HAMMER2_BREF_TYPE_VOLUME;
+       broot.data_off = 0 | HAMMER2_PBUFRADIX;
+       show_bref(fd, 0, 0, &broot);
+       close(fd);
+
+       return 0;
+}
+
+static void
+show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref)
+{
+       hammer2_media_data_t media;
+       hammer2_blockref_t *bscan;
+       int bcount;
+       int i;
+       int didnl;
+       int obrace = 1;
+       size_t bytes;
+       const char *type_str;
+       char *str = NULL;
+
+       switch(bref->type) {
+       case HAMMER2_BREF_TYPE_EMPTY:
+               type_str = "empty";
+               break;
+       case HAMMER2_BREF_TYPE_INODE:
+               type_str = "inode";
+               break;
+       case HAMMER2_BREF_TYPE_INDIRECT:
+               type_str = "indblk";
+               break;
+       case HAMMER2_BREF_TYPE_DATA:
+               type_str = "data";
+               break;
+       case HAMMER2_BREF_TYPE_VOLUME:
+               type_str = "volume";
+               break;
+       default:
+               type_str = "unknown";
+               break;
+       }
+
+
+       tabprintf(tab, "%s.%-3d %016jx/%-2d mir=%016jx mod=%016jx ",
+              type_str, bi,
+              bref->key, bref->keybits,
+              bref->mirror_tid, bref->modify_tid);
+       tab += SHOW_TAB;
+
+       bytes = (size_t)1 << (bref->data_off & HAMMER2_OFF_MASK_RADIX);
+       if (bytes > sizeof(media)) {
+               printf("(bad block size %zd)\n", bytes);
+               return;
+       }
+       if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) {
+               lseek(fd, bref->data_off & ~HAMMER2_OFF_MASK_RADIX, 0);
+               if (read(fd, &media, bytes) != (ssize_t)bytes) {
+                       printf("(media read failed)\n");
+                       return;
+               }
+       }
+
+       bscan = NULL;
+       bcount = 0;
+       didnl = 0;
+
+       switch(bref->type) {
+       case HAMMER2_BREF_TYPE_EMPTY:
+               obrace = 0;
+               break;
+       case HAMMER2_BREF_TYPE_INODE:
+               printf("{\n");
+               if (media.ipdata.op_flags & HAMMER2_OPFLAG_DIRECTDATA) {
+                       /* no blockrefs */
+               } else {
+                       bscan = &media.ipdata.u.blockset.blockref[0];
+                       bcount = HAMMER2_SET_COUNT;
+               }
+               tabprintf(tab, "filename \"%s\"\n", media.ipdata.filename);
+               tabprintf(tab, "version  %d\n", media.ipdata.version);
+               tabprintf(tab, "uflags   0x%08x\n",
+                         media.ipdata.uflags);
+               if (media.ipdata.rmajor || media.ipdata.rminor) {
+                       tabprintf(tab, "rmajor   %d\n",
+                                 media.ipdata.rmajor);
+                       tabprintf(tab, "rminor   %d\n",
+                                 media.ipdata.rminor);
+               }
+               tabprintf(tab, "ctime    %s\n",
+                         hammer2_time64_to_str(media.ipdata.ctime, &str));
+               tabprintf(tab, "mtime    %s\n",
+                         hammer2_time64_to_str(media.ipdata.mtime, &str));
+               tabprintf(tab, "atime    %s\n",
+                         hammer2_time64_to_str(media.ipdata.atime, &str));
+               tabprintf(tab, "btime    %s\n",
+                         hammer2_time64_to_str(media.ipdata.btime, &str));
+               tabprintf(tab, "uid      %s\n",
+                         hammer2_uuid_to_str(&media.ipdata.uid, &str));
+               tabprintf(tab, "gid      %s\n",
+                         hammer2_uuid_to_str(&media.ipdata.gid, &str));
+               tabprintf(tab, "type     %s\n",
+                         hammer2_iptype_to_str(media.ipdata.type));
+               tabprintf(tab, "opflgs   0x%02x\n",
+                         media.ipdata.op_flags);
+               tabprintf(tab, "capflgs  0x%04x\n",
+                         media.ipdata.cap_flags);
+               tabprintf(tab, "mode     %-7o\n",
+                         media.ipdata.mode);
+               tabprintf(tab, "inum     0x%016jx\n",
+                         media.ipdata.inum);
+               tabprintf(tab, "size     %ju\n",
+                         (uintmax_t)media.ipdata.size);
+               tabprintf(tab, "nlinks   %ju\n",
+                         (uintmax_t)media.ipdata.nlinks);
+               tabprintf(tab, "iparent  0x%016jx\n",
+                         (uintmax_t)media.ipdata.iparent);
+               tabprintf(tab, "name_key 0x%016jx\n",
+                         (uintmax_t)media.ipdata.name_key);
+               tabprintf(tab, "name_len %u\n",
+                         media.ipdata.name_len);
+               tabprintf(tab, "ncopies  %u\n",
+                         media.ipdata.ncopies);
+               tabprintf(tab, "compalg  %u\n",
+                         media.ipdata.comp_algo);
+               if (media.ipdata.op_flags & HAMMER2_OPFLAG_PFSROOT) {
+                       tabprintf(tab, "pfs_type %u (%s)\n",
+                                 media.ipdata.pfs_type,
+                                 hammer2_pfstype_to_str(media.ipdata.pfs_type));
+                       tabprintf(tab, "pfs_inum 0x%016jx\n",
+                                 (uintmax_t)media.ipdata.pfs_inum);
+                       tabprintf(tab, "pfs_id   %s\n",
+                                 hammer2_uuid_to_str(&media.ipdata.pfs_id,
+                                                     &str));
+                       tabprintf(tab, "pfs_fsid %s\n",
+                                 hammer2_uuid_to_str(&media.ipdata.pfs_fsid,
+                                                     &str));
+               }
+               tabprintf(tab, "data_quota  %ju\n",
+                         (uintmax_t)media.ipdata.data_quota);
+               tabprintf(tab, "data_count  %ju\n",
+                         (uintmax_t)media.ipdata.data_count);
+               tabprintf(tab, "inode_quota %ju\n",
+                         (uintmax_t)media.ipdata.inode_quota);
+               tabprintf(tab, "inode_count %ju\n",
+                         (uintmax_t)media.ipdata.inode_count);
+               tabprintf(tab, "attr_tid    0x%016jx\n",
+                         (uintmax_t)media.ipdata.attr_tid);
+               if (media.ipdata.type == HAMMER2_OBJTYPE_DIRECTORY) {
+                       tabprintf(tab, "dirent_tid  %016jx\n",
+                                 (uintmax_t)media.ipdata.dirent_tid);
+               }
+               break;
+       case HAMMER2_BREF_TYPE_INDIRECT:
+               bscan = &media.npdata.blockref[0];
+               bcount = bytes / sizeof(hammer2_blockref_t);
+               didnl = 1;
+               printf("{\n");
+               break;
+       case HAMMER2_BREF_TYPE_DATA:
+               if (VerboseOpt >= 2) {
+                       printf("{\n");
+               } else {
+                       printf("\n");
+                       obrace = 0;
+               }
+               break;
+       case HAMMER2_BREF_TYPE_VOLUME:
+               bscan = &media.voldata.sroot_blockset.blockref[0];
+               bcount = HAMMER2_SET_COUNT;
+               printf("{\n");
+               break;
+       default:
+               break;
+       }
+       if (str)
+               free(str);
+       for (i = 0; i < bcount; ++i) {
+               if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) {
+                       if (didnl == 0) {
+                               printf("\n");
+                               didnl = 1;
+                       }
+                       show_bref(fd, tab, i, &bscan[i]);
+               }
+       }
+       tab -= SHOW_TAB;
+       if (obrace) {
+               if (bref->type == HAMMER2_BREF_TYPE_INODE)
+                       tabprintf(tab, "} (%s.%d, \"%s\")\n",
+                                 type_str, bi, media.ipdata.filename);
+               else
+                       tabprintf(tab, "} (%s.%d)\n", type_str,bi);
+       }
+}
+
+static
+void
+tabprintf(int tab, const char *ctl, ...)
+{
+       va_list va;
+
+       printf("%*.*s", tab, tab, "");
+       va_start(va, ctl);
+       vprintf(ctl, va);
+       va_end(va);
+}
index fb4344d..5b0ebc7 100644 (file)
@@ -215,7 +215,7 @@ master_link_rx(hammer2_iocom_t *iocom)
                        break;
                case HAMMER2_DBG_SHELL:
                case HAMMER2_DBG_SHELL | HAMMER2_MSGF_REPLY:
-                       hammer2_debug_remote(msg);
+                       hammer2_shell_remote(msg);
                        break;
                default:
                        hammer2_replymsg(msg, HAMMER2_MSG_ERR_UNKNOWN);
index 72fc488..e7642af 100644 (file)
@@ -80,6 +80,7 @@
 #define HAMMER2_PATH_REMOTE    HAMMER2_DEFAULT_DIR "/remote"
 
 extern int DebugOpt;
+extern int VerboseOpt;
 extern int NormalExit;
 
 int hammer2_ioctl_handle(const char *sel_path);
@@ -97,7 +98,8 @@ int cmd_pfs_delete(const char *sel_path, const char *name);
 
 int cmd_service(void);
 int cmd_leaf(const char *sel_path);
-int cmd_debug(const char *hostname);
+int cmd_shell(const char *hostname);
+int cmd_show(const char *devpath);
 int cmd_rsainit(const char *dir_path);
 int cmd_rsaenc(const char **keys, int nkeys);
 int cmd_rsadec(const char **keys, int nkeys);
@@ -133,6 +135,10 @@ int hammer2_crypto_encrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq,
 void hammer2_crypto_encrypt_wrote(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq,
                        int nact);
 
+const char *hammer2_time64_to_str(uint64_t htime64, char **strp);
+const char *hammer2_uuid_to_str(uuid_t *uuid, char **strp);
+const char *hammer2_iptype_to_str(uint8_t type);
+const char *hammer2_pfstype_to_str(uint8_t type);
 
-void hammer2_debug_remote(hammer2_msg_t *msg);
+void hammer2_shell_remote(hammer2_msg_t *msg);
 void msg_printf(hammer2_msg_t *msg, const char *ctl, ...);
index 2be4662..a43f5cd 100644 (file)
@@ -38,6 +38,7 @@
 static void usage(int code);
 
 int DebugOpt;
+int VerboseOpt;
 int NormalExit = 1;    /* if set to 0 main() has to pthread_exit() */
 
 int
@@ -57,11 +58,14 @@ main(int ac, char **av)
        /*
         * Core options
         */
-       while ((ch = getopt(ac, av, "adqs:t:u:")) != -1) {
+       while ((ch = getopt(ac, av, "adqs:t:u:v")) != -1) {
                switch(ch) {
                case 'a':
                        all_opt = 1;
                        break;
+               case 'd':
+                       DebugOpt = 1;
+                       break;
                case 'q':
                        /*
                         * Quick mode - do not block verifying certain
@@ -102,8 +106,8 @@ main(int ac, char **av)
                         */
                        uuid_str = optarg;
                        break;
-               case 'd':
-                       DebugOpt = 1;
+               case 'v':
+                       ++VerboseOpt;
                        break;
                default:
                        fprintf(stderr, "Unknown option: %c\n", ch);
@@ -147,32 +151,32 @@ main(int ac, char **av)
                 * Get status of PFS and its connections (-a for all PFSs)
                 */
                ecode = cmd_remote_status(sel_path, all_opt);
-       } else if (strcmp(av[0], "pfs_list") == 0) {
+       } else if (strcmp(av[0], "pfs-list") == 0) {
                /*
                 * List all PFSs
                 */
                ecode = cmd_pfs_list(sel_path);
-       } else if (strcmp(av[0], "pfs_create") == 0) {
+       } else if (strcmp(av[0], "pfs-create") == 0) {
                /*
                 * Create new PFS using pfs_type
                 */
                if (ac < 2) {
-                       fprintf(stderr, "pfs_create: requires name\n");
+                       fprintf(stderr, "pfs-create: requires name\n");
                        usage(1);
                }
                ecode = cmd_pfs_create(sel_path, av[1], pfs_type, uuid_str);
-       } else if (strcmp(av[0], "pfs_delete") == 0) {
+       } else if (strcmp(av[0], "pfs-delete") == 0) {
                /*
                 * Delete a PFS by name
                 */
                if (ac < 2) {
-                       fprintf(stderr, "pfs_delete: requires name\n");
+                       fprintf(stderr, "pfs-delete: requires name\n");
                        usage(1);
                }
                ecode = cmd_pfs_delete(sel_path, av[1]);
        } else if (strcmp(av[0], "snapshot") == 0) {
                /*
-                * Create snapshot with optional pfs_type and optional
+                * Create snapshot with optional pfs-type and optional
                 * label override.
                 */
        } else if (strcmp(av[0], "service") == 0) {
@@ -207,12 +211,12 @@ main(int ac, char **av)
                 * complexity of the HAMMER2 VFS kernel code.
                 */
                ecode = cmd_leaf(sel_path);
-       } else if (strcmp(av[0], "debug") == 0) {
+       } else if (strcmp(av[0], "shell") == 0) {
                /*
                 * Connect to the command line monitor in the hammer2 master
                 * node for the machine using HAMMER2_DBG_SHELL messages.
                 */
-               ecode = cmd_debug((ac < 2) ? NULL : av[1]);
+               ecode = cmd_shell((ac < 2) ? NULL : av[1]);
        } else if (strcmp(av[0], "rsainit") == 0) {
                /*
                 * Initialize a RSA keypair.  If no target directory is
@@ -258,6 +262,17 @@ main(int ac, char **av)
                } else {
                        ecode = cmd_rsadec((const char **)&av[1], ac - 1);
                }
+       } else if (strcmp(av[0], "show") == 0) {
+               /*
+                * Raw dump of filesystem.  Use -v to check all crc's, and
+                * -vv to dump bulk file data.
+                */
+               if (ac != 2) {
+                       fprintf(stderr, "show: requires device path\n");
+                       usage(1);
+               } else {
+                       cmd_show(av[1]);
+               }
        } else {
                fprintf(stderr, "Unrecognized command: %s\n", av[0]);
                usage(1);
@@ -283,6 +298,21 @@ usage(int code)
        fprintf(stderr,
                "hammer2 [-s path] command...\n"
                "    -s path            Select filesystem\n"
+               "    -t type            PFS type for pfs-create\n"
+               "    -u uuid            uuid for pfs-create\n"
+               "\n"
+               "    connect <target>   Add cluster link\n"
+               "    disconnect <target> Del cluster link\n"
+               "    status             Report cluster status\n"
+               "    pfs-list           List PFSs\n"
+               "    pfs-create <label> Create a PFS\n"
+               "    pfs-delete <label> Destroy a PFS\n"
+               "    snapshot           Snapshot a PFS\n"
+               "    service            Start service daemon\n"
+               "    leaf               Start pfs leaf daemon\n"
+               "    shell [<host>]     Connect to debug shell\n"
+               "    rsainit            Initialize rsa fields\n"
+               "    show devpath       Raw hammer2 media dump\n"
        );
        exit(code);
 }
index 23935f6..a1d526e 100644 (file)
@@ -159,3 +159,86 @@ hammer2_bswap_head(hammer2_msg_hdr_t *head)
        head->aux_bytes = bswap16(head->aux_bytes);
        head->aux_icrc  = bswap32(head->aux_icrc);
 }
+
+const char *
+hammer2_time64_to_str(uint64_t htime64, char **strp)
+{
+       struct tm *tp;
+       time_t t;
+
+       if (*strp) {
+               free(*strp);
+               *strp = NULL;
+       }
+       *strp = malloc(64);
+       t = htime64 / 1000000;
+       tp = localtime(&t);
+       strftime(*strp, 64, "%d-%b-%Y %H:%M:%S", tp);
+       return (*strp);
+}
+
+const char *
+hammer2_uuid_to_str(uuid_t *uuid, char **strp)
+{
+       uint32_t status;
+       if (*strp) {
+               free(*strp);
+               *strp = NULL;
+       }
+       uuid_to_string(uuid, strp, &status);
+       return (*strp);
+}
+
+const char *
+hammer2_iptype_to_str(uint8_t type)
+{
+       switch(type) {
+       case HAMMER2_OBJTYPE_UNKNOWN:
+               return("UNKNOWN");
+       case HAMMER2_OBJTYPE_DIRECTORY:
+               return("DIR");
+       case HAMMER2_OBJTYPE_REGFILE:
+               return("FILE");
+       case HAMMER2_OBJTYPE_FIFO:
+               return("FIFO");
+       case HAMMER2_OBJTYPE_CDEV:
+               return("CDEV");
+       case HAMMER2_OBJTYPE_BDEV:
+               return("BDEV");
+       case HAMMER2_OBJTYPE_SOFTLINK:
+               return("SOFTLINK");
+       case HAMMER2_OBJTYPE_HARDLINK:
+               return("HARDLINK");
+       case HAMMER2_OBJTYPE_SOCKET:
+               return("SOCKET");
+       case HAMMER2_OBJTYPE_WHITEOUT:
+               return("WHITEOUT");
+       default:
+               return("ILLEGAL");
+       }
+}
+
+const char *
+hammer2_pfstype_to_str(uint8_t type)
+{
+       switch(type) {
+       case HAMMER2_PFSTYPE_NONE:
+               return("NONE");
+       case HAMMER2_PFSTYPE_ADMIN:
+               return("ADMIN");
+       case HAMMER2_PFSTYPE_CACHE:
+               return("CACHE");
+       case HAMMER2_PFSTYPE_COPY:
+               return("COPY");
+       case HAMMER2_PFSTYPE_SLAVE:
+               return("SLAVE");
+       case HAMMER2_PFSTYPE_SOFT_SLAVE:
+               return("SOFT_SLAVE");
+       case HAMMER2_PFSTYPE_SOFT_MASTER:
+               return("SOFT_MASTER");
+       case HAMMER2_PFSTYPE_MASTER:
+               return("MASTER");
+       default:
+               return("ILLEGAL");
+       }
+}